From: Chris Hofstaedtler Date: Mon, 3 Sep 2018 07:55:52 +0000 (+0100) Subject: Import pdns-recursor_4.1.4.orig.tar.bz2 X-Git-Tag: archive/raspbian/4.1.11-1+rpi1~6 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=9cd5d3a3bc43e21b87cf459aa2a0ebdf7419c75d;p=pdns-recursor.git Import pdns-recursor_4.1.4.orig.tar.bz2 [dgit import orig pdns-recursor_4.1.4.orig.tar.bz2] --- 9cd5d3a3bc43e21b87cf459aa2a0ebdf7419c75d diff --git a/.version b/.version new file mode 100644 index 0000000..a95f288 --- /dev/null +++ b/.version @@ -0,0 +1 @@ +4.1.4 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..ecbc059 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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. \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..71bad3d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,433 @@ +JSON11_LIBS = $(top_srcdir)/ext/json11/libjson11.la + +AM_CPPFLAGS = $(LUA_CFLAGS) $(YAHTTP_CFLAGS) $(BOOST_CPPFLAGS) $(BOTAN_CFLAGS) $(LIBSODIUM_CFLAGS) $(NET_SNMP_CFLAGS) $(SANITIZER_FLAGS) -O3 -Wall -pthread -DSYSCONFDIR=\"${sysconfdir}\" $(SYSTEMD_CFLAGS) + +AM_CPPFLAGS += \ + -I$(top_srcdir)/ext/json11 \ + -I$(top_srcdir)/ext/rapidjson/include \ + $(YAHTTP_CFLAGS) \ + $(LIBCRYPTO_INCLUDES) + +AM_CXXFLAGS = \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DPKGLIBDIR=\"$(pkglibdir)\" \ + -DLOCALSTATEDIR=\"$(socketdir)\" + +AM_LDFLAGS = \ + $(PROGRAM_LDFLAGS) \ + $(THREADFLAGS) + +ACLOCAL_AMFLAGS = -I m4 + +BUILT_SOURCES=htmlfiles.h \ + dnslabeltext.cc + +CLEANFILES = htmlfiles.h \ + dnsmessage.pb.cc \ + dnsmessage.pb.h + +htmlfiles.h: html/* + ./incfiles > $@ + +SUBDIRS=ext + +if LUA +AM_CPPFLAGS +=$(LUA_CFLAGS) +endif + +EXTRA_DIST = \ + NOTICE \ + .version \ + botansigners.cc \ + build-aux/gen-version \ + contrib/* \ + devpollmplexer.cc \ + dnslabeltext.cc \ + dnslabeltext.rl \ + dnsmessage.proto \ + effective_tld_names.dat \ + epollmplexer.cc \ + kqueuemplexer.cc \ + lua_hpp.mk \ + malloctrace.cc malloctrace.hh \ + mkpubsuffixcc \ + mtasker.cc \ + mtasker_fcontext.cc mtasker_ucontext.cc \ + opensslsigners.hh opensslsigners.cc \ + portsmplexer.cc \ + rrd/* \ + html incfiles \ + test_libcrypto \ + pdns-recursor.service.in \ + RECURSOR-MIB.txt + +dist-hook: + for file in $$(find $(distdir)/docs -type l); do \ + t=`stat -c%N $$file | awk '{print $$NF}' | sed "s/'//g"` ; \ + ln -fs ../$$t $$file; \ + done + +sbin_PROGRAMS = pdns_recursor +bin_PROGRAMS = rec_control + +TESTS=test_libcrypto + +if UNIT_TESTS +noinst_PROGRAMS = testrunner +TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message SRCDIR='$(srcdir)' +TESTS += testrunner +else +check-local: + @echo "Unit tests are not enabled" + @echo "Run ./configure --enable-unit-tests" +endif + +pdns_recursor_SOURCES = \ + arguments.cc \ + ascii.hh \ + base32.cc base32.hh \ + base64.cc base64.hh \ + cachecleaner.hh \ + comment.hh \ + dns.hh dns.cc \ + dns_random.hh dns_random.cc \ + dnsbackend.hh \ + dnslabeltext.cc \ + dnsname.cc dnsname.hh \ + dnspacket.hh \ + dnsparser.hh dnsparser.cc \ + dnsrecords.cc dnsrecords.hh \ + dnssecinfra.hh dnssecinfra.cc \ + dnsseckeeper.hh \ + dnswriter.cc dnswriter.hh \ + ednsoptions.cc ednsoptions.hh \ + ednssubnet.cc ednssubnet.hh \ + filterpo.cc filterpo.hh \ + gettime.cc gettime.hh \ + gss_context.cc gss_context.hh \ + iputils.hh iputils.cc \ + ixfr.cc ixfr.hh \ + json.cc json.hh \ + lazy_allocator.hh \ + lock.hh \ + logger.hh logger.cc \ + lua-recursor4.cc lua-recursor4.hh \ + lua-recursor4-ffi.hh \ + lwres.cc lwres.hh \ + misc.hh misc.cc \ + mplexer.hh \ + mtasker.hh \ + mtasker_context.cc mtasker_context.hh \ + namespaces.hh \ + negcache.hh negcache.cc \ + nsecrecords.cc \ + opensslsigners.cc opensslsigners.hh \ + packetcache.hh \ + pdns_recursor.cc \ + pdnsexception.hh \ + protobuf.cc protobuf.hh \ + pubsuffix.hh pubsuffix.cc \ + qtype.hh qtype.cc \ + randomhelper.cc \ + rcpgenerator.cc rcpgenerator.hh \ + rec-carbon.cc \ + rec-lua-conf.hh rec-lua-conf.cc \ + rec-protobuf.cc rec-protobuf.hh \ + rec-snmp.hh rec-snmp.cc \ + rec_channel.cc rec_channel.hh \ + rec_channel_rec.cc \ + recpacketcache.cc recpacketcache.hh \ + recursor_cache.cc recursor_cache.hh \ + reczones.cc \ + remote_logger.cc remote_logger.hh \ + resolver.hh resolver.cc \ + resolve-context.hh \ + responsestats.hh responsestats.cc \ + root-addresses.hh \ + root-dnssec.hh \ + rpzloader.cc rpzloader.hh \ + secpoll-recursor.cc \ + secpoll-recursor.hh \ + selectmplexer.cc \ + sholder.hh \ + sillyrecords.cc \ + snmp-agent.hh snmp-agent.cc \ + sortlist.cc sortlist.hh \ + sstuff.hh \ + syncres.cc syncres.hh \ + tsigverifier.cc tsigverifier.hh \ + ueberbackend.hh \ + unix_utility.cc \ + utility.hh \ + validate.cc validate.hh validate-recursor.cc validate-recursor.hh \ + version.cc version.hh \ + webserver.cc webserver.hh \ + ws-api.cc ws-api.hh \ + ws-recursor.cc ws-recursor.hh \ + zoneparser-tng.cc zoneparser-tng.hh + +if !HAVE_LUA_HPP +BUILT_SOURCES += lua.hpp +nodist_pdns_recursor_SOURCES = lua.hpp +CLEANFILES += lua.hpp +endif + +pdns_recursor_LDADD = \ + $(YAHTTP_LIBS) \ + $(JSON11_LIBS) \ + $(LIBCRYPTO_LIBS) \ + $(BOOST_CONTEXT_LIBS) \ + $(NET_SNMP_LIBS) \ + $(SYSTEMD_LIBS) \ + $(RT_LIBS) + +pdns_recursor_LDFLAGS = $(AM_LDFLAGS) \ + $(LIBCRYPTO_LDFLAGS) $(BOOST_CONTEXT_LDFLAGS) + +testrunner_SOURCES = \ + arguments.cc \ + base32.cc \ + base64.cc base64.hh \ + dns.cc dns.hh \ + dns_random.cc dns_random.hh \ + dnslabeltext.cc \ + dnsname.cc dnsname.hh \ + dnsparser.hh dnsparser.cc \ + dnsrecords.cc \ + dnssecinfra.cc \ + dnsseckeeper.hh \ + dnswriter.cc dnswriter.hh \ + ednscookies.cc ednscookies.hh \ + ednsoptions.cc ednsoptions.hh \ + ednssubnet.cc ednssubnet.hh \ + filterpo.cc filterpo.hh \ + gettime.cc gettime.hh \ + gss_context.cc gss_context.hh \ + iputils.cc iputils.hh \ + ixfr.cc ixfr.hh \ + logger.cc logger.hh \ + misc.cc misc.hh \ + mtasker_context.cc \ + negcache.hh negcache.cc \ + namespaces.hh \ + nsecrecords.cc \ + pdnsexception.hh \ + opensslsigners.cc opensslsigners.hh \ + protobuf.cc protobuf.hh \ + qtype.cc qtype.hh \ + randomhelper.cc \ + rcpgenerator.cc \ + rec-protobuf.cc rec-protobuf.hh \ + recpacketcache.cc recpacketcache.hh \ + recursor_cache.cc recursor_cache.hh \ + responsestats.cc \ + root-dnssec.hh \ + sillyrecords.cc \ + sholder.hh \ + sstuff.hh \ + syncres.cc syncres.hh \ + test-arguments_cc.cc \ + test-base32_cc.cc \ + test-base64_cc.cc \ + test-common.hh \ + test-dnsrecordcontent.cc \ + test-dns_random_hh.cc \ + test-dnsname_cc.cc \ + test-dnsparser_hh.cc \ + test-dnsrecords_cc.cc \ + test-ednsoptions_cc.cc \ + test-iputils_hh.cc \ + test-ixfr_cc.cc \ + test-misc_hh.cc \ + test-mtasker.cc \ + test-nmtree.cc \ + test-negcache_cc.cc \ + test-rcpgenerator_cc.cc \ + test-recpacketcache_cc.cc \ + test-recursorcache_cc.cc \ + test-signers.cc \ + test-syncres_cc.cc \ + test-tsig.cc \ + testrunner.cc \ + tsigverifier.cc tsigverifier.hh \ + unix_utility.cc \ + validate.cc validate.hh \ + validate-recursor.cc validate-recursor.hh \ + zoneparser-tng.cc zoneparser-tng.hh + +testrunner_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(BOOST_CONTEXT_LDFLAGS) \ + $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) \ + $(LIBCRYPTO_LDFLAGS) + +testrunner_LDADD = \ + $(BOOST_CONTEXT_LIBS) \ + $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \ + $(LIBCRYPTO_LIBS) \ + $(RT_LIBS) + +if BOTAN +pdns_recursor_SOURCES += \ + botansigners.cc +pdns_recursor_LDADD += $(BOTAN_LIBS) +testrunner_SOURCES += \ + botansigners.cc +testrunner_LDADD += $(BOTAN_LIBS) +endif + +if LIBSODIUM +pdns_recursor_SOURCES += \ + sodiumsigners.cc +pdns_recursor_LDADD += $(LIBSODIUM_LIBS) +testrunner_SOURCES += \ + sodiumsigners.cc +testrunner_LDADD += $(LIBSODIUM_LIBS) +endif + +if LIBDECAF +pdns_recursor_SOURCES += \ + decafsigners.cc +pdns_recursor_LDADD += $(LIBDECAF_LIBS) +endif + +if MALLOC_TRACE +pdns_recursor_SOURCES += \ + malloctrace.cc \ + malloctrace.hh +pdns_recursor_LDFLAGS += -rdynamic +endif + +if LUA +pdns_recursor_LDADD += $(LUA_LIBS) +endif + +if HAVE_FREEBSD +pdns_recursor_SOURCES += kqueuemplexer.cc +endif + +if HAVE_LINUX +pdns_recursor_SOURCES += epollmplexer.cc +endif + +if HAVE_SOLARIS +pdns_recursor_SOURCES += \ + devpollmplexer.cc \ + portsmplexer.cc +endif + +if HAVE_PROTOBUF +if HAVE_PROTOC +dnsmessage.pb.cc: dnsmessage.proto + $(AM_V_GEN)$(PROTOC) --cpp_out=./ $< + +BUILT_SOURCES += dnsmessage.pb.cc +pdns_recursor_LDADD += $(PROTOBUF_LIBS) +nodist_pdns_recursor_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h +pdns_recursor.$(OBJEXT): dnsmessage.pb.cc + +nodist_testrunner_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h +testrunner_LDADD += $(PROTOBUF_LIBS) +testrunner$(OBJEXT): dnsmessage.pb.cc + +endif +endif + +rec_control_SOURCES = \ + arguments.cc arguments.hh \ + dnsname.hh dnsname.cc \ + dnslabeltext.cc \ + logger.cc \ + misc.cc \ + qtype.cc \ + rec_channel.cc rec_channel.hh \ + rec_control.cc \ + unix_utility.cc + +dnslabeltext.cc: dnslabeltext.rl + $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc + +curl_verbose = $(curl_verbose_$(V)) +curl_verbose_ = $(curl_verbose_$(AM_DEFAULT_VERBOSITY)) +curl_verbose_0 = @echo " CURL " $@; +$(srcdir)/effective_tld_names.dat: + $(curl_verbose)if ! curl -s -S https://publicsuffix.org/list/public_suffix_list.dat > $@; then rm -f $@; exit 1; fi + +pubsuffix.cc: $(srcdir)/effective_tld_names.dat + $(AM_V_GEN)./mkpubsuffixcc + +## Config file +sysconf_DATA = recursor.conf-dist + +recursor.conf-dist: pdns_recursor + $(AM_V_GEN)./pdns_recursor --config > $@ + +## Manpages +MANPAGES=pdns_recursor.1 \ + rec_control.1 + +dist_man_MANS=$(MANPAGES) + +if HAVE_VIRTUALENV +if !HAVE_MANPAGES +$(MANPAGES): %.1: docs/manpages/%.rst .venv + .venv/bin/python -msphinx -b man docs . $< +endif # if !HAVE_MANPAGES + +.venv: docs/requirements.txt + virtualenv .venv + .venv/bin/pip install -U pip setuptools setuptools-git + .venv/bin/pip install -r docs/requirements.txt + +html-docs: docs/** .venv + .venv/bin/python -msphinx -b html docs html-docs + +latex/PowerDNS-Recursor.pdf: docs/** .venv + .venv/bin/python -msphinx -M latexpdf docs . + +PowerDNS-Recursor.pdf: latex/PowerDNS-Recursor.pdf + mv $< $@ + +html-docs.tar.bz2: html-docs + tar cjf $@ $< + +all-docs: PowerDNS-Recursor.pdf html-docs html-docs.tar.bz2 + +upload-docs: all-docs + rsync -crv --delete --no-p --chmod=g=rwX --exclude '*~' ./html-docs/ web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/ + rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html-docs.tar.bz2 web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/ + rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./PowerDNS-Recursor.pdf web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/ + +else # if HAVE_VIRTUALENV +$(MANPAGES): + echo "You need virtualenv to generate the manpages" + exit 1 + +PowerDNS-Recursor.pdf: + echo "You need virtualenv to generate the PDF" + exit 1 + +html-docs: + echo "You need virtualenv to generate the HTML docs" + exit 1 +endif + +if HAVE_SYSTEMD +pdns-recursor.service: pdns-recursor.service.in + $(AM_V_GEN)sed -e 's![@]sbindir[@]!$(sbindir)!' < $< > $@ + +pdns-recursor@.service: pdns-recursor.service + $(AM_V_GEN)sed -e 's!/pdns_recursor!& --config-name=%i!' \ + -e 's!Recursor!& %i!' \ + < $< > $@ + +systemdsystemunitdir = $(SYSTEMD_DIR) + +systemdsystemunit_DATA = \ + pdns-recursor.service \ + pdns-recursor@.service +endif + +if !HAVE_LUA_HPP +include lua_hpp.mk +endif diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..81fe2e3 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,2132 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 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@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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@ +@LUA_TRUE@am__append_1 = $(LUA_CFLAGS) +sbin_PROGRAMS = pdns_recursor$(EXEEXT) +bin_PROGRAMS = rec_control$(EXEEXT) +TESTS = test_libcrypto $(am__EXEEXT_1) +@UNIT_TESTS_TRUE@noinst_PROGRAMS = testrunner$(EXEEXT) +@UNIT_TESTS_TRUE@am__append_2 = testrunner +@HAVE_LUA_HPP_FALSE@am__append_3 = lua.hpp +@HAVE_LUA_HPP_FALSE@am__append_4 = lua.hpp +@BOTAN_TRUE@am__append_5 = \ +@BOTAN_TRUE@ botansigners.cc + +@BOTAN_TRUE@am__append_6 = $(BOTAN_LIBS) +@BOTAN_TRUE@am__append_7 = \ +@BOTAN_TRUE@ botansigners.cc + +@BOTAN_TRUE@am__append_8 = $(BOTAN_LIBS) +@LIBSODIUM_TRUE@am__append_9 = \ +@LIBSODIUM_TRUE@ sodiumsigners.cc + +@LIBSODIUM_TRUE@am__append_10 = $(LIBSODIUM_LIBS) +@LIBSODIUM_TRUE@am__append_11 = \ +@LIBSODIUM_TRUE@ sodiumsigners.cc + +@LIBSODIUM_TRUE@am__append_12 = $(LIBSODIUM_LIBS) +@LIBDECAF_TRUE@am__append_13 = \ +@LIBDECAF_TRUE@ decafsigners.cc + +@LIBDECAF_TRUE@am__append_14 = $(LIBDECAF_LIBS) +@MALLOC_TRACE_TRUE@am__append_15 = \ +@MALLOC_TRACE_TRUE@ malloctrace.cc \ +@MALLOC_TRACE_TRUE@ malloctrace.hh + +@MALLOC_TRACE_TRUE@am__append_16 = -rdynamic +@LUA_TRUE@am__append_17 = $(LUA_LIBS) +@HAVE_FREEBSD_TRUE@am__append_18 = kqueuemplexer.cc +@HAVE_LINUX_TRUE@am__append_19 = epollmplexer.cc +@HAVE_SOLARIS_TRUE@am__append_20 = \ +@HAVE_SOLARIS_TRUE@ devpollmplexer.cc \ +@HAVE_SOLARIS_TRUE@ portsmplexer.cc + +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__append_21 = dnsmessage.pb.cc +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__append_22 = $(PROTOBUF_LIBS) +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__append_23 = $(PROTOBUF_LIBS) +DIST_COMMON = $(srcdir)/lua_hpp.mk $(srcdir)/Makefile.in \ + $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(srcdir)/config.h.in \ + $(top_srcdir)/build-aux/depcomp $(dist_man_MANS) \ + $(top_srcdir)/build-aux/test-driver COPYING README \ + build-aux/compile build-aux/config.guess build-aux/config.sub \ + build-aux/depcomp build-aux/install-sh build-aux/missing \ + build-aux/ltmain.sh $(top_srcdir)/build-aux/compile \ + $(top_srcdir)/build-aux/config.guess \ + $(top_srcdir)/build-aux/config.sub \ + $(top_srcdir)/build-aux/install-sh \ + $(top_srcdir)/build-aux/ltmain.sh \ + $(top_srcdir)/build-aux/missing +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/m4/boost.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)/m4/pdns_check_clock_gettime.m4 \ + $(top_srcdir)/m4/pdns_check_curl.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ + $(top_srcdir)/m4/pdns_check_libdecaf.m4 \ + $(top_srcdir)/m4/pdns_check_libsodium.m4 \ + $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ + $(top_srcdir)/m4/pdns_check_network_libs.m4 \ + $(top_srcdir)/m4/pdns_check_os.m4 \ + $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ + $(top_srcdir)/m4/pdns_check_ragel.m4 \ + $(top_srcdir)/m4/pdns_check_virtualenv.m4 \ + $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ + $(top_srcdir)/m4/pdns_enable_botan.m4 \ + $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ + $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ + $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ + $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ + $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ + $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ + $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ + $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ + $(top_srcdir)/m4/pdns_stack_protector.m4 \ + $(top_srcdir)/m4/pdns_with_lua.m4 \ + $(top_srcdir)/m4/pdns_with_luajit.m4 \ + $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ + $(top_srcdir)/m4/pdns_with_protobuf.m4 \ + $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.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 = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ + "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(sysconfdir)" \ + "$(DESTDIR)$(systemdsystemunitdir)" +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) $(sbin_PROGRAMS) +am__pdns_recursor_SOURCES_DIST = arguments.cc ascii.hh base32.cc \ + base32.hh base64.cc base64.hh cachecleaner.hh comment.hh \ + dns.hh dns.cc dns_random.hh dns_random.cc dnsbackend.hh \ + dnslabeltext.cc dnsname.cc dnsname.hh dnspacket.hh \ + dnsparser.hh dnsparser.cc dnsrecords.cc dnsrecords.hh \ + dnssecinfra.hh dnssecinfra.cc dnsseckeeper.hh dnswriter.cc \ + dnswriter.hh ednsoptions.cc ednsoptions.hh ednssubnet.cc \ + ednssubnet.hh filterpo.cc filterpo.hh gettime.cc gettime.hh \ + gss_context.cc gss_context.hh iputils.hh iputils.cc ixfr.cc \ + ixfr.hh json.cc json.hh lazy_allocator.hh lock.hh logger.hh \ + logger.cc lua-recursor4.cc lua-recursor4.hh \ + lua-recursor4-ffi.hh lwres.cc lwres.hh misc.hh misc.cc \ + mplexer.hh mtasker.hh mtasker_context.cc mtasker_context.hh \ + namespaces.hh negcache.hh negcache.cc nsecrecords.cc \ + opensslsigners.cc opensslsigners.hh packetcache.hh \ + pdns_recursor.cc pdnsexception.hh protobuf.cc protobuf.hh \ + pubsuffix.hh pubsuffix.cc qtype.hh qtype.cc randomhelper.cc \ + rcpgenerator.cc rcpgenerator.hh rec-carbon.cc rec-lua-conf.hh \ + rec-lua-conf.cc rec-protobuf.cc rec-protobuf.hh rec-snmp.hh \ + rec-snmp.cc rec_channel.cc rec_channel.hh rec_channel_rec.cc \ + recpacketcache.cc recpacketcache.hh recursor_cache.cc \ + recursor_cache.hh reczones.cc remote_logger.cc \ + remote_logger.hh resolver.hh resolver.cc resolve-context.hh \ + responsestats.hh responsestats.cc root-addresses.hh \ + root-dnssec.hh rpzloader.cc rpzloader.hh secpoll-recursor.cc \ + secpoll-recursor.hh selectmplexer.cc sholder.hh \ + sillyrecords.cc snmp-agent.hh snmp-agent.cc sortlist.cc \ + sortlist.hh sstuff.hh syncres.cc syncres.hh tsigverifier.cc \ + tsigverifier.hh ueberbackend.hh unix_utility.cc utility.hh \ + validate.cc validate.hh validate-recursor.cc \ + validate-recursor.hh version.cc version.hh webserver.cc \ + webserver.hh ws-api.cc ws-api.hh ws-recursor.cc ws-recursor.hh \ + zoneparser-tng.cc zoneparser-tng.hh botansigners.cc \ + sodiumsigners.cc decafsigners.cc malloctrace.cc malloctrace.hh \ + kqueuemplexer.cc epollmplexer.cc devpollmplexer.cc \ + portsmplexer.cc +@BOTAN_TRUE@am__objects_1 = botansigners.$(OBJEXT) +@LIBSODIUM_TRUE@am__objects_2 = sodiumsigners.$(OBJEXT) +@LIBDECAF_TRUE@am__objects_3 = decafsigners.$(OBJEXT) +@MALLOC_TRACE_TRUE@am__objects_4 = malloctrace.$(OBJEXT) +@HAVE_FREEBSD_TRUE@am__objects_5 = kqueuemplexer.$(OBJEXT) +@HAVE_LINUX_TRUE@am__objects_6 = epollmplexer.$(OBJEXT) +@HAVE_SOLARIS_TRUE@am__objects_7 = devpollmplexer.$(OBJEXT) \ +@HAVE_SOLARIS_TRUE@ portsmplexer.$(OBJEXT) +am_pdns_recursor_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \ + base64.$(OBJEXT) dns.$(OBJEXT) dns_random.$(OBJEXT) \ + dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \ + dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) dnswriter.$(OBJEXT) \ + ednsoptions.$(OBJEXT) ednssubnet.$(OBJEXT) filterpo.$(OBJEXT) \ + gettime.$(OBJEXT) gss_context.$(OBJEXT) iputils.$(OBJEXT) \ + ixfr.$(OBJEXT) json.$(OBJEXT) logger.$(OBJEXT) \ + lua-recursor4.$(OBJEXT) lwres.$(OBJEXT) misc.$(OBJEXT) \ + mtasker_context.$(OBJEXT) negcache.$(OBJEXT) \ + nsecrecords.$(OBJEXT) opensslsigners.$(OBJEXT) \ + pdns_recursor.$(OBJEXT) protobuf.$(OBJEXT) pubsuffix.$(OBJEXT) \ + qtype.$(OBJEXT) randomhelper.$(OBJEXT) rcpgenerator.$(OBJEXT) \ + rec-carbon.$(OBJEXT) rec-lua-conf.$(OBJEXT) \ + rec-protobuf.$(OBJEXT) rec-snmp.$(OBJEXT) \ + rec_channel.$(OBJEXT) rec_channel_rec.$(OBJEXT) \ + recpacketcache.$(OBJEXT) recursor_cache.$(OBJEXT) \ + reczones.$(OBJEXT) remote_logger.$(OBJEXT) resolver.$(OBJEXT) \ + responsestats.$(OBJEXT) rpzloader.$(OBJEXT) \ + secpoll-recursor.$(OBJEXT) selectmplexer.$(OBJEXT) \ + sillyrecords.$(OBJEXT) snmp-agent.$(OBJEXT) sortlist.$(OBJEXT) \ + syncres.$(OBJEXT) tsigverifier.$(OBJEXT) \ + unix_utility.$(OBJEXT) validate.$(OBJEXT) \ + validate-recursor.$(OBJEXT) version.$(OBJEXT) \ + webserver.$(OBJEXT) ws-api.$(OBJEXT) ws-recursor.$(OBJEXT) \ + zoneparser-tng.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + $(am__objects_6) $(am__objects_7) +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_pdns_recursor_OBJECTS = \ +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsmessage.pb.$(OBJEXT) +pdns_recursor_OBJECTS = $(am_pdns_recursor_OBJECTS) \ + $(nodist_pdns_recursor_OBJECTS) +am__DEPENDENCIES_1 = +@BOTAN_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) +@LIBSODIUM_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) +@LIBDECAF_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) +@LUA_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1) +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__DEPENDENCIES_6 = \ +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(am__DEPENDENCIES_1) +pdns_recursor_DEPENDENCIES = $(am__DEPENDENCIES_1) $(JSON11_LIBS) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) \ + $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +pdns_recursor_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(pdns_recursor_LDFLAGS) $(LDFLAGS) \ + -o $@ +am_rec_control_OBJECTS = arguments.$(OBJEXT) dnsname.$(OBJEXT) \ + dnslabeltext.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \ + qtype.$(OBJEXT) rec_channel.$(OBJEXT) rec_control.$(OBJEXT) \ + unix_utility.$(OBJEXT) +rec_control_OBJECTS = $(am_rec_control_OBJECTS) +rec_control_LDADD = $(LDADD) +am__testrunner_SOURCES_DIST = arguments.cc base32.cc base64.cc \ + base64.hh dns.cc dns.hh dns_random.cc dns_random.hh \ + dnslabeltext.cc dnsname.cc dnsname.hh dnsparser.hh \ + dnsparser.cc dnsrecords.cc dnssecinfra.cc dnsseckeeper.hh \ + dnswriter.cc dnswriter.hh ednscookies.cc ednscookies.hh \ + ednsoptions.cc ednsoptions.hh ednssubnet.cc ednssubnet.hh \ + filterpo.cc filterpo.hh gettime.cc gettime.hh gss_context.cc \ + gss_context.hh iputils.cc iputils.hh ixfr.cc ixfr.hh logger.cc \ + logger.hh misc.cc misc.hh mtasker_context.cc negcache.hh \ + negcache.cc namespaces.hh nsecrecords.cc pdnsexception.hh \ + opensslsigners.cc opensslsigners.hh protobuf.cc protobuf.hh \ + qtype.cc qtype.hh randomhelper.cc rcpgenerator.cc \ + rec-protobuf.cc rec-protobuf.hh recpacketcache.cc \ + recpacketcache.hh recursor_cache.cc recursor_cache.hh \ + responsestats.cc root-dnssec.hh sillyrecords.cc sholder.hh \ + sstuff.hh syncres.cc syncres.hh test-arguments_cc.cc \ + test-base32_cc.cc test-base64_cc.cc test-common.hh \ + test-dnsrecordcontent.cc test-dns_random_hh.cc \ + test-dnsname_cc.cc test-dnsparser_hh.cc test-dnsrecords_cc.cc \ + test-ednsoptions_cc.cc test-iputils_hh.cc test-ixfr_cc.cc \ + test-misc_hh.cc test-mtasker.cc test-nmtree.cc \ + test-negcache_cc.cc test-rcpgenerator_cc.cc \ + test-recpacketcache_cc.cc test-recursorcache_cc.cc \ + test-signers.cc test-syncres_cc.cc test-tsig.cc testrunner.cc \ + tsigverifier.cc tsigverifier.hh unix_utility.cc validate.cc \ + validate.hh validate-recursor.cc validate-recursor.hh \ + zoneparser-tng.cc zoneparser-tng.hh botansigners.cc \ + sodiumsigners.cc +am_testrunner_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \ + base64.$(OBJEXT) dns.$(OBJEXT) dns_random.$(OBJEXT) \ + dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \ + dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) dnswriter.$(OBJEXT) \ + ednscookies.$(OBJEXT) ednsoptions.$(OBJEXT) \ + ednssubnet.$(OBJEXT) filterpo.$(OBJEXT) gettime.$(OBJEXT) \ + gss_context.$(OBJEXT) iputils.$(OBJEXT) ixfr.$(OBJEXT) \ + logger.$(OBJEXT) misc.$(OBJEXT) mtasker_context.$(OBJEXT) \ + negcache.$(OBJEXT) nsecrecords.$(OBJEXT) \ + opensslsigners.$(OBJEXT) protobuf.$(OBJEXT) qtype.$(OBJEXT) \ + randomhelper.$(OBJEXT) rcpgenerator.$(OBJEXT) \ + rec-protobuf.$(OBJEXT) recpacketcache.$(OBJEXT) \ + recursor_cache.$(OBJEXT) responsestats.$(OBJEXT) \ + sillyrecords.$(OBJEXT) syncres.$(OBJEXT) \ + test-arguments_cc.$(OBJEXT) test-base32_cc.$(OBJEXT) \ + test-base64_cc.$(OBJEXT) test-dnsrecordcontent.$(OBJEXT) \ + test-dns_random_hh.$(OBJEXT) test-dnsname_cc.$(OBJEXT) \ + test-dnsparser_hh.$(OBJEXT) test-dnsrecords_cc.$(OBJEXT) \ + test-ednsoptions_cc.$(OBJEXT) test-iputils_hh.$(OBJEXT) \ + test-ixfr_cc.$(OBJEXT) test-misc_hh.$(OBJEXT) \ + test-mtasker.$(OBJEXT) test-nmtree.$(OBJEXT) \ + test-negcache_cc.$(OBJEXT) test-rcpgenerator_cc.$(OBJEXT) \ + test-recpacketcache_cc.$(OBJEXT) \ + test-recursorcache_cc.$(OBJEXT) test-signers.$(OBJEXT) \ + test-syncres_cc.$(OBJEXT) test-tsig.$(OBJEXT) \ + testrunner.$(OBJEXT) tsigverifier.$(OBJEXT) \ + unix_utility.$(OBJEXT) validate.$(OBJEXT) \ + validate-recursor.$(OBJEXT) zoneparser-tng.$(OBJEXT) \ + $(am__objects_1) $(am__objects_2) +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_testrunner_OBJECTS = \ +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsmessage.pb.$(OBJEXT) +testrunner_OBJECTS = $(am_testrunner_OBJECTS) \ + $(nodist_testrunner_OBJECTS) +testrunner_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \ + $(am__DEPENDENCIES_6) +testrunner_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(testrunner_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(pdns_recursor_SOURCES) $(nodist_pdns_recursor_SOURCES) \ + $(rec_control_SOURCES) $(testrunner_SOURCES) \ + $(nodist_testrunner_SOURCES) +DIST_SOURCES = $(am__pdns_recursor_SOURCES_DIST) \ + $(rec_control_SOURCES) $(am__testrunner_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man_MANS) +DATA = $(sysconf_DATA) $(systemdsystemunit_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope check recheck distdir dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +@UNIT_TESTS_TRUE@am__EXEEXT_1 = testrunner$(EXEEXT) +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_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" +GZIP_ENV = --best +DIST_ARCHIVES = $(distdir).tar.bz2 +DIST_TARGETS = dist-bzip2 +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = $(LUA_CFLAGS) $(YAHTTP_CFLAGS) $(BOOST_CPPFLAGS) \ + $(BOTAN_CFLAGS) $(LIBSODIUM_CFLAGS) $(NET_SNMP_CFLAGS) \ + $(SANITIZER_FLAGS) -O3 -Wall -pthread \ + -DSYSCONFDIR=\"${sysconfdir}\" $(SYSTEMD_CFLAGS) \ + -I$(top_srcdir)/ext/json11 \ + -I$(top_srcdir)/ext/rapidjson/include $(YAHTTP_CFLAGS) \ + $(LIBCRYPTO_INCLUDES) $(am__append_1) +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ +BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ +BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_LDPATH = @BOOST_LDPATH@ +BOOST_ROOT = @BOOST_ROOT@ +BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ +BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ +BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ +BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ +BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ +BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ +BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ +BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ +BOTAN_CFLAGS = @BOTAN_CFLAGS@ +BOTAN_LIBS = @BOTAN_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CURL = @CURL@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DYNLINKFLAGS = @DYNLINKFLAGS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ +LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBDECAF_LIBS = @LIBDECAF_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NET_SNMP_CFLAGS = @NET_SNMP_CFLAGS@ +NET_SNMP_LIBS = @NET_SNMP_LIBS@ +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@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ +PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@ +PROTOBUF_LIBS = @PROTOBUF_LIBS@ +PROTOC = @PROTOC@ +RAGEL = @RAGEL@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RT_LIBS = @RT_LIBS@ +SANITIZER_FLAGS = @SANITIZER_FLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ +THREADFLAGS = @THREADFLAGS@ +VERSION = @VERSION@ +VIRTUALENV = @VIRTUALENV@ +WARN_CFLAGS = @WARN_CFLAGS@ +YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ +YAHTTP_LIBS = @YAHTTP_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +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@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pdns_configure_args = @pdns_configure_args@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +socketdir = @socketdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemd = @systemd@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +JSON11_LIBS = $(top_srcdir)/ext/json11/libjson11.la +AM_CXXFLAGS = \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DPKGLIBDIR=\"$(pkglibdir)\" \ + -DLOCALSTATEDIR=\"$(socketdir)\" + +AM_LDFLAGS = \ + $(PROGRAM_LDFLAGS) \ + $(THREADFLAGS) + +ACLOCAL_AMFLAGS = -I m4 +BUILT_SOURCES = htmlfiles.h dnslabeltext.cc $(am__append_3) \ + $(am__append_21) +CLEANFILES = htmlfiles.h dnsmessage.pb.cc dnsmessage.pb.h \ + $(am__append_4) +SUBDIRS = ext +EXTRA_DIST = \ + NOTICE \ + .version \ + botansigners.cc \ + build-aux/gen-version \ + contrib/* \ + devpollmplexer.cc \ + dnslabeltext.cc \ + dnslabeltext.rl \ + dnsmessage.proto \ + effective_tld_names.dat \ + epollmplexer.cc \ + kqueuemplexer.cc \ + lua_hpp.mk \ + malloctrace.cc malloctrace.hh \ + mkpubsuffixcc \ + mtasker.cc \ + mtasker_fcontext.cc mtasker_ucontext.cc \ + opensslsigners.hh opensslsigners.cc \ + portsmplexer.cc \ + rrd/* \ + html incfiles \ + test_libcrypto \ + pdns-recursor.service.in \ + RECURSOR-MIB.txt + +@UNIT_TESTS_TRUE@TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message SRCDIR='$(srcdir)' +pdns_recursor_SOURCES = arguments.cc ascii.hh base32.cc base32.hh \ + base64.cc base64.hh cachecleaner.hh comment.hh dns.hh dns.cc \ + dns_random.hh dns_random.cc dnsbackend.hh dnslabeltext.cc \ + dnsname.cc dnsname.hh dnspacket.hh dnsparser.hh dnsparser.cc \ + dnsrecords.cc dnsrecords.hh dnssecinfra.hh dnssecinfra.cc \ + dnsseckeeper.hh dnswriter.cc dnswriter.hh ednsoptions.cc \ + ednsoptions.hh ednssubnet.cc ednssubnet.hh filterpo.cc \ + filterpo.hh gettime.cc gettime.hh gss_context.cc \ + gss_context.hh iputils.hh iputils.cc ixfr.cc ixfr.hh json.cc \ + json.hh lazy_allocator.hh lock.hh logger.hh logger.cc \ + lua-recursor4.cc lua-recursor4.hh lua-recursor4-ffi.hh \ + lwres.cc lwres.hh misc.hh misc.cc mplexer.hh mtasker.hh \ + mtasker_context.cc mtasker_context.hh namespaces.hh \ + negcache.hh negcache.cc nsecrecords.cc opensslsigners.cc \ + opensslsigners.hh packetcache.hh pdns_recursor.cc \ + pdnsexception.hh protobuf.cc protobuf.hh pubsuffix.hh \ + pubsuffix.cc qtype.hh qtype.cc randomhelper.cc rcpgenerator.cc \ + rcpgenerator.hh rec-carbon.cc rec-lua-conf.hh rec-lua-conf.cc \ + rec-protobuf.cc rec-protobuf.hh rec-snmp.hh rec-snmp.cc \ + rec_channel.cc rec_channel.hh rec_channel_rec.cc \ + recpacketcache.cc recpacketcache.hh recursor_cache.cc \ + recursor_cache.hh reczones.cc remote_logger.cc \ + remote_logger.hh resolver.hh resolver.cc resolve-context.hh \ + responsestats.hh responsestats.cc root-addresses.hh \ + root-dnssec.hh rpzloader.cc rpzloader.hh secpoll-recursor.cc \ + secpoll-recursor.hh selectmplexer.cc sholder.hh \ + sillyrecords.cc snmp-agent.hh snmp-agent.cc sortlist.cc \ + sortlist.hh sstuff.hh syncres.cc syncres.hh tsigverifier.cc \ + tsigverifier.hh ueberbackend.hh unix_utility.cc utility.hh \ + validate.cc validate.hh validate-recursor.cc \ + validate-recursor.hh version.cc version.hh webserver.cc \ + webserver.hh ws-api.cc ws-api.hh ws-recursor.cc ws-recursor.hh \ + zoneparser-tng.cc zoneparser-tng.hh $(am__append_5) \ + $(am__append_9) $(am__append_13) $(am__append_15) \ + $(am__append_18) $(am__append_19) $(am__append_20) +@HAVE_LUA_HPP_FALSE@nodist_pdns_recursor_SOURCES = lua.hpp +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_pdns_recursor_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h +pdns_recursor_LDADD = $(YAHTTP_LIBS) $(JSON11_LIBS) $(LIBCRYPTO_LIBS) \ + $(BOOST_CONTEXT_LIBS) $(NET_SNMP_LIBS) $(SYSTEMD_LIBS) \ + $(RT_LIBS) $(am__append_6) $(am__append_10) $(am__append_14) \ + $(am__append_17) $(am__append_22) +pdns_recursor_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS) \ + $(BOOST_CONTEXT_LDFLAGS) $(am__append_16) +testrunner_SOURCES = arguments.cc base32.cc base64.cc base64.hh dns.cc \ + dns.hh dns_random.cc dns_random.hh dnslabeltext.cc dnsname.cc \ + dnsname.hh dnsparser.hh dnsparser.cc dnsrecords.cc \ + dnssecinfra.cc dnsseckeeper.hh dnswriter.cc dnswriter.hh \ + ednscookies.cc ednscookies.hh ednsoptions.cc ednsoptions.hh \ + ednssubnet.cc ednssubnet.hh filterpo.cc filterpo.hh gettime.cc \ + gettime.hh gss_context.cc gss_context.hh iputils.cc iputils.hh \ + ixfr.cc ixfr.hh logger.cc logger.hh misc.cc misc.hh \ + mtasker_context.cc negcache.hh negcache.cc namespaces.hh \ + nsecrecords.cc pdnsexception.hh opensslsigners.cc \ + opensslsigners.hh protobuf.cc protobuf.hh qtype.cc qtype.hh \ + randomhelper.cc rcpgenerator.cc rec-protobuf.cc \ + rec-protobuf.hh recpacketcache.cc recpacketcache.hh \ + recursor_cache.cc recursor_cache.hh responsestats.cc \ + root-dnssec.hh sillyrecords.cc sholder.hh sstuff.hh syncres.cc \ + syncres.hh test-arguments_cc.cc test-base32_cc.cc \ + test-base64_cc.cc test-common.hh test-dnsrecordcontent.cc \ + test-dns_random_hh.cc test-dnsname_cc.cc test-dnsparser_hh.cc \ + test-dnsrecords_cc.cc test-ednsoptions_cc.cc \ + test-iputils_hh.cc test-ixfr_cc.cc test-misc_hh.cc \ + test-mtasker.cc test-nmtree.cc test-negcache_cc.cc \ + test-rcpgenerator_cc.cc test-recpacketcache_cc.cc \ + test-recursorcache_cc.cc test-signers.cc test-syncres_cc.cc \ + test-tsig.cc testrunner.cc tsigverifier.cc tsigverifier.hh \ + unix_utility.cc validate.cc validate.hh validate-recursor.cc \ + validate-recursor.hh zoneparser-tng.cc zoneparser-tng.hh \ + $(am__append_7) $(am__append_11) +testrunner_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(BOOST_CONTEXT_LDFLAGS) \ + $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) \ + $(LIBCRYPTO_LDFLAGS) + +testrunner_LDADD = $(BOOST_CONTEXT_LIBS) \ + $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) $(LIBCRYPTO_LIBS) $(RT_LIBS) \ + $(am__append_8) $(am__append_12) $(am__append_23) +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_testrunner_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h +rec_control_SOURCES = \ + arguments.cc arguments.hh \ + dnsname.hh dnsname.cc \ + dnslabeltext.cc \ + logger.cc \ + misc.cc \ + qtype.cc \ + rec_channel.cc rec_channel.hh \ + rec_control.cc \ + unix_utility.cc + +curl_verbose = $(curl_verbose_$(V)) +curl_verbose_ = $(curl_verbose_$(AM_DEFAULT_VERBOSITY)) +curl_verbose_0 = @echo " CURL " $@; +sysconf_DATA = recursor.conf-dist +MANPAGES = pdns_recursor.1 \ + rec_control.1 + +dist_man_MANS = $(MANPAGES) +@HAVE_SYSTEMD_TRUE@systemdsystemunitdir = $(SYSTEMD_DIR) +@HAVE_SYSTEMD_TRUE@systemdsystemunit_DATA = \ +@HAVE_SYSTEMD_TRUE@ pdns-recursor.service \ +@HAVE_SYSTEMD_TRUE@ pdns-recursor@.service + +all: $(BUILT_SOURCES) config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .log .o .obj .test .test$(EXEEXT) .trs +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/lua_hpp.mk $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign 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; +$(srcdir)/lua_hpp.mk: + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + 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)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || 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)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_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 + +clean-noinstPROGRAMS: + @list='$(noinst_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) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ + fi; \ + 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 + +pdns_recursor$(EXEEXT): $(pdns_recursor_OBJECTS) $(pdns_recursor_DEPENDENCIES) $(EXTRA_pdns_recursor_DEPENDENCIES) + @rm -f pdns_recursor$(EXEEXT) + $(AM_V_CXXLD)$(pdns_recursor_LINK) $(pdns_recursor_OBJECTS) $(pdns_recursor_LDADD) $(LIBS) + +rec_control$(EXEEXT): $(rec_control_OBJECTS) $(rec_control_DEPENDENCIES) $(EXTRA_rec_control_DEPENDENCIES) + @rm -f rec_control$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(rec_control_OBJECTS) $(rec_control_LDADD) $(LIBS) + +testrunner$(EXEEXT): $(testrunner_OBJECTS) $(testrunner_DEPENDENCIES) $(EXTRA_testrunner_DEPENDENCIES) + @rm -f testrunner$(EXEEXT) + $(AM_V_CXXLD)$(testrunner_LINK) $(testrunner_OBJECTS) $(testrunner_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arguments.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botansigners.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decafsigners.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devpollmplexer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns_random.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnslabeltext.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsmessage.pb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsparser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsrecords.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnssecinfra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnswriter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednscookies.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednsoptions.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednssubnet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epollmplexer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filterpo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gss_context.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iputils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ixfr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kqueuemplexer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lua-recursor4.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lwres.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloctrace.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mtasker_context.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/negcache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsecrecords.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opensslsigners.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pdns_recursor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/portsmplexer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protobuf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pubsuffix.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtype.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/randomhelper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcpgenerator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-carbon.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-lua-conf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-protobuf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec_channel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec_channel_rec.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec_control.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recpacketcache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recursor_cache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reczones.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote_logger.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/responsestats.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpzloader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/secpoll-recursor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selectmplexer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sillyrecords.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp-agent.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sodiumsigners.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sortlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syncres.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-arguments_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-base32_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-base64_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dns_random_hh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsname_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsparser_hh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsrecordcontent.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsrecords_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ednsoptions_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-iputils_hh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ixfr_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-misc_hh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-mtasker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-negcache_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nmtree.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rcpgenerator_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-recpacketcache_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-recursorcache_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-signers.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-syncres_cc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-tsig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testrunner.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsigverifier.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix_utility.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/validate-recursor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/validate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/webserver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ws-api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ws-recursor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoneparser-tng.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-man1: $(dist_man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(dist_man_MANS)'; \ + test -n "$(man1dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.1[a-z]*$$/p'; \ + fi; \ + } | 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,^[^1][0-9a-z]*$$,1,;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)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$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)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + @list='$(sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sysconfdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ + done + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(sysconfdir)'; $(am__uninstall_files_from_dir) +install-systemdsystemunitDATA: $(systemdsystemunit_DATA) + @$(NORMAL_INSTALL) + @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \ + done + +uninstall-systemdsystemunitDATA: + @$(NORMAL_UNINSTALL) + @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir) + +# 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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + else \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +test_libcrypto.log: test_libcrypto + @p='test_libcrypto'; \ + b='test_libcrypto'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +testrunner.log: testrunner$(EXEEXT) + @p='testrunner$(EXEEXT)'; \ + b='testrunner'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + +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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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 + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -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__post_remove_distdir) +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_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.lz*) \ + lzip -dc $(distdir).tar.lz | $(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 u+w $(distdir) + mkdir $(distdir)/_build $(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 \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=.. --prefix="$$dc_install_base" \ + && $(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__post_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: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { 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 +@UNIT_TESTS_TRUE@check-local: +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive +all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(systemdsystemunitdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) 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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +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." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-noinstPROGRAMS clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-man install-systemdsystemunitDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-sbinPROGRAMS \ + install-sysconfDATA + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: install-man1 + +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 -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-man \ + uninstall-sbinPROGRAMS uninstall-sysconfDATA \ + uninstall-systemdsystemunitDATA + +uninstall-man: uninstall-man1 + +.MAKE: $(am__recursive_targets) all check check-am install install-am \ + install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-TESTS check-am check-local clean \ + clean-binPROGRAMS clean-cscope clean-generic clean-libtool \ + clean-noinstPROGRAMS clean-sbinPROGRAMS cscope cscopelist-am \ + ctags ctags-am dist dist-all dist-bzip2 dist-gzip dist-hook \ + dist-lzip dist-shar dist-tarZ dist-xz dist-zip distcheck \ + distclean distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS 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-man1 install-pdf \ + install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ + install-strip install-sysconfDATA \ + install-systemdsystemunitDATA installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + recheck tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-man uninstall-man1 \ + uninstall-sbinPROGRAMS uninstall-sysconfDATA \ + uninstall-systemdsystemunitDATA + + +htmlfiles.h: html/* + ./incfiles > $@ + +dist-hook: + for file in $$(find $(distdir)/docs -type l); do \ + t=`stat -c%N $$file | awk '{print $$NF}' | sed "s/'//g"` ; \ + ln -fs ../$$t $$file; \ + done +@UNIT_TESTS_FALSE@check-local: +@UNIT_TESTS_FALSE@ @echo "Unit tests are not enabled" +@UNIT_TESTS_FALSE@ @echo "Run ./configure --enable-unit-tests" + +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@dnsmessage.pb.cc: dnsmessage.proto +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(AM_V_GEN)$(PROTOC) --cpp_out=./ $< +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@pdns_recursor.$(OBJEXT): dnsmessage.pb.cc +@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@testrunner$(OBJEXT): dnsmessage.pb.cc + +dnslabeltext.cc: dnslabeltext.rl + $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc +$(srcdir)/effective_tld_names.dat: + $(curl_verbose)if ! curl -s -S https://publicsuffix.org/list/public_suffix_list.dat > $@; then rm -f $@; exit 1; fi + +pubsuffix.cc: $(srcdir)/effective_tld_names.dat + $(AM_V_GEN)./mkpubsuffixcc + +recursor.conf-dist: pdns_recursor + $(AM_V_GEN)./pdns_recursor --config > $@ + +@HAVE_MANPAGES_FALSE@@HAVE_VIRTUALENV_TRUE@$(MANPAGES): %.1: docs/manpages/%.rst .venv +@HAVE_MANPAGES_FALSE@@HAVE_VIRTUALENV_TRUE@ .venv/bin/python -msphinx -b man docs . $< + +@HAVE_VIRTUALENV_TRUE@.venv: docs/requirements.txt +@HAVE_VIRTUALENV_TRUE@ virtualenv .venv +@HAVE_VIRTUALENV_TRUE@ .venv/bin/pip install -U pip setuptools setuptools-git +@HAVE_VIRTUALENV_TRUE@ .venv/bin/pip install -r docs/requirements.txt + +@HAVE_VIRTUALENV_TRUE@html-docs: docs/** .venv +@HAVE_VIRTUALENV_TRUE@ .venv/bin/python -msphinx -b html docs html-docs + +@HAVE_VIRTUALENV_TRUE@latex/PowerDNS-Recursor.pdf: docs/** .venv +@HAVE_VIRTUALENV_TRUE@ .venv/bin/python -msphinx -M latexpdf docs . + +@HAVE_VIRTUALENV_TRUE@PowerDNS-Recursor.pdf: latex/PowerDNS-Recursor.pdf +@HAVE_VIRTUALENV_TRUE@ mv $< $@ + +@HAVE_VIRTUALENV_TRUE@html-docs.tar.bz2: html-docs +@HAVE_VIRTUALENV_TRUE@ tar cjf $@ $< + +@HAVE_VIRTUALENV_TRUE@all-docs: PowerDNS-Recursor.pdf html-docs html-docs.tar.bz2 + +@HAVE_VIRTUALENV_TRUE@upload-docs: all-docs +@HAVE_VIRTUALENV_TRUE@ rsync -crv --delete --no-p --chmod=g=rwX --exclude '*~' ./html-docs/ web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/ +@HAVE_VIRTUALENV_TRUE@ rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html-docs.tar.bz2 web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/ +@HAVE_VIRTUALENV_TRUE@ rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./PowerDNS-Recursor.pdf web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/ + +@HAVE_VIRTUALENV_FALSE@$(MANPAGES): +@HAVE_VIRTUALENV_FALSE@ echo "You need virtualenv to generate the manpages" +@HAVE_VIRTUALENV_FALSE@ exit 1 + +@HAVE_VIRTUALENV_FALSE@PowerDNS-Recursor.pdf: +@HAVE_VIRTUALENV_FALSE@ echo "You need virtualenv to generate the PDF" +@HAVE_VIRTUALENV_FALSE@ exit 1 + +@HAVE_VIRTUALENV_FALSE@html-docs: +@HAVE_VIRTUALENV_FALSE@ echo "You need virtualenv to generate the HTML docs" +@HAVE_VIRTUALENV_FALSE@ exit 1 + +@HAVE_SYSTEMD_TRUE@pdns-recursor.service: pdns-recursor.service.in +@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's![@]sbindir[@]!$(sbindir)!' < $< > $@ + +@HAVE_SYSTEMD_TRUE@pdns-recursor@.service: pdns-recursor.service +@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's!/pdns_recursor!& --config-name=%i!' \ +@HAVE_SYSTEMD_TRUE@ -e 's!Recursor!& %i!' \ +@HAVE_SYSTEMD_TRUE@ < $< > $@ +@HAVE_LUA_HPP_FALSE@lua.hpp: +@HAVE_LUA_HPP_FALSE@ $(AM_V_GEN)echo 'extern "C" {' > $@ +@HAVE_LUA_HPP_FALSE@ @echo '#include "lua.h"' >> $@ +@HAVE_LUA_HPP_FALSE@ @echo '#include "lualib.h"' >> $@ +@HAVE_LUA_HPP_FALSE@ @echo '#include "lauxlib.h"' >> $@ +@HAVE_LUA_HPP_FALSE@ @echo '}' >> $@ + +# 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/NOTICE b/NOTICE new file mode 100644 index 0000000..ddd9b42 --- /dev/null +++ b/NOTICE @@ -0,0 +1,16 @@ +This program is free software; you can redistribute it and/or modify +it under the terms of version 2 of the GNU General Public License as +published by the Free Software Foundation. + +In addition, for the avoidance of any doubt, permission is granted to +link this program with OpenSSL and to (re)distribute the binaries +produced as the result of such linking. + +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. diff --git a/README b/README new file mode 100644 index 0000000..2be4d19 --- /dev/null +++ b/README @@ -0,0 +1,86 @@ +PowerDNS Recursor +----------------- +For full details, please read https://doc.powerdns.com/md/recursor/ + +Here follow some brief notes that may be useful to get you going. + +Compiling +--------- +Starting with version 4.0.0, the PowerDNS recursor uses autotools and compiling +[from the tarball](https://downloads.powerdns.com/releases/) can be as simple as + +``` +$ ./configure +$ make +``` + +As for dependencies, Boost (http://boost.org/) and OpenSSL (https://openssl.org/) +are required. + +On most modern UNIX distributions, you can simply install 'boost' or +'boost-dev' or 'boost-devel'. Otherwise, just download boost, and point the +compiler at the right directory using CPPFLAGS. + +On Debian and Ubuntu, the following will get you the dependencies: + +``` +$ apt-get install libboost-dev libboost-serialization-dev libssl-dev g++ make pkg-config +``` + +Compiling from git checkout +=========================== +Source code is available on GitHub: + +``` +$ git clone https://github.com/PowerDNS/pdns.git +``` + +This repository contains the sources for the PowerDNS Recursor, the PowerDNS +Authoritative Server, and dnsdist (a powerful DNS loadbalancer). The sources for +the recursor are located in the `pdns/recursordist` subdirectory of the repository. + +To compile from a git checkout, install pandoc, ragel, automake and autoconf. +Then run + +``` +$ cd pdns/pdns/recursordist/ +$ ./bootstrap +$ ./configure +$ make +``` + +On macOS, you may need to `brew install openssl` and set `PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig` during configure. + +Lua scripting +------------- +To benefit from Lua scripting, as described on https://doc.powerdns.com/md/recursor/scripting/ +Install Lua and development headers. PowerDNS supports Lua 5.1, 5.2, 5.3 and LuaJIT. +On Debian/Ubuntu, install e.g. `liblua5.2-dev` to use Lua 5.2. + +The configure script will automatically detect the Lua version. If more than one +version of Lua is installed, the `--with-lua` configure flag can be set to the +desired version. e.g.: + +``` +$ ./configure --with-lua=lua51 +``` + +(On older versions of Debian/Ubuntu, you'll need to pass `--with-lua=lua5.1` instead.) + +Documentation +------------- +After compiling, run `pdns\_recursor --config` to view the configuration options +and a short description. The full documentation is online at +https://doc.powerdns.com/md/recursor/ + +Reporting bugs +-------------- +Bugs can be reported on GitHub: https://github.com/PowerDNS/pdns/issues, please +check first if your issue is not fixed in the latest version or has already been +reported. + +License +------- +PowerDNS is copyright © 2001-2018 by PowerDNS.COM BV and lots of +contributors, using the GNU GPLv2 license (see NOTICE for the +exact license and exception used). diff --git a/RECURSOR-MIB.txt b/RECURSOR-MIB.txt new file mode 100644 index 0000000..2f8bb52 --- /dev/null +++ b/RECURSOR-MIB.txt @@ -0,0 +1,917 @@ +-- -*- snmpv2 -*- +-- ---------------------------------------------------------------------- +-- MIB file for PowerDNS Recursor +-- ---------------------------------------------------------------------- + +PDNSRECURSOR-MIB DEFINITIONS ::= BEGIN + +IMPORTS + OBJECT-TYPE, MODULE-IDENTITY, enterprises, + Counter64, NOTIFICATION-TYPE + FROM SNMPv2-SMI + CounterBasedGauge64 + FROM HCNUM-TC + OBJECT-GROUP, MODULE-COMPLIANCE, NOTIFICATION-GROUP + FROM SNMPv2-CONF; + +rec MODULE-IDENTITY + LAST-UPDATED "201611290000Z" + ORGANIZATION "PowerDNS BV" + CONTACT-INFO "support@powerdns.com" + DESCRIPTION + "This MIB module describes information gathered through PowerDNS Recursor." + + REVISION "201611290000Z" + DESCRIPTION "Initial revision." + + ::= { powerdns 2 } + +powerdns OBJECT IDENTIFIER ::= { enterprises 43315 } + +stats OBJECT IDENTIFIER ::= { rec 1 } + +questions OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of questions" + ::= { stats 1 } + +ipv6Questions OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 questions" + ::= { stats 2 } + +tcpQuestions OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of TCP questions" + ::= { stats 3 } + +cacheHits OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of cache hits" + ::= { stats 4 } + +cacheMisses OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of cache misses" + ::= { stats 5 } + +cacheEntries OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of cache entries" + ::= { stats 6 } + +cacheBytes OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Size of the cache in bytes" + ::= { stats 7 } + +packetcacheHits OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packetcache hits" + ::= { stats 8 } + +packetcacheMisses OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packetcache misses" + ::= { stats 9 } + +packetcacheEntries OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packetcache entries" + ::= { stats 10 } + +packetcacheBytes OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Size of the packetcache in bytes" + ::= { stats 11 } + +mallocBytes OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes allocated by malloc" + ::= { stats 12 } + +servfailAnswers OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of servfail answers" + ::= { stats 13 } + +nxdomainAnswers OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of nxdomain answers" + ::= { stats 14 } + +noerrorAnswers OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of noerror answers" + ::= { stats 15 } + +unauthorizedUdp OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of unauthorized UDP queries" + ::= { stats 16 } + +unauthorizedTcp OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of unauthorized TCP queries" + ::= { stats 17 } + +tcpClientOverflow OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of TCP client connections refused because of too many connections" + ::= { stats 18 } + +clientParseErrors OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of client parse errors" + ::= { stats 19 } + +serverParseErrors OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of server parse errors" + ::= { stats 20 } + +tooOldDrops OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries dropped because of a timeout" + ::= { stats 21 } + +answers01 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries answered in less than 1 ms" + ::= { stats 22 } + +answers110 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries answered in 1-10 ms" + ::= { stats 23 } + +answers10100 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries answered in 10-100 ms" + ::= { stats 24 } + +answers1001000 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries answered in 100-1000 ms" + ::= { stats 25 } + +answersSlow OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries answered in more than 1000 ms" + ::= { stats 26 } + +auth4Answers01 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 queries answered in less than 1 ms" + ::= { stats 27 } + +auth4Answers110 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 queries answered in 1-10 ms" + ::= { stats 28 } + +auth4Answers10100 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 queries answered in 10-100 ms" + ::= { stats 29 } + +auth4Answers1001000 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 queries answered in 100-1000 ms" + ::= { stats 30 } + +auth4Answersslow OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 queries answered in more than 1000 ms" + ::= { stats 31 } + +auth6Answers01 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 queries answered in less than 1 ms" + ::= { stats 32 } + +auth6Answers110 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 queries answered in 1-10 ms" + ::= { stats 33 } + +auth6Answers10100 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 queries answered in 10-100 ms" + ::= { stats 34 } + +auth6Answers1001000 OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 queries answered in 100-1000 ms" + ::= { stats 35 } + +auth6AnswersSlow OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 queries answered in more than 1000 ms" + ::= { stats 36 } + +qaLatency OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Average latency in microseconds" + ::= { stats 37 } + +unexpectedPackets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of unexpected packets" + ::= { stats 38 } + +caseMismatches OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of case mismatches" + ::= { stats 39 } + +spoofPrevents OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of spoof prevents" + ::= { stats 40 } + +nssetInvalidations OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of nsset invalidations" + ::= { stats 41 } + +resourceLimits OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of resolution aborted because of a local resource limit" + ::= { stats 42 } + +overCapacityDrops OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries dropped because the threads limit was reached" + ::= { stats 43 } + +policyDrops OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries dropped because of a policy" + ::= { stats 44 } + +noPacketError OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls to recvmsg() that returned no packet even though the socket was ready" + ::= { stats 45 } + +dlgOnlyDrops OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of records dropped because of they belonged to a delegation-only zone" + ::= { stats 46 } + +ignoredPackets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of ignored packets" + ::= { stats 47 } + +maxMthreadStack OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Maximum size of the Mthread stack" + ::= { stats 48 } + +negcacheEntries OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of negcache entries" + ::= { stats 49 } + +throttleEntries OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of throttle entries" + ::= { stats 50 } + +nsspeedsEntries OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of nsspeeds entries" + ::= { stats 51 } + +failedHostEntries OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of failed host entries" + ::= { stats 52 } + +concurrentQueries OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of concurrent queries" + ::= { stats 53 } + +securityStatus OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current security status" + ::= { stats 54 } + +outgoingTimeouts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of outgoing timeouts" + ::= { stats 55 } + +outgoing4Timeouts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 outgoing timeouts" + ::= { stats 56 } + +outgoing6Timeouts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 outgoing timeouts" + ::= { stats 57 } + +tcpOutqueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of outgoing TCP queries sent" + ::= { stats 58 } + +allOutqueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of outgoing queries sent" + ::= { stats 59 } + +ipv6Outqueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 outgoing queries sent" + ::= { stats 60 } + +throttledOutqueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of throttled outgoing queries" + ::= { stats 61 } + +dontOutqueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of outgoing queries not sent because of a 'dont-query' setting" + ::= { stats 62 } + +unreachables OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of errors due to an unreachable server" + ::= { stats 63 } + +chainResends OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of chain resends" + ::= { stats 64 } + +tcpClients OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of TCP clients" + ::= { stats 65 } + +udpRecvbufErrors OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of UDP recvbuf errors (Linux only)" + ::= { stats 66 } + +udpSndbufErrors OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of UDP sndbuf errors (Linux only)" + ::= { stats 67 } + +udpNoportErrors OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of UDP noport errors (Linux only)" + ::= { stats 68 } + +udpinErrors OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of UDP in errors (Linux only)" + ::= { stats 69 } + +ednsPingMatches OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of EDNS Ping matches" + ::= { stats 70 } + +ednsPingMismatches OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of EDNS Ping mismatches" + ::= { stats 71 } + +dnssecQueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DNSSEC queries" + ::= { stats 72 } + +nopingOutqueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of outgoing queries w/o ping" + ::= { stats 73 } + +noednsOutqueries OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of outgoing queries w/o EDNS" + ::= { stats 74 } + +uptime OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Process uptime in seconds" + ::= { stats 75 } + +realMemoryUsage OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Memory usage" + ::= { stats 76 } + +fdUsage OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "File descriptors usage" + ::= { stats 77 } + +userMsec OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "CPU usage (user) in ms" + ::= { stats 78 } + +sysMsec OBJECT-TYPE + SYNTAX CounterBasedGauge64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "CPU usage (system) in ms" + ::= { stats 79 } + +dnssecValidations OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DNSSEC validations" + ::= { stats 80 } + +dnssecResultInsecure OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DNSSEC insecure results" + ::= { stats 81 } + +dnssecResultSecure OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DNSSEC secure results" + ::= { stats 82 } + +dnssecResultBogus OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DNSSEC bogus results" + ::= { stats 83 } + +dnssecResultIndeterminate OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DNSSEC indeterminate results" + ::= { stats 84 } + +dnssecResultNta OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DNSSEC NTA results" + ::= { stats 85 } + +policyResultNoaction OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of policy-mandated no-action results" + ::= { stats 86 } + +policyResultDrop OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of policy-mandated drops" + ::= { stats 87 } + +policyResultNxdomain OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of policy-mandated NXdomain results" + ::= { stats 88 } + +policyResultNodata OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of policy-mandated nodata results" + ::= { stats 89 } + +policyResultTruncate OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of policy-mandated truncate results" + ::= { stats 90 } + +policyResultCustom OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of policy-mandated custom results" + ::= { stats 91 } + +queryPipeFullDrops OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries dropped because the query distribution pipe was full" + ::= { stats 92 } + +--- +--- Traps / Notifications +--- + +trap OBJECT IDENTIFIER ::= { rec 10 } +traps OBJECT IDENTIFIER ::= { trap 0 } --- reverse-mappable +trapObjects OBJECT IDENTIFIER ::= { rec 11 } + +trapReason OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Reason for this trap" + ::= { trapObjects 1 } + +customTrap NOTIFICATION-TYPE + OBJECTS { + trapReason + } + STATUS current + DESCRIPTION "Trap sent by sendCustomTrap" + ::= { traps 1 } + +--- +--- Conformance +--- + +recConformance OBJECT IDENTIFIER ::= { rec 100 } + +recCompliances MODULE-COMPLIANCE + STATUS current + DESCRIPTION "PowerDNS Recursor compliance statement" + MODULE + MANDATORY-GROUPS { + recGroup, + recTrapsGroup + } + ::= { recConformance 1 } + +recGroup OBJECT-GROUP + OBJECTS { + questions, + ipv6Questions, + tcpQuestions, + cacheHits, + cacheMisses, + cacheEntries, + cacheBytes, + packetcacheHits, + packetcacheMisses, + packetcacheEntries, + packetcacheBytes, + mallocBytes, + servfailAnswers, + nxdomainAnswers, + noerrorAnswers, + unauthorizedUdp, + unauthorizedTcp, + tcpClientOverflow, + clientParseErrors, + serverParseErrors, + tooOldDrops, + answers01, + answers110, + answers10100, + answers1001000, + answersSlow, + auth4Answers01, + auth4Answers110, + auth4Answers10100, + auth4Answers1001000, + auth4Answersslow, + auth6Answers01, + auth6Answers110, + auth6Answers10100, + auth6Answers1001000, + auth6AnswersSlow, + qaLatency, + unexpectedPackets, + caseMismatches, + spoofPrevents, + nssetInvalidations, + resourceLimits, + overCapacityDrops, + policyDrops, + noPacketError, + dlgOnlyDrops, + ignoredPackets, + maxMthreadStack, + negcacheEntries, + throttleEntries, + nsspeedsEntries, + failedHostEntries, + concurrentQueries, + securityStatus, + outgoingTimeouts, + outgoing4Timeouts, + outgoing6Timeouts, + tcpOutqueries, + allOutqueries, + ipv6Outqueries, + throttledOutqueries, + dontOutqueries, + unreachables, + chainResends, + tcpClients, + udpRecvbufErrors, + udpSndbufErrors, + udpNoportErrors, + udpinErrors, + ednsPingMatches, + ednsPingMismatches, + dnssecQueries, + nopingOutqueries, + noednsOutqueries, + uptime, + realMemoryUsage, + fdUsage, + userMsec, + sysMsec, + dnssecValidations, + dnssecResultInsecure, + dnssecResultSecure, + dnssecResultBogus, + dnssecResultIndeterminate, + dnssecResultNta, + policyResultNoaction, + policyResultDrop, + policyResultNxdomain, + policyResultNodata, + policyResultTruncate, + policyResultCustom, + queryPipeFullDrops, + trapReason + } + STATUS current + DESCRIPTION "Objects conformance group for PowerDNS Recursor" + ::= { recConformance 2 } + +recTrapsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + customTrap + } + STATUS current + DESCRIPTION "Traps conformance group for PowerDNS Recursor" + ::= { recConformance 3 } + +END diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..f76e37a --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1402 @@ +# generated automatically by aclocal 1.14.1 -*- Autoconf -*- + +# Copyright (C) 1996-2013 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_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +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'.])]) + +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant . +# +# 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + + +# PKG_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable pkgconfigdir as the location where a module +# should install pkg-config .pc files. By default the directory is +# $libdir/pkgconfig, but the default can be changed by passing +# DIRECTORY. The user can override through the --with-pkgconfigdir +# parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_INSTALLDIR + + +# PKG_NOARCH_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable noarch_pkgconfigdir as the location where a +# module should install arch-independent pkg-config .pc files. By +# default the directory is $datadir/pkgconfig, but the default can be +# changed by passing DIRECTORY. The user can override through the +# --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_NOARCH_INSTALLDIR + + +# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# ------------------------------------------- +# Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])# PKG_CHECK_VAR + +# Copyright (C) 2002-2013 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.14' +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.14.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.14.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-2013 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], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2013 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_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$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-2013 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. + + +# 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", "OBJC", "OBJCXX", "UPC", or "GJC". +# 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 + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" 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". + rm -rf conftest.dir + 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 10 /bin/sh. + echo '/* dummy */' > 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 + ;; + msvc7 | msvc7msys | 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], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2013 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_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf 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"` + # 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'`; 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-2013 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 macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# 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.65])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], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +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], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [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([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# 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])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro 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 + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +]) + +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-2013 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-2013 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. + +# 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])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2013 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_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-2013 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_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 is modern enough. +# If it is, 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 --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2013 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_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])]) + +# Copyright (C) 1999-2013 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_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2013 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_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2013 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_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# 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 ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + 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 + 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 + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + 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]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2013 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_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2013 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-2013 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_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-2013 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_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. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + 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 /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_arg_default_enable_disable.m4]) +m4_include([m4/ax_cxx_compile_stdcxx_11.m4]) +m4_include([m4/boost.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]) +m4_include([m4/pdns_check_clock_gettime.m4]) +m4_include([m4/pdns_check_curl.m4]) +m4_include([m4/pdns_check_libcrypto.m4]) +m4_include([m4/pdns_check_libcrypto_ecdsa.m4]) +m4_include([m4/pdns_check_libdecaf.m4]) +m4_include([m4/pdns_check_libsodium.m4]) +m4_include([m4/pdns_check_lua_hpp.m4]) +m4_include([m4/pdns_check_network_libs.m4]) +m4_include([m4/pdns_check_os.m4]) +m4_include([m4/pdns_check_pthread_np.m4]) +m4_include([m4/pdns_check_ragel.m4]) +m4_include([m4/pdns_check_virtualenv.m4]) +m4_include([m4/pdns_d_fortify_source.m4]) +m4_include([m4/pdns_enable_botan.m4]) +m4_include([m4/pdns_enable_malloc_trace.m4]) +m4_include([m4/pdns_enable_reproducible.m4]) +m4_include([m4/pdns_enable_sanitizers.m4]) +m4_include([m4/pdns_enable_unit_tests.m4]) +m4_include([m4/pdns_enable_valgrind.m4]) +m4_include([m4/pdns_enable_verbose_logging.m4]) +m4_include([m4/pdns_param_ssp_buffer_size.m4]) +m4_include([m4/pdns_pie.m4]) +m4_include([m4/pdns_relro.m4]) +m4_include([m4/pdns_stack_protector.m4]) +m4_include([m4/pdns_with_lua.m4]) +m4_include([m4/pdns_with_luajit.m4]) +m4_include([m4/pdns_with_net_snmp.m4]) +m4_include([m4/pdns_with_protobuf.m4]) +m4_include([m4/systemd.m4]) +m4_include([m4/warnings.m4]) diff --git a/arguments.cc b/arguments.cc new file mode 100644 index 0000000..935c9ea --- /dev/null +++ b/arguments.cc @@ -0,0 +1,506 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "arguments.hh" +#include +#include +#include + +#include "namespaces.hh" +#include "logger.hh" +#include +#include +#include +#include +#include + +const ArgvMap::param_t::const_iterator ArgvMap::begin() +{ + return params.begin(); +} + +const ArgvMap::param_t::const_iterator ArgvMap::end() +{ + return params.end(); +} + +string & ArgvMap::set(const string &var) +{ + return params[var]; +} + +bool ArgvMap::mustDo(const string &var) +{ + return ((*this)[var]!="no") && ((*this)[var]!="off"); +} + +vectorArgvMap::list() +{ + vector ret; + for(map::const_iterator i=params.begin();i!=params.end();++i) + ret.push_back(i->first); + return ret; +} + +string ArgvMap::getHelp(const string &item) +{ + return helpmap[item]; +} + +string & ArgvMap::set(const string &var, const string &help) +{ + helpmap[var]=help; + d_typeMap[var]="Parameter"; + return set(var); +} + +void ArgvMap::setCmd(const string &var, const string &help) +{ + helpmap[var]=help; + d_typeMap[var]="Command"; + set(var)="no"; +} + +string & ArgvMap::setSwitch(const string &var, const string &help) +{ + helpmap[var]=help; + d_typeMap[var]="Switch"; + return set(var); +} + + +bool ArgvMap::contains(const string &var, const string &val) +{ + params_t::const_iterator param = params.find(var); + if(param == params.end() || param->second.empty()) { + return false; + } + vector parts; + vector::const_iterator i; + + stringtok( parts, param->second, ", \t" ); + for( i = parts.begin(); i != parts.end(); i++ ) { + if( *i == val ) { + return true; + } + } + + return false; +} + +string ArgvMap::helpstring(string prefix) +{ + if(prefix=="no") + prefix=""; + + string help; + + for(map::const_iterator i=helpmap.begin(); + i!=helpmap.end(); + i++) + { + if(!prefix.empty() && i->first.find(prefix) != 0) // only print items with prefix + continue; + + help+=" --"; + help+=i->first; + + string type=d_typeMap[i->first]; + + if(type=="Parameter") + help+="=..."; + else if(type=="Switch") + { + help+=" | --"+i->first+"=yes"; + help+=" | --"+i->first+"=no"; + } + + + help+="\n\t"; + help+=i->second; + help+="\n"; + + } + return help; +} + +string ArgvMap::configstring(bool current) +{ + string help; + + if (current) + help="# Autogenerated configuration file based on running instance\n"; + else + help="# Autogenerated configuration file template\n"; + + for(map::const_iterator i=helpmap.begin(); i!=helpmap.end(); i++) { + if(d_typeMap[i->first]=="Command") + continue; + + help+="#################################\n"; + help+="# "; + help+=i->first; + help+="\t"; + help+=i->second; + help+="\n#\n"; + if (current) { + help+=i->first+"="+params[i->first]+"\n\n"; + } else { + help+="# "+i->first+"="+params[i->first]+"\n\n"; + } + } + return help; +} + +const string & ArgvMap::operator[](const string &arg) +{ + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + return params[arg]; +} + +mode_t ArgvMap::asMode(const string &arg) +{ + mode_t mode; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + cptr_orig = params[arg].c_str(); + mode = static_cast(strtol(cptr_orig, &cptr_ret, 8)); + if (mode == 0 && cptr_ret == cptr_orig) + throw ArgException("'" + arg + string("' contains invalid octal mode")); + return mode; +} + +gid_t ArgvMap::asGid(const string &arg) +{ + gid_t gid; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + cptr_orig = params[arg].c_str(); + gid = static_cast(strtol(cptr_orig, &cptr_ret, 0)); + if (gid == 0 && cptr_ret == cptr_orig) { + // try to resolve + struct group *group = getgrnam(params[arg].c_str()); + if (group == NULL) + throw ArgException("'" + arg + string("' contains invalid group")); + gid = group->gr_gid; + } + return gid; +} + +uid_t ArgvMap::asUid(const string &arg) +{ + uid_t uid; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + cptr_orig = params[arg].c_str(); + uid = static_cast(strtol(cptr_orig, &cptr_ret, 0)); + if (uid == 0 && cptr_ret == cptr_orig) { + // try to resolve + struct passwd *pwent = getpwnam(params[arg].c_str()); + if (pwent == NULL) + throw ArgException("'" + arg + string("' contains invalid group")); + uid = pwent->pw_uid; + } + return uid; +} + +int ArgvMap::asNum(const string &arg, int def) +{ + int retval; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + // use default for empty values + if (params[arg].empty()) + return def; + + cptr_orig = params[arg].c_str(); + retval = static_cast(strtol(cptr_orig, &cptr_ret, 0)); + if (!retval && cptr_ret == cptr_orig) + throw ArgException("'"+arg+"' value '"+string(cptr_orig) + string( "' is not a valid number")); + + return retval; +} + +bool ArgvMap::isEmpty(const string &arg) +{ + if(!parmIsset(arg)) + return true; + return params[arg].empty(); +} + +double ArgvMap::asDouble(const string &arg) +{ + double retval; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + if (params[arg].empty()) + return 0.0; + + cptr_orig = params[arg].c_str(); + retval = strtod(cptr_orig, &cptr_ret); + + if (retval == 0 && cptr_ret == cptr_orig) + throw ArgException("'"+arg+string("' is not valid double")); + + return retval; +} + +ArgvMap::ArgvMap() +{ + +} + +bool ArgvMap::parmIsset(const string &var) +{ + return (params.find(var)!=params.end()); +} + +void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax) +{ + string var, val; + string::size_type pos; + bool incremental = false; + + if(arg.find("--") == 0 && (pos=arg.find("+="))!=string::npos) // this is a --port+=25 case + { + var=arg.substr(2,pos-2); + val=arg.substr(pos+2); + incremental = true; + } + else if(arg.find("--") == 0 && (pos=arg.find("="))!=string::npos) // this is a --port=25 case + { + var=arg.substr(2,pos-2); + val=arg.substr(pos+1); + } + else if(arg.find("--") == 0 && (arg.find("=")==string::npos)) // this is a --daemon case + { + var=arg.substr(2); + val=""; + } + else if(arg[0]=='-') + { + var=arg.substr(1); + val=""; + } + else // command + d_cmds.push_back(arg); + + boost::trim(var); + + if(var!="" && (parseOnly.empty() || var==parseOnly)) { + pos=val.find_first_not_of(" \t"); // strip leading whitespace + if(pos && pos!=string::npos) + val=val.substr(pos); + if(parmIsset(var)) + { + if(incremental) + { + if(params[var].empty()) + { + if(!d_cleared.count(var)) + throw ArgException("Incremental parameter '"+var+"' without a parent"); + params[var]=val; + } + else + params[var]+=", " + val; + } + else + { + params[var]=val; + d_cleared.insert(var); + } + } + else if(!lax) + throw ArgException("Trying to set unknown parameter '"+var+"'"); + } +} + +const vector&ArgvMap::getCommands() +{ + return d_cmds; +} + +void ArgvMap::parse(int &argc, char **argv, bool lax) +{ + d_cmds.clear(); + d_cleared.clear(); + for(int n=1;n extraConfigs; + gatherIncludes(extraConfigs); + for(const std::string& fn : extraConfigs) { + if (!file(fn.c_str(), lax, true)) { + L << Logger::Error << fn << " could not be parsed" << std::endl; + throw ArgException(fn + " could not be parsed"); + } + } + } + + return true; +} + +void ArgvMap::gatherIncludes(std::vector &extraConfigs) { + extraConfigs.clear(); + if (params["include-dir"].empty()) return; // nothing to do + struct stat st; + DIR *dir; + struct dirent *ent; + + // stat + if (stat(params["include-dir"].c_str(), &st)) { + L << Logger::Error << params["include-dir"] << " does not exist!" << std::endl; + throw ArgException(params["include-dir"] + " does not exist!"); + } + + // wonder if it's accessible directory + if (!S_ISDIR(st.st_mode)) { + L << Logger::Error << params["include-dir"] << " is not a directory" << std::endl; + throw ArgException(params["include-dir"] + " is not a directory"); + } + + if (!(dir = opendir(params["include-dir"].c_str()))) { + L << Logger::Error << params["include-dir"] << " is not accessible" << std::endl; + throw ArgException(params["include-dir"] + " is not accessible"); + } + + while((ent = readdir(dir)) != NULL) { + if (ent->d_name[0] == '.') continue; // skip any dots + if (boost::ends_with(ent->d_name, ".conf")) { + // build name + std::ostringstream namebuf; + namebuf << params["include-dir"].c_str() << "/" << ent->d_name; // FIXME: Use some path separator + // ensure it's readable file + if (stat(namebuf.str().c_str(), &st) || !S_ISREG(st.st_mode)) { + L << Logger::Error << namebuf.str() << " is not a file" << std::endl; + closedir(dir); + throw ArgException(namebuf.str() + " does not exist!"); + } + extraConfigs.push_back(namebuf.str()); + } + } + std::sort(extraConfigs.begin(), extraConfigs.end(), CIStringComparePOSIX()); + closedir(dir); +} diff --git a/arguments.hh b/arguments.hh new file mode 100644 index 0000000..9370595 --- /dev/null +++ b/arguments.hh @@ -0,0 +1,133 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 ARGUMENTS_HH +#define ARGUMENTS_HH + +#include +#include +#include +#include +#include +#include +#include "misc.hh" +#include "pdnsexception.hh" +#include +#include +#include + +#include "namespaces.hh" + +typedef PDNSException ArgException; + +/** This class helps parsing argc and argv into a map of parameters. We have 3 kinds of formats: + + + -w this leads to a key/value pair of "w"/void + + --port=25 "port"/"25" + + --daemon "daemon"/void + + We do not support "--port 25" syntax. + + It can also read from a file. This file can contain '#' to delimit comments. + + Some sample code: + + \code + + ArgvMap R; + + R.set("port")="25"; // use this to specify default parameters + R.file("./default.conf"); // parse configuration file + + R.parse(argc, argv); // read the arguments from main() + + cout<<"Will we be a daemon?: "<::const_iterator i; + cout<<"via iterator"<first<<"="<second< param_t; //!< use this if you need to know the content of the map + bool parmIsset(const string &var); //!< Checks if a parameter is set to *a* value + bool mustDo(const string &var); //!< if a switch is given, if we must do something (--help) + int asNum(const string &var, int def=0); //!< return a variable value as a number or the default if the variable is empty + mode_t asMode(const string &var); //!< return value interpreted as octal number + uid_t asUid(const string &var); //!< return user id, resolves if necessary + gid_t asGid(const string &var); //!< return group id, resolves if necessary + double asDouble(const string &var); //!< return a variable value as a number + string &set(const string &); //!< Gives a writable reference and allocates space for it + string &set(const string &, const string &); //!< Does the same but also allows one to specify a help message + void setCmd(const string &, const string &); //!< Add a command flag + string &setSwitch(const string &, const string &); //!< Add a command flag + string helpstring(string prefix=""); //!< generates the --help + string configstring(bool current=false); //!< generates the --mkconfig + bool contains(const string &var, const string &val); + bool isEmpty(const string &var); //!< checks if variable has value + + vectorlist(); + string getHelp(const string &item); + + const param_t::const_iterator begin(); //!< iterator semantics + const param_t::const_iterator end(); //!< iterator semantics + const string &operator[](const string &); //!< iterator semantics + const vector&getCommands(); + void gatherIncludes(std::vector &extraConfigs); +private: + void parseOne(const string &unparsed, const string &parseOnly="", bool lax=false); + typedef map params_t; + params_t params; + map helpmap; + map d_typeMap; + vector d_cmds; + std::set d_cleared; +}; + +extern ArgvMap &arg(); + +#endif /* ARGUMENTS_HH */ diff --git a/ascii.hh b/ascii.hh new file mode 100644 index 0000000..09f42de --- /dev/null +++ b/ascii.hh @@ -0,0 +1,41 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +inline bool dns_isspace(char c) +{ + return c==' ' || c=='\t' || c=='\r' || c=='\n'; +} + +inline unsigned char dns_toupper(unsigned char c) +{ + if(c>='a' && c<='z') + c+='A'-'a'; + return c; +} + +inline unsigned char dns_tolower(unsigned char c) +{ + if(c>='A' && c<='Z') + c+='a'-'A'; + return c; +} diff --git a/base32.cc b/base32.cc new file mode 100644 index 0000000..16d9d4b --- /dev/null +++ b/base32.cc @@ -0,0 +1,167 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include +#include +#include +#include "base32.hh" +#include "namespaces.hh" + +/* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */ +/* NOTE: length should not exceed 8; all callers inside PowerDNS only pass length=5 though */ +unsigned char extract_bits(const char *s, int start, int length) +{ + uint16_t x; + unsigned char cl, cc; + + if(!length) + return 0; + + cl = s[start / 8]; + if(start / 8 < (start + length-1)/8) + cc = s[start / 8 + 1]; + else + cc = 0; + + x = (uint16_t) (cl << 8 | cc); + x = x >> (16 - (length + (start % 8))); + x = (x & (0xffff >> (16 - length))); + return (x); +} + +/* same, set bit ranges in a char* */ +static void set_bits(char* s, int x, int start, int length) +{ + unsigned char cl, cc, cr; + uint32_t y; + int shift; + + shift = ((8 - ((start + length) % 8)) % 8); + y = (uint32_t) x << shift; + cl = (y >> 16) & 0xff; + cc = (y >> 8) & 0xff; + cr = y & 0xff; + if (shift + length > 16) { + s[start / 8] |= cl; + s[start / 8 + 1] |= cc; + s[start / 8 + 2] |= cr; + } + else { + if (shift + length > 8) { + s[start / 8] |= cc; + s[start / 8 + 1] |= cr; + } else { + s[start / 8] |= cr; + } + } +} + +/* convert a base32 hex character to its decoded equivalent */ +static int unbase32hex(char c) +{ + if(c >= '0' && c<='9') + return c-'0'; + if(c >= 'a' && c<='z') + return 10 + (c-'a'); + if(c >= 'A' && c<='Z') + return 10 + (c-'A'); + if(c=='=') + return '='; + return -1; +} + +/* convert a binary string to base32hex */ +string toBase32Hex(const std::string& input) +{ + static const char base32hex[] = "0123456789abcdefghijklmnopqrstuv="; + string ret; + ret.reserve(4+ 8*input.length()/5); // optimization + // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks + for(string::size_type offset = 0 ; offset < input.length(); offset+=5) { + int todo = input.length() - offset; + int stuffing; // how much '=' to add at the end + + switch(todo) { + case 1: + stuffing = 6; break; + case 2: + stuffing = 4; break; + case 3: + stuffing = 3; break; + case 4: + stuffing = 1; break; + default: // -> 0 or more than 5, no stuffing + stuffing = 0; break; + } + + for(int n=0; n < 8 - stuffing; ++n) + ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]); + ret.append(stuffing, '='); + } + + return ret; +} + +// convert base32hex encoded string to normal string +string fromBase32Hex(const std::string& input) +{ + string ret; + char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time + string::size_type n, toWrite=0; + for(n = 0; n < input.length(); ++n) { + int c=unbase32hex(input[n]); + if(c == '=' || c < 0) // stop at stuffing or error + break; + set_bits(block, c , (n % 8) * 5, 5); + if(++toWrite == 8) { + ret.append(block, sizeof(block)); + memset(block, 0, sizeof(block)); + toWrite = 0; + } + } + ret.append(block, (toWrite*5)/8); + + return ret; +} + +#if 0 +int main(int argc, char **argv) +{ + if(argc!=3 || (argc==3 && strcmp(argv[1],"from") && strcmp(argv[1],"to"))) { + printf("syntax: base32 from|to string\n"); + exit(0); + } + if(!strcmp(argv[1],"to")) { + printf("input: '%s'\noutput: '%s'\n", + argv[2], + toBase32Hex(argv[2]).c_str()); + } + else { + cout<<"input: '"< + +std::string toBase32Hex(const std::string& input); +std::string fromBase32Hex(const std::string& input); + +#endif diff --git a/base64.cc b/base64.cc new file mode 100644 index 0000000..6dbb904 --- /dev/null +++ b/base64.cc @@ -0,0 +1,103 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "base64.hh" +#include +#include +#include +#include + +int B64Decode(const std::string& src, std::string& dst) +{ + if (src.empty() ) { + dst.clear(); + return 0; + } + int dlen = ( src.length() * 6 + 7 ) / 8 ; + ssize_t olen = 0; + boost::scoped_array d( new unsigned char[dlen] ); + BIO *bio, *b64; + bio = BIO_new(BIO_s_mem()); + BIO_write(bio, src.c_str(), src.length()); + b64 = BIO_new(BIO_f_base64()); + bio = BIO_push(b64, bio); + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + olen = BIO_read(b64, d.get(), dlen); + if ((olen == 0 || olen == -1) && BIO_should_retry(bio)) { + BIO_free_all(bio); + throw std::runtime_error("BIO_read failed to read all data from memory buffer"); + } + BIO_free_all(bio); + if (olen > 0) { + dst = std::string( reinterpret_cast(d.get()), olen ); + return 0; + } + return -1; +} + +std::string Base64Encode(const std::string& src) +{ + if (!src.empty()) { + size_t olen = 0; + BIO *bio, *b64; + b64 = BIO_new(BIO_f_base64()); + bio = BIO_new(BIO_s_mem()); + bio = BIO_push(b64, bio); + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + int bioWriteRet = BIO_write(bio, src.c_str(), src.length()); + if (bioWriteRet < 0 || (size_t) bioWriteRet != src.length()) { + BIO_free_all(bio); + throw std::runtime_error("BIO_write failed to write all data to memory buffer"); + } + (void)BIO_flush(bio); + char* pp; + std::string out; + olen = BIO_get_mem_data(bio, &pp); + if (olen > 0) { + out = std::string(pp, olen); + } + BIO_free_all(bio); + return out; + } + return ""; +} + +#if 0 +#include +int main() { + std::string in = "PowerDNS Test String 1"; + std::string out = Base64Encode(in); + std::cout << out << std::endl; + if (out != "UG93ZXJETlMgVGVzdCBTdHJpbmcgMQ==") { + std::cerr << "output did not match expected data" << std::endl; + } + std::string roundtrip; + B64Decode(out, roundtrip); + std::cout << roundtrip << std::endl; + if (roundtrip != in) { + std::cerr << "roundtripped data did not match input data" << std::endl; + } + return 0; +} +#endif diff --git a/base64.hh b/base64.hh new file mode 100644 index 0000000..37ab35b --- /dev/null +++ b/base64.hh @@ -0,0 +1,30 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_BASE64_HH +#define PDNS_BASE64_HH + +#include + +int B64Decode(const std::string& src, std::string& dst); +std::string Base64Encode (const std::string& src); + +#endif diff --git a/botansigners.cc b/botansigners.cc new file mode 100644 index 0000000..cb04d72 --- /dev/null +++ b/botansigners.cc @@ -0,0 +1,263 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include +#include +#include "dnssecinfra.hh" + +using namespace Botan; + +/* Государственный гимн Российской Федерации + (Gosudarstvenny Gimn Rossiyskoy Federatsii) + "The National Anthem of the Russian Federation" + + ~ Rossiya - svyashchennaya nasha derzhava, ~ + ~ Rossiya - lyubimaya nasha strana. ~ + ~ Moguchaya volya, velikaya slava - ~ + ~ Tvoyo dostoyanye na vse vremena! ~ + */ + +class GOSTDNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit GOSTDNSCryptoKeyEngine(unsigned int algorithm) : DNSCryptoKeyEngine(algorithm) {} + ~GOSTDNSCryptoKeyEngine(){} + void create(unsigned int bits) override; + string getName() const override { return "Botan 2 GOST"; } + storvector_t convertToISCVector() const override; + std::string getPubKeyHash() const override; + std::string sign(const std::string& msg) const override; + std::string hash(const std::string& msg) const override; + bool verify(const std::string& msg, const std::string& signature) const override; + std::string getPublicKeyString() const override; + int getBits() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& content) override; + void fromPublicKeyString(const std::string& content) override; + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override + {} + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + static EC_Group getParams() + { + return EC_Group("gost_256A"); + } + + shared_ptr d_key; + shared_ptr d_pubkey; +}; + +/* + ~ Slav'sya, Otechestvo nashe svobodnoye, ~ + ~ Bratskikh narodov soyuz vekovoy, ~ + ~ Predkami dannaya mudrost' narodnaya! ~ + ~ Slav'sya, strana! My gordimsya toboy! ~ +*/ + + +void GOSTDNSCryptoKeyEngine::create(unsigned int bits) +{ + AutoSeeded_RNG rng; + d_key = std::make_shared(rng, getParams()); +} + +int GOSTDNSCryptoKeyEngine::getBits() const +{ + return 256; +} + +/* + ~ Ot yuzhnykh morey do polyarnogo kraya ~ + ~ Raskinulis' nashi lesa i polya. ~ + ~ Odna ty na svete! Odna ty takaya - ~ + ~ Khranimaya Bogom rodnaya zemlya! ~ +*/ + +DNSCryptoKeyEngine::storvector_t GOSTDNSCryptoKeyEngine::convertToISCVector() const +{ + static const unsigned char asn1Prefix[]= + {0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, + 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, 0x04, 0x22, 0x04, 0x20}; // this is DER, fixed for a 32 byte key + + storvector_t storvect; + storvect.push_back(make_pair("Algorithm", "12 (ECC-GOST)")); + + auto buffer = BigInt::encode(d_key->private_value()); + string gostasn1(reinterpret_cast(asn1Prefix), sizeof(asn1Prefix)); + gostasn1.append(buffer.begin(), buffer.end()); + storvect.push_back(make_pair("GostAsn1", gostasn1)); + return storvect; +} + +/* + ~ Slav'sya, Otechestvo nashe svobodnoye, ~ + ~ Bratskikh narodov soyuz vekovoy, ~ + ~ Predkami dannaya mudrost' narodnaya! ~ + ~ Slav'sya, strana! My gordimsya toboy! ~ +*/ + +void GOSTDNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap ) +{ + drc.d_algorithm = pdns_stou(stormap["algorithm"]); + string privateKey=stormap["gostasn1"]; + //cerr<<"PrivateKey.size() = "<(rng, getParams(), bigint); + + //cerr<<"Is the just imported key on the curve? " << d_key->public_point().on_the_curve()<public_point().is_zero()<private_value(); + auto buffer = BigInt::encode(x); + // cerr<<"And out again! "< msg_le(msg, msg + msg_len); + + for(size_t i = 0; i != msg_le.size() / 2; ++i) + std::swap(msg_le[i], msg_le[msg_le.size()-1-i]); + + return BigInt(&msg_le[0], msg_le.size()); + } + +} +void GOSTDNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + BigInt x, y; + + x=decode_le((const byte*)input.c_str(), input.length()/2); + y=decode_le((const byte*)input.c_str() + input.length()/2, input.length()/2); + + auto params = getParams(); +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(2,5,0) + PointGFp point(params.get_curve(), x,y); +#else + PointGFp point(params.point(x,y)); +#endif + d_pubkey = std::make_shared(params, point); + d_key.reset(); +} + +std::string GOSTDNSCryptoKeyEngine::getPubKeyHash() const +{ + const BigInt&x = d_key->private_value(); + auto buffer = BigInt::encode(x); + return string(buffer.begin(), buffer.end()); +} + +std::string GOSTDNSCryptoKeyEngine::getPublicKeyString() const +{ + std::shared_ptr pk = d_pubkey ? d_pubkey : d_key; + const BigInt&x =pk->public_point().get_affine_x(); + const BigInt&y =pk->public_point().get_affine_y(); + + size_t part_size = std::max(x.bytes(), y.bytes()); + + std::vector bits(2*part_size); + + x.binary_encode(&bits[part_size - x.bytes()]); + y.binary_encode(&bits[2*part_size - y.bytes()]); + + // Keys are stored in little endian format (WTF) + for(size_t i = 0; i != part_size / 2; ++i) + { + std::swap(bits[i], bits[part_size-1-i]); + std::swap(bits[part_size+i], bits[2*part_size-1-i]); + } + + return string(bits.begin(), bits.end()); +} + +/* + ~ Shirokiy prostor dlya mechty i dlya zhizni. ~ + ~ Gryadushchiye nam otkryvayut goda. ~ + ~ Nam silu dayot nasha vernost' Otchizne. ~ + ~ Tak bylo, tak yest' i tak budet vsegda! ~ + */ + +std::string GOSTDNSCryptoKeyEngine::sign(const std::string& msg) const +{ + AutoSeeded_RNG rng; + PK_Signer signer(*d_key, rng, "Raw"); + signer.update(hash(msg)); + auto signature = signer.signature(rng); + return string(signature.begin(), signature.end()); +} + +std::string GOSTDNSCryptoKeyEngine::hash(const std::string& orig) const +{ + GOST_34_11 hasher; + auto result = hasher.process(orig); + return string(result.begin(), result.end()); +} + + +bool GOSTDNSCryptoKeyEngine::verify(const std::string& message, const std::string& signature) const +{ + std::shared_ptr pk = d_pubkey ? d_pubkey : d_key; + PK_Verifier verifier(*pk, "Raw"); + verifier.update(hash(message)); + return verifier.check_signature(reinterpret_cast(signature.c_str()), signature.size()); +} + +/* + ~ Slav'sya, Otechestvo nashe svobodnoye, ~ + ~ Bratskikh narodov soyuz vekovoy, ~ + ~ Predkami dannaya mudrost' narodnaya! ~ + ~ Slav'sya, strana! My gordimsya toboy! ~ +*/ + + +////////////////////////////// + +namespace { +struct LoaderStruct +{ + LoaderStruct() + { + DNSCryptoKeyEngine::report(12, &GOSTDNSCryptoKeyEngine::maker); + } +} loaderBotan2; +} diff --git a/build-aux/compile b/build-aux/compile new file mode 100755 index 0000000..531136b --- /dev/null +++ b/build-aux/compile @@ -0,0 +1,347 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-10-14.11; # UTC + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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 . + +# 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 or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +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: diff --git a/build-aux/config.guess b/build-aux/config.guess new file mode 100755 index 0000000..1f5c50c --- /dev/null +++ b/build-aux/config.guess @@ -0,0 +1,1420 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2014 Free Software Foundation, Inc. + +timestamp='2014-03-23' + +# 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 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 . +# +# 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 Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner. +# +# 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 +# +# Please send patches with a ChangeLog entry to config-patches@gnu.org. + + +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 ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2014 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 + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# 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 tuples: *-*-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 ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_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'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + 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 /* 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 + + 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:*:[4567]) + 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 + #include + + 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 + 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:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + 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-${LIBC}`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/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + 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="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${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-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + 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-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + 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-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + 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' /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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-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 + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + 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 + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + 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 ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + 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 ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +cat >&2 < 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/build-aux/config.sub b/build-aux/config.sub new file mode 100755 index 0000000..bba4efb --- /dev/null +++ b/build-aux/config.sub @@ -0,0 +1,1799 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2014 Free Software Foundation, Inc. + +timestamp='2014-09-11' + +# 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 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 . +# +# 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 Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# +# 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2014 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-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | 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/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + 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*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -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 \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | 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 \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | 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 \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-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-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | 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-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | 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-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | 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-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | 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 + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + 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 | 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*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 + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-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 + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + 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 + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + 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 | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + 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 | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + 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 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + 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 + ;; + tile*) + basic_machine=$basic_machine-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 + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + 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* | -plan9* \ + | -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* \ + | -bitrig* | -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* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -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* | -tirtos*) + # 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 + ;; + -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 + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + 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 + ;; + 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/build-aux/depcomp b/build-aux/depcomp new file mode 100755 index 0000000..4ebd5b3 --- /dev/null +++ b/build-aux/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2013-05-30.07; # UTC + +# Copyright (C) 1999-2013 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 . + +# 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 . + +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 outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +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" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# 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 + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 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=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +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 -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## 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). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - 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 -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # 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. +## 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. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -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 -ne 0; then + 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 ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ + | tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # 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 + ;; + +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. + set_dir_from "$object" + set_base_from "$object" + 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 -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + 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. + set_dir_from "$object" + set_base_from "$object" + 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 -ne 0; then + 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,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_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. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool 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$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # 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 + ;; + +#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|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | 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" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | 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::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$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/build-aux/gen-version b/build-aux/gen-version new file mode 100755 index 0000000..a2ff215 --- /dev/null +++ b/build-aux/gen-version @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ ! -z "$BUILDER_VERSION" ]; then + printf $BUILDER_VERSION + echo $BUILDER_VERSION > .version + exit 0 +fi + +VERSION="unknown" + +DIRTY="" +git status | grep -q clean || DIRTY='.dirty' + +# Special environment variable to signal that we are building a release, as this +# has consequences for the version number. +if [ "${IS_RELEASE}" = "YES" ]; then + TAG="$(git describe --tags --exact-match 2> /dev/null | cut -d- -f 2-)" + if [ -n "${TAG}" ]; then + # We're on a tag + echo "${TAG}${DIRTY}" > .version + printf "${TAG}${DIRTY}" + exit 0 + fi + echo 'This is not a tag, either tag this commit or do not set $IS_RELEASE' >&2 + exit 1 +fi + +# +# Generate the version number based on the branch +# +if [ ! -z "$(git rev-parse --abbrev-ref HEAD 2> /dev/null)" ]; then + if $(git rev-parse --abbrev-ref HEAD | grep -q 'rel/'); then + REL_TYPE="$(git rev-parse --abbrev-ref HEAD | cut -d/ -f 2 | cut -d- -f 1)" + VERSION="$(git describe --match=${REL_TYPE}-* --tags --dirty=.dirty | cut -d- -f 2-)" + else + GIT_VERSION=$(git show --no-patch --format=format:%h HEAD) + BRANCH=".$(git rev-parse --abbrev-ref HEAD | perl -p -e 's/[^[:alnum:]]//g;')" + [ "${BRANCH}" = ".master" ] && BRANCH='' + VERSION="0.0${BRANCH}.${PDNS_BUILD_NUMBER}g${GIT_VERSION}${DIRTY}" + fi + echo "$VERSION" > .version +elif [ -f .version ]; then + VERSION="$(cat .version)" +fi + +printf $VERSION diff --git a/build-aux/install-sh b/build-aux/install-sh new file mode 100755 index 0000000..756420d --- /dev/null +++ b/build-aux/install-sh @@ -0,0 +1,534 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-11-20.07; # 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 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + 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 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + 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 + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 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 problematic for 'test' and other utilities. + 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 + + # 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. + ;; + *) + # $RANDOM is not portable (e.g. dash); use it when possible to + # lower collision chance + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + + # As "mkdir -p" follows symlinks and we work in /tmp possibly; so + # create the $tmpdir first (and fail if unsuccessful) to make sure + # that nobody tries to guess the $tmpdir name. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/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-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 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 X"$d" = X && 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/build-aux/ltmain.sh b/build-aux/ltmain.sh new file mode 100644 index 0000000..bffda54 --- /dev/null +++ b/build-aux/ltmain.sh @@ -0,0 +1,9661 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 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 +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed 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. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# 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.4.2 Debian-2.4.2-1.11 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.2 Debian-2.4.2-1.11" +TIMESTAMP="" +package_revision=1.3337 + +# 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 + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +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 +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# 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" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${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 file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# 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 "${1}" | $SED -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 "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# 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 "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# 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=${PATH_SEPARATOR-:} + 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' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|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: ${opt_mode+$opt_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_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_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 "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED '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 "$my_tmpdir" +} + + +# 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 "$1" | $SED "$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 "$1" | $SED \ + -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_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$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 () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + 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-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# 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_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# 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 +} + +# 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 +} + + +# 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 + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg 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 + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + 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_preserve_dup_deps + ;; + esac + + $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 + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_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=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# 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_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# 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_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$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_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + 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 "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # 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_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # 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 </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# 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. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # 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_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # 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_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# 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) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append 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_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append 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_append_quoted base_compile "$lastarg" + 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 | *.go | *.obj | *.sx | *.cu | *.cup) + 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 "$srcfile" | $SED 's%^.*/%%; 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 + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + 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 + func_append 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 + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append 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 "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_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 build PIC objects only + -prefer-non-pic try to build 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 + -Wc,FLAG pass FLAG directly to the compiler + +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-dir 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 + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -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 + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +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 \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# 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 $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # 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 + func_append 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 + -* | *.la | *.lo ) ;; + *) + # 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_append_quoted args "$file" + 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 "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + 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" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + 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 "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_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. + case $nonopt in *shtool*) :;; *) false;; esac; 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" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_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 -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + 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. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # 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 "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -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 "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "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_shared_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" && func_append 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 "$lib" | $SED '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 "$relink_command" | $SED '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 "$file$stripped_ext" | $SED "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_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_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 "$opt_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 + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#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 "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $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" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + 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 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; +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) ;; + *) func_append 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 "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "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 "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "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. +# Despite the name, also deal with 64 bit binaries. +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 + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $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_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# 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" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + 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 | sort | $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 | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# 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=${1-no} + + $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. +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 + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED '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 \"\$file\" | $SED '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 \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_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 \"\$thisdir\" | $SED '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" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # 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 \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${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\ +" +} + + +# 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 < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#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 + +/* path handling portability macros */ +#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 */ + +#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) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +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_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +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_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 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; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + 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; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + 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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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) + { + lt_debugprintf (__FILE__, __LINE__, + "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 + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "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; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#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; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + 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) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# 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 + bindir= + 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 + bindir) + bindir="$arg" + prev= + continue + ;; + 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 + func_append dlfiles " $arg" + else + func_append 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 "*) ;; + *) func_append 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 +# func_append 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 + func_append 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. + func_append 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 "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append 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 + ;; + + -bindir) + prev=bindir + 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" + if test -z "$func_stripname_result"; 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 + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # 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 "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append 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* | *-*-haiku*) + # 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 + func_append 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 + func_append 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|--sysroot) + func_append 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|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append 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_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append 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" + func_append arg " $func_quote_for_eval_result" + func_append 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" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append 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" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append 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 + func_append 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. + func_append 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. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + 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 \"\${$shlibpath_var}\" \| \$SED \'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" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # 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_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append 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 "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append 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= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append 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|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append 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 "*) ;; + * ) func_append 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" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_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" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$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 \"$deplib\"" 2>/dev/null | $SED 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. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append 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 "$inherited_linker_flags" | $SED '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 "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED '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" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append 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. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append 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= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + 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. + func_append dlprefiles " $lib $dependency_libs" + else + func_append 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 "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$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 + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append 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 + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append 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" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append 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" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + 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 + func_append 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" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_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_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append 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:"*) ;; + *) func_append 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append 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 + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append 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 "$opt_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$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append 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:"*) ;; + *) func_append 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:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_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:"*) ;; + *) func_append 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 + [\\/]*) + func_append 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 "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append 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" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + 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_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + 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 + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append 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 " $new_inherited_linker_flags" | $SED '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 "*) ;; + *) func_append 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 "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append 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 + func_append 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" + func_append 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!" + func_append 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 + # correct linux to gnu/linux during the next big refactor + 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|qnx|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) # correct to gnu/linux during the next big refactor + 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. + func_append 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" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_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 + func_append 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 + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "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 + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append 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 "*) ;; + *) func_append 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 "*) ;; + *) func_append 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* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append 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 + func_append 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 </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + 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 "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append 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. + func_append 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 "*) + func_append 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 \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append 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. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; 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 " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + 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 + ;; + esac + ;; + 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 " $newdeplibs" | $SED '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 " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED '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 "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append 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 + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_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 + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append 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 "$opt_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 + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$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" + func_append 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 cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + 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 "$include_expsyms" | $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 + func_append 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 "*) ;; + *) + func_append 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" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append 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\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_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 + func_basename "$output" + output_la=$func_basename_result + + # 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 + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + 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 + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + 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. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$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~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append 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 "$opt_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 "$include_expsyms" | $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 + func_append 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" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append 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 "$opt_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 "$opt_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 "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $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 " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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 "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append 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 "*) ;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append 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;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$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 + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + 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 "$compile_command" | $SED '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=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # 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 + func_append 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 + func_append 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 "$link_command" | $SED '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 $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + 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 "$compile_var$compile_command$compile_rpath" | $SED '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 "$link_command" | $SED '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 $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # 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 "$relink_command" | $SED "$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 + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append 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" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append 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" + func_append 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" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + 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 + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + 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 "$relink_command" | $SED "$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" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append 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" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append 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" + func_append newdlprefiles " ${lt_sysroot:+=}$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 + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + 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 "$opt_mode" = link || test "$opt_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) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + 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 + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${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 + func_append 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 + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_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 + func_append 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 + func_append 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 + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # 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 "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_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/build-aux/missing b/build-aux/missing new file mode 100755 index 0000000..db98974 --- /dev/null +++ b/build-aux/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2013-10-28.13; # UTC + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Originally written by Fran,cois Pinard , 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 . + +# 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 + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and +'g' are ignored when checking the name. + +Send bug reports to ." + 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 + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=http://www.perl.org/ +flex_URL=http://flex.sourceforge.net/ +gnu_software_URL=http://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# 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/build-aux/test-driver b/build-aux/test-driver new file mode 100755 index 0000000..d306056 --- /dev/null +++ b/build-aux/test-driver @@ -0,0 +1,139 @@ +#! /bin/sh +# test-driver - basic testsuite driver script. + +scriptversion=2013-07-13.22; # UTC + +# Copyright (C) 2011-2013 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 . + +# 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 or send patches to +# . + +# Make unconditional expansion of undefined variables an error. This +# helps a lot in preventing typo-related bugs. +set -u + +usage_error () +{ + echo "$0: $*" >&2 + print_usage >&2 + exit 2 +} + +print_usage () +{ + cat <$log_file 2>&1 +estatus=$? +if test $enable_hard_errors = no && test $estatus -eq 99; then + estatus=1 +fi + +case $estatus:$expect_failure in + 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; + 0:*) col=$grn res=PASS recheck=no gcopy=no;; + 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; + 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; + *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; + *:*) col=$red res=FAIL recheck=yes gcopy=yes;; +esac + +# Report outcome to console. +echo "${col}${res}${std}: $test_name" + +# Register the test result, and other relevant metadata. +echo ":test-result: $res" > $trs_file +echo ":global-test-result: $res" >> $trs_file +echo ":recheck: $recheck" >> $trs_file +echo ":copy-in-global-log: $gcopy" >> $trs_file + +# 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/cachecleaner.hh b/cachecleaner.hh new file mode 100644 index 0000000..1d80b17 --- /dev/null +++ b/cachecleaner.hh @@ -0,0 +1,203 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +#include "lock.hh" + +// this function can clean any cache that has a getTTD() method on its entries, a preRemoval() method and a 'sequence' index as its second index +// the ritual is that the oldest entries are in *front* of the sequence collection, so on a hit, move an item to the end +// on a miss, move it to the beginning +template void pruneCollection(C& container, T& collection, unsigned int maxCached, unsigned int scanFraction=1000) +{ + time_t now=time(0); + unsigned int toTrim=0; + + unsigned int cacheSize=collection.size(); + + if(cacheSize > maxCached) { + toTrim = cacheSize - maxCached; + } + +// cout<<"Need to trim "<::type sequence_t; + sequence_t& sidx=collection.template get<1>(); + + unsigned int tried=0, lookAt, erased=0; + + // two modes - if toTrim is 0, just look through 1/scanFraction of all records + // and nuke everything that is expired + // otherwise, scan first 5*toTrim records, and stop once we've nuked enough + if(toTrim) + lookAt=5*toTrim; + else + lookAt=cacheSize/scanFraction; + + typename sequence_t::iterator iter=sidx.begin(), eiter; + for(; iter != sidx.end() && tried < lookAt ; ++tried) { + if(iter->getTTD() < now) { + container.preRemoval(*iter); + sidx.erase(iter++); + erased++; + } + else + ++iter; + + if(toTrim && erased >= toTrim) + break; + } + + //cout<<"erased "<= toTrim) // done + return; + + toTrim -= erased; + + //if(toTrim) + // cout<<"Still have "< void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front) +{ + typedef typename T::template nth_index<1>::type sequence_t; + sequence_t& sidx=collection.template get<1>(); + typename sequence_t::iterator si=collection.template project<1>(iter); + if(front) + sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue + else + sidx.relocate(sidx.end(), si); // back +} + +template void moveCacheItemToFront(T& collection, typename T::iterator& iter) +{ + moveCacheItemToFrontOrBack(collection, iter, true); +} + +template void moveCacheItemToBack(T& collection, typename T::iterator& iter) +{ + moveCacheItemToFrontOrBack(collection, iter, false); +} + +template uint64_t pruneLockedCollectionsVector(vector& maps, uint64_t maxCached, uint64_t cacheSize) +{ + time_t now = time(nullptr); + uint64_t totErased = 0; + uint64_t toTrim = 0; + uint64_t lookAt = 0; + + // two modes - if toTrim is 0, just look through 10% of the cache and nuke everything that is expired + // otherwise, scan first 5*toTrim records, and stop once we've nuked enough + if (maxCached && cacheSize > maxCached) { + toTrim = cacheSize - maxCached; + lookAt = 5 * toTrim; + } else { + lookAt = cacheSize / 10; + } + + for(auto& mc : maps) { + WriteLock wl(&mc.d_mut); + auto& sidx = boost::multi_index::get<2>(mc.d_map); + uint64_t erased = 0, lookedAt = 0; + for(auto i = sidx.begin(); i != sidx.end(); lookedAt++) { + if(i->ttd < now) { + i = sidx.erase(i); + erased++; + } else { + ++i; + } + + if(toTrim && erased > toTrim / maps.size()) + break; + + if(lookedAt > lookAt / maps.size()) + break; + } + totErased += erased; + } + + return totErased; +} + +template uint64_t purgeLockedCollectionsVector(vector& maps) +{ + uint64_t delcount=0; + + for(auto& mc : maps) { + WriteLock wl(&mc.d_mut); + delcount += mc.d_map.size(); + mc.d_map.clear(); + } + + return delcount; +} + +template uint64_t purgeLockedCollectionsVector(vector& maps, const std::string& match) +{ + uint64_t delcount=0; + string prefix(match); + prefix.resize(prefix.size()-1); + DNSName dprefix(prefix); + for(auto& mc : maps) { + WriteLock wl(&mc.d_mut); + auto& idx = boost::multi_index::get<1>(mc.d_map); + auto iter = idx.lower_bound(dprefix); + auto start = iter; + + for(; iter != idx.end(); ++iter) { + if(!iter->qname.isPartOf(dprefix)) { + break; + } + delcount++; + } + idx.erase(start, iter); + } + + return delcount; +} + +template uint64_t purgeExactLockedCollection(T& mc, const DNSName& qname) +{ + uint64_t delcount=0; + WriteLock wl(&mc.d_mut); + auto& idx = boost::multi_index::get<1>(mc.d_map); + auto range = idx.equal_range(qname); + if(range.first != range.second) { + delcount += distance(range.first, range.second); + idx.erase(range.first, range.second); + } + + return delcount; +} diff --git a/comment.hh b/comment.hh new file mode 100644 index 0000000..f159af3 --- /dev/null +++ b/comment.hh @@ -0,0 +1,45 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_COMMENT_HH +#define PDNS_COMMENT_HH + +#include "utility.hh" +#include "qtype.hh" +#include + +class Comment +{ +public: + Comment() : modified_at(0), domain_id(0) {}; + ~Comment() {}; + + // data + DNSName qname; //!< the name of the associated RRset, for example: www.powerdns.com + time_t modified_at; + string account; //!< account last updating this comment + string content; //!< The actual comment. Example: blah blah + + int domain_id; + QType qtype; //!< qtype of the associated RRset, ie A, CNAME, MX etc +}; + +#endif /* PDNS_COMMENT_HH */ diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..237c28c --- /dev/null +++ b/config.h.in @@ -0,0 +1,227 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Set to the user and host that builds PowerDNS */ +#undef BUILD_HOST + +/* Define to 1 if you have the `accept4' function. */ +#undef HAVE_ACCEPT4 + +/* Defined if the requested minimum BOOST version is satisfied */ +#undef HAVE_BOOST + +/* Defined if the Boost context library is available */ +#undef HAVE_BOOST_CONTEXT + +/* Define to 1 if you have */ +#undef HAVE_BOOST_CONTEXT_DETAIL_FCONTEXT_HPP + +/* Define to 1 if you have */ +#undef HAVE_BOOST_CONTEXT_FCONTEXT_HPP + +/* Defined if the Boost system library is available */ +#undef HAVE_BOOST_SYSTEM + +/* Define to 1 if you have */ +#undef HAVE_BOOST_SYSTEM_ERROR_CODE_HPP + +/* Define to 1 if you have */ +#undef HAVE_BOOST_TEST_UNIT_TEST_HPP + +/* Defined if the Boost thread library is available */ +#undef HAVE_BOOST_THREAD + +/* Define to 1 if you have */ +#undef HAVE_BOOST_THREAD_HPP + +/* Defined if the Boost unit_test_framework library is available */ +#undef HAVE_BOOST_UNIT_TEST_FRAMEWORK + +/* Define to 1 if you have botan */ +#undef HAVE_BOTAN + +/* Define to 1 if you have clock_gettime */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the `crypto_box_easy_afternm' function. */ +#undef HAVE_CRYPTO_BOX_EASY_AFTERNM + +/* define if the compiler supports basic C++11 syntax */ +#undef HAVE_CXX11 + +/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you + don't. */ +#undef HAVE_DECL_NID_SECP384R1 + +/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0 + if you don't. */ +#undef HAVE_DECL_NID_X9_62_PRIME256V1 + +/* Define to 1 if you have the declaration of `snmp_select_info2', and to 0 if + you don't. */ +#undef HAVE_DECL_SNMP_SELECT_INFO2 + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define if ASAN fiber annotation interface is available. */ +#undef HAVE_FIBER_SANITIZER + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* define to 1 if OpenSSL ecdsa support is available. */ +#undef HAVE_LIBCRYPTO_ECDSA + +/* Define to 1 if you have libdecaf */ +#undef HAVE_LIBDECAF + +/* Define to 1 if you have libsodium */ +#undef HAVE_LIBSODIUM + +/* Define to 1 if you have lua */ +#undef HAVE_LUA + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if using Net SNMP. */ +#undef HAVE_NET_SNMP + +/* Define if using protobuf. */ +#undef HAVE_PROTOBUF + +/* Define to 1 if you have pthread_setaffinity_np */ +#undef HAVE_PTHREAD_SETAFFINITY_NP + +/* Define to 1 if you have the `recvmmsg' function. */ +#undef HAVE_RECVMMSG + +/* Define to 1 if you have the header + file. */ +#undef HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H + +/* Define to 1 if __sanitizer_finish_switch_fiber takes only a pointer */ +#undef HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR + +/* Define to 1 if __sanitizer_finish_switch_fiber takes three pointers */ +#undef HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS + +/* Define to 1 if you have the `sendmmsg' function. */ +#undef HAVE_SENDMMSG + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasestr' function. */ +#undef HAVE_STRCASESTR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Systemd available and enabled */ +#undef HAVE_SYSTEMD + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_VALGRIND_VALGRIND_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to 1 if you want to benefit from malloc trace */ +#undef MALLOC_TRACE + +/* If your OS is so broken that it needs an additional prototype */ +#undef NEED_INET_NTOP_PROTO + +/* If POSIX typedefs need to be defined */ +#undef NEED_POSIX_TYPEDEF + +/* 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 + +/* pdns-recursor configure arguments */ +#undef PDNS_CONFIG_ARGS + +/* Define if using Valgrind. */ +#undef PDNS_USE_VALGRIND + +/* This is the PowerDNS Recursor */ +#undef RECURSOR + +/* Define to 1 for reproducible builds */ +#undef REPRODUCIBLE + +/* 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 + + +/* Define to 1 if verbose logging is enabled */ +#undef VERBOSELOG + +/* Version number of package */ +#undef VERSION + +/* 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 diff --git a/configure b/configure new file mode 100755 index 0000000..62b1e1a --- /dev/null +++ b/configure @@ -0,0 +1,24059 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for pdns-recursor 4.1.4. +# +# +# Copyright (C) 1992-1996, 1998-2012 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. +as_myself= +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 + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # 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. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +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 +test -x / || 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 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || 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 : + export CONFIG_SHELL + # 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. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +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 about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a 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_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_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; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # 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 -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +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 + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# 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'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &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='pdns-recursor' +PACKAGE_TARNAME='pdns-recursor' +PACKAGE_VERSION='4.1.4' +PACKAGE_STRING='pdns-recursor 4.1.4' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="pdns_recursor.cc" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +PROGRAM_LDFLAGS +YAHTTP_LIBS +YAHTTP_CFLAGS +AM_CPPFLAGS +HAVE_MANPAGES_FALSE +HAVE_MANPAGES_TRUE +HAVE_VIRTUALENV_FALSE +HAVE_VIRTUALENV_TRUE +VIRTUALENV +HAVE_SYSTEMD_FALSE +HAVE_SYSTEMD_TRUE +SYSTEMD_LIBS +SYSTEMD_CFLAGS +SYSTEMD_MODULES_LOAD +SYSTEMD_DIR +systemd +PDNS_USE_VALGRIND_FALSE +PDNS_USE_VALGRIND_TRUE +MALLOC_TRACE_FALSE +MALLOC_TRACE_TRUE +WARN_CFLAGS +SANITIZER_FLAGS +RELRO_LDFLAGS +PIE_LDFLAGS +PIE_CFLAGS +socketdir +CURL +RAGEL +HAVE_NET_SNMP_FALSE +HAVE_NET_SNMP_TRUE +NET_SNMP_LIBS +NET_SNMP_CFLAGS +LIBDECAF_LIBS +LIBDECAF_FALSE +LIBDECAF_TRUE +LIBSODIUM_FALSE +LIBSODIUM_TRUE +LIBSODIUM_LIBS +LIBSODIUM_CFLAGS +LIBCRYPTO_LDFLAGS +LIBCRYPTO_LIBS +LIBCRYPTO_INCLUDES +BOTAN_LIBS +BOTAN_CFLAGS +BOTAN_FALSE +BOTAN_TRUE +HAVE_LUA_HPP_FALSE +HAVE_LUA_HPP_TRUE +LUA_FALSE +LUA_TRUE +LUA_LIBS +LUA_CFLAGS +BOOST_UNIT_TEST_FRAMEWORK_LIBS +BOOST_UNIT_TEST_FRAMEWORK_LDPATH +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS +UNIT_TESTS_FALSE +UNIT_TESTS_TRUE +BOOST_CONTEXT_LIBS +BOOST_CONTEXT_LDPATH +BOOST_CONTEXT_LDFLAGS +BOOST_THREAD_LIBS +BOOST_THREAD_LDPATH +BOOST_THREAD_LDFLAGS +BOOST_SYSTEM_LIBS +BOOST_LDPATH +BOOST_SYSTEM_LDPATH +BOOST_SYSTEM_LDFLAGS +BOOST_CPPFLAGS +DISTCHECK_CONFIGURE_FLAGS +BOOST_ROOT +HAVE_PROTOC_FALSE +HAVE_PROTOC_TRUE +HAVE_PROTOBUF_FALSE +HAVE_PROTOBUF_TRUE +PROTOC +PROTOBUF_LIBS +PROTOBUF_CFLAGS +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +RT_LIBS +DYNLINKFLAGS +THREADFLAGS +HAVE_SOLARIS_FALSE +HAVE_SOLARIS_TRUE +HAVE_LINUX_FALSE +HAVE_LINUX_TRUE +HAVE_FREEBSD_FALSE +HAVE_FREEBSD_TRUE +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +LIBTOOL +HAVE_CXX11 +EGREP +GREP +CXXCPP +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +pdns_configure_args +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +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_silent_rules +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +with_sysroot +enable_libtool_lock +with_protobuf +with_boost +enable_static_boost +enable_unit_tests +enable_reproducible +with_luajit +with_lua +enable_verbose_logging +enable_botan +with_libcrypto +enable_libsodium +enable_libdecaf +with_net_snmp +with_socketdir +enable_hardening +enable_asan +enable_msan +enable_tsan +enable_lsan +enable_ubsan +enable_malloc_trace +enable_valgrind +enable_systemd +with_systemd +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CXXCPP +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +PROTOBUF_CFLAGS +PROTOBUF_LIBS +BOOST_ROOT +LUA_CFLAGS +LUA_LIBS +BOTAN_CFLAGS +BOTAN_LIBS +LIBSODIUM_CFLAGS +LIBSODIUM_LIBS +SYSTEMD_CFLAGS +SYSTEMD_LIBS' + + +# 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 + 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 pdns-recursor 4.1.4 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/pdns-recursor] + --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 pdns-recursor 4.1.4:";; + 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] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --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-static-boost Prefer the static boost libraries over the shared + ones [no] + --enable-unit-tests enable unit test building [default=no] + --enable-reproducible Create reproducible builds. Use this only if you are + a distribution maintainer and need reproducible + builds. If you compile PowerDNS yourself, leave this + disabled, as it might make debugging harder. + [default=no] + --enable-verbose-logging + enable verbose logging [default=no] + --enable-botan use Botan [default=no] + --enable-libsodium use libsodium [default=auto] + --enable-libdecaf use libdecaf [default=no] + --disable-hardening disable compiler security checks [default=no] + --enable-asan enable AddressSanitizer [default=no] + --enable-msan enable MemorySanitizer [default=no] + --enable-tsan enable ThreadSanitizer [default=no] + --enable-lsan enable LeakSanitizer [default=no] + --enable-ubsan enable Undefined Behaviour Sanitizer [default=no] + --enable-malloc-trace enable malloc-trace [default=no] + --enable-valgrind enable Valgrind support [default=no] + --enable-systemd Enable systemd support (default is DISABLED, but + will be enabled when libraries are found) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). + --with-protobuf enable protobuf support [default=auto] + --with-boost=DIR prefix of Boost $boost_required_version [guess] + --with-luajit build LuaJIT bindings [default=auto] + --with-lua build Lua Bindings [default=auto] + --with-libcrypto=DIR root of the OpenSSL directory + --with-net-snmp enable net snmp support [default=auto] + --with-socketdir where the controlsocket lives [default=/var/run] + --with-systemd set directory for systemd service files + --with-systemd-modules-load set directory for systemd modules load files + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + PROTOBUF_CFLAGS + C compiler flags for PROTOBUF, overriding pkg-config + PROTOBUF_LIBS + linker flags for PROTOBUF, overriding pkg-config + BOOST_ROOT Location of Boost installation + LUA_CFLAGS C compiler flags for LUA, overriding pkg-config + LUA_LIBS linker flags for LUA, overriding pkg-config + BOTAN_CFLAGS + C compiler flags for BOTAN, overriding pkg-config + BOTAN_LIBS linker flags for BOTAN, overriding pkg-config + LIBSODIUM_CFLAGS + C compiler flags for LIBSODIUM, overriding pkg-config + LIBSODIUM_LIBS + linker flags for LIBSODIUM, overriding pkg-config + SYSTEMD_CFLAGS + C compiler flags for SYSTEMD, overriding pkg-config + SYSTEMD_LIBS + linker flags for SYSTEMD, overriding pkg-config + +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 the package provider. +_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 +pdns-recursor configure 4.1.4 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_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_cxx_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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_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_cxx_preproc_warn_flag$ac_cxx_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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_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_cxx_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; 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_cxx_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_cxx_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_cxx_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;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; 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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_header_mongrel + +# ac_fn_cxx_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_cxx_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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_run + +# ac_fn_cxx_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_cxx_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 \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_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 || + 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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# 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 \${$3+:} false; 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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# 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 \${$3+:} false; 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 declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + 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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_cxx_check_func LINENO FUNC VAR +# ------------------------------------ +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_cxx_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 \${$3+:} false; 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 declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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_cxx_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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_func + +# ac_fn_cxx_check_decl LINENO SYMBOL VAR INCLUDES +# ----------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_cxx_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_decl +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 pdns-recursor $as_me 4.1.4, which was +generated by GNU Autoconf 2.69. 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 + +# 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 + + +ac_aux_dir= +for ac_dir in build-aux "$srcdir"/build-aux; 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 build-aux \"$srcdir\"/build-aux" "$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. + + +am__api_version='1.14' + +# 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 ${ac_cv_path_install+:} false; 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 as_fn_executable_p "$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; } +# 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 ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + 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 + 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 + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + 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; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +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 --is-lightweight"; then + am_missing_run="$MISSING " +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 ${ac_cv_prog_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_path_mkdir+:} false; 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 + as_fn_executable_p "$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; } + +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 ${ac_cv_prog_AWK+:} false; 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 as_fn_executable_p "$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 \${ac_cv_prog_make_${ac_make}_set+:} false; 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 + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +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='pdns-recursor' + VERSION='4.1.4' + + +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"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar plaintar pax cpio none' + +# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 +$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; } + if test $am_uid -le $am_max_uid; 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" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 +$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; } + if test $am_gid -le $am_max_gid; 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" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 +$as_echo_n "checking how to create a ustar tar archive... " >&6; } + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_ustar-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + { echo "$as_me:$LINENO: $_am_tar --version" >&5 + ($_am_tar --version) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && break + done + am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=ustar -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 ustar -w "$$tardir"' + am__tar_='pax -L -x ustar -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H ustar -L' + am__tar_='find "$tardir" -print | cpio -o -H ustar -L' + am__untar='cpio -i -H ustar -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_ustar}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 + (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + rm -rf conftest.dir + if test -s conftest.tar; then + { echo "$as_me:$LINENO: $am__untar &5 + ($am__untar &5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 + (cat conftest.dir/file) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + if ${am_cv_prog_tar_ustar+:} false; then : + $as_echo_n "(cached) " >&6 +else + am_cv_prog_tar_ustar=$_am_tool +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 +$as_echo "$am_cv_prog_tar_ustar" >&6; } + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=0;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + + + + +ac_config_headers="$ac_config_headers config.h" + + +# 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 ${ac_cv_build+:} false; 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 ${ac_cv_host+:} false; 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 + + +: ${CFLAGS="-Wall -g -O2"} +: ${CXXFLAGS="-Wall -g -O2"} + +pdns_configure_args="$ac_configure_args" + + +cat >>confdefs.h <<_ACEOF +#define PDNS_CONFIG_ARGS "$pdns_configure_args" +_ACEOF + + +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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_CC+:} false; 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 as_fn_executable_p "$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 +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 ${ac_cv_objext+:} false; 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 ${ac_cv_c_compiler_gnu+:} false; 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 ${ac_cv_prog_cc_g+:} false; 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 ${ac_cv_prog_cc_c89+:} false; 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 +#include +struct stat; +/* 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 + +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 whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +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 + +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='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +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 ${am_cv_CC_dependencies_compiler_type+:} false; 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". + rm -rf conftest.dir + 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 10 /bin/sh. + echo '/* dummy */' > 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 + ;; + msvc7 | msvc7msys | 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=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + 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 ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$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 +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +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 ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$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_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + 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 + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# 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 ${ac_cv_cxx_compiler_gnu+:} false; 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_cxx_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_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_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_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +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="$CXX" 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 ${am_cv_CXX_dependencies_compiler_type+:} false; 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". + rm -rf conftest.dir + 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_CXX_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 10 /bin/sh. + echo '/* dummy */' > 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 + ;; + msvc7 | msvc7msys | 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_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_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; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_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 +_ACEOF +if ac_fn_cxx_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_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_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 +_ACEOF +if ac_fn_cxx_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 \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_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 ${ac_cv_path_GREP+:} false; 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" + as_fn_executable_p "$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 ${ac_cv_path_EGREP+:} false; 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" + as_fn_executable_p "$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 ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_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 + +_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 + +_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 +#include +#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_cxx_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_cxx_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_cxx_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" = xyes; 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 ${ac_cv_safe_to_define___extensions__+:} false; 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_cxx_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 + + + + + +$as_echo "#define RECURSOR 1" >>confdefs.h + + +# Warn when pkg.m4 is missing + + + ax_cxx_compile_cxx11_required=true + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + ac_success=no + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 +$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; } +if ${ax_cv_cxx_compile_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ax_cv_cxx_compile_cxx11=yes +else + ax_cv_cxx_compile_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 +$as_echo "$ax_cv_cxx_compile_cxx11" >&6; } + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + if test x$ac_success = xno; then + for switch in -std=gnu++11 -std=gnu++0x; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS="$ac_save_CXXFLAGS" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 +$as_echo "$as_me: No compiler with C++11 support was found" >&6;} + else + HAVE_CXX11=1 + +$as_echo "#define HAVE_CXX11 1" >>confdefs.h + + fi + + + fi + +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.4.2' +macro_revision='1.3337' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify 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' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +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 ${ac_cv_path_SED+:} false; 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" + as_fn_executable_p "$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 ${ac_cv_path_FGREP+:} false; 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" + as_fn_executable_p "$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 ${lt_cv_path_LD+:} false; 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 &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 ${lt_cv_prog_gnu_ld+:} false; 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 &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 ${lt_cv_path_NM+:} false; 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 "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + 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 ${ac_cv_prog_DUMPBIN+:} false; 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 as_fn_executable_p "$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 "link -dump" +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 ${ac_cv_prog_ac_ct_DUMPBIN+:} false; 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 as_fn_executable_p "$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 + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + 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 ${lt_cv_nm_interface+:} false; 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:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: 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 ${lt_cv_sys_max_cmd_len+:} false; 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; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + 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 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + 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" && \ + test undefined != "$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"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$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%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && 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 how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $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 ${lt_cv_ld_reload_flag+:} false; 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 + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + 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 ${ac_cv_prog_OBJDUMP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_OBJDUMP+:} false; 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 as_fn_executable_p "$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 ${lt_cv_deplibs_check_method+:} false; 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. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && 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 + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + 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 + ;; + +haiku*) + 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])(-bit)?( [LM]SB)? 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | 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_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +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}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $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 +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $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_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="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 + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + 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 ${ac_cv_prog_AR+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$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 +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 + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +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 ${ac_cv_prog_ac_ct_AR+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$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_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 + + + test -n "$ac_ct_AR" && break +done + + 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 +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +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 ${ac_cv_prog_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_RANLIB+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_RANLIB+:} false; 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 as_fn_executable_p "$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 \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 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 ${lt_cv_sys_global_symbol_pipe+:} false; 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};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /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 + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # 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 +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#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. */ +LT_DLSYM_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_globsym_save_LIBS=$LIBS + lt_globsym_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_globsym_save_LIBS + CFLAGS=$lt_globsym_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 + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + + +# 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 '$LINENO' "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*|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*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*) + 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" + ;; + powerpcle-*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*) + 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 ${lt_cv_cc_needs_belf+:} false; 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 + ;; +*-*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*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + 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" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $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 +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $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_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + 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 + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + 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 ${ac_cv_prog_DSYMUTIL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_NMEDIT+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_NMEDIT+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_LIPO+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_LIPO+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_OTOOL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_OTOOL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_OTOOL64+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_OTOOL64+:} false; 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 as_fn_executable_p "$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 ${lt_cv_apple_cc_single_mod+:} false; 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 there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 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 ${lt_cv_ld_exported_symbols_list+:} false; 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; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&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" != ":" && test "$lt_cv_ld_force_load" = "no"; 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" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf + + + + + +# 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; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +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 ${lt_cv_objdir+:} false; 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 + +# 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 "$cc_temp" | $SED "s%.*/%%; 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 ${lt_cv_path_MAGIC_CMD+:} false; 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 ${lt_cv_path_MAGIC_CMD+:} false; 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 + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $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 ${lt_cv_prog_compiler_rtti_exceptions+:} false; 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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= + + + 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' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + 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 + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + 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 | 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' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # 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* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # 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='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + 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* | sunf77* | sunf90* | sunf95*) + 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}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# 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 ${lt_cv_prog_compiler_pic_works+:} false; 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 ${lt_cv_prog_compiler_static_works+:} false; 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 "$_lt_linker_boilerplate" | $SED '/^$/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 ${lt_cv_prog_compiler_c_o+:} false; 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 ${lt_cv_prog_compiler_c_o+:} false; 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_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 | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = 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.19, 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 install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_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 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' + export_dynamic_flag_spec='${wl}--export-all-symbols' + 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/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + 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 + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + 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=' $pic_flag' + 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; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # 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; func_echo_all \"$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]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + 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; func_echo_all \"$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* | bgf* | bgxlf* | mpixlf*) + # 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='${wl}-rpath ${wl}$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_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 $linker_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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + 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") || (\$ 2 == "W")) && (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. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + 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 + } + }' + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +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 func_echo_all "${wl}${allow_undefined_flag}"; 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. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + 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 + } + }' + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +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' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + 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. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # 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 $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + 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 `func_echo_all "$deplibs" | $SED '\''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' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + 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=func_echo_all + 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 + ;; + + # 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 $pic_flag -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 $pic_flag ${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 && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${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_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 && test "$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 $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag ${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' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + 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 "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${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 + + ;; + 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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + 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) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=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_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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 $pic_flag ${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 $pic_flag ${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; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $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 + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + 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 + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # 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 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # 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; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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.so + # instead of lib.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=`func_echo_all "$lib" | $SED '\''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 # correct to gnu/linux during the next big refactor + 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,$cc_basename in + yes,*) + # gcc + 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="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + 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 + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + 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 + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # 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' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # 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 # correct to gnu/linux during the next big refactor + 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 + ;; + +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[23].*) 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 + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + 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=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + 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' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + 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 : + lt_cv_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 + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # 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;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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 ${ac_cv_lib_dl_dlopen+:} false; 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" = xyes; 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" = xyes; 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 ${ac_cv_lib_dld_shl_load+:} false; 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" = xyes; 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" = xyes; 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 ${ac_cv_lib_dl_dlopen+:} false; 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" = xyes; 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 ${ac_cv_lib_svld_dlopen+:} false; 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" = xyes; 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 ${ac_cv_lib_dld_dld_link+:} false; 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" = xyes; 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 ${lt_cv_dlopen_self+:} false; 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 $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#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 + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* 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 ${lt_cv_dlopen_self_static+:} false; 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 $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#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 + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* 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=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +CC="$lt_save_CC" + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_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; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_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 +_ACEOF +if ac_fn_cxx_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_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_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 +_ACEOF +if ac_fn_cxx_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 \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$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. + + + + + + +# 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 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* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + 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++"} + CFLAGS=$CXXFLAGS + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + 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_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# 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 ${lt_cv_path_LD+:} false; 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 &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 ${lt_cv_prog_gnu_ld+:} false; 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 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_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 + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${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 + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + 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. + archive_cmds_CXX='$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 -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $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; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=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. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${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 + hardcode_direct_CXX=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_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + 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 + + export_dynamic_flag_spec_CXX='${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_CXX=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_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`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 "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`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 "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$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. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`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 "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`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 "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${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_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$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 + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_CXX=' ' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=yes + file_list_spec_CXX='@' + # 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_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' + enable_shared_with_static_runtimes_CXX=yes + # Don't use ranlib + old_postinstall_cmds_CXX='chmod 644 $oldlib' + postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$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... + archive_expsym_cmds_CXX='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 + ld_shlibs_CXX=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_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=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="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_CXX="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}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$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}" + archive_expsym_cmds_CXX="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 + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=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 + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$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; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${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 + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=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 + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$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; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${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 + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${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_CXX='$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_CXX='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++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -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. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | 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. + archive_cmds_CXX='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' + archive_expsym_cmds_CXX='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; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$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."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$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 + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='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 | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='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 | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='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 | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$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 + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$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 + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # 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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='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 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=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='func_echo_all' + + # 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. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=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*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=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. + archive_cmds_CXX='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' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='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 "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # 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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # 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 -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='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' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=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?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # 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. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$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. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -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 -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='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 -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$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. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$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 + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$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... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +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 + # 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 ${prev}${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 + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} 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 "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${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 "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$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 "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +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. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +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 + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # 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 + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-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_CXX='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-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_CXX='-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 + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + 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_prog_compiler_pic_CXX=-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_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-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_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--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 + ;; + 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). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+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_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-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_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-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_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +{ $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 ${lt_cv_prog_compiler_pic_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } +lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $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 ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=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 "$_lt_linker_boilerplate" | $SED '/^$/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_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +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 ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_CXX=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_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&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 ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_CXX=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_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = 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; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + 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 + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX 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; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $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_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 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 + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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.so + # instead of lib.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=`func_echo_all "$lib" | $SED '\''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 # correct to gnu/linux during the next big refactor + 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,$cc_basename in + yes,*) + # gcc + 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}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + 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 + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + 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 + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # 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' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # 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_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + ;; + +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[23].*) 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 + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + 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=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + 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' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_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 + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # 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;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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != 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, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = 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 + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + 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_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + + + THREADFLAGS="" + + case "$host_os" in + solaris2.1*) + LIBS="-lposix4 -lpthread $LIBS" + CXXFLAGS="-D_REENTRANT $CXXFLAGS" + have_solaris="yes" + ;; + solaris2.8 | solaris2.9 ) + +$as_echo "#define NEED_POSIX_TYPEDEF /**/" >>confdefs.h + + +$as_echo "#define NEED_INET_NTOP_PROTO /**/" >>confdefs.h + + LIBS="-lposix4 -lpthread $LIBS" + CXXFLAGS="-D_REENTRANT $CXXFLAGS" + have_solaris="yes" + ;; + linux*) + THREADFLAGS="-pthread" + have_linux="yes" + ;; + darwin*) + CXXFLAGS="-D__APPLE_USE_RFC_3542 -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $CXXFLAGS" + ;; + freebsd*) + THREADFLAGS="-pthread" + have_freebsd="yes" + ;; + *) + LDFLAGS="-pthread $LDFLAGS" + CXXFLAGS="-pthread $CXXFLAGS" + ;; + esac + + if test "x$have_freebsd" = "xyes"; then + HAVE_FREEBSD_TRUE= + HAVE_FREEBSD_FALSE='#' +else + HAVE_FREEBSD_TRUE='#' + HAVE_FREEBSD_FALSE= +fi + + if test "x$have_linux" = "xyes"; then + HAVE_LINUX_TRUE= + HAVE_LINUX_FALSE='#' +else + HAVE_LINUX_TRUE='#' + HAVE_LINUX_FALSE= +fi + + if test "x$have_solaris" = "xyes"; then + HAVE_SOLARIS_TRUE= + HAVE_SOLARIS_FALSE='#' +else + HAVE_SOLARIS_TRUE='#' + HAVE_SOLARIS_FALSE= +fi + + + case "$host" in + mips* | powerpc-* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -latomic" >&5 +$as_echo_n "checking whether the linker accepts -latomic... " >&6; } + LDFLAGS="-latomic $LDFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + as_fn_error $? "Unable to link against libatomic, cannot continue" "$LINENO" 5 + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ;; + esac + + + DYNLINKFLAGS=-export-dynamic + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5 +$as_echo_n "checking for library containing inet_aton... " >&6; } +if ${ac_cv_search_inet_aton+:} false; 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 inet_aton (); +int +main () +{ +return inet_aton (); + ; + return 0; +} +_ACEOF +for ac_lib in '' resolv; 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_cxx_try_link "$LINENO"; then : + ac_cv_search_inet_aton=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_inet_aton+:} false; then : + break +fi +done +if ${ac_cv_search_inet_aton+:} false; then : + +else + ac_cv_search_inet_aton=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5 +$as_echo "$ac_cv_search_inet_aton" >&6; } +ac_res=$ac_cv_search_inet_aton +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 gethostbyname" >&5 +$as_echo_n "checking for library containing gethostbyname... " >&6; } +if ${ac_cv_search_gethostbyname+:} false; 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 gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +for ac_lib in '' nsl; 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_cxx_try_link "$LINENO"; then : + ac_cv_search_gethostbyname=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_gethostbyname+:} false; then : + break +fi +done +if ${ac_cv_search_gethostbyname+:} false; then : + +else + ac_cv_search_gethostbyname=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 +$as_echo "$ac_cv_search_gethostbyname" >&6; } +ac_res=$ac_cv_search_gethostbyname +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 socket" >&5 +$as_echo_n "checking for library containing socket... " >&6; } +if ${ac_cv_search_socket+:} false; 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 socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +for ac_lib in '' socket; 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_cxx_try_link "$LINENO"; then : + ac_cv_search_socket=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_socket+:} false; then : + break +fi +done +if ${ac_cv_search_socket+:} false; then : + +else + ac_cv_search_socket=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 +$as_echo "$ac_cv_search_socket" >&6; } +ac_res=$ac_cv_search_socket +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 gethostent" >&5 +$as_echo_n "checking for library containing gethostent... " >&6; } +if ${ac_cv_search_gethostent+:} false; 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 gethostent (); +int +main () +{ +return gethostent (); + ; + return 0; +} +_ACEOF +for ac_lib in '' nsl; 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_cxx_try_link "$LINENO"; then : + ac_cv_search_gethostent=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_gethostent+:} false; then : + break +fi +done +if ${ac_cv_search_gethostent+:} false; then : + +else + ac_cv_search_gethostent=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostent" >&5 +$as_echo "$ac_cv_search_gethostent" >&6; } +ac_res=$ac_cv_search_gethostent +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + for ac_func in recvmmsg sendmmsg accept4 +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_cxx_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 + + + +# Boost Context was introduced in 1.51 (Aug 2012), but there was an immediate +# API break in 1.52 (Nov 2012), so we only support that, and later. +pdns_context_library="System V ucontexts" + + + + + OLD_LIBS="$LIBS"; LIBS="" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 +$as_echo_n "checking for library containing clock_gettime... " >&6; } +if ${ac_cv_search_clock_gettime+:} false; 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 clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt; 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_cxx_try_link "$LINENO"; then : + ac_cv_search_clock_gettime=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_clock_gettime+:} false; then : + break +fi +done +if ${ac_cv_search_clock_gettime+:} false; then : + +else + ac_cv_search_clock_gettime=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 +$as_echo "$ac_cv_search_clock_gettime" >&6; } +ac_res=$ac_cv_search_clock_gettime +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h + +fi + + RT_LIBS=$LIBS + + LIBS="$OLD_LIBS" + + +boost_required_version=1.35 + + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $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 + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $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 + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + 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 + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; 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" >&5 +$as_echo "no" >&6; } + PKG_CONFIG="" + fi +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we need to link in protobuf" >&5 +$as_echo_n "checking if we need to link in protobuf... " >&6; } + +# Check whether --with-protobuf was given. +if test "${with_protobuf+set}" = set; then : + withval=$with_protobuf; with_protobuf=$withval +else + with_protobuf=auto +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_protobuf" >&5 +$as_echo "$with_protobuf" >&6; } + + if test "x$with_protobuf" != "xno"; then : + + if test "x$with_protobuf" = "xyes" -o "x$with_protobuf" = "xauto"; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PROTOBUF" >&5 +$as_echo_n "checking for PROTOBUF... " >&6; } + +if test -n "$PROTOBUF_CFLAGS"; then + pkg_cv_PROTOBUF_CFLAGS="$PROTOBUF_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"protobuf\""; } >&5 + ($PKG_CONFIG --exists --print-errors "protobuf") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PROTOBUF_CFLAGS=`$PKG_CONFIG --cflags "protobuf" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PROTOBUF_LIBS"; then + pkg_cv_PROTOBUF_LIBS="$PROTOBUF_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"protobuf\""; } >&5 + ($PKG_CONFIG --exists --print-errors "protobuf") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PROTOBUF_LIBS=`$PKG_CONFIG --libs "protobuf" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PROTOBUF_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "protobuf" 2>&1` + else + PROTOBUF_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "protobuf" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PROTOBUF_PKG_ERRORS" >&5 + + : +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + : +else + PROTOBUF_CFLAGS=$pkg_cv_PROTOBUF_CFLAGS + PROTOBUF_LIBS=$pkg_cv_PROTOBUF_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + : +fi + # Extract the first word of "protoc", so it can be a program name with args. +set dummy protoc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PROTOC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PROTOC"; then + ac_cv_prog_PROTOC="$PROTOC" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PROTOC="protoc" + $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 +PROTOC=$ac_cv_prog_PROTOC +if test -n "$PROTOC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROTOC" >&5 +$as_echo "$PROTOC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +fi + +fi + if test "x$with_protobuf" = "xyes"; then : + + if test x"$PROTOBUF_LIBS" = "x"; then : + + as_fn_error $? "Protobuf requested but libraries were not found" "$LINENO" 5 + +fi + if test x"$PROTOC" = "x"; then : + + as_fn_error $? "Protobuf requested but the protobuf compiler was not found" "$LINENO" 5 + +fi + +fi + if test x"$PROTOBUF_LIBS" != "x"; then + HAVE_PROTOBUF_TRUE= + HAVE_PROTOBUF_FALSE='#' +else + HAVE_PROTOBUF_TRUE='#' + HAVE_PROTOBUF_FALSE= +fi + + if test x"$PROTOC" != "x"; then + HAVE_PROTOC_TRUE= + HAVE_PROTOC_FALSE='#' +else + HAVE_PROTOC_TRUE='#' + HAVE_PROTOC_FALSE= +fi + + if test x"$PROTOBUF_LIBS" != "x"; then : + +$as_echo "#define HAVE_PROTOBUF 1" >>confdefs.h + +fi + +if test "x$PROTOBUF_LIBS" != "x" -a x"$PROTOC" != "x"; then : + # The protobuf code needs boost::uuid, which is available from 1.42 onward + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Bumping minimal Boost requirement to 1.42. To keep the requirement at 1.35, disable protobuf support" >&5 +$as_echo "$as_me: WARNING: Bumping minimal Boost requirement to 1.42. To keep the requirement at 1.35, disable protobuf support" >&2;} + boost_required_version=1.42 + +fi + +echo "$as_me: this is boost.m4 serial 26 PowerDNS modified" >&5 +boost_save_IFS=$IFS +boost_version_req=$boost_required_version +IFS=. +set x $boost_version_req 0 0 0 +IFS=$boost_save_IFS +shift +boost_version_req=`expr "$1" '*' 100000 + "$2" '*' 100 + "$3"` +boost_version_req_string=$1.$2.$3 + +# Check whether --with-boost was given. +if test "${with_boost+set}" = set; then : + withval=$with_boost; +fi +# If BOOST_ROOT is set and the user has not provided a value to +# --with-boost, then treat BOOST_ROOT as if it the user supplied it. +if test x"$BOOST_ROOT" != x; then + if test x"$with_boost" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&5 +$as_echo "$as_me: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&6;} + with_boost=$BOOST_ROOT + else + { $as_echo "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&5 +$as_echo "$as_me: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&6;} + fi +fi +DISTCHECK_CONFIGURE_FLAGS="$DISTCHECK_CONFIGURE_FLAGS '--with-boost=$with_boost'" +boost_save_CPPFLAGS=$CPPFLAGS + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boost headers version >= $boost_version_req_string" >&5 +$as_echo_n "checking for Boost headers version >= $boost_version_req_string... " >&6; } +if ${boost_cv_inc_path+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_inc_path=no +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#if !defined BOOST_VERSION +# error BOOST_VERSION is not defined +#elif BOOST_VERSION < $boost_version_req +# error Boost headers version < $boost_version_req +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF + # If the user provided a value to --with-boost, use it and only it. + case $with_boost in #( + ''|yes) set x '' /opt/local/include /usr/local/include /opt/include \ + /usr/include C:/Boost/include;; #( + *) set x "$with_boost/include" "$with_boost";; + esac + shift + for boost_dir + do + # Without --layout=system, Boost (or at least some versions) installs + # itself in /include/boost-. This inner loop helps to + # find headers in such directories. + # + # Any ${boost_dir}/boost-x_xx directories are searched in reverse version + # order followed by ${boost_dir}. The final '.' is a sentinel for + # searching $boost_dir" itself. Entries are whitespace separated. + # + # I didn't indent this loop on purpose (to avoid over-indented code) + boost_layout_system_search_list=`cd "$boost_dir" 2>/dev/null \ + && ls -1 | "${GREP}" '^boost-' | sort -rn -t- -k2 \ + && echo .` + for boost_inc in $boost_layout_system_search_list + do + if test x"$boost_inc" != x.; then + boost_inc="$boost_dir/$boost_inc" + else + boost_inc="$boost_dir" # Uses sentinel in boost_layout_system_search_list + fi + if test x"$boost_inc" != x; then + # We are going to check whether the version of Boost installed + # in $boost_inc is usable by running a compilation that + # #includes it. But if we pass a -I/some/path in which Boost + # is not installed, the compiler will just skip this -I and + # use other locations (either from CPPFLAGS, or from its list + # of system include directories). As a result we would use + # header installed on the machine instead of the /some/path + # specified by the user. So in that precise case (trying + # $boost_inc), make sure the version.hpp exists. + # + # Use test -e as there can be symlinks. + test -e "$boost_inc/boost/version.hpp" || continue + CPPFLAGS="$CPPFLAGS -I$boost_inc" + fi + if ac_fn_cxx_try_compile "$LINENO"; then : + boost_cv_inc_path=yes +else + boost_cv_version=no +fi +rm -f core conftest.err conftest.$ac_objext + if test x"$boost_cv_inc_path" = xyes; then + if test x"$boost_inc" != x; then + boost_cv_inc_path=$boost_inc + fi + break 2 + fi + done + done +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_inc_path" >&5 +$as_echo "$boost_cv_inc_path" >&6; } + case $boost_cv_inc_path in #( + no) + boost_errmsg="cannot find Boost headers version >= $boost_version_req_string" + as_fn_error $? "$boost_errmsg" "$LINENO" 5 + + ;;#( + yes) + BOOST_CPPFLAGS= + ;;#( + *) + BOOST_CPPFLAGS="-I$boost_cv_inc_path" + ;; + esac + if test x"$boost_cv_inc_path" != xno; then + +$as_echo "#define HAVE_BOOST 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boost's header version" >&5 +$as_echo_n "checking for Boost's header version... " >&6; } +if ${boost_cv_lib_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +boost-lib-version = BOOST_LIB_VERSION +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + grep -v '#' | + grep -v '^[[:space:]]*$' | + tr -d '\r' | + tr -s '\n' ' ' | + $SED -n -e "/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}" >conftest.i 2>&1; then : + boost_cv_lib_version=`cat conftest.i` +fi +rm -rf conftest* +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_version" >&5 +$as_echo "$boost_cv_lib_version" >&6; } + # e.g. "134" for 1_34_1 or "135" for 1_35 + boost_major_version=`echo "$boost_cv_lib_version" | sed 's/_//;s/_.*//'` + case $boost_major_version in #( + '' | *[!0-9]*) + as_fn_error $? "invalid value: boost_major_version='$boost_major_version'" "$LINENO" 5 + ;; + esac +fi +CPPFLAGS=$boost_save_CPPFLAGS + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the flags needed to use pthreads" >&5 +$as_echo_n "checking for the flags needed to use pthreads... " >&6; } +if ${boost_cv_pthread_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_pthread_flag= + # The ordering *is* (sometimes) important. Some notes on the + # individual items follow: + # (none): in case threads are in libc; should be tried before -Kthread and + # other compiler flags to prevent continual compiler warnings + # -lpthreads: AIX (must check this before -lpthread) + # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + # -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads) + # -pthreads: Solaris/GCC + # -mthreads: MinGW32/GCC, Lynx/GCC + # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it + # doesn't hurt to check since this sometimes defines pthreads too; + # also defines -D_REENTRANT) + # ... -mt is also the pthreads flag for HP/aCC + # -lpthread: GNU Linux, etc. + # --thread-safe: KAI C++ + case $host_os in #( + *solaris*) + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + boost_pthread_flags="-pthreads -lpthread -mt -pthread";; #( + *) + boost_pthread_flags="-lpthreads -Kthread -kthread -llthread -pthread \ + -pthreads -mthreads -lpthread --thread-safe -mt";; + esac + # Generate the test file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); + ; + return 0; +} +_ACEOF + for boost_pthread_flag in '' $boost_pthread_flags; do + boost_pthread_ok=false + boost_pthreads__save_LIBS=$LIBS + LIBS="$LIBS $boost_pthread_flag" + if ac_fn_cxx_try_link "$LINENO"; then : + if grep ".*$boost_pthread_flag" conftest.err; then + echo "This flag seems to have triggered warnings" >&5 + else + boost_pthread_ok=:; boost_cv_pthread_flag=$boost_pthread_flag + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + LIBS=$boost_pthreads__save_LIBS + $boost_pthread_ok && break + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_pthread_flag" >&5 +$as_echo "$boost_cv_pthread_flag" >&6; } +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the toolset name used by Boost for $CXX" >&5 +$as_echo_n "checking for the toolset name used by Boost for $CXX... " >&6; } +if ${boost_cv_lib_tag+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_lib_tag=unknown +if test x$boost_cv_inc_path != xno; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + # The following tests are mostly inspired by boost/config/auto_link.hpp + # The list is sorted to most recent/common to oldest compiler (in order + # to increase the likelihood of finding the right compiler with the + # least number of compilation attempt). + # Beware that some tests are sensible to the order (for instance, we must + # look for MinGW before looking for GCC3). + # I used one compilation test per compiler with a #error to recognize + # each compiler so that it works even when cross-compiling (let me know + # if you know a better approach). + # Known missing tags (known from Boost's tools/build/v2/tools/common.jam): + # como, edg, kcc, bck, mp, sw, tru, xlc + # I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines + # the same defines as GCC's). + for i in \ + "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw72" \ + "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc72" \ + "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 1 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw71" \ + "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc71" \ + "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 0 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw70" \ + "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc70" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw63" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc63" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw62" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc62" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw61" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc61" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw60" \ + "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc60" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw54" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc54" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw53" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc53" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw52" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc52" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw51" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc51" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw50" \ + "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc50" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw410" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC @ gcc410" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw49" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC @ gcc49" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw48" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC @ gcc48" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw47" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC @ gcc47" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw46" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC @ gcc46" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw45" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC @ gcc45" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw44" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc44" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw43" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc43" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw42" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc42" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw41" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc41" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw40" \ + "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc40" \ + "defined __GNUC__ && __GNUC__ == 3 && !defined __ICC \ + && (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw" \ + "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc34" \ + "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc33" \ + "defined _MSC_VER && _MSC_VER >= 1500 @ vc90" \ + "defined _MSC_VER && _MSC_VER == 1400 @ vc80" \ + "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc32" \ + "defined _MSC_VER && _MSC_VER == 1310 @ vc71" \ + "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc31" \ + "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc30" \ + "defined __BORLANDC__ @ bcb" \ + "defined __ICC && (defined __unix || defined ) @ il" \ + "defined __ICL @ iw" \ + "defined _MSC_VER && _MSC_VER == 1300 @ vc7" \ + "defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ == 95 && !defined __ICC @ gcc295" \ + "defined __MWERKS__ && __MWERKS__ <= 0x32FF @ cw9" \ + "defined _MSC_VER && _MSC_VER < 1300 && !defined UNDER_CE @ vc6" \ + "defined _MSC_VER && _MSC_VER < 1300 && defined UNDER_CE @ evc4" \ + "defined __MWERKS__ && __MWERKS__ <= 0x31FF @ cw8" + do + boost_tag_test=`expr "X$i" : 'X\([^@]*\) @ '` + boost_tag=`expr "X$i" : 'X[^@]* @ \(.*\)'` + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if $boost_tag_test +/* OK */ +#else +# error $boost_tag_test +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + boost_cv_lib_tag=$boost_tag; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + case $boost_cv_lib_tag in #( + # Some newer (>= 1.35?) versions of Boost seem to only use "gcc" as opposed + # to "gcc41" for instance. + *-gcc | *'-gcc ') :;; #( Don't re-add -gcc: it's already in there. + gcc*) + boost_tag_x= + case $host_os in #( + darwin*) + if test $boost_major_version -ge 136; then + # The `x' added in r46793 of Boost. + boost_tag_x=x + fi;; + esac + # We can specify multiple tags in this variable because it's used by + # BOOST_FIND_LIB that does a `for tag in -$boost_cv_lib_tag' ... + boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc" + ;; #( + unknown) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not figure out which toolset name to use for $CXX" >&5 +$as_echo "$as_me: WARNING: could not figure out which toolset name to use for $CXX" >&2;} + boost_cv_lib_tag= + ;; + esac +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_tag" >&5 +$as_echo "$boost_cv_lib_tag" >&6; } +# Check whether --enable-static-boost was given. +if test "${enable_static_boost+set}" = set; then : + enableval=$enable_static_boost; enable_static_boost=yes +else + enable_static_boost=no +fi + +# Check whether we do better use `mt' even though we weren't ask to. +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if defined _REENTRANT || defined _MT || defined __MT__ +/* use -mt */ +#else +# error MT not needed +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + boost_guess_use_mt=: +else + boost_guess_use_mt=false +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Boost is new enough to use the context library..." >&5 +$as_echo_n "checking whether Boost is new enough to use the context library...... " >&6; } + if test $boost_major_version -ge 152; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + if test $boost_major_version -ge 157; then + boost_thread_save_LIBS=$LIBS +boost_thread_save_LDFLAGS=$LDFLAGS +boost_thread_save_CPPFLAGS=$CPPFLAGS +# Link-time dependency from thread to system was added as of 1.49.0. +if test $boost_major_version -ge 149; then +if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost system library" >&5 +$as_echo "$as_me: Boost not available, not searching for the Boost system library" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/system/error_code.hpp" >&5 +$as_echo "$as_me: Boost not available, not searching for boost/system/error_code.hpp" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/system/error_code.hpp" "ac_cv_header_boost_system_error_code_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_system_error_code_hpp" = xyes; then : + +$as_echo "#define HAVE_BOOST_SYSTEM_ERROR_CODE_HPP 1" >>confdefs.h + +else + as_fn_error $? "cannot find boost/system/error_code.hpp" "$LINENO" 5 +fi + + +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost system library" >&5 +$as_echo_n "checking for the Boost system library... " >&6; } +if ${boost_cv_lib_system+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_lib_system=no + case "" in #( + (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( + (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( + (*) boost_mt=; boost_rtopt=;; + esac + if test $enable_static_boost = yes; then + boost_rtopt="s$boost_rtopt" + fi + # Find the proper debug variant depending on what we've been asked to find. + case $boost_rtopt in #( + (*d*) boost_rt_d=$boost_rtopt;; #( + (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn') + boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #( + (*) boost_rt_d='-d';; + esac + # If the PREFERRED-RT-OPT are not empty, prepend a `-'. + test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt" + $boost_guess_use_mt && boost_mt=-mt + # Look for the abs path the static archive. + # $libext is computed by Libtool but let's make sure it's non empty. + test -z "$libext" && + as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5 + boost_save_ac_objext=$ac_objext + # Generate the test file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +boost::system::error_code e; e.clear(); + ; + return 0; +} +_ACEOF + if ac_fn_cxx_try_compile "$LINENO"; then : + ac_objext=do_not_rm_me_plz +else + as_fn_error $? "cannot compile a test that uses Boost system" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext + ac_objext=$boost_save_ac_objext + boost_failed_libs= +# Don't bother to ident the following nested for loops, only the 2 +# innermost ones matter. +for boost_lib_ in system; do +for boost_tag_ in -$boost_cv_lib_tag ''; do +for boost_ver_ in -$boost_cv_lib_version ''; do +for boost_mt_ in $boost_mt -mt ''; do +for boost_rtopt_ in $boost_rtopt '' -d; do + for boost_lib in \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_ver_ + do + # Avoid testing twice the same lib + case $boost_failed_libs in #( + (*@$boost_lib@*) continue;; + esac + # If with_boost is empty, we'll search in /lib first, which is not quite + # right so instead we'll try to a location based on where the headers are. + boost_tmp_lib=$with_boost + test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include} + for boost_ldpath in "$boost_tmp_lib/lib" '' \ + /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \ + "$with_boost" C:/Boost/lib /lib* + do + # Don't waste time with directories that don't exist. + if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then + continue + fi + boost_save_LDFLAGS=$LDFLAGS + # Are we looking for a static library? + case $boost_ldpath:$boost_rtopt_ in #( + (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt) + boost_cv_lib_system_LIBS="$boost_ldpath/lib$boost_lib.$libext" + test -e "$boost_cv_lib_system_LIBS" || continue;; #( + (*) # No: use -lboost_foo to find the shared library. + boost_cv_lib_system_LIBS="-l$boost_lib";; + esac + boost_save_LIBS=$LIBS + LIBS="$boost_cv_lib_system_LIBS $LIBS" + test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_cv_lib_system=yes +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_cv_lib_system=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + ac_objext=$boost_save_ac_objext + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + if test x"$boost_cv_lib_system" = xyes; then + # Check or used cached result of whether or not using -R or + # -rpath makes sense. Some implementations of ld, such as for + # Mac OSX, require -rpath but -R is the flag known to work on + # other systems. https://github.com/tsuna/boost.m4/issues/19 + if ${boost_cv_rpath_link_ldflag+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $boost_ldpath in + '') # Nothing to do. + boost_cv_rpath_link_ldflag= + boost_rpath_link_ldflag_found=yes;; + *) + for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do + LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + LIBS="$boost_save_LIBS $boost_cv_lib_system_LIBS" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_rpath_link_ldflag_found=yes + break +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_rpath_link_ldflag_found=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + done + ;; + esac + if test "x$boost_rpath_link_ldflag_found" != "xyes"; then : + as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5 +fi + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + +fi + + test x"$boost_ldpath" != x && + boost_cv_lib_system_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + boost_cv_lib_system_LDPATH="$boost_ldpath" + break 7 + else + boost_failed_libs="$boost_failed_libs@$boost_lib@" + fi + done + done +done +done +done +done +done # boost_lib_ +rm -f conftest.$ac_objext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_system" >&5 +$as_echo "$boost_cv_lib_system" >&6; } +case $boost_cv_lib_system in #( + (yes) $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +$as_echo "#define HAVE_BOOST_SYSTEM 1" >>confdefs.h + BOOST_SYSTEM_LDFLAGS=$boost_cv_lib_system_LDFLAGS + BOOST_SYSTEM_LDPATH=$boost_cv_lib_system_LDPATH + BOOST_LDPATH=$boost_cv_lib_system_LDPATH + BOOST_SYSTEM_LIBS=$boost_cv_lib_system_LIBS + ;; +esac +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + + + +fi # end of the Boost.System check. +LIBS="$LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag" +LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS" +CPPFLAGS="$CPPFLAGS $boost_cv_pthread_flag" + +# When compiling for the Windows platform, the threads library is named +# differently. This suffix doesn't exist in new versions of Boost, or +# possibly new versions of GCC on mingw I am assuming it's Boost's change for +# now and I am setting version to 1.48, for lack of knowledge as to when this +# change occurred. +if test $boost_major_version -lt 148; then + case $host_os in + (*mingw*) boost_thread_lib_ext=_win32;; + esac +fi +if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost thread library" >&5 +$as_echo "$as_me: Boost not available, not searching for the Boost thread library" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/thread.hpp" >&5 +$as_echo "$as_me: Boost not available, not searching for boost/thread.hpp" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/thread.hpp" "ac_cv_header_boost_thread_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_thread_hpp" = xyes; then : + +$as_echo "#define HAVE_BOOST_THREAD_HPP 1" >>confdefs.h + +else + as_fn_error $? "cannot find boost/thread.hpp" "$LINENO" 5 +fi + + +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost thread library" >&5 +$as_echo_n "checking for the Boost thread library... " >&6; } +if ${boost_cv_lib_thread+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_lib_thread=no + case "" in #( + (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( + (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( + (*) boost_mt=; boost_rtopt=;; + esac + if test $enable_static_boost = yes; then + boost_rtopt="s$boost_rtopt" + fi + # Find the proper debug variant depending on what we've been asked to find. + case $boost_rtopt in #( + (*d*) boost_rt_d=$boost_rtopt;; #( + (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn') + boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #( + (*) boost_rt_d='-d';; + esac + # If the PREFERRED-RT-OPT are not empty, prepend a `-'. + test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt" + $boost_guess_use_mt && boost_mt=-mt + # Look for the abs path the static archive. + # $libext is computed by Libtool but let's make sure it's non empty. + test -z "$libext" && + as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5 + boost_save_ac_objext=$ac_objext + # Generate the test file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +boost::thread t; boost::mutex m; + ; + return 0; +} +_ACEOF + if ac_fn_cxx_try_compile "$LINENO"; then : + ac_objext=do_not_rm_me_plz +else + as_fn_error $? "cannot compile a test that uses Boost thread" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext + ac_objext=$boost_save_ac_objext + boost_failed_libs= +# Don't bother to ident the following nested for loops, only the 2 +# innermost ones matter. +for boost_lib_ in thread$boost_thread_lib_ext; do +for boost_tag_ in -$boost_cv_lib_tag ''; do +for boost_ver_ in -$boost_cv_lib_version ''; do +for boost_mt_ in $boost_mt -mt ''; do +for boost_rtopt_ in $boost_rtopt '' -d; do + for boost_lib in \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_ver_ + do + # Avoid testing twice the same lib + case $boost_failed_libs in #( + (*@$boost_lib@*) continue;; + esac + # If with_boost is empty, we'll search in /lib first, which is not quite + # right so instead we'll try to a location based on where the headers are. + boost_tmp_lib=$with_boost + test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include} + for boost_ldpath in "$boost_tmp_lib/lib" '' \ + /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \ + "$with_boost" C:/Boost/lib /lib* + do + # Don't waste time with directories that don't exist. + if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then + continue + fi + boost_save_LDFLAGS=$LDFLAGS + # Are we looking for a static library? + case $boost_ldpath:$boost_rtopt_ in #( + (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt) + boost_cv_lib_thread_LIBS="$boost_ldpath/lib$boost_lib.$libext" + test -e "$boost_cv_lib_thread_LIBS" || continue;; #( + (*) # No: use -lboost_foo to find the shared library. + boost_cv_lib_thread_LIBS="-l$boost_lib";; + esac + boost_save_LIBS=$LIBS + LIBS="$boost_cv_lib_thread_LIBS $LIBS" + test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_cv_lib_thread=yes +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_cv_lib_thread=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + ac_objext=$boost_save_ac_objext + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + if test x"$boost_cv_lib_thread" = xyes; then + # Check or used cached result of whether or not using -R or + # -rpath makes sense. Some implementations of ld, such as for + # Mac OSX, require -rpath but -R is the flag known to work on + # other systems. https://github.com/tsuna/boost.m4/issues/19 + if ${boost_cv_rpath_link_ldflag+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $boost_ldpath in + '') # Nothing to do. + boost_cv_rpath_link_ldflag= + boost_rpath_link_ldflag_found=yes;; + *) + for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do + LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + LIBS="$boost_save_LIBS $boost_cv_lib_thread_LIBS" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_rpath_link_ldflag_found=yes + break +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_rpath_link_ldflag_found=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + done + ;; + esac + if test "x$boost_rpath_link_ldflag_found" != "xyes"; then : + as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5 +fi + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + +fi + + test x"$boost_ldpath" != x && + boost_cv_lib_thread_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + boost_cv_lib_thread_LDPATH="$boost_ldpath" + break 7 + else + boost_failed_libs="$boost_failed_libs@$boost_lib@" + fi + done + done +done +done +done +done +done # boost_lib_ +rm -f conftest.$ac_objext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_thread" >&5 +$as_echo "$boost_cv_lib_thread" >&6; } +case $boost_cv_lib_thread in #( + (yes) $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +$as_echo "#define HAVE_BOOST_THREAD 1" >>confdefs.h + BOOST_THREAD_LDFLAGS=$boost_cv_lib_thread_LDFLAGS + BOOST_THREAD_LDPATH=$boost_cv_lib_thread_LDPATH + BOOST_LDPATH=$boost_cv_lib_thread_LDPATH + BOOST_THREAD_LIBS=$boost_cv_lib_thread_LIBS + ;; +esac +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + + +case $host_os in + (*mingw*) boost_thread_w32_socket_link=-lws2_32;; +esac + +BOOST_THREAD_LIBS="$BOOST_THREAD_LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag $boost_thread_w32_socket_link" +BOOST_THREAD_LDFLAGS="$BOOST_SYSTEM_LDFLAGS" +BOOST_CPPFLAGS="$BOOST_CPPFLAGS $boost_cv_pthread_flag" +LIBS=$boost_thread_save_LIBS +LDFLAGS=$boost_thread_save_LDFLAGS +CPPFLAGS=$boost_thread_save_CPPFLAGS + + + LIBS="$LIBS $BOOST_THREAD_LIBS" + LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the Boost context library actually links..." >&5 +$as_echo "$as_me: checking whether the Boost context library actually links..." >&6;} + if test $boost_major_version -ge 161; then + if test x"$boost_cv_inc_path" = xno; then + : +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/context/detail/fcontext.hpp" "ac_cv_header_boost_context_detail_fcontext_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_context_detail_fcontext_hpp" = xyes; then : + + if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost context library" >&5 +$as_echo "$as_me: Boost not available, not searching for the Boost context library" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/context/detail/fcontext.hpp" >&5 +$as_echo "$as_me: Boost not available, not searching for boost/context/detail/fcontext.hpp" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/context/detail/fcontext.hpp" "ac_cv_header_boost_context_detail_fcontext_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_context_detail_fcontext_hpp" = xyes; then : + +$as_echo "#define HAVE_BOOST_CONTEXT_DETAIL_FCONTEXT_HPP 1" >>confdefs.h + +else + as_fn_error $? "cannot find boost/context/detail/fcontext.hpp" "$LINENO" 5 +fi + + +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost context library" >&5 +$as_echo_n "checking for the Boost context library... " >&6; } +if ${boost_cv_lib_context+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_lib_context=no + case "" in #( + (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( + (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( + (*) boost_mt=; boost_rtopt=;; + esac + if test $enable_static_boost = yes; then + boost_rtopt="s$boost_rtopt" + fi + # Find the proper debug variant depending on what we've been asked to find. + case $boost_rtopt in #( + (*d*) boost_rt_d=$boost_rtopt;; #( + (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn') + boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #( + (*) boost_rt_d='-d';; + esac + # If the PREFERRED-RT-OPT are not empty, prepend a `-'. + test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt" + $boost_guess_use_mt && boost_mt=-mt + # Look for the abs path the static archive. + # $libext is computed by Libtool but let's make sure it's non empty. + test -z "$libext" && + as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5 + boost_save_ac_objext=$ac_objext + # Generate the test file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_cxx_try_compile "$LINENO"; then : + ac_objext=do_not_rm_me_plz +else + as_fn_error $? "cannot compile a test that uses Boost context" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext + ac_objext=$boost_save_ac_objext + boost_failed_libs= +# Don't bother to ident the following nested for loops, only the 2 +# innermost ones matter. +for boost_lib_ in context; do +for boost_tag_ in -$boost_cv_lib_tag ''; do +for boost_ver_ in -$boost_cv_lib_version ''; do +for boost_mt_ in $boost_mt -mt ''; do +for boost_rtopt_ in $boost_rtopt '' -d; do + for boost_lib in \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_ver_ + do + # Avoid testing twice the same lib + case $boost_failed_libs in #( + (*@$boost_lib@*) continue;; + esac + # If with_boost is empty, we'll search in /lib first, which is not quite + # right so instead we'll try to a location based on where the headers are. + boost_tmp_lib=$with_boost + test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include} + for boost_ldpath in "$boost_tmp_lib/lib" '' \ + /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \ + "$with_boost" C:/Boost/lib /lib* + do + # Don't waste time with directories that don't exist. + if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then + continue + fi + boost_save_LDFLAGS=$LDFLAGS + # Are we looking for a static library? + case $boost_ldpath:$boost_rtopt_ in #( + (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt) + boost_cv_lib_context_LIBS="$boost_ldpath/lib$boost_lib.$libext" + test -e "$boost_cv_lib_context_LIBS" || continue;; #( + (*) # No: use -lboost_foo to find the shared library. + boost_cv_lib_context_LIBS="-l$boost_lib";; + esac + boost_save_LIBS=$LIBS + LIBS="$boost_cv_lib_context_LIBS $LIBS" + test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_cv_lib_context=yes +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_cv_lib_context=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + ac_objext=$boost_save_ac_objext + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + if test x"$boost_cv_lib_context" = xyes; then + # Check or used cached result of whether or not using -R or + # -rpath makes sense. Some implementations of ld, such as for + # Mac OSX, require -rpath but -R is the flag known to work on + # other systems. https://github.com/tsuna/boost.m4/issues/19 + if ${boost_cv_rpath_link_ldflag+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $boost_ldpath in + '') # Nothing to do. + boost_cv_rpath_link_ldflag= + boost_rpath_link_ldflag_found=yes;; + *) + for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do + LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + LIBS="$boost_save_LIBS $boost_cv_lib_context_LIBS" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_rpath_link_ldflag_found=yes + break +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_rpath_link_ldflag_found=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + done + ;; + esac + if test "x$boost_rpath_link_ldflag_found" != "xyes"; then : + as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5 +fi + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + +fi + + test x"$boost_ldpath" != x && + boost_cv_lib_context_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + boost_cv_lib_context_LDPATH="$boost_ldpath" + break 7 + else + boost_failed_libs="$boost_failed_libs@$boost_lib@" + fi + done + done +done +done +done +done +done # boost_lib_ +rm -f conftest.$ac_objext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_context" >&5 +$as_echo "$boost_cv_lib_context" >&6; } +case $boost_cv_lib_context in #( + (yes) $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +$as_echo "#define HAVE_BOOST_CONTEXT 1" >>confdefs.h + BOOST_CONTEXT_LDFLAGS=$boost_cv_lib_context_LDFLAGS + BOOST_CONTEXT_LDPATH=$boost_cv_lib_context_LDPATH + BOOST_LDPATH=$boost_cv_lib_context_LDPATH + BOOST_CONTEXT_LIBS=$boost_cv_lib_context_LIBS + ;; +esac +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + + +else + : +fi + + +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + + else + if test x"$boost_cv_inc_path" = xno; then + : +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/context/fcontext.hpp" "ac_cv_header_boost_context_fcontext_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_context_fcontext_hpp" = xyes; then : + + if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost context library" >&5 +$as_echo "$as_me: Boost not available, not searching for the Boost context library" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/context/fcontext.hpp" >&5 +$as_echo "$as_me: Boost not available, not searching for boost/context/fcontext.hpp" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/context/fcontext.hpp" "ac_cv_header_boost_context_fcontext_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_context_fcontext_hpp" = xyes; then : + +$as_echo "#define HAVE_BOOST_CONTEXT_FCONTEXT_HPP 1" >>confdefs.h + +else + as_fn_error $? "cannot find boost/context/fcontext.hpp" "$LINENO" 5 +fi + + +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost context library" >&5 +$as_echo_n "checking for the Boost context library... " >&6; } +if ${boost_cv_lib_context+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_lib_context=no + case "" in #( + (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( + (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( + (*) boost_mt=; boost_rtopt=;; + esac + if test $enable_static_boost = yes; then + boost_rtopt="s$boost_rtopt" + fi + # Find the proper debug variant depending on what we've been asked to find. + case $boost_rtopt in #( + (*d*) boost_rt_d=$boost_rtopt;; #( + (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn') + boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #( + (*) boost_rt_d='-d';; + esac + # If the PREFERRED-RT-OPT are not empty, prepend a `-'. + test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt" + $boost_guess_use_mt && boost_mt=-mt + # Look for the abs path the static archive. + # $libext is computed by Libtool but let's make sure it's non empty. + test -z "$libext" && + as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5 + boost_save_ac_objext=$ac_objext + # Generate the test file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_cxx_try_compile "$LINENO"; then : + ac_objext=do_not_rm_me_plz +else + as_fn_error $? "cannot compile a test that uses Boost context" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext + ac_objext=$boost_save_ac_objext + boost_failed_libs= +# Don't bother to ident the following nested for loops, only the 2 +# innermost ones matter. +for boost_lib_ in context; do +for boost_tag_ in -$boost_cv_lib_tag ''; do +for boost_ver_ in -$boost_cv_lib_version ''; do +for boost_mt_ in $boost_mt -mt ''; do +for boost_rtopt_ in $boost_rtopt '' -d; do + for boost_lib in \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_ver_ + do + # Avoid testing twice the same lib + case $boost_failed_libs in #( + (*@$boost_lib@*) continue;; + esac + # If with_boost is empty, we'll search in /lib first, which is not quite + # right so instead we'll try to a location based on where the headers are. + boost_tmp_lib=$with_boost + test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include} + for boost_ldpath in "$boost_tmp_lib/lib" '' \ + /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \ + "$with_boost" C:/Boost/lib /lib* + do + # Don't waste time with directories that don't exist. + if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then + continue + fi + boost_save_LDFLAGS=$LDFLAGS + # Are we looking for a static library? + case $boost_ldpath:$boost_rtopt_ in #( + (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt) + boost_cv_lib_context_LIBS="$boost_ldpath/lib$boost_lib.$libext" + test -e "$boost_cv_lib_context_LIBS" || continue;; #( + (*) # No: use -lboost_foo to find the shared library. + boost_cv_lib_context_LIBS="-l$boost_lib";; + esac + boost_save_LIBS=$LIBS + LIBS="$boost_cv_lib_context_LIBS $LIBS" + test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_cv_lib_context=yes +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_cv_lib_context=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + ac_objext=$boost_save_ac_objext + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + if test x"$boost_cv_lib_context" = xyes; then + # Check or used cached result of whether or not using -R or + # -rpath makes sense. Some implementations of ld, such as for + # Mac OSX, require -rpath but -R is the flag known to work on + # other systems. https://github.com/tsuna/boost.m4/issues/19 + if ${boost_cv_rpath_link_ldflag+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $boost_ldpath in + '') # Nothing to do. + boost_cv_rpath_link_ldflag= + boost_rpath_link_ldflag_found=yes;; + *) + for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do + LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + LIBS="$boost_save_LIBS $boost_cv_lib_context_LIBS" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_rpath_link_ldflag_found=yes + break +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_rpath_link_ldflag_found=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + done + ;; + esac + if test "x$boost_rpath_link_ldflag_found" != "xyes"; then : + as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5 +fi + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + +fi + + test x"$boost_ldpath" != x && + boost_cv_lib_context_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + boost_cv_lib_context_LDPATH="$boost_ldpath" + break 7 + else + boost_failed_libs="$boost_failed_libs@$boost_lib@" + fi + done + done +done +done +done +done +done # boost_lib_ +rm -f conftest.$ac_objext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_context" >&5 +$as_echo "$boost_cv_lib_context" >&6; } +case $boost_cv_lib_context in #( + (yes) $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +$as_echo "#define HAVE_BOOST_CONTEXT 1" >>confdefs.h + BOOST_CONTEXT_LDFLAGS=$boost_cv_lib_context_LDFLAGS + BOOST_CONTEXT_LDPATH=$boost_cv_lib_context_LDPATH + BOOST_LDPATH=$boost_cv_lib_context_LDPATH + BOOST_CONTEXT_LIBS=$boost_cv_lib_context_LIBS + ;; +esac +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + + +else + : +fi + + +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + + fi + case $boost_cv_lib_context in + (yes) + pdns_context_library="Boost context" + { $as_echo "$as_me:${as_lineno-$LINENO}: MTasker will use the Boost context library for context switching" >&5 +$as_echo "$as_me: MTasker will use the Boost context library for context switching" >&6;} + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost context library is missing" >&5 +$as_echo "$as_me: Boost context library is missing" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: MTasker will use System V ucontexts for context switching" >&5 +$as_echo "$as_me: MTasker will use System V ucontexts for context switching" >&6;} + ;; + esac + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: MTasker will use System V ucontexts for context switching" >&5 +$as_echo "$as_me: MTasker will use System V ucontexts for context switching" >&6;} + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable unit test building" >&5 +$as_echo_n "checking whether to enable unit test building... " >&6; } + # Check whether --enable-unit-tests was given. +if test "${enable_unit_tests+set}" = set; then : + enableval=$enable_unit_tests; enable_unit_tests=$enableval +else + enable_unit_tests=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_unit_tests" >&5 +$as_echo "$enable_unit_tests" >&6; } + if test "x$enable_unit_tests" != "xno"; then + UNIT_TESTS_TRUE= + UNIT_TESTS_FALSE='#' +else + UNIT_TESTS_TRUE='#' + UNIT_TESTS_FALSE= +fi + + + if test "x$enable_unit_tests" != "xno"; then : + + if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost unit_test_framework library" >&5 +$as_echo "$as_me: Boost not available, not searching for the Boost unit_test_framework library" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test x"$boost_cv_inc_path" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/test/unit_test.hpp" >&5 +$as_echo "$as_me: Boost not available, not searching for boost/test/unit_test.hpp" >&6;} +else +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +ac_fn_cxx_check_header_mongrel "$LINENO" "boost/test/unit_test.hpp" "ac_cv_header_boost_test_unit_test_hpp" "$ac_includes_default" +if test "x$ac_cv_header_boost_test_unit_test_hpp" = xyes; then : + +$as_echo "#define HAVE_BOOST_TEST_UNIT_TEST_HPP 1" >>confdefs.h + +else + as_fn_error $? "cannot find boost/test/unit_test.hpp" "$LINENO" 5 +fi + + +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost unit_test_framework library" >&5 +$as_echo_n "checking for the Boost unit_test_framework library... " >&6; } +if ${boost_cv_lib_unit_test_framework+:} false; then : + $as_echo_n "(cached) " >&6 +else + boost_cv_lib_unit_test_framework=no + case "mt" in #( + (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( + (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "Xmt" : 'Xmt-*\(.*\)'`;; #( + (*) boost_mt=; boost_rtopt=mt;; + esac + if test $enable_static_boost = yes; then + boost_rtopt="s$boost_rtopt" + fi + # Find the proper debug variant depending on what we've been asked to find. + case $boost_rtopt in #( + (*d*) boost_rt_d=$boost_rtopt;; #( + (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn') + boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #( + (*) boost_rt_d='-d';; + esac + # If the PREFERRED-RT-OPT are not empty, prepend a `-'. + test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt" + $boost_guess_use_mt && boost_mt=-mt + # Look for the abs path the static archive. + # $libext is computed by Libtool but let's make sure it's non empty. + test -z "$libext" && + as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5 + boost_save_ac_objext=$ac_objext + # Generate the test file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +using boost::unit_test::test_suite; + test_suite* init_unit_test_suite(int argc, char ** argv) + { return NULL; } +int +main () +{ +BOOST_CHECK(2 == 2); + ; + return 0; +} +_ACEOF + if ac_fn_cxx_try_compile "$LINENO"; then : + ac_objext=do_not_rm_me_plz +else + as_fn_error $? "cannot compile a test that uses Boost unit_test_framework" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext + ac_objext=$boost_save_ac_objext + boost_failed_libs= +# Don't bother to ident the following nested for loops, only the 2 +# innermost ones matter. +for boost_lib_ in unit_test_framework; do +for boost_tag_ in -$boost_cv_lib_tag ''; do +for boost_ver_ in -$boost_cv_lib_version ''; do +for boost_mt_ in $boost_mt -mt ''; do +for boost_rtopt_ in $boost_rtopt '' -d; do + for boost_lib in \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_ver_ + do + # Avoid testing twice the same lib + case $boost_failed_libs in #( + (*@$boost_lib@*) continue;; + esac + # If with_boost is empty, we'll search in /lib first, which is not quite + # right so instead we'll try to a location based on where the headers are. + boost_tmp_lib=$with_boost + test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include} + for boost_ldpath in "$boost_tmp_lib/lib" '' \ + /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \ + "$with_boost" C:/Boost/lib /lib* + do + # Don't waste time with directories that don't exist. + if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then + continue + fi + boost_save_LDFLAGS=$LDFLAGS + # Are we looking for a static library? + case $boost_ldpath:$boost_rtopt_ in #( + (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt) + boost_cv_lib_unit_test_framework_LIBS="$boost_ldpath/lib$boost_lib.$libext" + test -e "$boost_cv_lib_unit_test_framework_LIBS" || continue;; #( + (*) # No: use -lboost_foo to find the shared library. + boost_cv_lib_unit_test_framework_LIBS="-l$boost_lib";; + esac + boost_save_LIBS=$LIBS + LIBS="$boost_cv_lib_unit_test_framework_LIBS $LIBS" + test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_cv_lib_unit_test_framework=yes +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_cv_lib_unit_test_framework=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + ac_objext=$boost_save_ac_objext + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + if test x"$boost_cv_lib_unit_test_framework" = xyes; then + # Check or used cached result of whether or not using -R or + # -rpath makes sense. Some implementations of ld, such as for + # Mac OSX, require -rpath but -R is the flag known to work on + # other systems. https://github.com/tsuna/boost.m4/issues/19 + if ${boost_cv_rpath_link_ldflag+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $boost_ldpath in + '') # Nothing to do. + boost_cv_rpath_link_ldflag= + boost_rpath_link_ldflag_found=yes;; + *) + for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do + LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + LIBS="$boost_save_LIBS $boost_cv_lib_unit_test_framework_LIBS" + rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5 +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_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext + }; then : + boost_rpath_link_ldflag_found=yes + break +else + if $boost_use_source; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + fi + boost_rpath_link_ldflag_found=no +fi +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext + done + ;; + esac + if test "x$boost_rpath_link_ldflag_found" != "xyes"; then : + as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5 +fi + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + +fi + + test x"$boost_ldpath" != x && + boost_cv_lib_unit_test_framework_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + boost_cv_lib_unit_test_framework_LDPATH="$boost_ldpath" + break 7 + else + boost_failed_libs="$boost_failed_libs@$boost_lib@" + fi + done + done +done +done +done +done +done # boost_lib_ +rm -f conftest.$ac_objext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_unit_test_framework" >&5 +$as_echo "$boost_cv_lib_unit_test_framework" >&6; } +case $boost_cv_lib_unit_test_framework in #( + (yes) $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +$as_echo "#define HAVE_BOOST_UNIT_TEST_FRAMEWORK 1" >>confdefs.h + BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS=$boost_cv_lib_unit_test_framework_LDFLAGS + BOOST_UNIT_TEST_FRAMEWORK_LDPATH=$boost_cv_lib_unit_test_framework_LDPATH + BOOST_LDPATH=$boost_cv_lib_unit_test_framework_LDPATH + BOOST_UNIT_TEST_FRAMEWORK_LIBS=$boost_cv_lib_unit_test_framework_LIBS + ;; +esac +CPPFLAGS=$boost_save_CPPFLAGS +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +fi + + + + if test "$boost_cv_lib_unit_test_framework" = "no"; then : + + as_fn_error $? "Boost Unit Test library not found" "$LINENO" 5 + +fi + +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable reproducible builds." >&5 +$as_echo_n "checking whether to enable reproducible builds.... " >&6; } + # Check whether --enable-reproducible was given. +if test "${enable_reproducible+set}" = set; then : + enableval=$enable_reproducible; enable_reproducible=$enableval +else + enable_reproducible=no +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_reproducible" >&5 +$as_echo "$enable_reproducible" >&6; } + + if test x"$enable_reproducible" = "xyes"; then : + + +$as_echo "#define REPRODUCIBLE 1" >>confdefs.h + + +else + + build_user=$(id -u -n) + + case "$host_os" in + solaris2.1* | SunOS | openbsd*) + build_host_host=$(hostname) + build_host_domain=$(domainname) + build_host="$build_host_host.$build_host_domain" + ;; + *) + build_host=$(hostname -f || hostname || echo 'localhost') + ;; + esac + +cat >>confdefs.h <<_ACEOF +#define BUILD_HOST "$build_user@$build_host" +_ACEOF + + +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in LuaJIT" >&5 +$as_echo_n "checking whether we will be linking in LuaJIT... " >&6; } + +# Check whether --with-luajit was given. +if test "${with_luajit+set}" = set; then : + withval=$with_luajit; with_luajit=$withval +else + with_luajit=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_luajit" >&5 +$as_echo "$with_luajit" >&6; } + + if test "x$with_luajit" = "xyes"; then : + + LUAJITPC="$with_luajit" + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5 +$as_echo_n "checking for LUA... " >&6; } + +if test -n "$LUA_CFLAGS"; then + pkg_cv_LUA_CFLAGS="$LUA_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5 + ($PKG_CONFIG --exists --print-errors "luajit") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "luajit" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LUA_LIBS"; then + pkg_cv_LUA_LIBS="$LUA_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5 + ($PKG_CONFIG --exists --print-errors "luajit") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "luajit" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "luajit" 2>&1` + else + LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "luajit" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LUA_PKG_ERRORS" >&5 + + LUAJITPC="" + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + LUAJITPC="" + +else + LUA_CFLAGS=$pkg_cv_LUA_CFLAGS + LUA_LIBS=$pkg_cv_LUA_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_LUA 1" >>confdefs.h + +fi + if test "x$LUAJITPC" = "x"; then : + + as_fn_error $? "LuaJIT not found" "$LINENO" 5 + +fi + +fi + + if test "x$with_luajit" = "xyes"; then + LUA_TRUE= + LUA_FALSE='#' +else + LUA_TRUE='#' + LUA_FALSE= +fi + + +if test "x$with_luajit" = "xno"; then : + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in Lua" >&5 +$as_echo_n "checking whether we will be linking in Lua... " >&6; } + +# Check whether --with-lua was given. +if test "${with_lua+set}" = set; then : + withval=$with_lua; with_lua=$withval +else + with_lua=auto + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_lua" >&5 +$as_echo "$with_lua" >&6; } + + if test "x$with_lua" != "xno"; then : + + if test "x$with_lua" = "xyes" -o "x$with_lua" = "xauto"; then : + for LUAPC in lua5.3 lua-5.3 lua53 lua5.2 lua-5.2 lua52 lua5.1 lua-5.1 lua51 lua; do + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5 +$as_echo_n "checking for LUA... " >&6; } + +if test -n "$LUA_CFLAGS"; then + pkg_cv_LUA_CFLAGS="$LUA_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "$LUAPC >= 5.1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LUA_LIBS"; then + pkg_cv_LUA_LIBS="$LUA_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "$LUAPC >= 5.1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1` + else + LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LUA_PKG_ERRORS" >&5 + + LUAPC="" +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + LUAPC="" +else + LUA_CFLAGS=$pkg_cv_LUA_CFLAGS + LUA_LIBS=$pkg_cv_LUA_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +$as_echo "#define HAVE_LUA 1" >>confdefs.h + + with_lua=yes + +fi # otherwise pkg_check will fail + if test "x$LUA_LIBS" != "x"; then break; fi + done + +else + LUAPC="$with_lua" + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5 +$as_echo_n "checking for LUA... " >&6; } + +if test -n "$LUA_CFLAGS"; then + pkg_cv_LUA_CFLAGS="$LUA_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "$LUAPC >= 5.1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LUA_LIBS"; then + pkg_cv_LUA_LIBS="$LUA_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "$LUAPC >= 5.1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1` + else + LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LUA_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($LUAPC >= 5.1) were not met: + +$LUA_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables LUA_CFLAGS +and LUA_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables LUA_CFLAGS +and LUA_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + LUA_CFLAGS=$pkg_cv_LUA_CFLAGS + LUA_LIBS=$pkg_cv_LUA_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +$as_echo "#define HAVE_LUA 1" >>confdefs.h + + with_lua=yes + +fi + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chosen LUA" >&5 +$as_echo_n "checking for chosen LUA... " >&6; } + if test "x$LUAPC" = "x"; then : + + if test "x$with_lua" = "xyes"; then : + as_fn_error $? "cannot find lua" "$LINENO" 5 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + +fi +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LUAPC" >&5 +$as_echo "$LUAPC" >&6; } + +fi + +fi + if test "x$with_lua" = "xyes"; then + LUA_TRUE= + LUA_FALSE='#' +else + LUA_TRUE='#' + LUA_FALSE= +fi + + + +fi +if test "x$LUAPC" = "x" -a "x$LUAJITPC" = "x"; then : + + as_fn_error $? "Neither Lua nor LuaJIT found, Lua support is not optional" "$LINENO" 5 + +fi +if test "x$LUAJITPC" != "x"; then : + + # export all symbols to be able to use the Lua FFI interface + { $as_echo "$as_me:${as_lineno-$LINENO}: Adding -rdynamic to export all symbols for the Lua FFI interface" >&5 +$as_echo "$as_me: Adding -rdynamic to export all symbols for the Lua FFI interface" >&6;} + LDFLAGS="$LDFLAGS -rdynamic" + +fi + + + + if test "x$LUAPC" != "x" -o "x$LUAJITPC" != "x" ; then : + + ac_fn_cxx_check_header_mongrel "$LINENO" "lua.hpp" "ac_cv_header_lua_hpp" "$ac_includes_default" +if test "x$ac_cv_header_lua_hpp" = xyes; then : + have_lua_hpp=y +fi + + + +fi + if test x"$have_lua_hpp" = "xy" ; then + HAVE_LUA_HPP_TRUE= + HAVE_LUA_HPP_FALSE='#' +else + HAVE_LUA_HPP_TRUE='#' + HAVE_LUA_HPP_FALSE= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable verbose logging" >&5 +$as_echo_n "checking whether to enable verbose logging... " >&6; } + + # Check whether --enable-verbose-logging was given. +if test "${enable_verbose_logging+set}" = set; then : + enableval=$enable_verbose_logging; enable_verbose_logging=$enableval +else + enable_verbose_logging=no + +fi + + + if test "x$enable_verbose_logging" != "xno"; then : + +$as_echo "#define VERBOSELOG 1" >>confdefs.h + + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_verbose_logging" >&5 +$as_echo "$enable_verbose_logging" >&6; } + + +# Crypto libraries + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in Botan 2.x" >&5 +$as_echo_n "checking whether we will be linking in Botan 2.x... " >&6; } + # Check whether --enable-botan was given. +if test "${enable_botan+set}" = set; then : + enableval=$enable_botan; enable_botan=$enableval +else + enable_botan=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_botan" >&5 +$as_echo "$enable_botan" >&6; } + if test "x$enable_botan" != "xno"; then + BOTAN_TRUE= + BOTAN_FALSE='#' +else + BOTAN_TRUE='#' + BOTAN_FALSE= +fi + + + if test "x$enable_botan" != "xno"; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BOTAN" >&5 +$as_echo_n "checking for BOTAN... " >&6; } + +if test -n "$BOTAN_CFLAGS"; then + pkg_cv_BOTAN_CFLAGS="$BOTAN_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"botan-2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "botan-2") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_BOTAN_CFLAGS=`$PKG_CONFIG --cflags "botan-2" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$BOTAN_LIBS"; then + pkg_cv_BOTAN_LIBS="$BOTAN_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"botan-2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "botan-2") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_BOTAN_LIBS=`$PKG_CONFIG --libs "botan-2" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + BOTAN_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "botan-2" 2>&1` + else + BOTAN_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "botan-2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$BOTAN_PKG_ERRORS" >&5 + + as_fn_error $? "Could not find botan" "$LINENO" 5 + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "Could not find botan" "$LINENO" 5 + +else + BOTAN_CFLAGS=$pkg_cv_BOTAN_CFLAGS + BOTAN_LIBS=$pkg_cv_BOTAN_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_BOTAN 1" >>confdefs.h + +fi + +fi + + + found=false + +# Check whether --with-libcrypto was given. +if test "${with_libcrypto+set}" = set; then : + withval=$with_libcrypto; + case "$withval" in + "" | y | ye | yes | n | no) + as_fn_error $? "Invalid --with-libcrypto value" "$LINENO" 5 + ;; + *) ssldirs="$withval" + ;; + esac + +else + + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PKG_CONFIG"; then + ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config" + $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 +PKG_CONFIG=$ac_cv_prog_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_PKG_CONFIG"; then + ac_ct_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_PKG_CONFIG"; then + ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config" + $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_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG +if test -n "$ac_ct_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5 +$as_echo "$ac_ct_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_PKG_CONFIG" = x; then + PKG_CONFIG="" + 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 + PKG_CONFIG=$ac_ct_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_prog_PKG_CONFIG" +fi + + if test x"$PKG_CONFIG" != x""; then + LIBCRYPTO_LDFLAGS=`$PKG_CONFIG libcrypto --libs-only-L 2>/dev/null` + if test $? = 0; then + LIBCRYPTO_LIBS=`$PKG_CONFIG libcrypto --libs-only-l 2>/dev/null` + LIBCRYPTO_INCLUDES=`$PKG_CONFIG libcrypto --cflags-only-I 2>/dev/null` + ssldir=`$PKG_CONFIG libcrypto --variable=prefix 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + + +fi + + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + LIBCRYPTO_INCLUDES= + for ssldir in $ssldirs; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/crypto.h in $ssldir" >&5 +$as_echo_n "checking for openssl/crypto.h in $ssldir... " >&6; } + if test -f "$ssldir/include/openssl/crypto.h"; then + LIBCRYPTO_INCLUDES="-I$ssldir/include" + LIBCRYPTO_LDFLAGS="-L$ssldir/lib" + LIBCRYPTO_LIBS="-lcrypto" + found=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL's libcrypto works" >&5 +$as_echo_n "checking whether compiling and linking against OpenSSL's libcrypto works... " >&6; } + echo "Trying link with LIBCRYPTO_LDFLAGS=$LIBCRYPTO_LDFLAGS;" \ + "LIBCRYPTO_LIBS=$LIBCRYPTO_LIBS; LIBCRYPTO_INCLUDES=$LIBCRYPTO_INCLUDES" >&5 + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $LIBCRYPTO_LDFLAGS" + LIBS="$LIBCRYPTO_LIBS $LIBS" + CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ERR_load_CRYPTO_strings() + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; 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" >&5 +$as_echo "no" >&6; } + + as_fn_error $? "OpenSSL/libcrypto not found" "$LINENO" 5 + + + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + + + + + + + + # Set the environment correctly for a possibly non-default OpenSSL path that was found by/supplied to PDNS_CHECK_LIBCRYPTO + save_CPPFLAGS="$CPPFLAGS" + save_LDFLAGS="$LDFLAGS" + save_LIBS="$LIBS" + + CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS" + LDFLAGS="$LIBCRYPTO_LDFLAGS $LDFLAGS" + LIBS="$LIBCRYPTO_LIBS $LIBS" + + # Find the headers we need for ECDSA + libcrypto_ecdsa=yes + as_ac_Header=`$as_echo "ac_cv_header_$ssldir/include/openssl/ecdsa.h" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ssldir/include/openssl/ecdsa.h" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + + ac_fn_cxx_check_decl "$LINENO" "NID_X9_62_prime256v1" "ac_cv_have_decl_NID_X9_62_prime256v1" "$ac_includes_default +#include <$ssldir/include/openssl/evp.h> + +" +if test "x$ac_cv_have_decl_NID_X9_62_prime256v1" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_NID_X9_62_PRIME256V1 $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + : +else + + libcrypto_ecdsa=no + +fi +ac_fn_cxx_check_decl "$LINENO" "NID_secp384r1" "ac_cv_have_decl_NID_secp384r1" "$ac_includes_default +#include <$ssldir/include/openssl/evp.h> + +" +if test "x$ac_cv_have_decl_NID_secp384r1" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_NID_SECP384R1 $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + : +else + + libcrypto_ecdsa=no + +fi + + +else + + libcrypto_ecdsa=no + +fi + + + + if test "x$libcrypto_ecdsa" = "xyes"; then : + + +$as_echo "#define HAVE_LIBCRYPTO_ECDSA 1" >>confdefs.h + + +fi + + # Restore variables + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libsodium" >&5 +$as_echo_n "checking whether we will be linking in libsodium... " >&6; } + # Check whether --enable-libsodium was given. +if test "${enable_libsodium+set}" = set; then : + enableval=$enable_libsodium; enable_libsodium=$enableval +else + enable_libsodium=auto +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libsodium" >&5 +$as_echo "$enable_libsodium" >&6; } + + if test "x$enable_libsodium" != "xno"; then : + + if test "x$enable_libsodium" = "xyes" -o "x$enable_libsodium" = "xauto"; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSODIUM" >&5 +$as_echo_n "checking for LIBSODIUM... " >&6; } + +if test -n "$LIBSODIUM_CFLAGS"; then + pkg_cv_LIBSODIUM_CFLAGS="$LIBSODIUM_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsodium") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBSODIUM_CFLAGS=`$PKG_CONFIG --cflags "libsodium" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBSODIUM_LIBS"; then + pkg_cv_LIBSODIUM_LIBS="$LIBSODIUM_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsodium") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBSODIUM_LIBS=`$PKG_CONFIG --libs "libsodium" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsodium" 2>&1` + else + LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsodium" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBSODIUM_PKG_ERRORS" >&5 + + : +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + : +else + LIBSODIUM_CFLAGS=$pkg_cv_LIBSODIUM_CFLAGS + LIBSODIUM_LIBS=$pkg_cv_LIBSODIUM_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +$as_echo "#define HAVE_LIBSODIUM 1" >>confdefs.h + + save_CFLAGS=$CFLAGS + save_LIBS=$LIBS + CFLAGS="$LIBSODIUM_CFLAGS $CFLAGS" + LIBS="$LIBSODIUM_LIBS $LIBS" + for ac_func in crypto_box_easy_afternm +do : + ac_fn_cxx_check_func "$LINENO" "crypto_box_easy_afternm" "ac_cv_func_crypto_box_easy_afternm" +if test "x$ac_cv_func_crypto_box_easy_afternm" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_CRYPTO_BOX_EASY_AFTERNM 1 +_ACEOF + +fi +done + + CFLAGS=$save_CFLAGS + LIBS=$save_LIBS + +fi + +fi + +fi + if test "x$LIBSODIUM_LIBS" != "x"; then + LIBSODIUM_TRUE= + LIBSODIUM_FALSE='#' +else + LIBSODIUM_TRUE='#' + LIBSODIUM_FALSE= +fi + + if test "x$enable_libsodium" = "xyes"; then : + + if test x"$LIBSODIUM_LIBS" = "x"; then : + + as_fn_error $? "libsodium requested but libraries were not found" "$LINENO" 5 + +fi + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libdecaf" >&5 +$as_echo_n "checking whether we will be linking in libdecaf... " >&6; } + # Check whether --enable-libdecaf was given. +if test "${enable_libdecaf+set}" = set; then : + enableval=$enable_libdecaf; enable_libdecaf=$enableval +else + enable_libdecaf=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libdecaf" >&5 +$as_echo "$enable_libdecaf" >&6; } + + if test "x$enable_libdecaf" != "xno"; then + LIBDECAF_TRUE= + LIBDECAF_FALSE='#' +else + LIBDECAF_TRUE='#' + LIBDECAF_FALSE= +fi + + + if test "x$enable_libdecaf" != "xno"; then : + + save_LIBS=$LIBS + LIBS="" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing decaf_ed25519_sign" >&5 +$as_echo_n "checking for library containing decaf_ed25519_sign... " >&6; } +if ${ac_cv_search_decaf_ed25519_sign+:} false; 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 decaf_ed25519_sign (); +int +main () +{ +return decaf_ed25519_sign (); + ; + return 0; +} +_ACEOF +for ac_lib in '' decaf; 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_cxx_try_link "$LINENO"; then : + ac_cv_search_decaf_ed25519_sign=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_decaf_ed25519_sign+:} false; then : + break +fi +done +if ${ac_cv_search_decaf_ed25519_sign+:} false; then : + +else + ac_cv_search_decaf_ed25519_sign=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_decaf_ed25519_sign" >&5 +$as_echo "$ac_cv_search_decaf_ed25519_sign" >&6; } +ac_res=$ac_cv_search_decaf_ed25519_sign +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + + +$as_echo "#define HAVE_LIBDECAF 1" >>confdefs.h + + LIBDECAF_LIBS="$LIBS" + + +else + + as_fn_error $? "Could not find libdecaf" "$LINENO" 5 + +fi + + LIBS="$save_LIBS" + +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we need to link in Net SNMP" >&5 +$as_echo_n "checking if we need to link in Net SNMP... " >&6; } + +# Check whether --with-net-snmp was given. +if test "${with_net_snmp+set}" = set; then : + withval=$with_net_snmp; with_net_snmp=$withval +else + with_net_snmp=auto +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_net_snmp" >&5 +$as_echo "$with_net_snmp" >&6; } + + if test "x$with_net_snmp" != "xno"; then : + + if test "x$with_net_snmp" = "xyes" -o "x$with_net_snmp" = "xauto"; then : + + # Extract the first word of "net-snmp-config", so it can be a program name with args. +set dummy net-snmp-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NET_SNMP_CFLAGS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NET_SNMP_CFLAGS"; then + ac_cv_prog_NET_SNMP_CFLAGS="$NET_SNMP_CFLAGS" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NET_SNMP_CFLAGS="`net-snmp-config --cflags`" + $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 +NET_SNMP_CFLAGS=$ac_cv_prog_NET_SNMP_CFLAGS +if test -n "$NET_SNMP_CFLAGS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NET_SNMP_CFLAGS" >&5 +$as_echo "$NET_SNMP_CFLAGS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + # Extract the first word of "net-snmp-config", so it can be a program name with args. +set dummy net-snmp-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NET_SNMP_LIBS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NET_SNMP_LIBS"; then + ac_cv_prog_NET_SNMP_LIBS="$NET_SNMP_LIBS" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NET_SNMP_LIBS="`net-snmp-config --agent-libs`" + $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 +NET_SNMP_LIBS=$ac_cv_prog_NET_SNMP_LIBS +if test -n "$NET_SNMP_LIBS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NET_SNMP_LIBS" >&5 +$as_echo "$NET_SNMP_LIBS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + ac_fn_cxx_check_decl "$LINENO" "snmp_select_info2" "ac_cv_have_decl_snmp_select_info2" "$ac_includes_default + #include + #include + #include + #include + #include + #include + +" +if test "x$ac_cv_have_decl_snmp_select_info2" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_SNMP_SELECT_INFO2 $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + : +else + : +fi + + +fi + +fi + if test "x$with_net_snmp" = "xyes"; then : + + if test x"$NET_SNMP_LIBS" = "x"; then : + + as_fn_error $? "Net SNMP requested but libraries were not found" "$LINENO" 5 + +fi + +fi + if test x"$NET_SNMP_LIBS" != "x"; then + HAVE_NET_SNMP_TRUE= + HAVE_NET_SNMP_FALSE='#' +else + HAVE_NET_SNMP_TRUE='#' + HAVE_NET_SNMP_FALSE= +fi + + if test x"$NET_SNMP_LIBS" != "x"; then : + +$as_echo "#define HAVE_NET_SNMP 1" >>confdefs.h + +fi + + +# check for tools we might need + + # Extract the first word of "ragel", so it can be a program name with args. +set dummy ragel; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RAGEL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RAGEL"; then + ac_cv_prog_RAGEL="$RAGEL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RAGEL="ragel" + $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 +RAGEL=$ac_cv_prog_RAGEL +if test -n "$RAGEL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RAGEL" >&5 +$as_echo "$RAGEL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$RAGEL" = "x"; then + if test ! -f "${srcdir}/dnslabeltext.cc"; then + as_fn_error $? "ragel is missing and you don't have ${srcdir}/dnslabeltext.cc. Install ragel or download sources from www.powerdns.com" "$LINENO" 5 + fi + fi + + + # Extract the first word of "curl", so it can be a program name with args. +set dummy curl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CURL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CURL"; then + ac_cv_prog_CURL="$CURL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CURL="curl" + $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 +CURL=$ac_cv_prog_CURL +if test -n "$CURL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CURL" >&5 +$as_echo "$CURL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$CURL" = "x"; then + if test ! -f "${srcdir}/effective_tld_names.dat"; then + as_fn_error $? "curl is missing and you don't have ${srcdir}//effective_tld_names.dat. Install curl or download sources from www.powerdns.com" "$LINENO" 5 + fi + fi + + +for ac_func in strcasestr +do : + ac_fn_cxx_check_func "$LINENO" "strcasestr" "ac_cv_func_strcasestr" +if test "x$ac_cv_func_strcasestr" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRCASESTR 1 +_ACEOF + +fi +done + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_setaffinity_np" >&5 +$as_echo_n "checking for library containing pthread_setaffinity_np... " >&6; } +if ${ac_cv_search_pthread_setaffinity_np+:} false; 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_setaffinity_np (); +int +main () +{ +return pthread_setaffinity_np (); + ; + 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_cxx_try_link "$LINENO"; then : + ac_cv_search_pthread_setaffinity_np=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_pthread_setaffinity_np+:} false; then : + break +fi +done +if ${ac_cv_search_pthread_setaffinity_np+:} false; then : + +else + ac_cv_search_pthread_setaffinity_np=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_setaffinity_np" >&5 +$as_echo "$ac_cv_search_pthread_setaffinity_np" >&6; } +ac_res=$ac_cv_search_pthread_setaffinity_np +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define HAVE_PTHREAD_SETAFFINITY_NP 1" >>confdefs.h + +fi + + + + +socketdir="/var/run" + +# Check whether --with-socketdir was given. +if test "${with_socketdir+set}" = set; then : + withval=$with_socketdir; socketdir="$withval" + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will enable compiler security checks" >&5 +$as_echo_n "checking whether we will enable compiler security checks... " >&6; } +# Check whether --enable-hardening was given. +if test "${enable_hardening+set}" = set; then : + enableval=$enable_hardening; enable_hardening=$enableval +else + enable_hardening=yes + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_hardening" >&5 +$as_echo "$enable_hardening" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror -Wunknown-warning-option" >&5 +$as_echo_n "checking whether C++ compiler handles -Werror -Wunknown-warning-option... " >&6; } +if ${gl_cv_warn_cxx__Werror__Wunknown_warning_option+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror -Wunknown-warning-option" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__Werror__Wunknown_warning_option=yes +else + gl_cv_warn_cxx__Werror__Wunknown_warning_option=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&5 +$as_echo "$gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&6; } +if test "x$gl_cv_warn_cxx__Werror__Wunknown_warning_option" = xyes; then : + gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror' +else + gl_unknown_warnings_are_errors= +fi + +if test "x$enable_hardening" != "xno"; then : + + + + PIE_CFLAGS= + PIE_LDFLAGS= + OLD_CXXFLAGS=$CXXFLAGS + case "$host" in + *-*-mingw* | *-*-msvc* | *-*-cygwin* ) + ;; *) + CXXFLAGS="-fPIE -DPIE" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -pie" >&5 +$as_echo_n "checking whether C++ compiler handles -pie... " >&6; } +if ${gl_cv_warn_cxx__pie+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -pie" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +__thread unsigned int t_id; + +int +main () +{ +t_id = 1; + ; + return 0; +} + +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__pie=yes +else + gl_cv_warn_cxx__pie=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__pie" >&5 +$as_echo "$gl_cv_warn_cxx__pie" >&6; } +if test "x$gl_cv_warn_cxx__pie" = xyes; then : + + PIE_CFLAGS="-fPIE -DPIE" + PIE_LDFLAGS="-pie" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wl,-pie" >&5 +$as_echo_n "checking whether C++ compiler handles -Wl,-pie... " >&6; } +if ${gl_cv_warn_cxx__Wl__pie+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wl,-pie" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +__thread unsigned int t_id; + +int +main () +{ +t_id = 1; + ; + return 0; +} + +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__Wl__pie=yes +else + gl_cv_warn_cxx__Wl__pie=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wl__pie" >&5 +$as_echo "$gl_cv_warn_cxx__Wl__pie" >&6; } +if test "x$gl_cv_warn_cxx__Wl__pie" = xyes; then : + + PIE_CFLAGS="-fPIE -DPIE" + PIE_LDFLAGS="-Wl,-pie" + +fi + + +fi + + esac + CXXFLAGS=$OLD_CXXFLAGS + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fstack-protector" >&5 +$as_echo_n "checking whether C++ compiler handles -fstack-protector... " >&6; } +if ${gl_cv_warn_cxx__fstack_protector+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fstack-protector" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__fstack_protector=yes +else + gl_cv_warn_cxx__fstack_protector=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fstack_protector" >&5 +$as_echo "$gl_cv_warn_cxx__fstack_protector" >&6; } +if test "x$gl_cv_warn_cxx__fstack_protector" = xyes; then : + + CFLAGS="-fstack-protector $CFLAGS" + CXXFLAGS="-fstack-protector $CXXFLAGS" + +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles --param ssp-buffer-size=4" >&5 +$as_echo_n "checking whether C++ compiler handles --param ssp-buffer-size=4... " >&6; } +if ${gl_cv_warn_cxx___param_ssp_buffer_size_4+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors --param ssp-buffer-size=4" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx___param_ssp_buffer_size_4=yes +else + gl_cv_warn_cxx___param_ssp_buffer_size_4=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx___param_ssp_buffer_size_4" >&5 +$as_echo "$gl_cv_warn_cxx___param_ssp_buffer_size_4" >&6; } +if test "x$gl_cv_warn_cxx___param_ssp_buffer_size_4" = xyes; then : + + CFLAGS="--param ssp-buffer-size=4 $CFLAGS" + CXXFLAGS="--param ssp-buffer-size=4 $CXXFLAGS" + +fi + + + + OLD_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="-Wall -W -Werror $CXXFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=2" >&5 +$as_echo_n "checking whether C++ compiler handles -D_FORTIFY_SOURCE=2... " >&6; } +if ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_2+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=2" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=yes +else + gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&5 +$as_echo "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&6; } +if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" = xyes; then : + + CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS" + CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $OLD_CXXFLAGS" + +else + CXXFLAGS="$OLD_CXXFLAGS" +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for how to force completely read-only GOT table" >&5 +$as_echo_n "checking for how to force completely read-only GOT table... " >&6; } + + RELRO_LDFLAGS= + ld_help=`$CXX -Wl,-help 2>&1` + case $ld_help in + *"-z relro"*) RELRO_LDFLAGS="-Wl,-z -Wl,relro" ;; + esac + case $ld_help in + *"-z now"*) RELRO_LDFLAGS="$RELRO_LDFLAGS -Wl,-z -Wl,now" ;; + esac + + if test "x$RELRO_LDFLAGS" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RELRO_LDFLAGS" >&5 +$as_echo "$RELRO_LDFLAGS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 +$as_echo "unknown" >&6; } + +fi + + +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable AddressSanitizer" >&5 +$as_echo_n "checking whether to enable AddressSanitizer... " >&6; } + # Check whether --enable-asan was given. +if test "${enable_asan+set}" = set; then : + enableval=$enable_asan; enable_asan=$enableval +else + enable_asan=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_asan" >&5 +$as_echo "$enable_asan" >&6; } + + if test "x$enable_asan" != "xno"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=address" >&5 +$as_echo_n "checking whether C++ compiler handles -fsanitize=address... " >&6; } +if ${gl_cv_warn_cxx__fsanitize_address+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=address" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__fsanitize_address=yes +else + gl_cv_warn_cxx__fsanitize_address=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_address" >&5 +$as_echo "$gl_cv_warn_cxx__fsanitize_address" >&6; } +if test "x$gl_cv_warn_cxx__fsanitize_address" = xyes; then : + + SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS" + for ac_header in sanitizer/common_interface_defs.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sanitizer/common_interface_defs.h" "ac_cv_header_sanitizer_common_interface_defs_h" "$ac_includes_default" +if test "x$ac_cv_header_sanitizer_common_interface_defs_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H 1 +_ACEOF + asan_headers=yes +else + asan_headers=no +fi + +done + + if test x"$asan_headers" = "xyes" ; then : + ac_fn_cxx_check_decl "$LINENO" "__sanitizer_start_switch_fiber" "ac_cv_have_decl___sanitizer_start_switch_fiber" "#include + +" +if test "x$ac_cv_have_decl___sanitizer_start_switch_fiber" = xyes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the exact signature of __sanitizer_finish_switch_fiber" >&5 +$as_echo_n "checking for the exact signature of __sanitizer_finish_switch_fiber... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ + + __sanitizer_finish_switch_fiber(nullptr); + + ; + return 0; +} + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: a single pointer" >&5 +$as_echo "a single pointer" >&6; } + +$as_echo "#define HAVE_FIBER_SANITIZER 1" >>confdefs.h + + +$as_echo "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR 1" >>confdefs.h + + +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ + + __sanitizer_finish_switch_fiber(nullptr, nullptr, nullptr); + + ; + return 0; +} + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: three pointers" >&5 +$as_echo "three pointers" >&6; } + +$as_echo "#define HAVE_FIBER_SANITIZER 1" >>confdefs.h + + +$as_echo "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS 1" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 +$as_echo "unknown" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: ASAN fiber switching is not available due to an unknown API version" >&5 +$as_echo "$as_me: ASAN fiber switching is not available due to an unknown API version" >&6;} + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: ASAN fiber switching is not available" >&5 +$as_echo "$as_me: ASAN fiber switching is not available" >&6;} + +fi + + +fi + +else + as_fn_error $? "Cannot enable AddressSanitizer" "$LINENO" 5 + +fi + + +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable MemorySanitizer" >&5 +$as_echo_n "checking whether to enable MemorySanitizer... " >&6; } + # Check whether --enable-msan was given. +if test "${enable_msan+set}" = set; then : + enableval=$enable_msan; enable_msan=$enableval +else + enable_msan=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_msan" >&5 +$as_echo "$enable_msan" >&6; } + + if test "x$enable_msan" != "xno"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=memory" >&5 +$as_echo_n "checking whether C++ compiler handles -fsanitize=memory... " >&6; } +if ${gl_cv_warn_cxx__fsanitize_memory+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=memory" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__fsanitize_memory=yes +else + gl_cv_warn_cxx__fsanitize_memory=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_memory" >&5 +$as_echo "$gl_cv_warn_cxx__fsanitize_memory" >&6; } +if test "x$gl_cv_warn_cxx__fsanitize_memory" = xyes; then : + SANITIZER_FLAGS="-fsanitize=memory $SANITIZER_FLAGS" +else + as_fn_error $? "Cannot enable MemorySanitizer" "$LINENO" 5 + +fi + + +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ThreadSanitizer" >&5 +$as_echo_n "checking whether to enable ThreadSanitizer... " >&6; } + # Check whether --enable-tsan was given. +if test "${enable_tsan+set}" = set; then : + enableval=$enable_tsan; enable_tsan=$enableval +else + enable_tsan=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tsan" >&5 +$as_echo "$enable_tsan" >&6; } + + if test "x$enable_tsan" != "xno"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=thread" >&5 +$as_echo_n "checking whether C++ compiler handles -fsanitize=thread... " >&6; } +if ${gl_cv_warn_cxx__fsanitize_thread+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=thread" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__fsanitize_thread=yes +else + gl_cv_warn_cxx__fsanitize_thread=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_thread" >&5 +$as_echo "$gl_cv_warn_cxx__fsanitize_thread" >&6; } +if test "x$gl_cv_warn_cxx__fsanitize_thread" = xyes; then : + SANITIZER_FLAGS="-fsanitize=thread $SANITIZER_FLAGS" +else + as_fn_error $? "Cannot enable ThreadSanitizer" "$LINENO" 5 + +fi + + +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable LeakSanitizer" >&5 +$as_echo_n "checking whether to enable LeakSanitizer... " >&6; } + # Check whether --enable-lsan was given. +if test "${enable_lsan+set}" = set; then : + enableval=$enable_lsan; enable_lsan=$enableval +else + enable_lsan=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_lsan" >&5 +$as_echo "$enable_lsan" >&6; } + + if test "x$enable_lsan" != "xno"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=leak" >&5 +$as_echo_n "checking whether C++ compiler handles -fsanitize=leak... " >&6; } +if ${gl_cv_warn_cxx__fsanitize_leak+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=leak" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__fsanitize_leak=yes +else + gl_cv_warn_cxx__fsanitize_leak=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_leak" >&5 +$as_echo "$gl_cv_warn_cxx__fsanitize_leak" >&6; } +if test "x$gl_cv_warn_cxx__fsanitize_leak" = xyes; then : + SANITIZER_FLAGS="-fsanitize=leak $SANITIZER_FLAGS" +else + as_fn_error $? "Cannot enable LeakSanitizer" "$LINENO" 5 + +fi + + +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable Undefined Behaviour Sanitizer" >&5 +$as_echo_n "checking whether to enable Undefined Behaviour Sanitizer... " >&6; } + # Check whether --enable-ubsan was given. +if test "${enable_ubsan+set}" = set; then : + enableval=$enable_ubsan; enable_ubsan=$enableval +else + enable_ubsan=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_ubsan" >&5 +$as_echo "$enable_ubsan" >&6; } + + if test "x$enable_ubsan" != "xno"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=undefined" >&5 +$as_echo_n "checking whether C++ compiler handles -fsanitize=undefined... " >&6; } +if ${gl_cv_warn_cxx__fsanitize_undefined+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=undefined" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__fsanitize_undefined=yes +else + gl_cv_warn_cxx__fsanitize_undefined=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_undefined" >&5 +$as_echo "$gl_cv_warn_cxx__fsanitize_undefined" >&6; } +if test "x$gl_cv_warn_cxx__fsanitize_undefined" = xyes; then : + SANITIZER_FLAGS="-fsanitize=undefined $SANITIZER_FLAGS" +else + as_fn_error $? "Cannot enable Undefined Behaviour Sanitizer" "$LINENO" 5 + +fi + + +fi + + + + if test "x$enable_asan" != "xno" -a "x$enable_tsan" != "xno"; then : + + as_fn_error $? "Address Sanitizer is not compatible with Thread Sanitizer" "$LINENO" 5 + +fi + + if test "x$enable_msan" != "xno" -a "x$enable_asan" != "xno"; then : + + as_fn_error $? "Memory Sanitizer is not compatible with Address Sanitizer" "$LINENO" 5 + +fi + + if test "x$enable_msan" != "xno" -a "x$enable_lsan" != "xno"; then : + + as_fn_error $? "Memory Sanitizer is not compatible with Leak Sanitizer" "$LINENO" 5 + +fi + + if test "x$enable_msan" != "xno" -a "x$enable_tsan" != "xno"; then : + + as_fn_error $? "Memory Sanitizer is not compatible with Thread Sanitizer" "$LINENO" 5 + +fi + + if test "x$enable_asan" != "xno" -o "x$enable_tsan" != "xno" -o "x$enable_lsan" != "xno" -o "x$enable_ubsan" != "xno" -o "x$enable_msan" != "xno"; then : + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fno-omit-frame-pointer" >&5 +$as_echo_n "checking whether C++ compiler handles -fno-omit-frame-pointer... " >&6; } +if ${gl_cv_warn_cxx__fno_omit_frame_pointer+:} false; then : + $as_echo_n "(cached) " >&6 +else + + gl_save_compiler_FLAGS="$CXXFLAGS" + as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fno-omit-frame-pointer" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gl_cv_warn_cxx__fno_omit_frame_pointer=yes +else + gl_cv_warn_cxx__fno_omit_frame_pointer=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CXXFLAGS="$gl_save_compiler_FLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fno_omit_frame_pointer" >&5 +$as_echo "$gl_cv_warn_cxx__fno_omit_frame_pointer" >&6; } +if test "x$gl_cv_warn_cxx__fno_omit_frame_pointer" = xyes; then : + as_fn_append WARN_CFLAGS " -fno-omit-frame-pointer" +fi + + + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable code malloc-trace" >&5 +$as_echo_n "checking whether to enable code malloc-trace... " >&6; } + # Check whether --enable-malloc-trace was given. +if test "${enable_malloc_trace+set}" = set; then : + enableval=$enable_malloc_trace; enable_malloc_trace=$enableval +else + enable_malloc_trace=no + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_malloc_trace" >&5 +$as_echo "$enable_malloc_trace" >&6; } + if test "x$enable_malloc_trace" = "xyes"; then + MALLOC_TRACE_TRUE= + MALLOC_TRACE_FALSE='#' +else + MALLOC_TRACE_TRUE='#' + MALLOC_TRACE_FALSE= +fi + + if test "x$enable_malloc_trace" = "xyes"; then : + +$as_echo "#define MALLOC_TRACE 1" >>confdefs.h + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable Valgrind support" >&5 +$as_echo_n "checking whether to enable Valgrind support... " >&6; } + # Check whether --enable-valgrind was given. +if test "${enable_valgrind+set}" = set; then : + enableval=$enable_valgrind; enable_valgrind=$enableval +else + enable_valgrind=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_valgrind" >&5 +$as_echo "$enable_valgrind" >&6; } + + if test "x$enable_valgrind" != "xno"; then : + + if test "x$enable_valgrind" = "xyes" -o "x$enable_valgrind" = "xauto"; then : + + for ac_header in valgrind/valgrind.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" +if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VALGRIND_VALGRIND_H 1 +_ACEOF + valgrind_headers=yes +else + valgrind_headers=no +fi + +done + + +fi + +fi + if test "x$enable_valgrind" = "xyes"; then : + + if test x"$valgrind_headers" = "no"; then : + + as_fn_error $? "Valgrind support requested but required Valgrind headers were not found" "$LINENO" 5 + +fi + +fi + if test x"$valgrind_headers" = "xyes" ; then + PDNS_USE_VALGRIND_TRUE= + PDNS_USE_VALGRIND_FALSE='#' +else + PDNS_USE_VALGRIND_TRUE='#' + PDNS_USE_VALGRIND_FALSE= +fi + + if test x"$valgrind_headers" = "xyes" ; then : + +$as_echo "#define PDNS_USE_VALGRIND 1" >>confdefs.h + +fi + + + + +# Check whether --enable-systemd was given. +if test "${enable_systemd+set}" = set; then : + enableval=$enable_systemd; +fi + + +if test "x$enable_systemd" = "xno"; then : + + ax_cv_systemd="n" + +elif test "x$enable_systemd" = "xyes"; then : + + ax_cv_systemd="y" + +elif test -z $ax_cv_systemd; then : + + ax_cv_systemd="n" + +fi +systemd=$ax_cv_systemd + + + + +# Check whether --with-systemd was given. +if test "${with_systemd+set}" = set; then : + withval=$with_systemd; SYSTEMD_DIR="$withval" +else + SYSTEMD_DIR="" +fi + + + + +# Check whether --with-systemd was given. +if test "${with_systemd+set}" = set; then : + withval=$with_systemd; SYSTEMD_MODULES_LOAD="$withval" +else + SYSTEMD_MODULES_LOAD="" +fi + + + + + + ac_fn_cxx_check_header_mongrel "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default" +if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes; then : + + for libname in systemd-daemon systemd; do + as_ac_Lib=`$as_echo "ac_cv_lib_$libname''_sd_listen_fds" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sd_listen_fds in -l$libname" >&5 +$as_echo_n "checking for sd_listen_fds in -l$libname... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-l$libname $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 sd_listen_fds (); +int +main () +{ +return sd_listen_fds (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + + libsystemd_daemon="lib$libname" + systemd=y + libsystemd=y + +fi + + done + +fi + + + + + if test "x$enable_systemd" != "xno"; then : + + if test "x$systemd" = "xy" ; then : + + +$as_echo "#define HAVE_SYSTEMD 1" >>confdefs.h + + systemd=y + + + if test "x$libsystemd" = x; then : + + as_fn_error $? "Unable to find a suitable libsystemd library" "$LINENO" 5 + +fi + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5 +$as_echo_n "checking for SYSTEMD... " >&6; } + +if test -n "$SYSTEMD_CFLAGS"; then + pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$libsystemd_daemon") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "$libsystemd_daemon" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SYSTEMD_LIBS"; then + pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$libsystemd_daemon") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "$libsystemd_daemon" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$libsystemd_daemon" 2>&1` + else + SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$libsystemd_daemon" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SYSTEMD_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($libsystemd_daemon) were not met: + +$SYSTEMD_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables SYSTEMD_CFLAGS +and SYSTEMD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables SYSTEMD_CFLAGS +and SYSTEMD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS + SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + + + + if test "x$SYSTEMD_DIR" = x; then : + + SYSTEMD_DIR="\$(prefix)/lib/systemd/system/" + +fi + + if test "x$SYSTEMD_DIR" = x; then : + + as_fn_error $? "SYSTEMD_DIR is unset" "$LINENO" 5 + +fi + + if test "x$SYSTEMD_MODULES_LOAD" = x; then : + + SYSTEMD_MODULES_LOAD="\$(prefix)/lib/modules-load.d/" + +fi + + if test "x$SYSTEMD_MODULES_LOAD" = x; then : + + as_fn_error $? "SYSTEMD_MODULES_LOAD is unset" "$LINENO" 5 + +fi + + +else + systemd=n +fi + +else + systemd=n +fi + + + if test x"$systemd" = "xy" ; then + HAVE_SYSTEMD_TRUE= + HAVE_SYSTEMD_FALSE='#' +else + HAVE_SYSTEMD_TRUE='#' + HAVE_SYSTEMD_FALSE= +fi + + + # Extract the first word of "virtualenv", so it can be a program name with args. +set dummy virtualenv; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_VIRTUALENV+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$VIRTUALENV"; then + ac_cv_prog_VIRTUALENV="$VIRTUALENV" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_VIRTUALENV="virtualenv" + $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 + + test -z "$ac_cv_prog_VIRTUALENV" && ac_cv_prog_VIRTUALENV="no" +fi +fi +VIRTUALENV=$ac_cv_prog_VIRTUALENV +if test -n "$VIRTUALENV"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VIRTUALENV" >&5 +$as_echo "$VIRTUALENV" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + if test "x$VIRTUALENV" = "xno"; then : + + if test ! -f "$srcdir/pdns_recursor.1"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: virtualenv is missing, unable to build manpages." >&5 +$as_echo "$as_me: WARNING: virtualenv is missing, unable to build manpages." >&2;} + +fi + +fi + if test "x$VIRTUALENV" != "xno"; then + HAVE_VIRTUALENV_TRUE= + HAVE_VIRTUALENV_FALSE='#' +else + HAVE_VIRTUALENV_TRUE='#' + HAVE_VIRTUALENV_FALSE= +fi + + if test -e "$srcdir/pdns_recursor.1"; then + HAVE_MANPAGES_TRUE= + HAVE_MANPAGES_FALSE='#' +else + HAVE_MANPAGES_TRUE='#' + HAVE_MANPAGES_FALSE= +fi + + + + + +AM_CPPFLAGS="-I\$(top_builddir) -I\$(top_srcdir) $THREADFLAGS $BOOST_CPPFLAGS" + + + +YAHTTP_CFLAGS='-I$(top_srcdir)/ext/yahttp' + +YAHTTP_LIBS='$(top_builddir)/ext/yahttp/yahttp/libyahttp.la' + + +LDFLAGS="$RELRO_LDFLAGS $LDFLAGS" +CFLAGS="$PIE_CFLAGS $CFLAGS" +CXXFLAGS="$SANITIZER_FLAGS $PIE_CFLAGS $CXXFLAGS" +PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS" + + +ac_config_files="$ac_config_files Makefile ext/Makefile ext/json11/Makefile ext/yahttp/Makefile ext/yahttp/yahttp/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 + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + 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 + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + 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 "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_FREEBSD_TRUE}" && test -z "${HAVE_FREEBSD_FALSE}"; then + as_fn_error $? "conditional \"HAVE_FREEBSD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_LINUX_TRUE}" && test -z "${HAVE_LINUX_FALSE}"; then + as_fn_error $? "conditional \"HAVE_LINUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_SOLARIS_TRUE}" && test -z "${HAVE_SOLARIS_FALSE}"; then + as_fn_error $? "conditional \"HAVE_SOLARIS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PROTOBUF_TRUE}" && test -z "${HAVE_PROTOBUF_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PROTOBUF\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PROTOC_TRUE}" && test -z "${HAVE_PROTOC_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PROTOC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${UNIT_TESTS_TRUE}" && test -z "${UNIT_TESTS_FALSE}"; then + as_fn_error $? "conditional \"UNIT_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LUA_TRUE}" && test -z "${LUA_FALSE}"; then + as_fn_error $? "conditional \"LUA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LUA_TRUE}" && test -z "${LUA_FALSE}"; then + as_fn_error $? "conditional \"LUA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_LUA_HPP_TRUE}" && test -z "${HAVE_LUA_HPP_FALSE}"; then + as_fn_error $? "conditional \"HAVE_LUA_HPP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BOTAN_TRUE}" && test -z "${BOTAN_FALSE}"; then + as_fn_error $? "conditional \"BOTAN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBSODIUM_TRUE}" && test -z "${LIBSODIUM_FALSE}"; then + as_fn_error $? "conditional \"LIBSODIUM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBDECAF_TRUE}" && test -z "${LIBDECAF_FALSE}"; then + as_fn_error $? "conditional \"LIBDECAF\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_NET_SNMP_TRUE}" && test -z "${HAVE_NET_SNMP_FALSE}"; then + as_fn_error $? "conditional \"HAVE_NET_SNMP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MALLOC_TRACE_TRUE}" && test -z "${MALLOC_TRACE_FALSE}"; then + as_fn_error $? "conditional \"MALLOC_TRACE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${PDNS_USE_VALGRIND_TRUE}" && test -z "${PDNS_USE_VALGRIND_FALSE}"; then + as_fn_error $? "conditional \"PDNS_USE_VALGRIND\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_SYSTEMD_TRUE}" && test -z "${HAVE_SYSTEMD_FALSE}"; then + as_fn_error $? "conditional \"HAVE_SYSTEMD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_VIRTUALENV_TRUE}" && test -z "${HAVE_VIRTUALENV_FALSE}"; then + as_fn_error $? "conditional \"HAVE_VIRTUALENV\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_MANPAGES_TRUE}" && test -z "${HAVE_MANPAGES_FALSE}"; then + as_fn_error $? "conditional \"HAVE_MANPAGES\" 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. +as_myself= +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 -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +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 + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# 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 pdns-recursor $as_me 4.1.4, which was +generated by GNU Autoconf 2.69. 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 the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +pdns-recursor config.status 4.1.4 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 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 "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +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 \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +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_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_separator_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$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 \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX \ +postlink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +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 + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "ext/Makefile") CONFIG_FILES="$CONFIG_FILES ext/Makefile" ;; + "ext/json11/Makefile") CONFIG_FILES="$CONFIG_FILES ext/json11/Makefile" ;; + "ext/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/Makefile" ;; + "ext/yahttp/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/yahttp/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= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_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 -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# 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` +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 {' >"$ac_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 >>"\$ac_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 +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_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 < "$ac_tmp/subs1.awk" > "$ac_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 >"$ac_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_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; 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 +' >$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="$ac_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 >"$ac_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 "$ac_tmp/subs.awk" \ + >$ac_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' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_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 "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_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 "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_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 "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_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"" || { + # Older Autoconf 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"` + # 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'`; 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, 2009, 2010, 2011 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="CXX " + +# ### 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 + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# 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 + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# 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 + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# 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 + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# 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 + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# 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 + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# 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 + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# 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 + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# 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 + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# 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 + +# 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 + +# 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 + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_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 + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### 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 '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +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}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# 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_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# 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_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# 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_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + 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 + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 +$as_echo "$as_me: " >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuration summary" >&5 +$as_echo "$as_me: Configuration summary" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: =====================" >&5 +$as_echo "$as_me: =====================" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 +$as_echo "$as_me: " >&6;} +if test "x$pdns_configure_args" != "x"; then : + summary_conf_opts=$pdns_configure_args +else + summary_conf_opts="(no options)" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: PowerDNS Recursor configured with: $summary_conf_opts" >&5 +$as_echo "$as_me: PowerDNS Recursor configured with: $summary_conf_opts" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 +$as_echo "$as_me: " >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: CC: $CC" >&5 +$as_echo "$as_me: CC: $CC" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: CXX: $CXX" >&5 +$as_echo "$as_me: CXX: $CXX" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: LD: $LD" >&5 +$as_echo "$as_me: LD: $LD" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: CFLAGS: $CFLAGS" >&5 +$as_echo "$as_me: CFLAGS: $CFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: CPPFLAGS: $CPPFLAGS" >&5 +$as_echo "$as_me: CPPFLAGS: $CPPFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: CXXFLAGS: $CXXFLAGS" >&5 +$as_echo "$as_me: CXXFLAGS: $CXXFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: LDFLAGS: $LDFLAGS" >&5 +$as_echo "$as_me: LDFLAGS: $LDFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: LIBS: $LIBS" >&5 +$as_echo "$as_me: LIBS: $LIBS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&5 +$as_echo "$as_me: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 +$as_echo "$as_me: " >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Features enabled" >&5 +$as_echo "$as_me: Features enabled" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: ----------------" >&5 +$as_echo "$as_me: ----------------" >&6;} +if test "x$LUAPC" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: Lua: $LUAPC" >&5 +$as_echo "$as_me: Lua: $LUAPC" >&6;} +else + if test "x$LUAJITPC" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: LuaJit: $LUAJITPC" >&5 +$as_echo "$as_me: LuaJit: $LUAJITPC" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: Lua/LuaJit: no" >&5 +$as_echo "$as_me: Lua/LuaJit: no" >&6;} +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL ECDSA: $libcrypto_ecdsa" >&5 +$as_echo "$as_me: OpenSSL ECDSA: $libcrypto_ecdsa" >&6;} +if test "x$LIBSODIUM_LIBS" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: libsodium ed25519: yes" >&5 +$as_echo "$as_me: libsodium ed25519: yes" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: libsodium ed25519: no" >&5 +$as_echo "$as_me: libsodium ed25519: no" >&6;} + +fi +if test "x$LIBDECAF_LIBS" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: libdecaf ed25519 and ed448: yes" >&5 +$as_echo "$as_me: libdecaf ed25519 and ed448: yes" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: libdecaf ed25519 and ed448: no" >&5 +$as_echo "$as_me: libdecaf ed25519 and ed448: no" >&6;} + +fi +if test "x$BOTAN_LIBS" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: Botan gost: yes" >&5 +$as_echo "$as_me: Botan gost: yes" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: Botan gost: no" >&5 +$as_echo "$as_me: Botan gost: no" >&6;} + +fi +if test "x$PROTOBUF_LIBS" != "x" -a x"$PROTOC" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: Protobuf: yes" >&5 +$as_echo "$as_me: Protobuf: yes" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: Protobuf: no" >&5 +$as_echo "$as_me: Protobuf: no" >&6;} + +fi +if test "x$NET_SNMP_LIBS" != "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: SNMP: yes" >&5 +$as_echo "$as_me: SNMP: yes" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: SNMP: no" >&5 +$as_echo "$as_me: SNMP: no" >&6;} + +fi +if test "x$systemd" != "xn"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: systemd: yes" >&5 +$as_echo "$as_me: systemd: yes" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: systemd: no" >&5 +$as_echo "$as_me: systemd: no" >&6;} + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: Context library: $pdns_context_library" >&5 +$as_echo "$as_me: Context library: $pdns_context_library" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 +$as_echo "$as_me: " >&6;} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d1758ac --- /dev/null +++ b/configure.ac @@ -0,0 +1,242 @@ +AC_PREREQ([2.61]) + +AC_INIT([pdns-recursor], m4_esyscmd(build-aux/gen-version)) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip tar-ustar -Wno-portability subdir-objects parallel-tests 1.11]) +AM_SILENT_RULES([yes]) +AC_CONFIG_SRCDIR([pdns_recursor.cc]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_CONFIG_HEADERS([config.h]) + +AC_CANONICAL_HOST +: ${CFLAGS="-Wall -g -O2"} +: ${CXXFLAGS="-Wall -g -O2"} + +AC_SUBST([pdns_configure_args],["$ac_configure_args"]) +AC_DEFINE_UNQUOTED([PDNS_CONFIG_ARGS], + ["$pdns_configure_args"], + [pdns-recursor configure arguments] +) + +AC_PROG_CC +AC_PROG_CXX +AC_LANG([C++]) + +AC_GNU_SOURCE + +AC_DEFINE([RECURSOR], [1], + [This is the PowerDNS Recursor] +) + +# Warn when pkg.m4 is missing +m4_pattern_forbid([^_?PKG_[A-Z_]+$], [*** pkg.m4 missing, please install pkg-config]) + +AX_CXX_COMPILE_STDCXX_11([ext], [mandatory]) +AC_PROG_LIBTOOL + +PDNS_CHECK_OS +PDNS_CHECK_NETWORK_LIBS + +# Boost Context was introduced in 1.51 (Aug 2012), but there was an immediate +# API break in 1.52 (Nov 2012), so we only support that, and later. +pdns_context_library="System V ucontexts" + +AC_DEFUN([PDNS_SELECT_CONTEXT_IMPL], [ + AC_MSG_CHECKING([whether Boost is new enough to use the context library...]) + if test $boost_major_version -ge 152; then + AC_MSG_RESULT([yes]) + if test $boost_major_version -ge 157; then + BOOST_THREAD([$1]) + m4_pattern_allow([^BOOST_THREAD_(LIBS|LDFLAGS)$])dnl + LIBS="$LIBS $BOOST_THREAD_LIBS" + LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS" + fi + AC_MSG_NOTICE([checking whether the Boost context library actually links...]) + if test $boost_major_version -ge 161; then + BOOST_FIND_HEADER([boost/context/detail/fcontext.hpp], [ : ], [ + BOOST_FIND_LIB([context], [$1], [boost/context/detail/fcontext.hpp], [[]]) + ]) + else + BOOST_FIND_HEADER([boost/context/fcontext.hpp], [ : ], [ + BOOST_FIND_LIB([context], [$1], [boost/context/fcontext.hpp], [[]]) + ]) + fi + case $boost_cv_lib_context in + (yes) + pdns_context_library="Boost context" + AC_MSG_NOTICE([MTasker will use the Boost context library for context switching]) + ;; + *) + AC_MSG_NOTICE([Boost context library is missing]) + AC_MSG_NOTICE([MTasker will use System V ucontexts for context switching]) + ;; + esac + else + AC_MSG_RESULT([no]) + AC_MSG_NOTICE([MTasker will use System V ucontexts for context switching]) + fi +]) + +PDNS_CHECK_CLOCK_GETTIME + +boost_required_version=1.35 + +PDNS_WITH_PROTOBUF +AS_IF([test "x$PROTOBUF_LIBS" != "x" -a x"$PROTOC" != "x"], + # The protobuf code needs boost::uuid, which is available from 1.42 onward + [AC_MSG_WARN([Bumping minimal Boost requirement to 1.42. To keep the requirement at 1.35, disable protobuf support]) + boost_required_version=1.42] +) + +BOOST_REQUIRE([$boost_required_version]) +PDNS_SELECT_CONTEXT_IMPL + +PDNS_ENABLE_UNIT_TESTS +PDNS_ENABLE_REPRODUCIBLE + +PDNS_WITH_LUAJIT +AS_IF([test "x$with_luajit" = "xno"], [ + PDNS_WITH_LUA +]) +AS_IF([test "x$LUAPC" = "x" -a "x$LUAJITPC" = "x"], [ + AC_MSG_ERROR([Neither Lua nor LuaJIT found, Lua support is not optional]) +]) +AS_IF([test "x$LUAJITPC" != "x"], [ + # export all symbols to be able to use the Lua FFI interface + AC_MSG_NOTICE([Adding -rdynamic to export all symbols for the Lua FFI interface]) + LDFLAGS="$LDFLAGS -rdynamic" +]) +PDNS_CHECK_LUA_HPP + +PDNS_ENABLE_VERBOSE_LOGGING + +# Crypto libraries +PDNS_ENABLE_BOTAN +PDNS_CHECK_LIBCRYPTO([ +],[ + AC_MSG_ERROR([OpenSSL/libcrypto not found]) + ] +) +PDNS_CHECK_LIBCRYPTO_ECDSA +PDNS_CHECK_LIBSODIUM +PDNS_CHECK_LIBDECAF + +PDNS_WITH_NET_SNMP + +# check for tools we might need +PDNS_CHECK_RAGEL([pdns/dnslabeltext.cc], [www.powerdns.com]) +PDNS_CHECK_CURL + +AC_CHECK_FUNCS([strcasestr]) + +PDNS_CHECK_PTHREAD_NP + +AC_SUBST([socketdir]) +socketdir="/var/run" +AC_ARG_WITH([socketdir], + [AS_HELP_STRING([--with-socketdir], [where the controlsocket lives @<:@default=/var/run@:>@])], + [socketdir="$withval"] +) + +AC_MSG_CHECKING([whether we will enable compiler security checks]) +AC_ARG_ENABLE([hardening], + [AS_HELP_STRING([--disable-hardening], [disable compiler security checks @<:@default=no@:>@])], + [enable_hardening=$enableval], + [enable_hardening=yes] +) +AC_MSG_RESULT([$enable_hardening]) + +AS_IF([test "x$enable_hardening" != "xno"], [ + AC_CC_PIE + AC_CC_STACK_PROTECTOR + AC_CC_PARAM_SSP_BUFFER_SIZE([4]) + AC_CC_D_FORTIFY_SOURCE + AC_LD_RELRO +]) + +PDNS_ENABLE_SANITIZERS +PDNS_ENABLE_MALLOC_TRACE +PDNS_ENABLE_VALGRIND +AX_AVAILABLE_SYSTEMD +AM_CONDITIONAL([HAVE_SYSTEMD], [ test x"$systemd" = "xy" ]) +PDNS_CHECK_VIRTUALENV + +AC_SUBST(LIBS) + +AC_SUBST([AM_CPPFLAGS], + ["AS_ESCAPE([-I$(top_builddir) -I$(top_srcdir)]) $THREADFLAGS $BOOST_CPPFLAGS"] +) + +AC_SUBST([YAHTTP_CFLAGS], ['-I$(top_srcdir)/ext/yahttp']) +AC_SUBST([YAHTTP_LIBS], ['$(top_builddir)/ext/yahttp/yahttp/libyahttp.la']) + +LDFLAGS="$RELRO_LDFLAGS $LDFLAGS" +CFLAGS="$PIE_CFLAGS $CFLAGS" +CXXFLAGS="$SANITIZER_FLAGS $PIE_CFLAGS $CXXFLAGS" +PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS" +AC_SUBST([PROGRAM_LDFLAGS]) + +AC_CONFIG_FILES([Makefile + ext/Makefile + ext/json11/Makefile + ext/yahttp/Makefile + ext/yahttp/yahttp/Makefile]) + +AC_OUTPUT + +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Configuration summary]) +AC_MSG_NOTICE([=====================]) +AC_MSG_NOTICE([]) +AS_IF([test "x$pdns_configure_args" != "x"], + [summary_conf_opts=$pdns_configure_args], + [summary_conf_opts="(no options)"] +) +AC_MSG_NOTICE([PowerDNS Recursor configured with: $summary_conf_opts]) +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([CC: $CC]) +AC_MSG_NOTICE([CXX: $CXX]) +AC_MSG_NOTICE([LD: $LD]) +AC_MSG_NOTICE([CFLAGS: $CFLAGS]) +AC_MSG_NOTICE([CPPFLAGS: $CPPFLAGS]) +AC_MSG_NOTICE([CXXFLAGS: $CXXFLAGS]) +AC_MSG_NOTICE([LDFLAGS: $LDFLAGS]) +AC_MSG_NOTICE([LIBS: $LIBS]) +AC_MSG_NOTICE([BOOST_CPPFLAGS: $BOOST_CPPFLAGS]) +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Features enabled]) +AC_MSG_NOTICE([----------------]) +AS_IF([test "x$LUAPC" != "x"], + [AC_MSG_NOTICE([Lua: $LUAPC])], + [AS_IF([test "x$LUAJITPC" != "x"], + [AC_MSG_NOTICE([LuaJit: $LUAJITPC])], + [AC_MSG_NOTICE([Lua/LuaJit: no])]) +]) +AC_MSG_NOTICE([OpenSSL ECDSA: $libcrypto_ecdsa]) +AS_IF([test "x$LIBSODIUM_LIBS" != "x"], + [AC_MSG_NOTICE([libsodium ed25519: yes])], + [AC_MSG_NOTICE([libsodium ed25519: no])] +) +AS_IF([test "x$LIBDECAF_LIBS" != "x"], + [AC_MSG_NOTICE([libdecaf ed25519 and ed448: yes])], + [AC_MSG_NOTICE([libdecaf ed25519 and ed448: no])] +) +AS_IF([test "x$BOTAN_LIBS" != "x"], + [AC_MSG_NOTICE([Botan gost: yes])], + [AC_MSG_NOTICE([Botan gost: no])] +) +AS_IF([test "x$PROTOBUF_LIBS" != "x" -a x"$PROTOC" != "x"], + [AC_MSG_NOTICE([Protobuf: yes])], + [AC_MSG_NOTICE([Protobuf: no])] +) +AS_IF([test "x$NET_SNMP_LIBS" != "x"], + [AC_MSG_NOTICE([SNMP: yes])], + [AC_MSG_NOTICE([SNMP: no])] +) +AS_IF([test "x$systemd" != "xn"], + [AC_MSG_NOTICE([systemd: yes])], + [AC_MSG_NOTICE([systemd: no])] +) +AC_MSG_NOTICE([Context library: $pdns_context_library]) +AC_MSG_NOTICE([]) diff --git a/contrib/SMF-powerdns-recursor.xml b/contrib/SMF-powerdns-recursor.xml new file mode 100644 index 0000000..4892e24 --- /dev/null +++ b/contrib/SMF-powerdns-recursor.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/dns64.lua b/contrib/dns64.lua new file mode 100644 index 0000000..bf779a3 --- /dev/null +++ b/contrib/dns64.lua @@ -0,0 +1,29 @@ +-- this small script implements dns64 without any specials or customization +prefix = "fe80::21b:77ff:0:0" + +function nodata ( dq ) + if dq.qtype ~= pdns.AAAA then + return false + end -- only AAAA records + + -- don't fake AAAA records if DNSSEC validation failed + if dq.validationState == pdns.validationstates.Bogus then + return false + end + + dq.followupFunction = "getFakeAAAARecords" + dq.followupPrefix = prefix + dq.followupName = dq.qname + return true +end + +-- the ip6.arpa address is the reverse of the prefix address above +function preresolve ( dq ) + if dq.qtype == pdns.PTR and dq.qname:isPartOf(newDN("f.f.7.7.b.1.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa.")) then + dq.followupFunction = "getFakePTRRecords" + dq.followupPrefix = prefix + dq.followupName = dq.qname + return true + end + return false +end diff --git a/contrib/kv-example-script.lua b/contrib/kv-example-script.lua new file mode 100644 index 0000000..18b4df5 --- /dev/null +++ b/contrib/kv-example-script.lua @@ -0,0 +1,58 @@ + +--[[ +This implements a two-step domain filtering solution where the status of an IP address +and a domain name need to be looked up. +To do so, we use the udpQuestionResponse answers which generically allows us to do asynchronous +lookups via UDP. +Such lookups can be slow, but they won't block PowerDNS while we wait for them. + +To benefit from this hook, +.. + +To test, use the 'kvresp' example program provided. +--]] + +function preresolve (dq) + print ("prereesolve handler called for: "..dq.remoteaddr:toString().. ", local: ".. dq.localaddr:toString()..", ".. dq.qname:toString()..", ".. dq.qtype) + dq.followupFunction="udpQueryResponse" + dq.udpCallback="gotdomaindetails" + dq.udpQueryDest=newCA("127.0.0.1:5555") + dq.udpQuery = "DOMAIN "..dq.qname:toString() + return true; +end + +function gotdomaindetails(dq) + print("gotdomaindetails called, got: "..dq.udpAnswer) + if(dq.udpAnswer == "0") + then + print("This domain needs no filtering, not looking up this domain") + dq.followupFunction="" + return false + end + print("Domain might need filtering for some users") + dq.variable = true -- disable packet cache + local data={} + data["domaindetails"]= dq.udpAnswer + dq.data=data + dq.udpQuery="IP "..dq.remoteaddr:toString() + dq.udpCallback="gotipdetails" + print("returning true in gotipdetails") + return true +end + +function gotipdetails(dq) + dq.followupFunction="" + print("So status of IP is "..dq.udpAnswer.." and status of domain is "..dq.data.domaindetails) + if(dq.data.domaindetails=="1" and dq.udpAnswer=="1") + then + print("IP wants filtering and domain is of the filtered kind") + dq:addAnswer(pdns.CNAME, "blocked.powerdns.com") + return true + else + print("Returning false (normal resolution should proceed, for this user)") + return false + end +end + + + diff --git a/contrib/powerdns-example-script.lua b/contrib/powerdns-example-script.lua new file mode 100644 index 0000000..a22c9ed --- /dev/null +++ b/contrib/powerdns-example-script.lua @@ -0,0 +1,142 @@ +pdnslog("pdns-recursor Lua script starting!", pdns.loglevels.Warning) + +blockset = newDS() +blockset:add{"powerdns.org", "xxx"} + +dropset = newDS(); +dropset:add("123.cn") + +malwareset = newDS() +malwareset:add("nl") + +magic2 = newDN("www.magic2.com") + + +magicMetric = getMetric("magic") + +-- shows the various ways of blocking, dropping, changing questions +-- return false to say you did not take over the question, but we'll still listen to 'variable' +-- to selectively disable the cache +function preresolve(dq) + print("Got question for "..dq.qname:toString().." from "..dq.remoteaddr:toString().." to "..dq.localaddr:toString()) + + local ednssubnet=dq:getEDNSSubnet() + if(ednssubnet) then + print("Packet EDNS subnet source: "..ednssubnet:toString()..", "..ednssubnet:getNetwork():toString()) + end + + + local a=dq:getEDNSOption(3) + if(a) then + print("There is an EDNS option 3 present: "..a) + end + + loc = newCA("127.0.0.1") + if(dq.remoteaddr:equal(loc)) + then + print("Query from loopback") + end + + -- note that the comparisons below are CaSe InSensiTivE and you don't have to worry about trailing dots + if(dq.qname:equal("magic.com")) + then + magicMetric:inc() + print("Magic!") + else + print("not magic..") + end + + if(dq.qname:__eq(magic2)) -- we hope to improve this syntax + then + print("Faster magic") -- compares against existing DNSName + end -- sadly, dq.qname == magic2 won't work yet + + if blockset:check(dq.qname) then + dq.variable = true -- disable packet cache in any case + if dq.qtype == pdns.A then + dq:addAnswer(pdns.A, "1.2.3.4") + dq:addAnswer(pdns.TXT, "\"Hello!\"", 3601) -- ttl + return true; + end + end + + if dropset:check(dq.qname) then + dq.rcode = pdns.DROP + return true; + end + + + + if malwareset:check(dq.qname) then + dq:addAnswer(pdns.CNAME, "xs.powerdns.com.") + dq.rcode = 0 + dq.followupFunction="followCNAMERecords" -- this makes PowerDNS lookup your CNAME + return true; + end + + return false; +end + + +-- this implements DNS64 + +function nodata(dq) + if dq.qtype == pdns.AAAA then + dq.followupFunction="getFakeAAAARecords" + dq.followupName=dq.qname + dq.followupPrefix="fe80::" + return true + end + + if dq.qtype == pdns.PTR then + dq.followupFunction="getFakePTRRecords" + dq.followupName=dq.qname + dq.followupPrefix="fe80::" + return true + end + return false +end + + +badips = newNMG() +badips:addMask("127.1.0.0/16") + +-- this check is applied before any packet parsing is done +function ipfilter(rem, loc, dh) + print("ipfilter called, rem: ", rem:toStringWithPort(), "loc: ",loc:toStringWithPort(),"match:", badips:match(rem)) + print("id: ",dh:getID(), "aa: ", dh:getAA(), "ad: ", dh:getAD(), "arcount: ", dh:getARCOUNT()) + print("ports: ",rem:getPort(),loc:getPort()) + return badips:match(rem) +end + +-- postresolve runs after the packet has been answered, and can be used to change things +-- or still drop +function postresolve(dq) + print("postresolve called for ",dq.qname:toString()) + local records = dq:getRecords() + for k,v in pairs(records) do + print(k, v.name:toString(), v:getContent()) + if v.type == pdns.A and v:getContent() == "185.31.17.73" + then + print("Changing content!") + v:changeContent("130.161.252.29") + v.ttl=1 + end + end + dq:setRecords(records) + return true +end + +nxdomainsuffix=newDN("com") + +function nxdomain(dq) + print("Hooking: ",dq.qname:toString()) + if dq.qname:isPartOf(nxdomainsuffix) + then + dq.rcode=0 -- make it a normal answer + dq:addAnswer(pdns.CNAME, "ourhelpfulservice.com") + dq:addAnswer(pdns.A, "1.2.3.4", 60, "ourhelpfulservice.com") + return true + end + return false +end \ No newline at end of file diff --git a/contrib/syncres.dot b/contrib/syncres.dot new file mode 100644 index 0000000..b931eea --- /dev/null +++ b/contrib/syncres.dot @@ -0,0 +1,368 @@ +digraph { + graph [fontname = "monospace"]; + node [fontname = "monospace"]; + edge [fontname = "monospace"]; + + subgraph cluster_beginResolve { + label="SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector&ret)\nreturns the RCODE\nret is filled with all relevant records"; + + beginResolve_doResolve [label="SyncRes::doResolve()", color=red]; + beginResolve_doSpecialNamesResolve [label="SyncRes::doSpecialNamesResolve()", color=red] + + "Is this an AXFR request?"; + "Is this an AXFR request?" -> beginResolve_return_minus_1 [label=yes]; + "Is this an AXFR request?" -> beginResolve_doSpecialNamesResolve [label=no]; + + beginResolve_doSpecialNamesResolve -> "Is the qlass IN?" [label="Was not a special name"]; + beginResolve_doSpecialNamesResolve -> beginResolve_return_0 [label="Was handled!"]; + + "Is the qlass IN?" -> beginResolve_return_minus_1 [label=no]; + "Is the qlass IN?" -> beginResolve_doResolve [label=yes]; + beginResolve_doResolve -> beginResolve_return_doResolve; + beginResolve_return_doResolve [label="return result from doResolve", color=green]; + beginResolve_return_0 [label="return 0", color=green]; + beginResolve_return_minus_1 [label="return -1", color=green]; + } + + subgraph cluster_doResolve { + label="SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, set& beenthere)"; + + doResolve_doOOBResolve [label="SyncRes::doOOBResolve()", color=red]; + doResolve_doCNAMECacheCheck [label="SyncRes::doCNAMECacheCheck()", color=red]; + doResolve_asyncresolveWrapper [label="SyncRes::asyncresolveWrapper()", color=red]; + doResolve_doCacheCheck [label="SyncRes::doCacheCheck()", color=red]; + doResolve_getBestNSNamesFromCache [label="SyncRes::getBestNSNamesFromCache()", color=red]; + doResolve_doResolveAt [label="SyncRes::doResolveAt()", color=red]; + + doResolve_return_res [label="return res", color=green]; + doResolve_return_servfail [label="return SERVFAIL", color=green]; + + "SERVFAIL if too deep" -> "Check if called from getRootNS()"; + "Check if called from getRootNS()" -> "Check if RD-bit was not set (d_cacheonly)" [label=yes]; + "Check if called from getRootNS()" -> doResolve_getBestNSNamesFromCache [label=no]; + "Check if RD-bit was not set (d_cacheonly)" -> doResolve_doCNAMECacheCheck [label=no]; + "Check if RD-bit was not set (d_cacheonly)" -> "Check if there is a forward or auth-zone" [label=yes]; + "Check if there is a forward or auth-zone" -> doResolve_doCNAMECacheCheck [label=no]; + "Check if there is a forward or auth-zone" -> "Check if we are auth" [label=yes]; + "Check if we are auth" -> doResolve_asyncresolveWrapper [label="no, so forward"]; + "Check if we are auth" -> doResolve_doOOBResolve [label=yes]; + doResolve_doOOBResolve -> "return res from doOOBResolve()"; + "return res from doOOBResolve()" [color=green]; + doResolve_asyncresolveWrapper -> "return result from asyncresolveWrapper()"; + "return result from asyncresolveWrapper()" [color=green]; + + doResolve_doCNAMECacheCheck -> doResolve_doCacheCheck [label="returned false"]; + doResolve_doCNAMECacheCheck -> doResolve_return_res [label="returned true"]; + + doResolve_doCacheCheck -> doResolve_getBestNSNamesFromCache [label="returned false"]; + doResolve_doCacheCheck -> doResolve_return_res [label="returned true"]; + + doResolve_getBestNSNamesFromCache -> doResolve_doResolveAt; + doResolve_doResolveAt -> doResolve_return_res [label="res == -2"]; + doResolve_doResolveAt -> doResolve_return_servfail [label="res < 0 &&\nres != -2"]; + doResolve_doResolveAt -> doResolve_return_res [label="res >= 0"]; + } + + subgraph cluster_doCacheCheck { + label="SyncRes::doCacheCheck(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, int &res)"; + + doCacheCheck_return_false [label="return false", color=green]; + "Did we have a positive or negative answer?" -> doCacheCheck_return_true [label=yes]; + "Did we have a positive or negative answer?" -> doCacheCheck_return_false [label=no]; + doCacheCheck_return_true [label="return true", color=green]; + + "Allocate return qname, qtype and qttl vars (RVARS) as qname, qtype" -> "Is the last label of qname negatively cached by root and is root-nx-trust enabled?"; + + "Is the last label of qname negatively cached by root and is root-nx-trust enabled?" -> "Set res to NXDOMAIN, set RVARS to to this label|SOA" [label=yes]; + "Is the last label of qname negatively cached by root and is root-nx-trust enabled?" -> "Do we have a negative entry from an auth?" [label=no]; + "Do we have a negative entry from an auth?" -> "Set RCODE (NOERROR or NXDOMAIN), set RVARS to (smaller) qname|SOA" [label=yes]; + "Set RCODE (NOERROR or NXDOMAIN), set RVARS to (smaller) qname|SOA" -> "Add DNSSEC proof from cache"; + "Set res to NXDOMAIN, set RVARS to to this label|SOA" -> "Do we have a positive for RVARS from an auth?"; + + "Do we have a negative entry from an auth?" -> "Do we have a positive for RVARS from an auth?" [label=no]; + + "Do we have a positive for RVARS from an auth?" -> "Did we have a positive or negative answer?" [label=no]; + "Add DNSSEC proof from cache" -> "Do we have a positive for RVARS from an auth?"; + + "Do we have a positive for RVARS from an auth?" -> "Add positive answers to ret if not expired" [label=yes]; + "Add positive answers to ret if not expired" -> "Add DNSSEC data to ret"; + "Add DNSSEC data to ret" -> "Did we have a positive or negative answer?"; + } + + subgraph cluster_getBestNSFromCache { + label="SyncRes::getBestNSFromCache(const DNSName &qname, const QType& qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, set& beenthere)\nFills the bestns vector with the 'closest' nameservers for qname\nflawedNSSet will be true if the NSSet has no glue.\nbeenthere contains the list of nameservers already visited during this recursion."; + + getBestNSFromCache_return [label="return", color=green]; + + getBestNSFromCache_chopoff_continue -> "Get NS-records for domain from cache" -> "Get one record from the records" -> "Has the TTL expired?"; + "Get one record from the records" -> "Are there records in bestns?" [label="Checked all records"]; + + "Has the TTL expired?" -> "Get one record from the records" [label=yes]; + "Has the TTL expired?" -> "Is the NS RDATA part of the domain &&\nDo we have A and/or AAAA records for it?" [label=no]; + "Is the NS RDATA part of the domain &&\nDo we have A and/or AAAA records for it?" -> "Set flawednsset=true" [label=no]; + + "Is the NS RDATA part of the domain &&\nDo we have A and/or AAAA records for it?" -> "Add the NS-record to bestns" [label=yes]; + "Add the NS-record to bestns" -> "Get one record from the records"; + + "Set flawednsset=true" -> "Get one record from the records"; + + "Are there records in bestns?" -> getBestNSFromCache_chopoff_continue [label=no]; + "Are there records in bestns?" -> "Is any of the NS records in bestns in beenthere?" [label=yes]; + + + "Is any of the NS records in bestns in beenthere?" -> "Add these records to beenthere" [label=no]; + "Add these records to beenthere" -> getBestNSFromCache_return; + + "Is any of the NS records in bestns in beenthere?" -> "Clear bestns" [label=yes]; + "Clear bestns" -> "Was this the root domain?"; + "Was this the root domain?" -> getBestNSFromCache_chopoff_continue [label=no]; + "Was this the root domain?" -> "Re-prime the root" [label=yes]; + "Re-prime the root" -> getBestNSFromCache_return; + getBestNSFromCache_chopoff_continue [label="chopoff left-most label"]; + + {rank=sink; getBestNSFromCache_chopoff_continue; getBestNSFromCache_return} + } + + subgraph cluster_doOOBResolve { + label="SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, int& res)\nReturns true if data came from local auth-store.\nvector ret is filled with answers"; + + doOOBResolve_getBestAuthZone [label="SyncRes::getBestAuthZone()", color=red]; + doOOBResolve_return_false [label="return false", color=green]; + doOOBResolve_return_true [label="return true", color=green]; + + doOOBResolve_getBestAuthZone -> doOOBResolve_return_false [label="returned iterator to end of authstorage"]; + doOOBResolve_getBestAuthZone -> "Add auth-records matching qname+qtype || CNAME || NS to ret" [label="returned iterator in the authstorage"]; + "Add auth-records matching qname+qtype || CNAME || NS to ret" -> doOOBResolve_return_true [label="records were added to ret"] + "Add auth-records matching qname+qtype || CNAME || NS to ret" -> "Did we have any data for the qname?" [label="no records were added to ret"]; + + "Did we have any data for the qname?" -> "Add SOA to AUTHORITY in ret" [label="yes (empty NOERROR)"]; + "Add SOA to AUTHORITY in ret" -> "Set res to NOERROR" -> doOOBResolve_return_true; + + "Did we have any data for the qname?" -> "Is there a wildcard match?" [label=no]; + "Is there a wildcard match?" -> "Add auth-records from wildcard to ret" [label=yes]; + "Add auth-records from wildcard to ret" -> "Set res to NOERROR"; + + "Is there a wildcard match?" -> "Add NS-records from auth-zone" [label=no]; + + "Add NS-records from auth-zone" -> "Set res to NOERROR" [label="NS record were added"]; + "Add NS-records from auth-zone" -> "Try to add SOA" [label="No NS record were added"]; + + "Try to add SOA" -> "Set res to NXDOMAIN" -> doOOBResolve_return_true; + } + + subgraph cluster_asyncresolveWrapper { + label="SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional& srcmask, LWResult* res\nWraps asyncresolve() from lwres.cc to do EDNS probing."; + + {rank=min; "Get current EDNSStatus for ip"} + + asyncresolveWrapper_asyncresolve [label="asyncresolve()", color=red]; + asyncresolveWrapper_return_minus_1 [label="return -1 (transport error)", color=green]; + asyncresolveWrapper_return_minus_2 [label="return -2 (OS limits error)", color=green]; + asyncresolveWrapper_return_0 [label="return 0 (timeout)", color=green]; + asyncresolveWrapper_return_1 [label="return 1 (success)", color=green]; + asyncresolveWrapper_setEDNSLevel_0 [label="Set EDNSLevel=0"] + asyncresolveWrapper_setEDNSLevel_0 -> "Is EDNSStatus NOEDNS?"; + + "Get current EDNSStatus for ip" -> "Is the current EDNSStatus older than an hour?"; + "Is the current EDNSStatus older than an hour?" -> "Set EDNSStatus to Unknown" [label=yes]; + "Set EDNSStatus to Unknown" -> asyncresolveWrapper_setEDNSLevel_0; + "Is the current EDNSStatus older than an hour?" -> asyncresolveWrapper_setEDNSLevel_0 [label=no]; + + "Is EDNSStatus NOEDNS?" -> "Set EDNSLevel=0" [label=yes] + "Set EDNSLevel=0" -> asyncresolveWrapper_asyncresolve; + + "Is EDNSStatus NOEDNS?" -> "Is EDNSStatus UNKNOWN, EDNSOK, EDSIGNORANT or is EDNS mandatory?" [label=no] + "Is EDNSStatus UNKNOWN, EDNSOK, EDSIGNORANT or is EDNS mandatory?" -> "Set EDNSLevel=1" [label=yes] + "Set EDNSLevel=1" -> asyncresolveWrapper_asyncresolve; + "Is EDNSStatus UNKNOWN, EDNSOK, EDSIGNORANT or is EDNS mandatory?" -> asyncresolveWrapper_asyncresolve [label=no]; + + asyncresolveWrapper_asyncresolve -> asyncresolveWrapper_return_minus_1 [label="transport error"]; + asyncresolveWrapper_asyncresolve -> asyncresolveWrapper_return_minus_2 [label="OS limits error"]; + asyncresolveWrapper_asyncresolve -> asyncresolveWrapper_return_0 [label="timeout error"]; + asyncresolveWrapper_asyncresolve -> "Is the EDNSStatus UNKNOWN||EDNSOK||EDNSIGNORANT?" [label="resolve OK!"]; + + "Is the EDNSStatus UNKNOWN||EDNSOK||EDNSIGNORANT?" -> "Was the RCODE FORMERR||NOTIMP?" [label=yes]; + "Was the RCODE FORMERR||NOTIMP?" -> "set EDNSStatus to NOEDNS" [label=yes]; + "set EDNSStatus to NOEDNS" -> "Is EDNSStatus NOEDNS?"; + + "Was the RCODE FORMERR||NOTIMP?" -> "Did the remote server respond with EDNS?" [label=no]; + "Did the remote server respond with EDNS?" -> "Set EDNSStatus to EDNSOK" [label=yes]; + "Set EDNSStatus to EDNSOK" -> "Is the original EDNSStatus different from the new?"; + + "Did the remote server respond with EDNS?" -> "Set EDNSStatus to EDNSIGNORANT" [label=no]; + "Set EDNSStatus to EDNSIGNORANT" -> "Is the original EDNSStatus different from the new?"; + + "Is the EDNSStatus UNKNOWN||EDNSOK||EDNSIGNORANT?" -> "Is the original EDNSStatus different from the new?" [label=no]; + "Is the original EDNSStatus different from the new?" -> "Save new EDNSStatus" [label=yes]; + "Is the original EDNSStatus different from the new?" -> asyncresolveWrapper_return_1 [label=no]; + "Save new EDNSStatus" -> asyncresolveWrapper_return_1; + } + + subgraph cluster_doResolveAt { + label="SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, set&beenthere)\nreturns -1 in case of no results, -2 when a FilterEngine Policy was hit, rcode otherwise"; + + doResolveAt_nameServersBlockedByRPZ [label="SyncRes::nameserversBlockedByRPZ()", color=red]; + doResolveAt_doOOBResolve_for_NS [label="SyncRes::doOOBResolve()", color=red]; + doResolveAt_retrieveAddressesForNS [label="SyncRes::retrieveAddressesForNS()", color=red]; + doResolveAt_nameserverIPBlockedByRPZ [label="SyncRes::nameserverIPBlockedByRPZ()", color=red]; + doResolveAt_Lua_preoutquery [label="Lua preoutquery", color=red]; + doResolveAt_asyncresolveWrapper [label="SyncRes::asyncresolveWrapper()", color=red]; + doResolveAt_processRecords [label="SyncRes::processRecords()", color=red]; + doResolveAt_doResolve [label="SyncRes::doResolve()", color=red]; + + doResolveAt_return_minus_2 [label="return -2", color=green]; + doResolveAt_return_minus_1 [label="return -1", color=green]; + doResolveAt_return_0 [label="return 0", color=green]; + doResolveAt_return_rcode [label="return rcode", color=green]; + doResolveAt_return_servfail [label="return SERVFAIL", color=green]; + doResolveAt_return_nxdomain [label="return NXDOMAIN", color=green]; + + doResolveAt_mainloop_continue [label="continue"]; + doResolveAt_mainloop_continue -> "Get nameserver from nameservers"; + + doResolveAt_nsiploop_continue [label="continue"]; + doResolveAt_nsiploop_continue -> "Get IP from IPs"; + + doResolveAt_nameServersBlockedByRPZ -> doResolveAt_return_minus_2 [label="RPZ NSDNAME hit"]; + doResolveAt_nameServersBlockedByRPZ -> "Get nameserver from nameservers" [lhead=cluster_doResolveAt_mainloop, label="RPZ NSDNAME not hit"]; + + doResolveAt_ImmediateServFailException [label="throw ImmediateServFailException", color=green]; + + "Get nameserver from nameservers" -> doResolveAt_mainloop_continue [label="qname == nsname"]; + "Get nameserver from nameservers" -> doResolveAt_return_minus_1 [label="All nameservers tried"]; + "Get nameserver from nameservers" -> "Is the nameserver out of band?"; + "Is the nameserver out of band?" -> doResolveAt_doOOBResolve_for_NS [label=yes]; + doResolveAt_doOOBResolve_for_NS -> "updateCacheFromRecords()"; + "Is the nameserver out of band?" -> doResolveAt_retrieveAddressesForNS [label=no]; + doResolveAt_retrieveAddressesForNS -> doResolveAt_mainloop_continue [label="No IPs returned"]; + doResolveAt_retrieveAddressesForNS -> doResolveAt_nameserverIPBlockedByRPZ [label="IPs returned"]; + doResolveAt_nameserverIPBlockedByRPZ -> doResolveAt_return_minus_2 [label="RPZ NSIP hit"]; + doResolveAt_nameserverIPBlockedByRPZ -> "Get IP from IPs" [label="RPZ NSIP not hit"]; + + "Get IP from IPs" -> doResolveAt_nsiploop_continue [label="IP is throttled"]; + "Get IP from IPs" -> doResolveAt_ImmediateServFailException [label="Too many queries sent while resolving"]; + "Get IP from IPs" -> doResolveAt_ImmediateServFailException [label="Resolving took too long"]; + "Get IP from IPs" -> doResolveAt_mainloop_continue [label="No IP address worked"]; + "Get IP from IPs" -> doResolveAt_Lua_preoutquery; + + doResolveAt_Lua_preoutquery -> "Check resolveret" [label="true"]; + doResolveAt_Lua_preoutquery -> doResolveAt_getEDNSSubnetMask [label="false"]; + doResolveAt_getEDNSSubnetMask -> doResolveAt_asyncresolveWrapper; + doResolveAt_asyncresolveWrapper -> "Check resolveret"; + "Check resolveret" -> doResolveAt_ImmediateServFailException [label="resolveret == -3\n(kill query)"]; + "Check resolveret" -> "resolveret == 1"; + "resolveret == 1" -> doResolveAt_nsiploop_continue [label="nameserver returned\nSERVFAIL || REFUSED"]; + "resolveret == 1" -> "updateCacheFromRecords()"; + "updateCacheFromRecords()" -> doResolveAt_return_rcode [label="rcode != NOERROR"]; // line 1473 + "updateCacheFromRecords()" -> doResolveAt_processRecords; // line 1484 + doResolveAt_processRecords -> doResolveAt_return_0 [label="done == true"]; + doResolveAt_processRecords -> "Have newtarget?"; + + "Have newtarget?" -> "qname == newtarget || depth > 10?" [label=yes]; + "qname == newtarget || depth > 10?" -> doResolveAt_return_servfail [label=yes]; + "qname == newtarget || depth > 10?" -> doResolveAt_doResolve [label=no]; + doResolveAt_doResolve -> doResolveAt_return_rcode; + + "Have newtarget?" -> "Have NXDOMAIN from upstream?" [label=no]; + "Have NXDOMAIN from upstream?" -> "Add NSECs if needed" [label=yes]; + "Add NSECs if needed" -> doResolveAt_return_nxdomain; + + "Have NXDOMAIN from upstream?" -> "Have empty NOERROR?" [label=no]; + "Have empty NOERROR?" -> "Add NSEC records if needed" [label=yes]; + "Add NSEC records if needed" -> doResolveAt_return_0; + + "Have empty NOERROR?" -> "Have realreferral?" [label=no]; + "Have realreferral?" -> "Was a server in nsset blocker by RPZNSDNAME?" [label=yes]; + "Was a server in nsset blocker by RPZNSDNAME?" -> doResolveAt_return_minus_2 [label=yes]; + "Was a server in nsset blocker by RPZNSDNAME?" -> "Get nameserver from nameservers" [label=no]; + + "Have realreferral?" -> "Was this an OOB nameserver?" [label=no]; + "Was this an OOB nameserver?" -> "Get nameserver from nameservers" [label="no, nameserver was lame"]; + "Was this an OOB nameserver?" -> "Get nameserver from nameservers" [label=yes]; + } + + subgraph cluster_processRecords { + label="SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector& ret, set& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, bool& sawDS)\nreturns true is this level of recursion is done"; + +// { rank=same; "Get record from lwr.d_records" processRecords_return_done} + +// { rank=same; "Is this a proper CNAME referral?" "Is this a DNSSEC record in the ANSWER section?" "Is this the actual answer?" "Is this an NS record in the AUTHORITY?" "Is this a DS in the AUTHORITY?" "Is this a proper NXDOMAIN?" "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?"} + + "Get record from lwr.d_records"; + "Get record from lwr.d_records" -> "Is this a proper NXDOMAIN?"; // line 1177 + "Get record from lwr.d_records" -> processRecords_return_done [label="All records checked"]; + "Get record from lwr.d_records" -> "Get record from lwr.d_records" [label="type != OPT &&\nclass != IN"]; + + "Is this a proper NXDOMAIN?" -> "is newtarget empty?" [label=yes]; // note, we have a CNAME chasing bug here issue #679 + "is newtarget empty?" -> processRecords_wasVariable [label=no]; + "is newtarget empty?" -> "Add this SOA to ret" [label=yes]; + processRecords_wasVariable [label="SyncRes::wasVariable", color=red] + "Add this SOA to ret" -> processRecords_wasVariable; + processRecords_wasVariable -> "Set negindic to true" [label="was indeed variable"]; + processRecords_wasVariable -> "Add to negative cache" [label="was not variable"]; + "Add to negative cache" -> "If s_rootNXTrust && auth.isRoot()"; + "If s_rootNXTrust && auth.isRoot()" -> "Set negindic to true" [label=no]; + "If s_rootNXTrust && auth.isRoot()" -> "Add tld label to negative cache" [label=yes]; + "Add tld label to negative cache" -> "Set negindic to true"; + "Set negindic to true" -> "Get record from lwr.d_records"; + + "Is this a proper NXDOMAIN?" -> "Is this a proper CNAME referral?" [label=no]; + "Is this a proper CNAME referral?" -> "Add CNAME record to ret" [label=yes]; + "Add CNAME record to ret" -> "Set newtarget to this CNAME" -> "Get record from lwr.d_records"; + + "Is this a proper CNAME referral?" -> "Is this a DNSSEC record in the ANSWER section?" [label=no]; + "Is this a DNSSEC record in the ANSWER section?" -> "Is the record.qtype not RRSIG and is the record's qname the qname we want?"[label=yes]; + "Is the record.qtype not RRSIG and is the record's qname the qname we want?" -> "Add this record to ret" [label=yes]; + "Add this record to ret" -> "Get record from lwr.d_records"; + "Is the record.qtype not RRSIG and is the record's qname the qname we want?" -> "Get record from lwr.d_records" [label=no]; + + "Is this a DNSSEC record in the ANSWER section?" -> "Is this the actual answer?" [label=no]; + "Is this the actual answer?" -> "Set done=true" [label=yes]; + "Set done=true" -> "Add answer record to ret" -> "Get record from lwr.d_records"; + + "Is this the actual answer?" -> "Is this an NS record in the AUTHORITY?" [label=no]; + "Is this an NS record in the AUTHORITY?" -> "Is record.d_name more specific than the our current auth?" [label=yes]; + "Is record.d_name more specific than the our current auth?" -> "set newauth to record.d_name" [label=yes]; + "set newauth to record.d_name" -> "set realreferral=true" -> "add NS record to ret"; + "Is record.d_name more specific than the our current auth?" -> "add NS record to ret" [label=no]; + "add NS record to ret" -> "Get record from lwr.d_records"; + + "Is this an NS record in the AUTHORITY?" -> "Is this a DS in the AUTHORITY?" [label=no]; + "Is this a DS in the AUTHORITY?" -> "set sawDS=true" [label=yes]; + "set sawDS=true" -> "Get record from lwr.d_records"; + + "Is this a DS in the AUTHORITY?" -> "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?" [label=no]; + "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?" -> "is newtarget empty?" [label=yes]; + "is newtarget empty?" -> "Harvest DNSSEC data and add to negative cache" [label=yes]; + "is newtarget empty?" -> "Get record from lwr.d_records"; + "Harvest DNSSEC data and add to negative cache" -> "Set negindic to true" -> "Get record from lwr.d_records"; + + "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?" -> "Get record from lwr.d_records" [label=no]; + + processRecords_return_done [label="return done", color=green]; + } + + subgraph cluster_doCNAMECacheCheck { + label="SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector& ret, unsigned int depth, int &res)\nreturns true if this function handled the query"; + + doCNAMECacheCheck_return_true [label="return true", color=green]; + doCNAMECacheCheck_return_false [label="return false", color=green]; + + doCNAMECacheCheck_servfail [label="Set res to SERVFAIL"]; + doCNAMECacheCheck_servfail -> doCNAMECacheCheck_return_true; + + doCNAMECacheCheck_doResolve [label="SyncRes::doResolve", color=red]; + + "Too deep recursion or CNAMEs?" -> doCNAMECacheCheck_servfail [label=yes]; + "Too deep recursion or CNAMEs?" -> "Get cache entries for qname|CNAME" [label=no]; + "Get cache entries for qname|CNAME" -> "get a record from the cache entries" -> "Is the TTL not expired?"; + "Is the TTL not expired?" -> "get a record from the cache entries" [label=yes]; + "Is the TTL not expired?" -> "Add record and RRSIGS to ret" [label=no]; + "Add record and RRSIGS to ret" -> "is qtype CNAME?"; + "is qtype CNAME?" -> doCNAMECacheCheck_doResolve [label=no]; + doCNAMECacheCheck_doResolve -> "Set res to the result of doResolve" -> doCNAMECacheCheck_return_true; + "is qtype CNAME?" -> "Set res=0" [label=yes]; + "Set res=0" -> doCNAMECacheCheck_return_true; + "Get cache entries for qname|CNAME" -> doCNAMECacheCheck_return_false [label="No cache entries"]; + } +} diff --git a/contrib/systemd-pdns-recursor.service b/contrib/systemd-pdns-recursor.service new file mode 100644 index 0000000..37341b6 --- /dev/null +++ b/contrib/systemd-pdns-recursor.service @@ -0,0 +1,22 @@ +[Unit] +Description=PowerDNS recursing nameserver +Documentation=man:pdns_recursor(1) man:rec_control(1) +Wants=network-online.target nss-lookup.target +Before=nss-lookup.target +After=network-online.target + +[Service] +Type=forking +ExecStart=/usr/sbin/pdns_recursor --daemon +Restart=on-failure +StartLimitInterval=0 +PrivateTmp=true +PrivateDevices=true +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID +NoNewPrivileges=true +ProtectSystem=full +ProtectHome=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 + +[Install] +WantedBy=multi-user.target diff --git a/contrib/upstart-recursor.conf b/contrib/upstart-recursor.conf new file mode 100644 index 0000000..d1b9c00 --- /dev/null +++ b/contrib/upstart-recursor.conf @@ -0,0 +1,9 @@ +# recursor - the PowerDNS Recursor +# for in /etc/init/recursor.conf +description "PowerDNS Recursor" + +start on runlevel [2345] +stop on runlevel [!2345] +respawn + +exec /usr/sbin/pdns_recursor --daemon=no diff --git a/decafsigners.cc b/decafsigners.cc new file mode 100644 index 0000000..f39dfa0 --- /dev/null +++ b/decafsigners.cc @@ -0,0 +1,293 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include + +#include "dnssecinfra.hh" + +using namespace decaf; + +class DecafED25519DNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit DecafED25519DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo) + { + + } + string getName() const override { return "Decaf ED25519"; } + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string getPubKeyHash() const override; + std::string sign(const std::string& msg) const override; + bool verify(const std::string& msg, const std::string& signature) const override; + std::string getPublicKeyString() const override; + int getBits() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override + {} + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + unsigned char d_pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES]; + unsigned char d_seckey[DECAF_EDDSA_25519_PRIVATE_BYTES]; +}; + +void DecafED25519DNSCryptoKeyEngine::create(unsigned int bits) +{ + if(bits != (unsigned int)getBits()) { + throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED25519 class"); + } + + SpongeRng rng("/dev/urandom"); + + typename EdDSA::PrivateKey priv(rng); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +int DecafED25519DNSCryptoKeyEngine::getBits() const +{ + return DECAF_EDDSA_25519_PRIVATE_BYTES << 3; +} + +DNSCryptoKeyEngine::storvector_t DecafED25519DNSCryptoKeyEngine::convertToISCVector() const +{ + /* + Private-key-format: v1.2 + Algorithm: 15 (ED25519) + PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI= + */ + + storvector_t storvector; + + storvector.push_back(make_pair("Algorithm", "15 (ED25519)")); + storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES))); + + return storvector; +} + +void DecafED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap ) +{ + /* + Private-key-format: v1.2 + Algorithm: 15 (ED25519) + PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI= + */ + + drc.d_algorithm = pdns_stou(stormap["algorithm"]); + string privateKey = stormap["privatekey"]; + + if (privateKey.length() != DECAF_EDDSA_25519_PRIVATE_BYTES) + throw runtime_error("Private key size mismatch in ISCMap, DecafED25519 class"); + + typename EdDSA::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_25519_PRIVATE_BYTES)); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +std::string DecafED25519DNSCryptoKeyEngine::getPubKeyHash() const +{ + return this->getPublicKeyString(); +} + +std::string DecafED25519DNSCryptoKeyEngine::getPublicKeyString() const +{ + return string((char*)d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES); +} + +void DecafED25519DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + if (input.length() != DECAF_EDDSA_25519_PUBLIC_BYTES) + throw runtime_error("Public key size mismatch, DecafED25519 class"); + + memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_25519_PUBLIC_BYTES); +} + +std::string DecafED25519DNSCryptoKeyEngine::sign(const std::string& msg) const +{ + typename EdDSA::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES)); + + SecureBuffer message(msg.begin(), msg.end()); + + SecureBuffer sig = priv.sign(message); + + return string(sig.begin(), sig.end()); +} + +bool DecafED25519DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const +{ + if (signature.length() != DECAF_EDDSA_25519_SIGNATURE_BYTES) + return false; + + typename EdDSA::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES)); + + SecureBuffer sig(signature.begin(), signature.end()); + SecureBuffer message(msg.begin(), msg.end()); + + try { + pub.verify(sig, message); + } catch(CryptoException) { + return false; + } + + return true; +} + + +class DecafED448DNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit DecafED448DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo) + { + + } + string getName() const override { return "Decaf ED448"; } + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string getPubKeyHash() const override; + std::string sign(const std::string& msg) const override; + bool verify(const std::string& msg, const std::string& signature) const override; + std::string getPublicKeyString() const override; + int getBits() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override + {} + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + unsigned char d_pubkey[DECAF_EDDSA_448_PUBLIC_BYTES]; + unsigned char d_seckey[DECAF_EDDSA_448_PRIVATE_BYTES]; +}; + +void DecafED448DNSCryptoKeyEngine::create(unsigned int bits) +{ + if(bits != (unsigned int)getBits()) { + throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED448 class"); + } + + SpongeRng rng("/dev/urandom"); + + typename EdDSA::PrivateKey priv(rng); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +int DecafED448DNSCryptoKeyEngine::getBits() const +{ + return DECAF_EDDSA_448_PRIVATE_BYTES << 3; +} + +DNSCryptoKeyEngine::storvector_t DecafED448DNSCryptoKeyEngine::convertToISCVector() const +{ + /* + Private-key-format: v1.2 + Algorithm: 16 (ED448) + PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA + */ + + storvector_t storvector; + + storvector.push_back(make_pair("Algorithm", "16 (ED448)")); + storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES))); + + return storvector; +} + +void DecafED448DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap ) +{ + /* + Private-key-format: v1.2 + Algorithm: 16 (ED448) + PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA + */ + + drc.d_algorithm = pdns_stou(stormap["algorithm"]); + string privateKey = stormap["privatekey"]; + + if (privateKey.length() != DECAF_EDDSA_448_PRIVATE_BYTES) + throw runtime_error("Private key size mismatch in ISCMap, DecafED448 class"); + + typename EdDSA::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_448_PRIVATE_BYTES)); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +std::string DecafED448DNSCryptoKeyEngine::getPubKeyHash() const +{ + return this->getPublicKeyString(); +} + +std::string DecafED448DNSCryptoKeyEngine::getPublicKeyString() const +{ + return string((char*)d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES); +} + +void DecafED448DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + if (input.length() != DECAF_EDDSA_448_PUBLIC_BYTES) + throw runtime_error("Public key size mismatch, DecafED448 class"); + + memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_448_PUBLIC_BYTES); +} + +std::string DecafED448DNSCryptoKeyEngine::sign(const std::string& msg) const +{ + typename EdDSA::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES)); + + SecureBuffer message(msg.begin(), msg.end()); + + SecureBuffer sig = priv.sign(message); + + return string(sig.begin(), sig.end()); +} + +bool DecafED448DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const +{ + if (signature.length() != DECAF_EDDSA_448_SIGNATURE_BYTES) + return false; + + typename EdDSA::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES)); + + SecureBuffer sig(signature.begin(), signature.end()); + SecureBuffer message(msg.begin(), msg.end()); + + try { + pub.verify(sig, message); + } catch(CryptoException) { + return false; + } + + return true; +} + + +namespace { +struct LoaderDecafStruct +{ + LoaderDecafStruct() + { + DNSCryptoKeyEngine::report(15, &DecafED25519DNSCryptoKeyEngine::maker, true); + DNSCryptoKeyEngine::report(16, &DecafED448DNSCryptoKeyEngine::maker); + } +} loaderdecaf; +} diff --git a/devpollmplexer.cc b/devpollmplexer.cc new file mode 100644 index 0000000..5e11404 --- /dev/null +++ b/devpollmplexer.cc @@ -0,0 +1,187 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +/* + * NOTE: sys/devpoll.h relies on sigset_t being already defined so we need + * to include sys/signal.h *before* including sys/devpoll.h. + */ +#include +#include +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include +#include "misc.hh" +#include "syncres.hh" + +#include "namespaces.hh" + +class DevPollFDMultiplexer : public FDMultiplexer +{ +public: + DevPollFDMultiplexer(); + virtual ~DevPollFDMultiplexer() + { + close(d_devpollfd); + } + + virtual int run(struct timeval* tv, int timeout=500); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "/dev/poll"; + } +private: + int d_devpollfd; +}; + + +static FDMultiplexer* makeDevPoll() +{ + return new DevPollFDMultiplexer(); +} + +static struct DevPollRegisterOurselves +{ + DevPollRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makeDevPoll)); // priority 0! + } +} doItDevPoll; + + +//int DevPollFDMultiplexer::s_maxevents=1024; +DevPollFDMultiplexer::DevPollFDMultiplexer() +{ + d_devpollfd=open("/dev/poll", O_RDWR); + if(d_devpollfd < 0) + throw FDMultiplexerException("Setting up /dev/poll: "+stringerror()); + +} + +void DevPollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + struct pollfd devent; + devent.fd=fd; + devent.events= (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT; + devent.revents = 0; + + if(write(d_devpollfd, &devent, sizeof(devent)) != sizeof(devent)) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to /dev/poll/ set: "+stringerror()); + } +} + +void DevPollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); + + struct pollfd devent; + devent.fd=fd; + devent.events= POLLREMOVE; + devent.revents = 0; + + if(write(d_devpollfd, &devent, sizeof(devent)) != sizeof(devent)) { + cbmap.erase(fd); + throw FDMultiplexerException("Removing fd from epoll set: "+stringerror()); + } +} + +int DevPollFDMultiplexer::run(struct timeval* now, int timeout) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + struct dvpoll dvp; + dvp.dp_nfds = d_readCallbacks.size() + d_writeCallbacks.size(); + dvp.dp_fds = new pollfd[dvp.dp_nfds]; + dvp.dp_timeout = timeout; + int ret=ioctl(d_devpollfd, DP_POLL, &dvp); + gettimeofday(now,0); // MANDATORY! + + if(ret < 0 && errno!=EINTR) { + delete[] dvp.dp_fds; + throw FDMultiplexerException("/dev/poll returned error: "+stringerror()); + } + + if(ret < 1) { // thanks AB! + delete[] dvp.dp_fds; + return 0; + } + + d_inrun=true; + for(int n=0; n < ret; ++n) { + d_iter=d_readCallbacks.find(dvp.dp_fds[n].fd); + + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + continue; // so we don't refind ourselves as writable! + } + d_iter=d_writeCallbacks.find(dvp.dp_fds[n].fd); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + } + } + delete[] dvp.dp_fds; + d_inrun=false; + return ret; +} + +#if 0 +void acceptData(int fd, funcparam_t& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< +#include +#include +#include +#include "dnsparser.hh" + +std::vector RCode::rcodes_s = boost::assign::list_of + ("No Error") + ("Form Error") + ("Server Failure") + ("Non-Existent domain") + ("Not Implemented") + ("Query Refused") + ("Name Exists when it should not") + ("RR Set Exists when it should not") + ("RR Set that should exist does not") + ("Server Not Authoritative for zone / Not Authorized") + ("Name not contained in zone") + ("Err#11") + ("Err#12") + ("Err#13") + ("Err#14") + ("Err#15") + ("Bad OPT Version / TSIG Signature Failure") + ("Key not recognized") + ("Signature out of time window") + ("Bad TKEY Mode") + ("Duplicate key name") + ("Algorithm not supported") + ("Bad Truncation") +; + +std::string RCode::to_s(unsigned short rcode) { + if (rcode > RCode::rcodes_s.size()-1 ) + return std::string("Err#")+std::to_string(rcode); + return RCode::rcodes_s[rcode]; +} + +class BoundsCheckingPointer +{ +public: + explicit BoundsCheckingPointer(const char* a, size_t length) + : d_ptr(a), d_length(length) + {} + + explicit BoundsCheckingPointer(const std::string& str) + : d_ptr(str.c_str()), d_length(str.size()) + {} + + + char operator[](size_t offset) const + { + if(offset < d_length) + return d_ptr[offset]; + throw runtime_error("out of bounds: "+std::to_string(offset)+" >= " + std::to_string(d_length)); + } +private: + const char* d_ptr; + const size_t d_length; +}; + + +// goal is to hash based purely on the question name, and turn error into 'default' +uint32_t hashQuestion(const char* packet, uint16_t len, uint32_t init) +{ + if(len < 12) + return init; + + uint32_t ret=init; + const unsigned char* end = (const unsigned char*)packet+len; + const unsigned char* pos = (const unsigned char*)packet+12; + + unsigned char labellen; + while((labellen=*pos++) && pos < end) { + if(pos + labellen + 1 > end) // include length field in hash + return 0; + ret=burtleCI(pos, labellen+1, ret); + pos += labellen; + } + return ret; +} + + +string& attodot(string &str) +{ + if(str.find_first_of("@")==string::npos) + return str; + + for (unsigned int i = 0; i < str.length(); i++) + { + if (str[i] == '@') { + str[i] = '.'; + break; + } else if (str[i] == '.') { + str.insert(i++, "\\"); + } + } + return str; +} diff --git a/dns.hh b/dns.hh new file mode 100644 index 0000000..88a658c --- /dev/null +++ b/dns.hh @@ -0,0 +1,241 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include +#include +#include +#include +#include +#include "qtype.hh" +#include "dnsname.hh" +#include +#include +class DNSBackend; +struct DNSRecord; + +struct SOAData +{ + SOAData() : ttl(0), serial(0), refresh(0), retry(0), expire(0), default_ttl(0), db(0), domain_id(-1), scopeMask(0) {}; + + DNSName qname; + DNSName nameserver; + DNSName hostmaster; + uint32_t ttl; + uint32_t serial; + uint32_t refresh; + uint32_t retry; + uint32_t expire; + uint32_t default_ttl; + DNSBackend *db; + int domain_id; + uint8_t scopeMask; +}; + +class RCode +{ +public: + enum rcodes_ { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, YXDomain=6, YXRRSet=7, NXRRSet=8, NotAuth=9, NotZone=10}; + static std::string to_s(unsigned short rcode); + static std::vector rcodes_s; +}; + +class Opcode +{ +public: + enum { Query=0, IQuery=1, Status=2, Notify=4, Update=5 }; +}; + +// enum for policy decisions, used by both auth and recursor. Not all values supported everywhere. +namespace PolicyDecision { enum returnTypes { PASS=-1, DROP=-2, TRUNCATE=-3 }; }; + +//! This class represents a resource record +class DNSResourceRecord +{ +public: + DNSResourceRecord() : last_modified(0), ttl(0), signttl(0), domain_id(-1), qclass(1), scopeMask(0), auth(1), disabled(0) {}; + ~DNSResourceRecord(){}; + static DNSResourceRecord fromWire(const DNSRecord& d); + + enum Place : uint8_t {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning within, say, a DNSPacket + + void setContent(const string& content); + string getZoneRepresentation(bool noDot=false) const; + + // data + DNSName qname; //!< the name of this record, for example: www.powerdns.com + DNSName wildcardname; + string content; //!< what this record points to. Example: 10.1.2.3 + + // Aligned on 8-byte boundries on systems where time_t is 8 bytes and int + // is 4 bytes, aka modern linux on x86_64 + time_t last_modified; //!< For autocalculating SOA serial numbers - the backend needs to fill this in + + uint32_t ttl; //!< Time To Live of this record + uint32_t signttl; //!< If non-zero, use this TTL as original TTL in the RRSIG + + int domain_id; //!< If a backend implements this, the domain_id of the zone this record is in + QType qtype; //!< qtype of this record, ie A, CNAME, MX etc + uint16_t qclass; //!< class of this record + + uint8_t scopeMask; + bool auth; + bool disabled; + + bool operator==(const DNSResourceRecord& rhs); + + bool operator<(const DNSResourceRecord &b) const + { + if(qname < b.qname) + return true; + if(qname == b.qname) + return(content < b.content); + return false; + } +}; + +#define GCCPACKATTRIBUTE __attribute__((packed)) + +struct dnsrecordheader +{ + uint16_t d_type; + uint16_t d_class; + uint32_t d_ttl; + uint16_t d_clen; +} GCCPACKATTRIBUTE; + +struct EDNS0Record +{ + uint8_t extRCode, version; + uint16_t Z; +} GCCPACKATTRIBUTE; + +static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4"); + +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#include +#elif __linux__ || __GNU__ +# include + +#else // with thanks to + +# define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +# define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +# define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ + +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(__i386) || defined(__ia64) || defined(__amd64) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) || \ + (defined(__Lynx__) && defined(__x86__)) +# define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(__sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined(__hp3000s900) || defined(MPE) || \ + defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \ + (defined(__Lynx__) && \ + (defined(__68k__) || defined(__sparc__) || defined(__powerpc__))) +# define BYTE_ORDER BIG_ENDIAN +#endif + +#endif + +struct dnsheader { + unsigned id :16; /* query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritative answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritative answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +}; + +static_assert(sizeof(dnsheader) == 12, "dnsheader size must be 12"); + +inline uint16_t * getFlagsFromDNSHeader(struct dnsheader * dh) +{ + return (uint16_t*) (((char *) dh) + sizeof(uint16_t)); +} + +#define DNS_TYPE_SIZE (2) +#define DNS_CLASS_SIZE (2) +#define DNS_TTL_SIZE (4) +#define DNS_RDLENGTH_SIZE (2) +#define EDNS_EXTENDED_RCODE_SIZE (1) +#define EDNS_VERSION_SIZE (1) +#define EDNS_OPTION_CODE_SIZE (2) +#define EDNS_OPTION_LENGTH_SIZE (2) + +#if BYTE_ORDER == BIG_ENDIAN +#define FLAGS_RD_OFFSET (8) +#define FLAGS_CD_OFFSET (12) +#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN +#define FLAGS_RD_OFFSET (0) +#define FLAGS_CD_OFFSET (12) +#endif + +#define L theL() +extern time_t s_starttime; + +uint32_t hashQuestion(const char* packet, uint16_t len, uint32_t init); + +struct TSIGTriplet +{ + DNSName name, algo; + string secret; +}; + +/** for use by DNSPacket, converts a SOAData class to a ascii line again */ +string serializeSOAData(const SOAData &data); +string &attodot(string &str); //!< for when you need to insert an email address in the SOA diff --git a/dns_random.cc b/dns_random.cc new file mode 100644 index 0000000..873de38 --- /dev/null +++ b/dns_random.cc @@ -0,0 +1,94 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#if OPENSSL_VERSION_NUMBER > 0x1010000fL && !defined LIBRESSL_VERSION_NUMBER +// Older OpenSSL does not have CRYPTO_ctr128_encrypt. Before 1.1.0 the header +// file did not have the necessary extern "C" wrapper. In 1.1.0, AES_ctr128_encrypt +// was removed. +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dns_random.hh" + +using namespace std; + +static AES_KEY aes_key; +static unsigned int g_offset; +static unsigned char g_counter[16], g_stream[16]; +static uint32_t g_in; + +static bool g_initialized; + +void dns_random_init(const char data[16]) +{ + g_offset = 0; + memset(&g_stream, 0, sizeof(g_stream)); + if (AES_set_encrypt_key((const unsigned char*)data, 128, &aes_key) < 0) { + throw std::runtime_error("AES_set_encrypt_key failed"); + } + + struct timeval now; + gettimeofday(&now, 0); + + static_assert(sizeof(g_counter) >= (sizeof(now.tv_usec) + sizeof(now.tv_sec)), "g_counter must be large enough to get tv_sec + tv_usec"); + memcpy(g_counter, &now.tv_usec, sizeof(now.tv_usec)); + memcpy(g_counter+sizeof(now.tv_usec), &now.tv_sec, sizeof(now.tv_sec)); + g_in = getpid() | (getppid()<<16); + + g_initialized = true; + srandom(dns_random(numeric_limits::max())); +} + +unsigned int dns_random(unsigned int n) +{ + if(!g_initialized) + abort(); + uint32_t out; +#if OPENSSL_VERSION_NUMBER > 0x1010000fL && !defined LIBRESSL_VERSION_NUMBER + CRYPTO_ctr128_encrypt((const unsigned char*)&g_in, (unsigned char*) &out, sizeof(g_in), &aes_key, g_counter, g_stream, &g_offset, (block128_f) AES_encrypt); +#else + AES_ctr128_encrypt((const unsigned char*)&g_in, (unsigned char*) &out, sizeof(g_in), &aes_key, g_counter, g_stream, &g_offset); +#endif + return out % n; +} + +#if 0 +int main() +{ + dns_random_init("0123456789abcdef"); + + for(int n = 0; n < 16; n++) + cerr< +#include +#include +#include +#include "pdnsexception.hh" +#include +#include +#include +#include +#include "misc.hh" +#include "qtype.hh" +#include "dns.hh" +#include +#include "namespaces.hh" +#include "comment.hh" +#include "dnsname.hh" +#include "dnsrecords.hh" + +class DNSBackend; +struct DomainInfo +{ + DomainInfo() : last_check(0), backend(NULL), id(0), notified_serial(0), serial(0), kind(DomainInfo::Native) {} + + DNSName zone; + time_t last_check; + string account; + vector masters; + DNSBackend *backend; + + uint32_t id; + uint32_t notified_serial; + + uint32_t serial; + enum DomainKind : uint8_t { Master, Slave, Native } kind; + + bool operator<(const DomainInfo& rhs) const + { + return zone < rhs.zone; + } + + const char *getKindString() const + { + return DomainInfo::getKindString(kind); + } + + static const char *getKindString(enum DomainKind kind) + { + const char *kinds[]={"Master", "Slave", "Native"}; + return kinds[kind]; + } + + static DomainKind stringToKind(const string& kind) + { + if(pdns_iequals(kind,"SLAVE")) + return DomainInfo::Slave; + else if(pdns_iequals(kind,"MASTER")) + return DomainInfo::Master; + else + return DomainInfo::Native; + } + +}; + +struct TSIGKey { + DNSName name; + DNSName algorithm; + std::string key; +}; + +class DNSPacket; + +//! This virtual base class defines the interface for backends for the ahudns. +/** To create a backend, inherit from this class and implement functions for all virtual methods. + Methods should not throw an exception if they are sure they did not find the requested data. However, + if an error occurred which prevented them temporarily from performing a lockup, they should throw a DBException, + which will cause the nameserver to send out a ServFail or take other evasive action. Probably only locking + issues should lead to DBExceptions. + + More serious errors, which may indicate that the database connection is hosed, or a configuration error occurred, should + lead to the throwing of an PDNSException. This exception will fall straight through the UeberBackend and the PacketHandler + and be caught by the Distributor, which will delete your DNSBackend instance and spawn a new one. +*/ +class DNSBackend +{ +public: + //! lookup() initiates a lookup. A lookup without results should not throw! + virtual void lookup(const QType &qtype, const DNSName &qdomain, DNSPacket *pkt_p=0, int zoneId=-1)=0; + virtual bool get(DNSResourceRecord &)=0; //!< retrieves one DNSResource record, returns false if no more were available + virtual bool get(DNSZoneRecord &r); + + //! Initiates a list of the specified domain + /** Once initiated, DNSResourceRecord objects can be retrieved using get(). Should return false + if the backend does not consider itself responsible for the id passed. + \param domain_id ID of which a list is requested + */ + virtual bool list(const DNSName &target, int domain_id, bool include_disabled=false)=0; + + virtual ~DNSBackend(){}; + + //! fills the soadata struct with the SOA details. Returns false if there is no SOA. + virtual bool getSOA(const DNSName &name, SOAData &soadata); + + //! Calculates a SOA serial for the zone and stores it in the third argument. + virtual bool calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial); + + virtual bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector& rrset) + { + return false; + } + + virtual bool listSubZone(const DNSName &zone, int domain_id) + { + return false; + } + + // the DNSSEC related (getDomainMetadata has broader uses too) + bool isDnssecDomainMetadata (const string& name) { + return (name == "PRESIGNED" || name == "NSEC3PARAM" || name == "NSEC3NARROW"); + } + virtual bool getAllDomainMetadata(const DNSName& name, std::map >& meta) { return false; }; + virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector& meta) { return false; } + virtual bool getDomainMetadataOne(const DNSName& name, const std::string& kind, std::string& value) + { + std::vector meta; + if (getDomainMetadata(name, kind, meta)) { + if(!meta.empty()) { + value = *meta.begin(); + return true; + } + } + return false; + } + + virtual bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector& meta) {return false;} + virtual bool setDomainMetadataOne(const DNSName& name, const std::string& kind, const std::string& value) + { + const std::vector meta(1, value); + return setDomainMetadata(name, kind, meta); + } + + + virtual void getAllDomains(vector *domains, bool include_disabled=false) { } + + /** Determines if we are authoritative for a zone, and at what level */ + virtual bool getAuth(const DNSName &target, SOAData *sd); + + struct KeyData { + std::string content; + unsigned int id; + unsigned int flags; + bool active; + }; + + virtual bool getDomainKeys(const DNSName& name, std::vector& keys) { return false;} + virtual bool removeDomainKey(const DNSName& name, unsigned int id) { return false; } + virtual bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id){ return false; } + virtual bool activateDomainKey(const DNSName& name, unsigned int id) { return false; } + virtual bool deactivateDomainKey(const DNSName& name, unsigned int id) { return false; } + + virtual bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) { return false; } + virtual bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) { return false; } + virtual bool deleteTSIGKey(const DNSName& name) { return false; } + virtual bool getTSIGKeys(std::vector< struct TSIGKey > &keys) { return false; } + + virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) + { + std::cerr<<"Default beforeAndAfterAbsolute called!"<& insert, set& erase, bool remove) + { + return false; + } + + virtual bool doesDNSSEC() + { + return false; + } + + // end DNSSEC + + // comments support + virtual bool listComments(uint32_t domain_id) + { + return false; // unsupported by this backend + } + + virtual bool getComment(Comment& comment) + { + return false; + } + + virtual void feedComment(const Comment& comment) + { + } + + virtual bool replaceComments(const uint32_t domain_id, const DNSName& qname, const QType& qt, const vector& comments) + { + return false; + } + + //! returns true if master ip is master for domain name. + virtual bool isMaster(const DNSName &name, const string &ip) + { + return false; + } + + //! starts the transaction for updating domain qname (FIXME: what is id?) + virtual bool startTransaction(const DNSName &qname, int id=-1) + { + return false; + } + + //! commits the transaction started by startTransaction + virtual bool commitTransaction() + { + return false; + } + + //! aborts the transaction started by strartTransaction, should leave state unaltered + virtual bool abortTransaction() + { + return false; + } + + virtual void reload() + { + } + + virtual void rediscover(string* status=0) + { + } + + //! feeds a record to a zone, needs a call to startTransaction first + virtual bool feedRecord(const DNSResourceRecord &rr, const DNSName &ordername) + { + return false; // no problem! + } + virtual bool feedEnts(int domain_id, map &nonterm) + { + return false; + } + virtual bool feedEnts3(int domain_id, const DNSName &domain, map &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) + { + return false; + } + + //! if this returns true, DomainInfo di contains information about the domain + virtual bool getDomainInfo(const DNSName &domain, DomainInfo &di) + { + return false; + } + //! slave capable backends should return a list of slaves that should be rechecked for staleness + virtual void getUnfreshSlaveInfos(vector* domains) + { + } + + //! get a list of IP addresses that should also be notified for a domain + virtual void alsoNotifies(const DNSName &domain, set *ips) + { + } + + //! get list of domains that have been changed since their last notification to slaves + virtual void getUpdatedMasters(vector* domains) + { + } + + //! Called by PowerDNS to inform a backend that a domain has been checked for freshness + virtual void setFresh(uint32_t domain_id) + { + + } + //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to slaves + virtual void setNotified(uint32_t id, uint32_t serial) + { + } + + //! Called when the Master of a domain should be changed + virtual bool setMaster(const DNSName &domain, const string &ip) + { + return false; + } + + //! Called when the Kind of a domain should be changed (master -> native and similar) + virtual bool setKind(const DNSName &domain, const DomainInfo::DomainKind kind) + { + return false; + } + + //! Called when the Account of a domain should be changed + virtual bool setAccount(const DNSName &domain, const string &account) + { + return false; + } + + //! Can be called to seed the getArg() function with a prefix + void setArgPrefix(const string &prefix); + + //! determine if ip is a supermaster or a domain + virtual bool superMasterBackend(const string &ip, const DNSName &domain, const vector&nsset, string *nameserver, string *account, DNSBackend **db) + { + return false; + } + + //! called by PowerDNS to create a new domain + virtual bool createDomain(const DNSName &domain) + { + return false; + } + + //! called by PowerDNS to create a slave record for a superMaster + virtual bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account) + { + return false; + } + + //! called to delete a domain, incl. all metadata, zone contents, etc. + virtual bool deleteDomain(const DNSName &domain) + { + return false; + } + + virtual string directBackendCmd(const string &query) + { + return "directBackendCmd not supported for this backend\n"; + } + + //! Search for records, returns true if search was done successfully. + virtual bool searchRecords(const string &pattern, int maxResults, vector& result) + { + return false; + } + + //! Search for comments, returns true if search was done successfully. + virtual bool searchComments(const string &pattern, int maxResults, vector& result) + { + return false; + } + + const string& getPrefix() { return d_prefix; }; +protected: + bool mustDo(const string &key); + const string &getArg(const string &key); + int getArgAsNum(const string &key); + +private: + string d_prefix; +}; + +class BackendFactory +{ +public: + BackendFactory(const string &name) : d_name(name) {} + virtual ~BackendFactory(){} + virtual DNSBackend *make(const string &suffix)=0; + virtual DNSBackend *makeMetadataOnly(const string &suffix) + { + return this->make(suffix); + } + virtual void declareArguments(const string &suffix=""){} + const string &getName() const; + +protected: + void declare(const string &suffix, const string ¶m, const string &explanation, const string &value); + +private: + const string d_name; +}; + +class BackendMakerClass +{ +public: + void report(BackendFactory *bf); + void launch(const string &instr); + vectorall(bool skipBIND=false); + void load(const string &module); + int numLauncheable(); + vector getModules(); + +private: + void load_all(); + typedef mapd_repository_t; + d_repository_t d_repository; + vector >d_instances; +}; + +extern BackendMakerClass &BackendMakers(); + +//! Exception that can be thrown by a DNSBackend to indicate a failure +class DBException : public PDNSException +{ +public: + DBException(const string &reason_) : PDNSException(reason_){} +}; + +/** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */ +void fillSOAData(const string &content, SOAData &data); +// same but more karmic +void fillSOAData(const DNSZoneRecord& in, SOAData& data); +// the reverse +std::shared_ptr makeSOAContent(const SOAData& sd); + +#endif diff --git a/dnslabeltext.cc b/dnslabeltext.cc new file mode 100644 index 0000000..a1efbd8 --- /dev/null +++ b/dnslabeltext.cc @@ -0,0 +1,527 @@ + +#line 1 "dnslabeltext.rl" +#include +#include +#include +#include +#include +#include "dnsname.hh" +#include "namespaces.hh" + +namespace { +void appendSplit(vector& ret, string& segment, char c) +{ + if(segment.size()>254) { + ret.push_back(segment); + segment.clear(); + } + segment.append(1, c); +} + +} + +vector segmentDNSText(const string& input ) +{ + // cerr<<"segmentDNSText("< ret; + + +#line 98 "dnslabeltext.cc" + { + cs = dnstext_start; + } + +#line 103 "dnslabeltext.cc" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const unsigned char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _dnstext_trans_keys + _dnstext_key_offsets[cs]; + _trans = _dnstext_index_offsets[cs]; + + _klen = _dnstext_single_lengths[cs]; + if ( _klen > 0 ) { + const unsigned char *_lower = _keys; + const unsigned char *_mid; + const unsigned char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (unsigned int)(_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _dnstext_range_lengths[cs]; + if ( _klen > 0 ) { + const unsigned char *_lower = _keys; + const unsigned char *_mid; + const unsigned char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += (unsigned int)((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + cs = _dnstext_trans_targs[_trans]; + + if ( _dnstext_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _dnstext_actions + _dnstext_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 40 "dnslabeltext.rl" + { + ret.push_back(segment); + segment.clear(); + } + break; + case 1: +#line 44 "dnslabeltext.rl" + { + segment.clear(); + } + break; + case 2: +#line 48 "dnslabeltext.rl" + { + char c = *p; + appendSplit(ret, segment, c); + } + break; + case 3: +#line 52 "dnslabeltext.rl" + { + char c = *p; + val *= 10; + val += c-'0'; + + } + break; + case 4: +#line 58 "dnslabeltext.rl" + { + appendSplit(ret, segment, val); + val=0; + } + break; + case 5: +#line 63 "dnslabeltext.rl" + { + appendSplit(ret, segment, *(p)); + } + break; +#line 218 "dnslabeltext.cc" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + const char *__acts = _dnstext_actions + _dnstext_eof_actions[cs]; + unsigned int __nacts = (unsigned int) *__acts++; + while ( __nacts-- > 0 ) { + switch ( *__acts++ ) { + case 0: +#line 40 "dnslabeltext.rl" + { + ret.push_back(segment); + segment.clear(); + } + break; +#line 241 "dnslabeltext.cc" + } + } + } + + _out: {} + } + +#line 76 "dnslabeltext.rl" + + + if ( cs < dnstext_first_final ) { + throw runtime_error("Unable to parse DNS TXT '"+input+"'"); + } + + return ret; +}; + + +DNSName::string_t segmentDNSNameRaw(const char* realinput) +{ + +#line 263 "dnslabeltext.cc" +static const char _dnsnameraw_actions[] = { + 0, 1, 0, 1, 1, 1, 2, 1, + 3, 1, 4, 1, 5, 2, 1, 5, + 2, 4, 0, 2, 4, 5 +}; + +static const char _dnsnameraw_key_offsets[] = { + 0, 0, 2, 4, 6, 8, 10, 12 +}; + +static const unsigned char _dnsnameraw_trans_keys[] = { + 46u, 92u, 48u, 57u, 48u, 57u, 48u, 57u, + 46u, 92u, 46u, 92u, 46u, 92u, 0 +}; + +static const char _dnsnameraw_single_lengths[] = { + 0, 2, 0, 0, 0, 2, 2, 2 +}; + +static const char _dnsnameraw_range_lengths[] = { + 0, 0, 1, 1, 1, 0, 0, 0 +}; + +static const char _dnsnameraw_index_offsets[] = { + 0, 0, 3, 5, 7, 9, 12, 15 +}; + +static const char _dnsnameraw_trans_targs[] = { + 0, 2, 5, 3, 5, 4, 0, 7, + 0, 6, 2, 5, 0, 2, 5, 6, + 2, 5, 0 +}; + +static const char _dnsnameraw_trans_actions[] = { + 0, 3, 13, 7, 5, 7, 0, 7, + 0, 1, 0, 11, 0, 3, 13, 16, + 9, 19, 0 +}; + +static const char _dnsnameraw_eof_actions[] = { + 0, 0, 0, 0, 0, 1, 0, 16 +}; + +static const int dnsnameraw_start = 1; +static const int dnsnameraw_first_final = 5; +static const int dnsnameraw_error = 0; + +static const int dnsnameraw_en_main = 1; + + +#line 92 "dnslabeltext.rl" + + (void)dnsnameraw_error; // silence warnings + (void)dnsnameraw_en_main; + + DNSName::string_t ret; + + if(!*realinput || *realinput == '.') { + ret.append(1, (char)0); + return ret; + } + + unsigned int inputlen=strlen(realinput); + ret.reserve(inputlen+1); + + const char *p = realinput, *pe = realinput + inputlen; + const char* eof = pe; + int cs; + char val = 0; + char labellen=0; + unsigned int lenpos=0; + +#line 336 "dnslabeltext.cc" + { + cs = dnsnameraw_start; + } + +#line 341 "dnslabeltext.cc" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const unsigned char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _dnsnameraw_trans_keys + _dnsnameraw_key_offsets[cs]; + _trans = _dnsnameraw_index_offsets[cs]; + + _klen = _dnsnameraw_single_lengths[cs]; + if ( _klen > 0 ) { + const unsigned char *_lower = _keys; + const unsigned char *_mid; + const unsigned char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (unsigned int)(_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _dnsnameraw_range_lengths[cs]; + if ( _klen > 0 ) { + const unsigned char *_lower = _keys; + const unsigned char *_mid; + const unsigned char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += (unsigned int)((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + cs = _dnsnameraw_trans_targs[_trans]; + + if ( _dnsnameraw_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _dnsnameraw_actions + _dnsnameraw_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 113 "dnslabeltext.rl" + { + if (labellen < 0 || labellen > 63) { + throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen)); + } + ret[lenpos]=labellen; + labellen=0; + } + break; + case 1: +#line 120 "dnslabeltext.rl" + { + lenpos=ret.size(); + ret.append(1, (char)0); + labellen=0; + } + break; + case 2: +#line 126 "dnslabeltext.rl" + { + char c = *p; + ret.append(1, c); + labellen++; + } + break; + case 3: +#line 131 "dnslabeltext.rl" + { + char c = *p; + val *= 10; + val += c-'0'; + } + break; + case 4: +#line 136 "dnslabeltext.rl" + { + ret.append(1, val); + labellen++; + val=0; + } + break; + case 5: +#line 142 "dnslabeltext.rl" + { + ret.append(1, *(p)); + labellen++; + } + break; +#line 463 "dnslabeltext.cc" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + const char *__acts = _dnsnameraw_actions + _dnsnameraw_eof_actions[cs]; + unsigned int __nacts = (unsigned int) *__acts++; + while ( __nacts-- > 0 ) { + switch ( *__acts++ ) { + case 0: +#line 113 "dnslabeltext.rl" + { + if (labellen < 0 || labellen > 63) { + throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen)); + } + ret[lenpos]=labellen; + labellen=0; + } + break; + case 4: +#line 136 "dnslabeltext.rl" + { + ret.append(1, val); + labellen++; + val=0; + } + break; +#line 497 "dnslabeltext.cc" + } + } + } + + _out: {} + } + +#line 163 "dnslabeltext.rl" + + + if ( cs < dnsnameraw_first_final ) { + throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs)); + } + ret.append(1, (char)0); + return ret; +}; + + + +#if 0 +int main() +{ + //char blah[]="\"blah\" \"bleh\" \"bloeh\\\"bleh\" \"\\97enzo\""; + char blah[]="\"v=spf1 ip4:67.106.74.128/25 ip4:63.138.42.224/28 ip4:65.204.46.224/27 \\013\\010ip4:66.104.217.176/28 \\013\\010ip4:209.48.147.0/27 ~all\""; + //char blah[]="\"abc \\097\\098 def\""; + printf("Input: '%s'\n", blah); + vector res=dnstext(blah); + cerr< +#include +#include +#include +#include +#include "dnsname.hh" +#include "namespaces.hh" + +namespace { +void appendSplit(vector& ret, string& segment, char c) +{ + if(segment.size()>254) { + ret.push_back(segment); + segment.clear(); + } + segment.append(1, c); +} + +} + +vector segmentDNSText(const string& input ) +{ + // cerr<<"segmentDNSText("< ret; + + %%{ + action segmentEnd { + ret.push_back(segment); + segment.clear(); + } + action segmentBegin { + segment.clear(); + } + + action reportEscaped { + char c = *fpc; + appendSplit(ret, segment, c); + } + action reportEscapedNumber { + char c = *fpc; + val *= 10; + val += c-'0'; + + } + action doneEscapedNumber { + appendSplit(ret, segment, val); + val=0; + } + + action reportPlain { + appendSplit(ret, segment, *(fpc)); + } + + escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber)); + plain = ((extend-'\\'-'"')|'\n'|'\t') $ reportPlain; + txtElement = escaped | plain; + + main := (('"' txtElement* '"' space?) >segmentBegin %segmentEnd)+; + + # Initialize and execute. + write init; + write exec; + }%% + + if ( cs < dnstext_first_final ) { + throw runtime_error("Unable to parse DNS TXT '"+input+"'"); + } + + return ret; +}; + + +DNSName::string_t segmentDNSNameRaw(const char* realinput) +{ +%%{ + machine dnsnameraw; + write data; + alphtype unsigned char; +}%% + (void)dnsnameraw_error; // silence warnings + (void)dnsnameraw_en_main; + + DNSName::string_t ret; + + if(!*realinput || *realinput == '.') { + ret.append(1, (char)0); + return ret; + } + + unsigned int inputlen=strlen(realinput); + ret.reserve(inputlen+1); + + const char *p = realinput, *pe = realinput + inputlen; + const char* eof = pe; + int cs; + char val = 0; + char labellen=0; + unsigned int lenpos=0; + %%{ + action labelEnd { + if (labellen < 0 || labellen > 63) { + throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen)); + } + ret[lenpos]=labellen; + labellen=0; + } + action labelBegin { + lenpos=ret.size(); + ret.append(1, (char)0); + labellen=0; + } + + action reportEscaped { + char c = *fpc; + ret.append(1, c); + labellen++; + } + action reportEscapedNumber { + char c = *fpc; + val *= 10; + val += c-'0'; + } + action doneEscapedNumber { + ret.append(1, val); + labellen++; + val=0; + } + + action reportPlain { + ret.append(1, *(fpc)); + labellen++; + } + + escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber)); + plain = (extend-'\\'-'.') $ reportPlain; + labelElement = escaped | plain; + + label = labelElement+ >labelBegin %labelEnd; + + main:= label ('.' label )* '.'?; + + #main := labelElement((labelElement+ '.') >labelBegin %labelEnd)+; + + # label = (plain | escaped | escdecb)+ >label_init %label_fin; + # dnsname := '.'? label ('.' label >label_sep)* '.'?; + + # Initialize and execute. + write init; + write exec; + }%% + + if ( cs < dnsnameraw_first_final ) { + throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs)); + } + ret.append(1, (char)0); + return ret; +}; + + + +#if 0 +int main() +{ + //char blah[]="\"blah\" \"bleh\" \"bloeh\\\"bleh\" \"\\97enzo\""; + char blah[]="\"v=spf1 ip4:67.106.74.128/25 ip4:63.138.42.224/28 ip4:65.204.46.224/27 \\013\\010ip4:66.104.217.176/28 \\013\\010ip4:209.48.147.0/27 ~all\""; + //char blah[]="\"abc \\097\\098 def\""; + printf("Input: '%s'\n", blah); + vector res=dnstext(blah); + cerr< +#include + +#include "dnswriter.hh" +#include "misc.hh" + +#include + +const DNSName g_rootdnsname("."), g_wildcarddnsname("*"); + +/* raw storage + in DNS label format, with trailing 0. W/o trailing 0, we are 'empty' + www.powerdns.com = 3www8powerdns3com0 +*/ + +std::ostream & operator<<(std::ostream &os, const DNSName& d) +{ + return os < 63) + throw std::range_error("label too long to append"); + + if(iter-pbegin > 254) // reserve two bytes, one for length and one for the root label + throw std::range_error("name too long to append"); + + d_storage[lenpos]=labellen; + } + d_storage.append(1, (char)0); + } + else { + d_storage=segmentDNSNameRaw(p); + if(d_storage.size() > 255) { + throw std::range_error("name too long"); + } + } + } +} + + +DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, uint16_t minOffset) +{ + if (offset >= len) + throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")"); + + if(!uncompress) { + if(const void * fnd=memchr(pos+offset, 0, len-offset)) { + d_storage.reserve(2+(const char*)fnd-(pos+offset)); + } + } + + packetParser(pos, len, offset, uncompress, qtype, qclass, consumed, 0, minOffset); +} + +// this should be the __only__ dns name parser in PowerDNS. +void DNSName::packetParser(const char* qpos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset) +{ + const unsigned char* pos=(const unsigned char*)qpos; + unsigned char labellen; + const unsigned char *opos = pos; + + if (offset >= len) + throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")"); + if (offset < (int) minOffset) + throw std::range_error("Trying to read before the beginning of the buffer ("+std::to_string(offset)+ " < "+std::to_string(minOffset)+")"); + + const unsigned char* end = pos + len; + pos += offset; + while((labellen=*pos++) && pos < end) { // "scan and copy" + if(labellen >= 0xc0) { + if(!uncompress) + throw std::range_error("Found compressed label, instructed not to follow"); + + labellen &= (~0xc0); + int newpos = (labellen << 8) + *(const unsigned char*)pos; + + if(newpos < offset) { + if(newpos < (int) minOffset) + throw std::range_error("Invalid label position during decompression ("+std::to_string(newpos)+ " < "+std::to_string(minOffset)+")"); + if (++depth > 100) + throw std::range_error("Abort label decompression after 100 redirects"); + packetParser((const char*)opos, len, newpos, true, 0, 0, 0, depth, minOffset); + } else + throw std::range_error("Found a forward reference during label decompression"); + pos++; + break; + } else if(labellen & 0xc0) { + throw std::range_error("Found an invalid label length in qname (only one of the first two bits is set)"); + } + if (pos + labellen < end) { + appendRawLabel((const char*)pos, labellen); + } + else + throw std::range_error("Found an invalid label length in qname"); + pos+=labellen; + } + if(d_storage.empty()) + d_storage.append(1, (char)0); // we just parsed the root + if(consumed) + *consumed = pos - opos - offset; + if(qtype) { + if (pos + 2 > end) { + throw std::range_error("Trying to read qtype past the end of the buffer ("+std::to_string((pos - opos) + 2)+ " > "+std::to_string(len)+")"); + } + *qtype=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1); + } + pos+=2; + if(qclass) { + if (pos + 2 > end) { + throw std::range_error("Trying to read qclass past the end of the buffer ("+std::to_string((pos - opos) + 2)+ " > "+std::to_string(len)+")"); + } + *qclass=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1); + } +} + +std::string DNSName::toString(const std::string& separator, const bool trailing) const +{ + if (empty()) { + throw std::out_of_range("Attempt to print an unset dnsname"); + } + + if(isRoot()) + return trailing ? separator : ""; + + std::string ret; + for(const auto& s : getRawLabels()) { + ret+= escapeLabel(s) + separator; + } + + return ret.substr(0, ret.size()-!trailing); +} + +std::string DNSName::toLogString() const +{ + if (empty()) { + return "(empty)"; + } + + return toStringRootDot(); +} + +std::string DNSName::toDNSString() const +{ + if (empty()) + throw std::out_of_range("Attempt to DNSString an unset dnsname"); + + return std::string(d_storage.c_str(), d_storage.length()); +} + +std::string DNSName::toDNSStringLC() const +{ + return toLower(toDNSString()); // label lengths are always < 'A' +} + +/** + * Get the length of the DNSName on the wire + * + * @return the total wirelength of the DNSName + */ +size_t DNSName::wirelength() const { + return d_storage.length(); +} + +// Are WE part of parent +bool DNSName::isPartOf(const DNSName& parent) const +{ + if(parent.empty() || empty()) + throw std::out_of_range("empty dnsnames aren't part of anything"); + + if(parent.d_storage.size() > d_storage.size()) + return false; + + // this is slightly complicated since we can't start from the end, since we can't see where a label begins/ends then + for(auto us=d_storage.cbegin(); us(distance) < parent.d_storage.size()) { + break; + } + if (static_cast(distance) == parent.d_storage.size()) { + auto p = parent.d_storage.cbegin(); + for(; us != d_storage.cend(); ++us, ++p) { + if(dns_tolower(*p) != dns_tolower(*us)) + return false; + } + return true; + } + if (*us < 0) { + throw std::out_of_range("negative label length in dnsname"); + } + } + return false; +} + +DNSName DNSName::makeRelative(const DNSName& zone) const +{ + DNSName ret(*this); + ret.makeUsRelative(zone); + return ret.empty() ? zone : ret; // HACK FIXME400 +} +void DNSName::makeUsRelative(const DNSName& zone) +{ + if (isPartOf(zone)) { + d_storage.erase(d_storage.size()-zone.d_storage.size()); + d_storage.append(1, (char)0); // put back the trailing 0 + } + else + clear(); +} + +DNSName DNSName::getCommonLabels(const DNSName& other) const +{ + DNSName result; + + const std::vector ours = getRawLabels(); + const std::vector others = other.getRawLabels(); + + for (size_t pos = 0; ours.size() > pos && others.size() > pos; pos++) { + const std::string& ourLabel = ours.at(ours.size() - pos - 1); + const std::string& otherLabel = others.at(others.size() - pos - 1); + + if (!pdns_iequals(ourLabel, otherLabel)) { + break; + } + + result.prependRawLabel(ourLabel); + } + + return result; +} + +DNSName DNSName::labelReverse() const +{ + DNSName ret; + + if(isRoot()) + return *this; // we don't create the root automatically below + + if (!empty()) { + vector l=getRawLabels(); + while(!l.empty()) { + ret.appendRawLabel(l.back()); + l.pop_back(); + } + } + return ret; +} + +void DNSName::appendRawLabel(const std::string& label) +{ + appendRawLabel(label.c_str(), label.length()); +} + +void DNSName::appendRawLabel(const char* start, unsigned int length) +{ + if(length==0) + throw std::range_error("no such thing as an empty label to append"); + if(length > 63) + throw std::range_error("label too long to append"); + if(d_storage.size() + length > 254) // reserve one byte for the label length + throw std::range_error("name too long to append"); + + if(d_storage.empty()) { + d_storage.append(1, (char)length); + } + else { + *d_storage.rbegin()=(char)length; + } + d_storage.append(start, length); + d_storage.append(1, (char)0); +} + +void DNSName::prependRawLabel(const std::string& label) +{ + if(label.empty()) + throw std::range_error("no such thing as an empty label to prepend"); + if(label.size() > 63) + throw std::range_error("label too long to prepend"); + if(d_storage.size() + label.size() > 254) // reserve one byte for the label length + throw std::range_error("name too long to prepend"); + + if(d_storage.empty()) + d_storage.append(1, (char)0); + + string_t prep(1, (char)label.size()); + prep.append(label.c_str(), label.size()); + d_storage = prep+d_storage; +} + +bool DNSName::slowCanonCompare(const DNSName& rhs) const +{ + auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels(); + return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare()); +} + +vector DNSName::getRawLabels() const +{ + vector ret; + ret.reserve(countLabels()); + // 3www4ds9a2nl0 + for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1) { + ret.push_back({(const char*)p+1, (size_t)*p}); // XXX FIXME + } + return ret; +} + +std::string DNSName::getRawLabel(unsigned int pos) const +{ + unsigned int currentPos = 0; + for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1, currentPos++) { + if (currentPos == pos) { + return std::string((const char*)p+1, (size_t)*p); + } + } + + throw std::out_of_range("trying to get label at position "+std::to_string(pos)+" of a DNSName that only has "+std::to_string(currentPos)+" labels"); +} + +DNSName DNSName::getLastLabel() const +{ + DNSName ret(*this); + ret.trimToLabels(1); + return ret; +} + +bool DNSName::chopOff() +{ + if(d_storage.empty() || d_storage[0]==0) + return false; + d_storage.erase(0, (unsigned int)d_storage[0]+1); + return true; +} + +bool DNSName::isWildcard() const +{ + if(d_storage.size() < 2) + return false; + auto p = d_storage.begin(); + return (*p == 0x01 && *++p == '*'); +} + +/* + * Returns true if the DNSName is a valid RFC 1123 hostname, this function uses + * a regex on the string, so it is probably best not used when speed is essential. + */ +bool DNSName::isHostname() const +{ + static Regex hostNameRegex = Regex("^(([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)\\.)+$"); + return hostNameRegex.match(this->toString()); +} + +unsigned int DNSName::countLabels() const +{ + unsigned int count=0; + for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1) + ++count; + return count; +} + +void DNSName::trimToLabels(unsigned int to) +{ + while(countLabels() > to && chopOff()) + ; +} + + +size_t hash_value(DNSName const& d) +{ + return d.hash(); +} + +string DNSName::escapeLabel(const std::string& label) +{ + string ret; + ret.reserve(label.size()); // saves 15% on bulk .COM load + for(uint8_t p : label) { + if(p=='.') + ret+="\\."; + else if(p=='\\') + ret+="\\\\"; + else if(p > 0x21 && p < 0x7e) + ret.append(1, (char)p); + else { + ret+="\\" + (boost::format("%03d") % (unsigned int)p).str(); + } + } + return ret; +} diff --git a/dnsname.hh b/dnsname.hh new file mode 100644 index 0000000..7307da4 --- /dev/null +++ b/dnsname.hh @@ -0,0 +1,383 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include +#include +#include +#include +#include +#include + +#include + +// it crashes on OSX and doesn't compile on OpenBSD +#if BOOST_VERSION >= 105300 && ! defined( __APPLE__ ) && ! defined(__OpenBSD__) +#include +#endif + +#include "ascii.hh" + +uint32_t burtleCI(const unsigned char* k, uint32_t length, uint32_t init); + +// #include "dns.hh" +// #include "logger.hh" + +//#include + +/* Quest in life: + accept escaped ascii presentations of DNS names and store them "natively" + accept a DNS packet with an offset, and extract a DNS name from it + build up DNSNames with prepend and append of 'raw' unescaped labels + + Be able to turn them into ASCII and "DNS name in a packet" again on request + + Provide some common operators for comparison, detection of being part of another domain + + NOTE: For now, everything MUST be . terminated, otherwise it is an error +*/ + +class DNSName +{ +public: + DNSName() {} //!< Constructs an *empty* DNSName, NOT the root! + explicit DNSName(const char* p); //!< Constructs from a human formatted, escaped presentation + explicit DNSName(const std::string& str) : DNSName(str.c_str()) {}; //!< Constructs from a human formatted, escaped presentation + DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0, unsigned int* consumed=0, uint16_t minOffset=0); //!< Construct from a DNS Packet, taking the first question if offset=12 + + bool isPartOf(const DNSName& rhs) const; //!< Are we part of the rhs name? + inline bool operator==(const DNSName& rhs) const; //!< DNS-native comparison (case insensitive) - empty compares to empty + bool operator!=(const DNSName& other) const { return !(*this == other); } + + std::string toString(const std::string& separator=".", const bool trailing=true) const; //!< Our human-friendly, escaped, representation + std::string toLogString() const; //!< like plain toString, but returns (empty) on empty names + std::string toStringNoDot() const { return toString(".", false); } + std::string toStringRootDot() const { if(isRoot()) return "."; else return toString(".", false); } + std::string toDNSString() const; //!< Our representation in DNS native format + std::string toDNSStringLC() const; //!< Our representation in DNS native format, lower cased + void appendRawLabel(const std::string& str); //!< Append this unescaped label + void appendRawLabel(const char* start, unsigned int length); //!< Append this unescaped label + void prependRawLabel(const std::string& str); //!< Prepend this unescaped label + std::vector getRawLabels() const; //!< Individual raw unescaped labels + std::string getRawLabel(unsigned int pos) const; //!< Get the specified raw unescaped label + DNSName getLastLabel() const; //!< Get the DNSName of the last label + bool chopOff(); //!< Turn www.powerdns.com. into powerdns.com., returns false for . + DNSName makeRelative(const DNSName& zone) const; + DNSName makeLowerCase() const + { + DNSName ret(*this); + ret.makeUsLowerCase(); + return ret; + } + void makeUsLowerCase() + { + for(auto & c : d_storage) { + c=dns_tolower(c); + } + } + void makeUsRelative(const DNSName& zone); + DNSName getCommonLabels(const DNSName& other) const; //!< Return the list of common labels from the top, for example 'c.d' for 'a.b.c.d' and 'x.y.c.d' + DNSName labelReverse() const; + bool isWildcard() const; + bool isHostname() const; + unsigned int countLabels() const; + size_t wirelength() const; //!< Number of total bytes in the name + bool empty() const { return d_storage.empty(); } + bool isRoot() const { return d_storage.size()==1 && d_storage[0]==0; } + void clear() { d_storage.clear(); } + void trimToLabels(unsigned int); + size_t hash(size_t init=0) const + { + return burtleCI((const unsigned char*)d_storage.c_str(), d_storage.size(), init); + } + DNSName& operator+=(const DNSName& rhs) + { + if(d_storage.size() + rhs.d_storage.size() > 256) // one extra byte for the second root label + throw std::range_error("name too long"); + if(rhs.empty()) + return *this; + + if(d_storage.empty()) + d_storage+=rhs.d_storage; + else + d_storage.replace(d_storage.length()-1, rhs.d_storage.length(), rhs.d_storage); + + return *this; + } + + bool operator<(const DNSName& rhs) const // this delivers _some_ kind of ordering, but not one useful in a DNS context. Really fast though. + { + return std::lexicographical_compare(d_storage.rbegin(), d_storage.rend(), + rhs.d_storage.rbegin(), rhs.d_storage.rend(), + [](const unsigned char& a, const unsigned char& b) { + return dns_tolower(a) < dns_tolower(b); + }); // note that this is case insensitive, including on the label lengths + } + + inline bool canonCompare(const DNSName& rhs) const; + bool slowCanonCompare(const DNSName& rhs) const; + +#if BOOST_VERSION >= 105300 && ! defined( __APPLE__ ) && ! defined(__OpenBSD__) + typedef boost::container::string string_t; +#else + typedef std::string string_t; +#endif + const string_t& getStorage() const { + return d_storage; + } +private: + string_t d_storage; + + void packetParser(const char* p, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset); + static std::string escapeLabel(const std::string& orig); + static std::string unescapeLabel(const std::string& orig); +}; + +size_t hash_value(DNSName const& d); + + +inline bool DNSName::canonCompare(const DNSName& rhs) const +{ + // 01234567890abcd + // us: 1a3www4ds9a2nl + // rhs: 3www6online3com + // to compare, we start at the back, is nl < com? no -> done + // + // 0,2,6,a + // 0,4,a + + uint8_t ourpos[64], rhspos[64]; + uint8_t ourcount=0, rhscount=0; + //cout<<"Asked to compare "< +{ + bool operator()(const DNSName&a, const DNSName& b) const + { + return a.canonCompare(b); + } +}; + +inline DNSName operator+(const DNSName& lhs, const DNSName& rhs) +{ + DNSName ret=lhs; + ret += rhs; + return ret; +} + +template +struct SuffixMatchTree +{ + SuffixMatchTree(const std::string& name="", bool endNode_=false) : d_name(name), endNode(endNode_) + {} + + SuffixMatchTree(const SuffixMatchTree& rhs) + { + d_name = rhs.d_name; + children = rhs.children; + endNode = rhs.endNode; + d_value = rhs.d_value; + } + std::string d_name; + mutable std::set children; + mutable bool endNode; + mutable T d_value; + bool operator<(const SuffixMatchTree& rhs) const + { + return strcasecmp(d_name.c_str(), rhs.d_name.c_str()) < 0; + } + typedef SuffixMatchTree value_type; + + template + void visit(const V& v) const { + for(const auto& c : children) + c.visit(v); + if(endNode) + v(*this); + } + + void add(const DNSName& name, const T& t) + { + add(name.getRawLabels(), t); + } + + void add(std::vector labels, const T& value) const + { + if(labels.empty()) { // this allows insertion of the root + endNode=true; + d_value=value; + } + else if(labels.size()==1) { + SuffixMatchTree newChild(*labels.begin(), true); + auto res=children.insert(newChild); + if(!res.second) { + // we might already have had the node as an + // intermediary one, but it's now an end node + if(!res.first->endNode) { + res.first->endNode = true; + } + } + res.first->d_value = value; + } + else { + SuffixMatchTree newnode(*labels.rbegin(), false); + auto res=children.insert(newnode); + labels.pop_back(); + res.first->add(labels, value); + } + } + + T* lookup(const DNSName& name) const + { + if(children.empty()) { // speed up empty set + if(endNode) + return &d_value; + return 0; + } + return lookup(name.getRawLabels()); + } + + T* lookup(std::vector labels) const + { + if(labels.empty()) { // optimization + if(endNode) + return &d_value; + return 0; + } + + SuffixMatchTree smn(*labels.rbegin()); + auto child = children.find(smn); + if(child == children.end()) { + if(endNode) + return &d_value; + return 0; + } + labels.pop_back(); + return child->lookup(labels); + } + +}; + +/* Quest in life: serve as a rapid block list. If you add a DNSName to a root SuffixMatchNode, + anything part of that domain will return 'true' in check */ +struct SuffixMatchNode +{ + SuffixMatchNode() + {} + std::string d_human; + SuffixMatchTree d_tree; + + void add(const DNSName& dnsname) + { + if(!d_human.empty()) + d_human.append(", "); + d_human += dnsname.toString(); + + d_tree.add(dnsname, true); + } + + void add(std::vector labels) + { + d_tree.add(labels, true); + } + + bool check(const DNSName& dnsname) const + { + return d_tree.lookup(dnsname) != nullptr; + } + + std::string toString() const + { + return d_human; + } + +}; + +std::ostream & operator<<(std::ostream &os, const DNSName& d); +namespace std { + template <> + struct hash { + size_t operator () (const DNSName& dn) const { return dn.hash(0); } + }; +} + +DNSName::string_t segmentDNSNameRaw(const char* input); // from ragel +bool DNSName::operator==(const DNSName& rhs) const +{ + if(rhs.empty() != empty() || rhs.d_storage.size() != d_storage.size()) + return false; + + auto us = d_storage.cbegin(); + auto p = rhs.d_storage.cbegin(); + for(; us != d_storage.cend() && p != rhs.d_storage.cend(); ++us, ++p) { + if(dns_tolower(*p) != dns_tolower(*us)) + return false; + } + return true; +} + +extern const DNSName g_rootdnsname, g_wildcarddnsname; diff --git a/dnspacket.hh b/dnspacket.hh new file mode 100644 index 0000000..5a717e3 --- /dev/null +++ b/dnspacket.hh @@ -0,0 +1,196 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 DNSPACKET_HH + +#define DNSPACKET_HH + +#include +#include +#include +#include +#include "iputils.hh" +#include "ednssubnet.hh" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "qtype.hh" +#include "dns.hh" +#include "misc.hh" +#include "utility.hh" +#include "logger.hh" +#include "pdnsexception.hh" +#include "dnsrecords.hh" + +class UeberBackend; +class DNSSECKeeper; + + +//! This class represents DNS packets, either received or to be sent. +class DNSPacket +{ +public: + DNSPacket(bool isQuery); + DNSPacket(const DNSPacket &orig); + + int noparse(const char *mesg, size_t len); //!< just suck the data inward + int parse(const char *mesg, size_t len); //!< parse a raw UDP or TCP packet and suck the data inward + const string& getString(); //!< for serialization - just passes the whole packet + + // address & socket manipulation + void setRemote(const ComboAddress*); + ComboAddress getRemote() const; + Netmask getRealRemote() const; + ComboAddress getLocal() const + { + ComboAddress ca; + socklen_t len=sizeof(ca); + getsockname(d_socket, (sockaddr*)&ca, &len); + return ca; + } + uint16_t getRemotePort() const; + + boost::optional d_anyLocal; + + Utility::sock_t getSocket() const + { + return d_socket; + } + void setSocket(Utility::sock_t sock); + + + // these manipulate 'd' + void setA(bool); //!< make this packet authoritative - manipulates 'd' + void setID(uint16_t); //!< set the DNS id of this packet - manipulates 'd' + void setRA(bool); //!< set the Recursion Available flag - manipulates 'd' + void setRD(bool); //!< set the Recursion Desired flag - manipulates 'd' + void setAnswer(bool); //!< Make this packet an answer - clears the 'stringbuffer' first, if passed 'true', does nothing otherwise, manipulates 'd' + + void setOpcode(uint16_t); //!< set the Opcode of this packet - manipulates 'd' + void setRcode(int v); //!< set the Rcode of this packet - manipulates 'd' + + void clearRecords(); //!< when building a packet, wipe all previously added records (clears 'rrs') + + /** Add a DNSZoneRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions, + Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the + DNSZoneRecord d_place field */ + void addRecord(const DNSZoneRecord &); // adds to 'rrs' + + void setQuestion(int op, const DNSName &qdomain, int qtype); // wipes 'd', sets a random id, creates start of packet (domain, type, class etc) + + DTime d_dt; //!< the time this packet was created. replyPacket() copies this in for you, so d_dt becomes the time spent processing the question+answer + void wrapup(); // writes out queued rrs, and generates the binary packet. also shuffles. also rectifies dnsheader 'd', and copies it to the stringbuffer + void spoofQuestion(const DNSPacket *qd); //!< paste in the exact right case of the question. Useful for PacketCache + unsigned int getMinTTL(); //!< returns lowest TTL of any record in the packet + bool isEmpty(); //!< returns true if there are no rrs in the packet + + vector getAPRecords(); //!< get a vector with DNSZoneRecords that need additional processing + vector getAnswerRecords(); //!< get a vector with DNSZoneRecords that are answers + void setCompress(bool compress); + + DNSPacket *replyPacket() const; //!< convenience function that creates a virgin answer packet to this question + + void commitD(); //!< copies 'd' into the stringbuffer + unsigned int getMaxReplyLen(); //!< retrieve the maximum length of the packet we should send in response + void setMaxReplyLen(int bytes); //!< set the max reply len (used when retrieving from the packet cache, and this changed) + + bool couldBeCached(); //!< returns 0 if this query should bypass the packet cache + bool hasEDNSSubnet(); + bool hasEDNS(); + uint8_t getEDNSVersion() const { return d_ednsversion; }; + void setEDNSRcode(uint16_t extRCode) + { + // WARNING: this is really 12 bits + d_ednsrcode=extRCode; + }; + uint8_t getEDNSRCode() const { return d_ednsrcode; }; + uint32_t getHash() const { return d_hash; }; + void setHash(uint32_t hash) { d_hash = hash; }; + + //////// DATA ! + + DNSName qdomain; //!< qname of the question 4 - unsure how this is used + DNSName qdomainwild; //!< wildcard matched by qname, used by LuaPolicyEngine + DNSName qdomainzone; //!< zone name for the answer (as reflected in SOA for negative responses), used by LuaPolicyEngine + string d_peer_principal; + const DNSName& getTSIGKeyname() const; + + uint16_t qclass; //!< class of the question - should always be INternet 2 + struct dnsheader d; //!< dnsheader at the start of the databuffer 12 + + QType qtype; //!< type of the question 2 + + TSIGRecordContent d_trc; //72 + + ComboAddress d_remote; //28 + TSIGHashEnum d_tsig_algo; //4 + + bool d_tcp; + bool d_dnssecOk; + bool d_havetsig; + + bool getTSIGDetails(TSIGRecordContent* tr, DNSName* keyname, uint16_t* tsigPos=nullptr) const; + void setTSIGDetails(const TSIGRecordContent& tr, const DNSName& keyname, const string& secret, const string& previous, bool timersonly=false); + bool getTKEYRecord(TKEYRecordContent* tr, DNSName* keyname) const; + + vector& getRRS() { return d_rrs; } + bool checkForCorrectTSIG(UeberBackend* B, DNSName* keyname, string* secret, TSIGRecordContent* trc) const; + + static bool s_doEDNSSubnetProcessing; + static uint16_t s_udpTruncationThreshold; //2 +private: + void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies + + bool d_wrapped; // 1 + int d_socket; // 4 + + string d_tsigsecret; + DNSName d_tsigkeyname; + string d_tsigprevious; + + vector d_rrs; // 8 + string d_rawpacket; // this is where everything lives 8 + string d_ednsping; + EDNSSubnetOpts d_eso; + + int d_maxreplylen; + uint8_t d_ednsversion; + // WARNING! This is really 12 bits + uint16_t d_ednsrcode; + + uint32_t d_hash{0}; + + bool d_compress; // 1 + bool d_tsigtimersonly; + bool d_wantsnsid; + bool d_haveednssubnet; + bool d_haveednssection; + bool d_isQuery; +}; + +#endif diff --git a/dnsparser.cc b/dnsparser.cc new file mode 100644 index 0000000..52fca0e --- /dev/null +++ b/dnsparser.cc @@ -0,0 +1,929 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "dnsparser.hh" +#include "dnswriter.hh" +#include +#include + +#include "namespaces.hh" + +class UnknownRecordContent : public DNSRecordContent +{ +public: + UnknownRecordContent(const DNSRecord& dr, PacketReader& pr) + : d_dr(dr) + { + pr.copyRecord(d_record, dr.d_clen); + } + + UnknownRecordContent(const string& zone) + { + // parse the input + vector parts; + stringtok(parts, zone); + if(parts.size()!=3 && !(parts.size()==2 && equals(parts[1],"0")) ) + throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+std::to_string(parts.size())+": "+zone ); + const string& relevant=(parts.size() > 2) ? parts[2] : ""; + unsigned int total=pdns_stou(parts[1]); + if(relevant.size() % 2 || relevant.size() / 2 != total) + throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str()); + string out; + out.reserve(total+1); + for(unsigned int n=0; n < total; ++n) { + int c; + sscanf(relevant.c_str()+2*n, "%02x", &c); + out.append(1, (char)c); + } + + d_record.insert(d_record.end(), out.begin(), out.end()); + } + + string getZoneRepresentation(bool noDot) const override + { + ostringstream str; + str<<"\\# "<<(unsigned int)d_record.size()<<" "; + char hex[4]; + for(size_t n=0; n d_record; +}; + +shared_ptr DNSRecordContent::unserialize(const DNSName& qname, uint16_t qtype, const string& serialized) +{ + dnsheader dnsheader; + memset(&dnsheader, 0, sizeof(dnsheader)); + dnsheader.qdcount=htons(1); + dnsheader.ancount=htons(1); + + vector packet; // build pseudo packet + + /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */ + + string encoded=qname.toDNSString(); + + packet.resize(sizeof(dnsheader) + 5 + encoded.size() + sizeof(struct dnsrecordheader) + serialized.size()); + + uint16_t pos=0; + + memcpy(&packet[0], &dnsheader, sizeof(dnsheader)); pos+=sizeof(dnsheader); + + char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a + memcpy(&packet[pos], &tmp, 5); pos+=5; + + memcpy(&packet[pos], encoded.c_str(), encoded.size()); pos+=(uint16_t)encoded.size(); + + struct dnsrecordheader drh; + drh.d_type=htons(qtype); + drh.d_class=htons(1); + drh.d_ttl=0; + drh.d_clen=htons(serialized.size()); + + memcpy(&packet[pos], &drh, sizeof(drh)); pos+=sizeof(drh); + memcpy(&packet[pos], serialized.c_str(), serialized.size()); pos+=(uint16_t)serialized.size(); + + MOADNSParser mdp(false, (char*)&*packet.begin(), (unsigned int)packet.size()); + shared_ptr ret= mdp.d_answers.begin()->first.d_content; + return ret; +} + +std::shared_ptr DNSRecordContent::mastermake(const DNSRecord &dr, + PacketReader& pr) +{ + uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT + + typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type)); + if(i==getTypemap().end() || !i->second) { + return std::make_shared(dr, pr); + } + + return std::shared_ptr(i->second(dr, pr)); +} + +std::shared_ptr DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass, + const string& content) +{ + zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype)); + if(i==getZmakermap().end()) { + return std::make_shared(content); + } + + return std::shared_ptr(i->second(content)); +} + +std::unique_ptr DNSRecordContent::makeunique(uint16_t qtype, uint16_t qclass, + const string& content) +{ + zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype)); + if(i==getZmakermap().end()) { + return std::unique_ptr(new UnknownRecordContent(content)); + } + + return std::unique_ptr(i->second(content)); +} + + +std::shared_ptr DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) { + // For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is + // not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent. + // For section 3.2.3, we do need content so we need to get it properly. But only for the correct QClasses. + if (oc == Opcode::Update && dr.d_place == DNSResourceRecord::ANSWER && dr.d_class != 1) + return std::make_shared(dr, pr); + + uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT + + typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type)); + if(i==getTypemap().end() || !i->second) { + return std::make_shared(dr, pr); + } + + return std::shared_ptr(i->second(dr, pr)); +} + + +DNSRecordContent::typemap_t& DNSRecordContent::getTypemap() +{ + static DNSRecordContent::typemap_t typemap; + return typemap; +} + +DNSRecordContent::n2typemap_t& DNSRecordContent::getN2Typemap() +{ + static DNSRecordContent::n2typemap_t n2typemap; + return n2typemap; +} + +DNSRecordContent::t2namemap_t& DNSRecordContent::getT2Namemap() +{ + static DNSRecordContent::t2namemap_t t2namemap; + return t2namemap; +} + +DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap() +{ + static DNSRecordContent::zmakermap_t zmakermap; + return zmakermap; +} + +DNSRecord::DNSRecord(const DNSResourceRecord& rr) +{ + d_name = rr.qname; + d_type = rr.qtype.getCode(); + d_ttl = rr.ttl; + d_class = rr.qclass; + d_place = DNSResourceRecord::ANSWER; + d_clen = 0; + d_content = DNSRecordContent::mastermake(d_type, rr.qclass, rr.content); +} + +// If you call this and you are not parsing a packet coming from a socket, you are doing it wrong. +DNSResourceRecord DNSResourceRecord::fromWire(const DNSRecord& d) { + DNSResourceRecord rr; + rr.qname = d.d_name; + rr.qtype = QType(d.d_type); + rr.ttl = d.d_ttl; + rr.content = d.d_content->getZoneRepresentation(true); + rr.auth = false; + rr.qclass = d.d_class; + return rr; +} + +void MOADNSParser::init(bool query, const char *packet, unsigned int len) +{ + if(len < sizeof(dnsheader)) + throw MOADNSException("Packet shorter than minimal header"); + + memcpy(&d_header, packet, sizeof(dnsheader)); + + if(d_header.opcode != Opcode::Query && d_header.opcode != Opcode::Notify && d_header.opcode != Opcode::Update) + throw MOADNSException("Can't parse non-query packet with opcode="+ std::to_string(d_header.opcode)); + + d_header.qdcount=ntohs(d_header.qdcount); + d_header.ancount=ntohs(d_header.ancount); + d_header.nscount=ntohs(d_header.nscount); + d_header.arcount=ntohs(d_header.arcount); + + if (query && (d_header.qdcount > 1)) + throw MOADNSException("Query with QD > 1 ("+std::to_string(d_header.qdcount)+")"); + + uint16_t contentlen=len-sizeof(dnsheader); + + d_content.resize(contentlen); + copy(packet+sizeof(dnsheader), packet+len, d_content.begin()); + + unsigned int n=0; + + PacketReader pr(d_content); + bool validPacket=false; + try { + d_qtype = d_qclass = 0; // sometimes replies come in with no question, don't present garbage then + + for(n=0;n < d_header.qdcount; ++n) { + d_qname=pr.getName(); + d_qtype=pr.get16BitInt(); + d_qclass=pr.get16BitInt(); + } + + struct dnsrecordheader ah; + vector record; + validPacket=true; + d_answers.reserve((unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount)); + for(n=0;n < (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount); ++n) { + DNSRecord dr; + + if(n < d_header.ancount) + dr.d_place=DNSResourceRecord::ANSWER; + else if(n < d_header.ancount + d_header.nscount) + dr.d_place=DNSResourceRecord::AUTHORITY; + else + dr.d_place=DNSResourceRecord::ADDITIONAL; + + unsigned int recordStartPos=pr.d_pos; + + DNSName name=pr.getName(); + + pr.getDnsrecordheader(ah); + dr.d_ttl=ah.d_ttl; + dr.d_type=ah.d_type; + dr.d_class=ah.d_class; + + dr.d_name=name; + dr.d_clen=ah.d_clen; + + if (query && (dr.d_place == DNSResourceRecord::ANSWER || dr.d_place == DNSResourceRecord::AUTHORITY || (dr.d_type != QType::OPT && dr.d_type != QType::TSIG && dr.d_type != QType::SIG && dr.d_type != QType::TKEY) || ((dr.d_type == QType::TSIG || dr.d_type == QType::SIG || dr.d_type == QType::TKEY) && dr.d_class != QClass::ANY))) { +// cerr<<"discarding RR, query is "<(dr, pr); + } + else { +// cerr<<"parsing RR, query is "<(&ah); + + for(n=0; n < sizeof(dnsrecordheader); ++n) + p[n]=d_content.at(d_pos++); + + ah.d_type=ntohs(ah.d_type); + ah.d_class=ntohs(ah.d_class); + ah.d_clen=ntohs(ah.d_clen); + ah.d_ttl=ntohl(ah.d_ttl); + + d_startrecordpos=d_pos; // needed for getBlob later on + d_recordlen=ah.d_clen; +} + + +void PacketReader::copyRecord(vector& dest, uint16_t len) +{ + dest.resize(len); + if(!len) + return; + + for(uint16_t n=0;n d_content.size()) + throw std::out_of_range("Attempt to copy outside of packet"); + + memcpy(dest, &d_content.at(d_pos), len); + d_pos+=len; +} + +void PacketReader::xfr48BitInt(uint64_t& ret) +{ + ret=0; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); +} + +uint32_t PacketReader::get32BitInt() +{ + uint32_t ret=0; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + + return ret; +} + + +uint16_t PacketReader::get16BitInt() +{ + return get16BitInt(d_content, d_pos); +} + +uint16_t PacketReader::get16BitInt(const vector&content, uint16_t& pos) +{ + uint16_t ret=0; + ret+=content.at(pos++); + ret<<=8; + ret+=content.at(pos++); + + return ret; +} + +uint8_t PacketReader::get8BitInt() +{ + return d_content.at(d_pos++); +} + +DNSName PacketReader::getName() +{ + unsigned int consumed; + try { + DNSName dn((const char*) d_content.data() - 12, d_content.size() + 12, d_pos + sizeof(dnsheader), true /* uncompress */, 0 /* qtype */, 0 /* qclass */, &consumed, sizeof(dnsheader)); + + // the -12 fakery is because we don't have the header in 'd_content', but we do need to get + // the internal offsets to work + d_pos+=consumed; + return dn; + } + catch(const std::range_error& re) { + throw std::out_of_range(string("dnsname issue: ")+re.what()); + } + catch(...) { + throw std::out_of_range("dnsname issue"); + } + throw PDNSException("PacketReader::getName(): name is empty"); +} + +static string txtEscape(const string &name) +{ + string ret; + char ebuf[5]; + + for(string::const_iterator i=name.begin();i!=name.end();++i) { + if((unsigned char) *i > 127 || (unsigned char) *i < 32) { + snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)*i); + ret += ebuf; + } + else if(*i=='"' || *i=='\\'){ + ret += '\\'; + ret += *i; + } + else + ret += *i; + } + return ret; +} + +// exceptions thrown here do not result in logging in the main pdns auth server - just so you know! +string PacketReader::getText(bool multi, bool lenField) +{ + string ret; + ret.reserve(40); + while(d_pos < d_startrecordpos + d_recordlen ) { + if(!ret.empty()) { + ret.append(1,' '); + } + uint16_t labellen; + if(lenField) + labellen=d_content.at(d_pos++); + else + labellen=d_recordlen - (d_pos - d_startrecordpos); + + ret.append(1,'"'); + if(labellen) { // no need to do anything for an empty string + string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1); + ret.append(txtEscape(val)); // the end is one beyond the packet + } + ret.append(1,'"'); + d_pos+=labellen; + if(!multi) + break; + } + + return ret; +} + +string PacketReader::getUnquotedText(bool lenField) +{ + int16_t stop_at; + if(lenField) + stop_at = (uint8_t)d_content.at(d_pos) + d_pos + 1; + else + stop_at = d_recordlen; + + if(stop_at == d_pos) + return ""; + + d_pos++; + string ret(&d_content.at(d_pos), &d_content.at(stop_at)); + d_pos = stop_at; + return ret; +} + +void PacketReader::xfrBlob(string& blob) +try +{ + if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen))) + blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1); + else + blob.clear(); + + d_pos = d_startrecordpos + d_recordlen; +} +catch(...) +{ + throw std::out_of_range("xfrBlob out of range"); +} + +void PacketReader::xfrBlobNoSpaces(string& blob, int length) { + xfrBlob(blob, length); +} + +void PacketReader::xfrBlob(string& blob, int length) +{ + if(length) { + blob.assign(&d_content.at(d_pos), &d_content.at(d_pos + length - 1 ) + 1 ); + + d_pos += length; + } + else + blob.clear(); +} + + +void PacketReader::xfrHexBlob(string& blob, bool keepReading) +{ + xfrBlob(blob); +} + +//FIXME400 remove this method completely +string simpleCompress(const string& elabel, const string& root) +{ + string label=elabel; + // FIXME400: this relies on the semi-canonical escaped output from getName + if(strchr(label.c_str(), '\\')) { + boost::replace_all(label, "\\.", "."); + boost::replace_all(label, "\\032", " "); + boost::replace_all(label, "\\\\", "\\"); + } + typedef vector > parts_t; + parts_t parts; + vstringtok(parts, label, "."); + string ret; + ret.reserve(label.size()+4); + for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { + if(!root.empty() && !strncasecmp(root.c_str(), label.c_str() + i->first, 1 + label.length() - i->first)) { // also match trailing 0, hence '1 +' + const unsigned char rootptr[2]={0xc0,0x11}; + ret.append((const char *) rootptr, 2); + return ret; + } + ret.append(1, (char)(i->second - i->first)); + ret.append(label.c_str() + i->first, i->second - i->first); + } + ret.append(1, (char)0); + return ret; +} + + +/** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs + * If you survive that, feel free to read from the pointer */ +class DNSPacketMangler +{ +public: + explicit DNSPacketMangler(std::string& packet) + : d_packet((char*) packet.c_str()), d_length(packet.length()), d_notyouroffset(12), d_offset(d_notyouroffset) + {} + DNSPacketMangler(char* packet, size_t length) + : d_packet(packet), d_length(length), d_notyouroffset(12), d_offset(d_notyouroffset) + {} + + void skipLabel() + { + uint8_t len; + while((len=get8BitInt())) { + if(len >= 0xc0) { // extended label + get8BitInt(); + return; + } + skipBytes(len); + } + } + void skipBytes(uint16_t bytes) + { + moveOffset(bytes); + } + void rewindBytes(uint16_t by) + { + rewindOffset(by); + } + uint32_t get32BitInt() + { + const char* p = d_packet + d_offset; + moveOffset(4); + uint32_t ret; + memcpy(&ret, (void*)p, sizeof(ret)); + return ntohl(ret); + } + uint16_t get16BitInt() + { + const char* p = d_packet + d_offset; + moveOffset(2); + uint16_t ret; + memcpy(&ret, (void*)p, sizeof(ret)); + return ntohs(ret); + } + + uint8_t get8BitInt() + { + const char* p = d_packet + d_offset; + moveOffset(1); + return *p; + } + + void skipRData() + { + int toskip = get16BitInt(); + moveOffset(toskip); + } + + void decreaseAndSkip32BitInt(uint32_t decrease) + { + const char *p = d_packet + d_offset; + moveOffset(4); + + uint32_t tmp; + memcpy(&tmp, (void*) p, sizeof(tmp)); + tmp = ntohl(tmp); + tmp-=decrease; + tmp = htonl(tmp); + memcpy(d_packet + d_offset-4, (const char*)&tmp, sizeof(tmp)); + } + void setAndSkip32BitInt(uint32_t value) + { + moveOffset(4); + + value = htonl(value); + memcpy(d_packet + d_offset-4, (const char*)&value, sizeof(value)); + } + uint32_t getOffset() const + { + return d_offset; + } +private: + void moveOffset(uint16_t by) + { + d_notyouroffset += by; + if(d_notyouroffset > d_length) + throw std::out_of_range("dns packet out of range: "+std::to_string(d_notyouroffset) +" > " + + std::to_string(d_length) ); + } + void rewindOffset(uint16_t by) + { + if(d_notyouroffset < by) + throw std::out_of_range("Rewinding dns packet out of range: "+std::to_string(d_notyouroffset) +" < " + + std::to_string(by)); + d_notyouroffset -= by; + if(d_notyouroffset < 12) + throw std::out_of_range("Rewinding dns packet out of range: "+std::to_string(d_notyouroffset) +" < " + + std::to_string(12)); + } + char* d_packet; + size_t d_length; + + uint32_t d_notyouroffset; // only 'moveOffset' can touch this + const uint32_t& d_offset; // look.. but don't touch + +}; + +// method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it +void editDNSPacketTTL(char* packet, size_t length, std::function visitor) +{ + if(length < sizeof(dnsheader)) + return; + try + { + dnsheader dh; + memcpy((void*)&dh, (const dnsheader*)packet, sizeof(dh)); + uint64_t numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount); + DNSPacketMangler dpm(packet, length); + + uint64_t n; + for(n=0; n < ntohs(dh.qdcount) ; ++n) { + dpm.skipLabel(); + /* type and class */ + dpm.skipBytes(4); + } + + for(n=0; n < numrecords; ++n) { + dpm.skipLabel(); + + uint8_t section = n < dh.ancount ? 1 : (n < (dh.ancount + dh.nscount) ? 2 : 3); + uint16_t dnstype = dpm.get16BitInt(); + uint16_t dnsclass = dpm.get16BitInt(); + + if(dnstype == QType::OPT) // not getting near that one with a stick + break; + + uint32_t dnsttl = dpm.get32BitInt(); + uint32_t newttl = visitor(section, dnsclass, dnstype, dnsttl); + if (newttl) { + dpm.rewindBytes(sizeof(newttl)); + dpm.setAndSkip32BitInt(newttl); + } + dpm.skipRData(); + } + } + catch(...) + { + return; + } +} + +// method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it +void ageDNSPacket(char* packet, size_t length, uint32_t seconds) +{ + if(length < sizeof(dnsheader)) + return; + try + { + const dnsheader* dh = reinterpret_cast(packet); + const uint64_t dqcount = ntohs(dh->qdcount); + const uint64_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); + DNSPacketMangler dpm(packet, length); + + uint64_t n; + for(n=0; n < dqcount; ++n) { + dpm.skipLabel(); + /* type and class */ + dpm.skipBytes(4); + } + // cerr<<"Skipped "<::max(); + if(length < sizeof(dnsheader)) { + return result; + } + try + { + const dnsheader* dh = (const dnsheader*) packet; + DNSPacketMangler dpm(const_cast(packet), length); + + const uint16_t qdcount = ntohs(dh->qdcount); + for(size_t n = 0; n < qdcount; ++n) { + dpm.skipLabel(); + /* type and class */ + dpm.skipBytes(4); + } + const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); + for(size_t n = 0; n < numrecords; ++n) { + dpm.skipLabel(); + const uint16_t dnstype = dpm.get16BitInt(); + /* class */ + dpm.skipBytes(2); + + if(dnstype == QType::OPT) + break; + + const uint32_t ttl = dpm.get32BitInt(); + if (result > ttl) + result = ttl; + + dpm.skipRData(); + } + } + catch(...) + { + } + return result; +} + +uint32_t getDNSPacketLength(const char* packet, size_t length) +{ + uint32_t result = length; + if(length < sizeof(dnsheader)) { + return result; + } + try + { + const dnsheader* dh = (const dnsheader*) packet; + DNSPacketMangler dpm(const_cast(packet), length); + + const uint16_t qdcount = ntohs(dh->qdcount); + for(size_t n = 0; n < qdcount; ++n) { + dpm.skipLabel(); + /* type and class */ + dpm.skipBytes(4); + } + const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); + for(size_t n = 0; n < numrecords; ++n) { + dpm.skipLabel(); + /* type (2), class (2) and ttl (4) */ + dpm.skipBytes(8); + dpm.skipRData(); + } + result = dpm.getOffset(); + } + catch(...) + { + } + return result; +} + +uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type) +{ + uint16_t result = 0; + if(length < sizeof(dnsheader)) { + return result; + } + try + { + const dnsheader* dh = (const dnsheader*) packet; + DNSPacketMangler dpm(const_cast(packet), length); + + const uint16_t qdcount = ntohs(dh->qdcount); + for(size_t n = 0; n < qdcount; ++n) { + dpm.skipLabel(); + if (section == 0) { + uint16_t dnstype = dpm.get16BitInt(); + if (dnstype == type) { + result++; + } + /* class */ + dpm.skipBytes(2); + } else { + /* type and class */ + dpm.skipBytes(4); + } + } + const uint16_t ancount = ntohs(dh->ancount); + for(size_t n = 0; n < ancount; ++n) { + dpm.skipLabel(); + if (section == 1) { + uint16_t dnstype = dpm.get16BitInt(); + if (dnstype == type) { + result++; + } + /* class */ + dpm.skipBytes(2); + } else { + /* type and class */ + dpm.skipBytes(4); + } + /* ttl */ + dpm.skipBytes(4); + dpm.skipRData(); + } + const uint16_t nscount = ntohs(dh->nscount); + for(size_t n = 0; n < nscount; ++n) { + dpm.skipLabel(); + if (section == 2) { + uint16_t dnstype = dpm.get16BitInt(); + if (dnstype == type) { + result++; + } + /* class */ + dpm.skipBytes(2); + } else { + /* type and class */ + dpm.skipBytes(4); + } + /* ttl */ + dpm.skipBytes(4); + dpm.skipRData(); + } + const uint16_t arcount = ntohs(dh->arcount); + for(size_t n = 0; n < arcount; ++n) { + dpm.skipLabel(); + if (section == 3) { + uint16_t dnstype = dpm.get16BitInt(); + if (dnstype == type) { + result++; + } + /* class */ + dpm.skipBytes(2); + } else { + /* type and class */ + dpm.skipBytes(4); + } + /* ttl */ + dpm.skipBytes(4); + dpm.skipRData(); + } + } + catch(...) + { + } + return result; +} diff --git a/dnsparser.hh b/dnsparser.hh new file mode 100644 index 0000000..78a73f0 --- /dev/null +++ b/dnsparser.hh @@ -0,0 +1,399 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 DNSPARSER_HH +#define DNSPARSER_HH + +#include +#include +#include +#include +#include +#include +// #include +#include "misc.hh" + +#include +#include +#include "dns.hh" +#include "dnswriter.hh" +#include "dnsname.hh" +#include "pdnsexception.hh" + +/** DNS records have three representations: + 1) in the packet + 2) parsed in a class, ready for use + 3) in the zone + + We should implement bidirectional transitions between 1&2 and 2&3. + Currently we have: 1 -> 2 + 2 -> 3 + + We can add: 2 -> 1 easily by reversing the packetwriter + And we might be able to reverse 2 -> 3 as well +*/ + +#include "namespaces.hh" +#include "namespaces.hh" + +class MOADNSException : public runtime_error +{ +public: + MOADNSException(const string& str) : runtime_error(str) + {} +}; + + +class MOADNSParser; + +class PacketReader +{ +public: + PacketReader(const vector& content) + : d_pos(0), d_startrecordpos(0), d_content(content) + { + if(content.size() > std::numeric_limits::max()) + throw std::out_of_range("packet too large"); + + d_recordlen = (uint16_t) content.size(); + not_used = 0; + } + + uint32_t get32BitInt(); + uint16_t get16BitInt(); + uint8_t get8BitInt(); + + void xfr48BitInt(uint64_t& val); + + void xfr32BitInt(uint32_t& val) + { + val=get32BitInt(); + } + + void xfrIP(uint32_t& val) + { + xfr32BitInt(val); + val=htonl(val); + } + + void xfrIP6(std::string &val) { + xfrBlob(val, 16); + } + + void xfrTime(uint32_t& val) + { + xfr32BitInt(val); + } + + + void xfr16BitInt(uint16_t& val) + { + val=get16BitInt(); + } + + void xfrType(uint16_t& val) + { + xfr16BitInt(val); + } + + + void xfr8BitInt(uint8_t& val) + { + val=get8BitInt(); + } + + + void xfrName(DNSName &name, bool compress=false, bool noDot=false) + { + name=getName(); + } + + void xfrText(string &text, bool multi=false, bool lenField=true) + { + text=getText(multi, lenField); + } + + void xfrUnquotedText(string &text, bool lenField){ + text=getUnquotedText(lenField); + } + + void xfrBlob(string& blob); + void xfrBlobNoSpaces(string& blob, int len); + void xfrBlob(string& blob, int length); + void xfrHexBlob(string& blob, bool keepReading=false); + + static uint16_t get16BitInt(const vector&content, uint16_t& pos); + + void getDnsrecordheader(struct dnsrecordheader &ah); + void copyRecord(vector& dest, uint16_t len); + void copyRecord(unsigned char* dest, uint16_t len); + + DNSName getName(); + string getText(bool multi, bool lenField); + string getUnquotedText(bool lenField); + + uint16_t d_pos; + + bool eof() { return true; }; + +private: + uint16_t d_startrecordpos; // needed for getBlob later on + uint16_t d_recordlen; // ditto + uint16_t not_used; // Aligns the whole class on 8-byte boundries + const vector& d_content; +}; + +struct DNSRecord; + +class DNSRecordContent +{ +public: + static std::shared_ptr mastermake(const DNSRecord &dr, PacketReader& pr); + static std::shared_ptr mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode); + static std::shared_ptr mastermake(uint16_t qtype, uint16_t qclass, const string& zone); + static std::unique_ptr makeunique(uint16_t qtype, uint16_t qclass, const string& content); + + virtual std::string getZoneRepresentation(bool noDot=false) const = 0; + virtual ~DNSRecordContent() {} + virtual void toPacket(DNSPacketWriter& pw)=0; + virtual string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard + { + vector packet; + DNSPacketWriter pw(packet, g_rootdnsname, 1); + if(canonic) + pw.setCanonic(true); + + if(lowerCase) + pw.setLowercase(true); + + pw.startRecord(qname, this->getType()); + this->toPacket(pw); + + string record; + pw.getRecordPayload(record); // needs to be called before commit() + return record; + } + + virtual bool operator==(const DNSRecordContent& rhs) const + { + return typeid(*this)==typeid(rhs) && this->getZoneRepresentation() == rhs.getZoneRepresentation(); + } + + static shared_ptr unserialize(const DNSName& qname, uint16_t qtype, const string& serialized); + + void doRecordCheck(const struct DNSRecord&){} + + typedef DNSRecordContent* makerfunc_t(const struct DNSRecord& dr, PacketReader& pr); + typedef DNSRecordContent* zmakerfunc_t(const string& str); + + static void regist(uint16_t cl, uint16_t ty, makerfunc_t* f, zmakerfunc_t* z, const char* name) + { + if(f) + getTypemap()[make_pair(cl,ty)]=f; + if(z) + getZmakermap()[make_pair(cl,ty)]=z; + + getT2Namemap().insert(make_pair(make_pair(cl,ty), name)); + getN2Typemap().insert(make_pair(name, make_pair(cl,ty))); + } + + static void unregist(uint16_t cl, uint16_t ty) + { + pair key=make_pair(cl, ty); + getTypemap().erase(key); + getZmakermap().erase(key); + } + + static uint16_t TypeToNumber(const string& name) + { + n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name)); + if(iter != getN2Typemap().end()) + return iter->second.second; + + if(boost::starts_with(name, "TYPE") || boost::starts_with(name, "type")) + return (uint16_t) pdns_stou(name.substr(4)); + + throw runtime_error("Unknown DNS type '"+name+"'"); + } + + static const string NumberToType(uint16_t num, uint16_t classnum=1) + { + t2namemap_t::const_iterator iter = getT2Namemap().find(make_pair(classnum, num)); + if(iter == getT2Namemap().end()) + return "TYPE" + std::to_string(num); + // throw runtime_error("Unknown DNS type with numerical id "+std::to_string(num)); + return iter->second; + } + + virtual uint16_t getType() const = 0; + +protected: + typedef std::map, makerfunc_t* > typemap_t; + typedef std::map, zmakerfunc_t* > zmakermap_t; + typedef std::map, string > t2namemap_t; + typedef std::map > n2typemap_t; + static typemap_t& getTypemap(); + static t2namemap_t& getT2Namemap(); + static n2typemap_t& getN2Typemap(); + static zmakermap_t& getZmakermap(); +}; + +struct DNSRecord +{ + DNSRecord() { + d_type = 0; + d_class = QClass::IN; + d_ttl = 0; + d_clen = 0; + d_place = DNSResourceRecord::ANSWER; + } + explicit DNSRecord(const DNSResourceRecord& rr); + DNSName d_name; + std::shared_ptr d_content; + uint16_t d_type; + uint16_t d_class; + uint32_t d_ttl; + uint16_t d_clen; + DNSResourceRecord::Place d_place; + + bool operator<(const DNSRecord& rhs) const + { + if(tie(d_name, d_type, d_class, d_ttl) < tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl)) + return true; + + if(tie(d_name, d_type, d_class, d_ttl) != tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl)) + return false; + + string lzrp, rzrp; + if(d_content) + lzrp=toLower(d_content->getZoneRepresentation()); + if(rhs.d_content) + rzrp=toLower(rhs.d_content->getZoneRepresentation()); + + return lzrp < rzrp; + } + + // this orders in canonical order and keeps the SOA record on top + static bool prettyCompare(const DNSRecord& a, const DNSRecord& b) + { + auto aType = (a.d_type == QType::SOA) ? 0 : a.d_type; + auto bType = (b.d_type == QType::SOA) ? 0 : b.d_type; + + if(a.d_name.canonCompare(b.d_name)) + return true; + if(b.d_name.canonCompare(a.d_name)) + return false; + + if(tie(aType, a.d_class, a.d_ttl) < tie(bType, b.d_class, b.d_ttl)) + return true; + + if(tie(aType, a.d_class, a.d_ttl) != tie(bType, b.d_class, b.d_ttl)) + return false; + + string lzrp, rzrp; + if(a.d_content) + lzrp=toLower(a.d_content->getZoneRepresentation()); + if(b.d_content) + rzrp=toLower(b.d_content->getZoneRepresentation()); + + return lzrp < rzrp; + } + + + bool operator==(const DNSRecord& rhs) const + { + if(d_type != rhs.d_type || d_class != rhs.d_class || d_name != rhs.d_name) + return false; + + return *d_content == *rhs.d_content; + } +}; + +struct DNSZoneRecord +{ + int domain_id{-1}; + uint8_t scopeMask{0}; + int signttl{0}; + DNSName wildcardname; + bool auth{true}; + DNSRecord dr; +}; + + +//! This class can be used to parse incoming packets, and is copyable +class MOADNSParser : public boost::noncopyable +{ +public: + //! Parse from a string + MOADNSParser(bool query, const string& buffer) : d_tsigPos(0) + { + init(query, buffer.c_str(), (unsigned int)buffer.size()); + } + + //! Parse from a pointer and length + MOADNSParser(bool query, const char *packet, unsigned int len) : d_tsigPos(0) + { + init(query, packet, len); + } + + DNSName d_qname; + uint16_t d_qclass, d_qtype; + //uint8_t d_rcode; + dnsheader d_header; + + typedef vector > answers_t; + + //! All answers contained in this packet (everything *but* the question section) + answers_t d_answers; + + shared_ptr getPacketReader(uint16_t offset) + { + shared_ptr pr(new PacketReader(d_content)); + pr->d_pos=offset; + return pr; + } + + uint16_t getTSIGPos() const + { + return d_tsigPos; + } +private: + void getDnsrecordheader(struct dnsrecordheader &ah); + void init(bool query, const char *packet, unsigned int len); + vector d_content; + uint16_t d_tsigPos; +}; + +string simpleCompress(const string& label, const string& root=""); +void ageDNSPacket(char* packet, size_t length, uint32_t seconds); +void ageDNSPacket(std::string& packet, uint32_t seconds); +void editDNSPacketTTL(char* packet, size_t length, std::function visitor); +uint32_t getDNSPacketMinTTL(const char* packet, size_t length); +uint32_t getDNSPacketLength(const char* packet, size_t length); +uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type); + +template +std::shared_ptr getRR(const DNSRecord& dr) +{ + return std::dynamic_pointer_cast(dr.d_content); +} + +#endif diff --git a/dnsrecords.cc b/dnsrecords.cc new file mode 100644 index 0000000..6786711 --- /dev/null +++ b/dnsrecords.cc @@ -0,0 +1,652 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "utility.hh" +#include "dnsrecords.hh" +#include "iputils.hh" + + +void DNSResourceRecord::setContent(const string &cont) { + content = cont; + switch(qtype.getCode()) { + case QType::SRV: + case QType::MX: + if (content.size() >= 2 && *(content.rbegin()+1) == ' ') + return; + case QType::CNAME: + case QType::DNAME: + case QType::NS: + case QType::PTR: + if(!content.empty()) + boost::erase_tail(content, 1); + } +} + +string DNSResourceRecord::getZoneRepresentation(bool noDot) const { + ostringstream ret; + vector parts; + string last; + + switch(qtype.getCode()) { + case QType::SRV: + case QType::MX: + stringtok(parts, content); + if (!parts.size()) + return ""; + last = *parts.rbegin(); + ret << content; + if (last == ".") + break; + if (*(last.rbegin()) != '.' && !noDot) + ret << "."; + break; + case QType::CNAME: + case QType::DNAME: + case QType::NS: + case QType::PTR: + ret< >& options) +{ + string::size_type pos=0; + uint16_t code, len; + while(d_data.size() >= 4 + pos) { + code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1]; + len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3]; + pos+=4; + + if(pos + len > d_data.size()) + break; + + string field(d_data.c_str() + pos, len); + pos+=len; + options.push_back(make_pair(code, field)); + } +} + +boilerplate_conv(TSIG, QType::TSIG, + conv.xfrName(d_algoName); + conv.xfr48BitInt(d_time); + conv.xfr16BitInt(d_fudge); + uint16_t size=d_mac.size(); + conv.xfr16BitInt(size); + if (size>0) conv.xfrBlobNoSpaces(d_mac, size); + conv.xfr16BitInt(d_origID); + conv.xfr16BitInt(d_eRcode); + size=d_otherData.size(); + conv.xfr16BitInt(size); + if (size>0) conv.xfrBlobNoSpaces(d_otherData, size); + ); + +MXRecordContent::MXRecordContent(uint16_t preference, const DNSName& mxname): d_preference(preference), d_mxname(mxname) +{ +} + +boilerplate_conv(MX, QType::MX, + conv.xfr16BitInt(d_preference); + conv.xfrName(d_mxname, true); + ) + +boilerplate_conv(KX, QType::KX, + conv.xfr16BitInt(d_preference); + conv.xfrName(d_exchanger, false); + ) + +boilerplate_conv(IPSECKEY, QType::IPSECKEY, + conv.xfr8BitInt(d_preference); + conv.xfr8BitInt(d_gatewaytype); + conv.xfr8BitInt(d_algorithm); + + // now we need to determine values + switch(d_gatewaytype) { + case 0: // NO KEY + break; + case 1: // IPv4 GW + conv.xfrIP(d_ip4); + break; + case 2: // IPv6 GW + conv.xfrIP6(d_ip6); + break; + case 3: // DNS label + conv.xfrName(d_gateway, false); + break; + default: + throw MOADNSException("Parsing record content: invalid gateway type"); + }; + + switch(d_algorithm) { + case 0: + break; + case 1: + case 2: + conv.xfrBlob(d_publickey); + break; + default: + throw MOADNSException("Parsing record content: invalid algorithm type"); + } +) + +boilerplate_conv(DHCID, 49, + conv.xfrBlob(d_content); + ) + + +boilerplate_conv(AFSDB, QType::AFSDB, + conv.xfr16BitInt(d_subtype); + conv.xfrName(d_hostname); + ) + + +boilerplate_conv(NAPTR, QType::NAPTR, + conv.xfr16BitInt(d_order); conv.xfr16BitInt(d_preference); + conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp); + conv.xfrName(d_replacement); + ) + + +SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const DNSName& target) +: d_weight(weight), d_port(port), d_target(target), d_preference(preference) +{} + +boilerplate_conv(SRV, QType::SRV, + conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port); + conv.xfrName(d_target); + ) + +SOARecordContent::SOARecordContent(const DNSName& mname, const DNSName& rname, const struct soatimes& st) +: d_mname(mname), d_rname(rname) +{ + d_st=st; +} + +boilerplate_conv(SOA, QType::SOA, + conv.xfrName(d_mname, true); + conv.xfrName(d_rname, true); + conv.xfr32BitInt(d_st.serial); + conv.xfr32BitInt(d_st.refresh); + conv.xfr32BitInt(d_st.retry); + conv.xfr32BitInt(d_st.expire); + conv.xfr32BitInt(d_st.minimum); + ); +#undef KEY +boilerplate_conv(KEY, QType::KEY, + conv.xfr16BitInt(d_flags); + conv.xfr8BitInt(d_protocol); + conv.xfr8BitInt(d_algorithm); + conv.xfrBlob(d_certificate); + ); + +boilerplate_conv(CERT, 37, + conv.xfr16BitInt(d_type); + if (d_type == 0) throw MOADNSException("CERT type 0 is reserved"); + + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfrBlob(d_certificate); + ) + +boilerplate_conv(TLSA, 52, + conv.xfr8BitInt(d_certusage); + conv.xfr8BitInt(d_selector); + conv.xfr8BitInt(d_matchtype); + conv.xfrHexBlob(d_cert, true); + ) + +boilerplate_conv(OPENPGPKEY, 61, + conv.xfrBlob(d_keyring); + ) + +boilerplate_conv(SMIMEA, 53, + conv.xfr8BitInt(d_certusage); + conv.xfr8BitInt(d_selector); + conv.xfr8BitInt(d_matchtype); + conv.xfrHexBlob(d_cert, true); + ) + +DSRecordContent::DSRecordContent() {} +boilerplate_conv(DS, 43, + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_digesttype); + conv.xfrHexBlob(d_digest, true); // keep reading across spaces + ) + +CDSRecordContent::CDSRecordContent() {} +boilerplate_conv(CDS, 59, + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_digesttype); + conv.xfrHexBlob(d_digest, true); // keep reading across spaces + ) + +DLVRecordContent::DLVRecordContent() {} +boilerplate_conv(DLV,32769 , + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_digesttype); + conv.xfrHexBlob(d_digest, true); // keep reading across spaces + ) + + +boilerplate_conv(SSHFP, 44, + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_fptype); + conv.xfrHexBlob(d_fingerprint, true); + ) + +boilerplate_conv(RRSIG, 46, + conv.xfrType(d_type); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_labels); + conv.xfr32BitInt(d_originalttl); + conv.xfrTime(d_sigexpire); + conv.xfrTime(d_siginception); + conv.xfr16BitInt(d_tag); + conv.xfrName(d_signer); + conv.xfrBlob(d_signature); + ) + +RRSIGRecordContent::RRSIGRecordContent() {} + +boilerplate_conv(DNSKEY, 48, + conv.xfr16BitInt(d_flags); + conv.xfr8BitInt(d_protocol); + conv.xfr8BitInt(d_algorithm); + conv.xfrBlob(d_key); + ) +DNSKEYRecordContent::DNSKEYRecordContent() {} + +boilerplate_conv(CDNSKEY, 60, + conv.xfr16BitInt(d_flags); + conv.xfr8BitInt(d_protocol); + conv.xfr8BitInt(d_algorithm); + conv.xfrBlob(d_key); + ) +CDNSKEYRecordContent::CDNSKEYRecordContent() {} + +boilerplate_conv(RKEY, 57, + conv.xfr16BitInt(d_flags); + conv.xfr8BitInt(d_protocol); + conv.xfrBlob(d_key); + ) +RKEYRecordContent::RKEYRecordContent() {} + +/* EUI48 start */ +void EUI48RecordContent::report(void) +{ + regist(1, QType::EUI48, &make, &make, "EUI48"); +} +DNSRecordContent* EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + if(dr.d_clen!=6) + throw MOADNSException("Wrong size for EUI48 record"); + + EUI48RecordContent* ret=new EUI48RecordContent(); + pr.copyRecord((uint8_t*) &ret->d_eui48, 6); + return ret; +} +DNSRecordContent* EUI48RecordContent::make(const string& zone) +{ + // try to parse + EUI48RecordContent *ret=new EUI48RecordContent(); + // format is 6 hex bytes and dashes + if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", + ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2, + ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) { + throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse"); + } + return ret; +} +void EUI48RecordContent::toPacket(DNSPacketWriter& pw) +{ + string blob(d_eui48, d_eui48+6); + pw.xfrBlob(blob); +} +string EUI48RecordContent::getZoneRepresentation(bool noDot) const +{ + char tmp[18]; + snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x", + d_eui48[0], d_eui48[1], d_eui48[2], + d_eui48[3], d_eui48[4], d_eui48[5]); + return tmp; +} + +/* EUI48 end */ + +/* EUI64 start */ + +void EUI64RecordContent::report(void) +{ + regist(1, QType::EUI64, &make, &make, "EUI64"); +} +DNSRecordContent* EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + if(dr.d_clen!=8) + throw MOADNSException("Wrong size for EUI64 record"); + + EUI64RecordContent* ret=new EUI64RecordContent(); + pr.copyRecord((uint8_t*) &ret->d_eui64, 8); + return ret; +} +DNSRecordContent* EUI64RecordContent::make(const string& zone) +{ + // try to parse + EUI64RecordContent *ret=new EUI64RecordContent(); + // format is 8 hex bytes and dashes + if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", + ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2, + ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5, + ret->d_eui64+6, ret->d_eui64+7) != 8) { + throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse"); + } + return ret; +} +void EUI64RecordContent::toPacket(DNSPacketWriter& pw) +{ + string blob(d_eui64, d_eui64+8); + pw.xfrBlob(blob); +} +string EUI64RecordContent::getZoneRepresentation(bool noDot) const +{ + char tmp[24]; + snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", + d_eui64[0], d_eui64[1], d_eui64[2], + d_eui64[3], d_eui64[4], d_eui64[5], + d_eui64[6], d_eui64[7]); + return tmp; +} + +/* EUI64 end */ + +boilerplate_conv(TKEY, QType::TKEY, + conv.xfrName(d_algo); + conv.xfr32BitInt(d_inception); + conv.xfr32BitInt(d_expiration); + conv.xfr16BitInt(d_mode); + conv.xfr16BitInt(d_error); + conv.xfr16BitInt(d_keysize); + if (d_keysize>0) conv.xfrBlobNoSpaces(d_key, d_keysize); + conv.xfr16BitInt(d_othersize); + if (d_othersize>0) conv.xfrBlobNoSpaces(d_other, d_othersize); + ) +TKEYRecordContent::TKEYRecordContent() { d_othersize = 0; } // fix CID#1288932 + +boilerplate_conv(URI, QType::URI, + conv.xfr16BitInt(d_priority); + conv.xfr16BitInt(d_weight); + conv.xfrText(d_target, true, false); + ) + +boilerplate_conv(CAA, QType::CAA, + conv.xfr8BitInt(d_flags); + conv.xfrUnquotedText(d_tag, true); + conv.xfrText(d_value, true, false); /* no lenField */ + ) + +static uint16_t makeTag(const std::string& data) +{ + const unsigned char* key=(const unsigned char*)data.c_str(); + unsigned int keysize=data.length(); + + unsigned long ac; /* assumed to be 32 bits or larger */ + unsigned int i; /* loop index */ + + for ( ac = 0, i = 0; i < keysize; ++i ) + ac += (i & 1) ? key[i] : key[i] << 8; + ac += (ac >> 16) & 0xFFFF; + return ac & 0xFFFF; +} + +uint16_t DNSKEYRecordContent::getTag() const +{ + DNSKEYRecordContent tmp(*this); + return makeTag(tmp.serialize(DNSName())); // this can't be const for some reason +} + +uint16_t DNSKEYRecordContent::getTag() +{ + return makeTag(this->serialize(DNSName())); +} + + +/* + * Fills `eo` by parsing the EDNS(0) OPT RR (RFC 6891) + */ +bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo) +{ + eo->d_Z=0; + if(mdp.d_header.arcount && !mdp.d_answers.empty()) { + for(const MOADNSParser::answers_t::value_type& val : mdp.d_answers) { + if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) { + eo->d_packetsize=val.first.d_class; + + EDNS0Record stuff; + uint32_t ttl=ntohl(val.first.d_ttl); + static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)"); + memcpy(&stuff, &ttl, sizeof(stuff)); + + eo->d_extRCode=stuff.extRCode; + eo->d_version=stuff.version; + eo->d_Z = ntohs(stuff.Z); + OPTRecordContent* orc = + dynamic_cast(val.first.d_content.get()); + if(!orc) + return false; + orc->getData(eo->d_options); + return true; + } + } + } + return false; +} + +DNSRecord makeOpt(int udpsize, int extRCode, int Z) +{ + EDNS0Record stuff; + stuff.extRCode=0; + stuff.version=0; + stuff.Z=htons(Z); + DNSRecord dr; + static_assert(sizeof(EDNS0Record) == sizeof(dr.d_ttl), "sizeof(EDNS0Record) must match sizeof(DNSRecord.d_ttl)"); + memcpy(&dr.d_ttl, &stuff, sizeof(stuff)); + dr.d_ttl=ntohl(dr.d_ttl); + dr.d_name=g_rootdnsname; + dr.d_type = QType::OPT; + dr.d_class=udpsize; + dr.d_place=DNSResourceRecord::ADDITIONAL; + dr.d_content = std::make_shared(); + // if we ever do options, I think we stuff them into OPTRecordContent::data + return dr; +} + + +void reportBasicTypes() +{ + ARecordContent::report(); + AAAARecordContent::report(); + NSRecordContent::report(); + CNAMERecordContent::report(); + MXRecordContent::report(); + SOARecordContent::report(); + SRVRecordContent::report(); + PTRRecordContent::report(); + DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT"); + TXTRecordContent::report(); + DNSRecordContent::regist(QClass::IN, QType::ANY, 0, 0, "ANY"); + DNSRecordContent::regist(QClass::IN, QType::AXFR, 0, 0, "AXFR"); + DNSRecordContent::regist(QClass::IN, QType::IXFR, 0, 0, "IXFR"); +} + +void reportOtherTypes() +{ + AFSDBRecordContent::report(); + DNAMERecordContent::report(); + ALIASRecordContent::report(); + SPFRecordContent::report(); + NAPTRRecordContent::report(); + LOCRecordContent::report(); + ENTRecordContent::report(); + HINFORecordContent::report(); + RPRecordContent::report(); + KEYRecordContent::report(); + DNSKEYRecordContent::report(); + DHCIDRecordContent::report(); + CDNSKEYRecordContent::report(); + RKEYRecordContent::report(); + RRSIGRecordContent::report(); + DSRecordContent::report(); + CDSRecordContent::report(); + SSHFPRecordContent::report(); + CERTRecordContent::report(); + NSECRecordContent::report(); + NSEC3RecordContent::report(); + NSEC3PARAMRecordContent::report(); + TLSARecordContent::report(); + SMIMEARecordContent::report(); + OPENPGPKEYRecordContent::report(); + DLVRecordContent::report(); + DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG"); + DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY"); + //TSIGRecordContent::report(); + OPTRecordContent::report(); + EUI48RecordContent::report(); + EUI64RecordContent::report(); + MINFORecordContent::report(); + URIRecordContent::report(); + CAARecordContent::report(); +} + +void reportAllTypes() +{ + reportBasicTypes(); + reportOtherTypes(); +} + +ComboAddress getAddr(const DNSRecord& dr, uint16_t defport) +{ + if(auto addr=getRR(dr)) { + return addr->getCA(defport); + } + else + return getRR(dr)->getCA(defport); +} + + +#if 0 +static struct Reporter +{ + Reporter() + { + reportAllTypes(); + } +} reporter __attribute__((init_priority(65535))); +#endif diff --git a/dnsrecords.hh b/dnsrecords.hh new file mode 100644 index 0000000..55afedb --- /dev/null +++ b/dnsrecords.hh @@ -0,0 +1,769 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_DNSRECORDS_HH +#define PDNS_DNSRECORDS_HH + +#include "dnsparser.hh" +#include "dnswriter.hh" +#include "rcpgenerator.hh" +#include +#include +#include "namespaces.hh" + +#define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \ + RNAME##RecordContent(const string& zoneData); \ + static void report(void); \ + static void unreport(void); \ + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); \ + static DNSRecordContent* make(const string& zonedata); \ + string getZoneRepresentation(bool noDot=false) const override; \ + void toPacket(DNSPacketWriter& pw) override; \ + uint16_t getType() const override { return QType::RNAME; } \ + template void xfrPacket(Convertor& conv, bool noDot=false); + +class NAPTRRecordContent : public DNSRecordContent +{ +public: + NAPTRRecordContent(uint16_t order, uint16_t preference, string flags, string services, string regexp, DNSName replacement); + + includeboilerplate(NAPTR); + template void xfrRecordContent(Convertor& conv); +private: + uint16_t d_order, d_preference; + string d_flags, d_services, d_regexp; + DNSName d_replacement; +}; + + +class ARecordContent : public DNSRecordContent +{ +public: + explicit ARecordContent(const ComboAddress& ca); + explicit ARecordContent(uint32_t ip); + includeboilerplate(A); + void doRecordCheck(const DNSRecord& dr); + ComboAddress getCA(int port=0) const; + bool operator==(const DNSRecordContent& rhs) const override + { + if(typeid(*this) != typeid(rhs)) + return false; + return d_ip == dynamic_cast(rhs).d_ip; + } +private: + uint32_t d_ip; +}; + +class AAAARecordContent : public DNSRecordContent +{ +public: + AAAARecordContent(std::string &val); + explicit AAAARecordContent(const ComboAddress& ca); + includeboilerplate(AAAA); + ComboAddress getCA(int port=0) const; + bool operator==(const DNSRecordContent& rhs) const override + { + if(typeid(*this) != typeid(rhs)) + return false; + return d_ip6 == dynamic_cast(&rhs)->d_ip6; + } +private: + string d_ip6; // why?? +}; + +class MXRecordContent : public DNSRecordContent +{ +public: + MXRecordContent(uint16_t preference, const DNSName& mxname); + + includeboilerplate(MX) + + uint16_t d_preference; + DNSName d_mxname; + + bool operator==(const DNSRecordContent& rhs) const override + { + if(typeid(*this) != typeid(rhs)) + return false; + auto rrhs =dynamic_cast(&rhs); + return std::tie(d_preference, d_mxname) == std::tie(rrhs->d_preference, rrhs->d_mxname); + } + +}; + +class KXRecordContent : public DNSRecordContent +{ +public: + KXRecordContent(uint16_t preference, const DNSName& exchanger); + + includeboilerplate(KX) + +private: + uint16_t d_preference; + DNSName d_exchanger; +}; + +class IPSECKEYRecordContent : public DNSRecordContent +{ +public: + IPSECKEYRecordContent(uint16_t preference, uint8_t gatewaytype, uint8_t algo, const DNSName& gateway, const string& publickey); + + includeboilerplate(IPSECKEY) + +private: + uint32_t d_ip4; + DNSName d_gateway; + string d_publickey; + string d_ip6; + uint8_t d_preference, d_gatewaytype, d_algorithm; +}; + +class DHCIDRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(DHCID) + +private: + string d_content; +}; + + +class SRVRecordContent : public DNSRecordContent +{ +public: + SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const DNSName& target); + + includeboilerplate(SRV) + + uint16_t d_weight, d_port; + DNSName d_target; + uint16_t d_preference; +}; + +class TSIGRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(TSIG) + TSIGRecordContent() {} + + uint16_t d_origID{0}; + uint16_t d_fudge{0}; + + DNSName d_algoName; + string d_mac; + string d_otherData; + uint64_t d_time{0}; + // uint16_t d_macSize; + uint16_t d_eRcode{0}; + // uint16_t d_otherLen +}; + + +class TXTRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(TXT) + + string d_text; +}; + +class ENTRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(ENT) +}; + +class SPFRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(SPF) + +private: + string d_text; +}; + + +class NSRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(NS) + explicit NSRecordContent(const DNSName& content) : d_content(content){} + const DNSName& getNS() const { return d_content; } + bool operator==(const DNSRecordContent& rhs) const override + { + if(typeid(*this) != typeid(rhs)) + return false; + auto rrhs =dynamic_cast(&rhs); + return d_content == rrhs->d_content; + } + +private: + DNSName d_content; +}; + +class PTRRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(PTR) + explicit PTRRecordContent(const DNSName& content) : d_content(content){} +private: + DNSName d_content; +}; + +class CNAMERecordContent : public DNSRecordContent +{ +public: + includeboilerplate(CNAME) + CNAMERecordContent(const DNSName& content) : d_content(content){} + DNSName getTarget() const { return d_content; } +private: + DNSName d_content; +}; + +class ALIASRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(ALIAS) + + DNSName d_content; +}; + + +class DNAMERecordContent : public DNSRecordContent +{ +public: + includeboilerplate(DNAME) + DNSName d_content; +}; + + +class MRRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(MR) + +private: + DNSName d_alias; +}; + +class MINFORecordContent : public DNSRecordContent +{ +public: + includeboilerplate(MINFO) + +private: + DNSName d_rmailbx; + DNSName d_emailbx; +}; + +class OPTRecordContent : public DNSRecordContent +{ +public: + OPTRecordContent(){} + includeboilerplate(OPT) + void getData(vector > &opts); +private: + string d_data; +}; + + +class HINFORecordContent : public DNSRecordContent +{ +public: + includeboilerplate(HINFO) + +private: + string d_cpu, d_host; +}; + +class RPRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(RP) + +private: + DNSName d_mbox, d_info; +}; + + +class DNSKEYRecordContent : public DNSRecordContent +{ +public: + DNSKEYRecordContent(); + includeboilerplate(DNSKEY) + uint16_t getTag() const; + uint16_t getTag(); + + uint16_t d_flags{0}; + uint8_t d_protocol{0}; + uint8_t d_algorithm{0}; + string d_key; + bool operator<(const DNSKEYRecordContent& rhs) const + { + return tie(d_flags, d_protocol, d_algorithm, d_key) < + tie(rhs.d_flags, rhs.d_protocol, rhs.d_algorithm, rhs.d_key); + } +}; + +class CDNSKEYRecordContent : public DNSRecordContent +{ +public: + CDNSKEYRecordContent(); + includeboilerplate(CDNSKEY) + uint16_t getTag(); + + uint16_t d_flags{0}; + uint8_t d_protocol{0}; + uint8_t d_algorithm{0}; + string d_key; +}; + +class DSRecordContent : public DNSRecordContent +{ +public: + DSRecordContent(); + bool operator==(const DNSRecordContent& rhs) const override + { + if(typeid(*this) != typeid(rhs)) + return false; + auto rrhs =dynamic_cast(&rhs); + return tie(d_tag, d_algorithm, d_digesttype, d_digest) == + tie(rrhs->d_tag, rrhs->d_algorithm, rrhs->d_digesttype, rrhs->d_digest); + } + bool operator<(const DSRecordContent& rhs) const + { + return tie(d_tag, d_algorithm, d_digesttype, d_digest) < + tie(rhs.d_tag, rhs.d_algorithm, rhs.d_digesttype, rhs.d_digest); + } + + includeboilerplate(DS) + + uint16_t d_tag{0}; + uint8_t d_algorithm{0}, d_digesttype{0}; + string d_digest; +}; + +class CDSRecordContent : public DNSRecordContent +{ +public: + CDSRecordContent(); + includeboilerplate(CDS) + + uint16_t d_tag{0}; + uint8_t d_algorithm{0}, d_digesttype{0}; + string d_digest; +}; + +class DLVRecordContent : public DNSRecordContent +{ +public: + DLVRecordContent(); + includeboilerplate(DLV) + + uint16_t d_tag{0}; + uint8_t d_algorithm{0}, d_digesttype{0}; + string d_digest; +}; + + +class SSHFPRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(SSHFP) + +private: + uint8_t d_algorithm, d_fptype; + string d_fingerprint; +}; + +class KEYRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(KEY) + +private: + uint16_t d_flags; + uint8_t d_protocol, d_algorithm; + string d_certificate; +}; + +class AFSDBRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(AFSDB) + +private: + uint16_t d_subtype; + DNSName d_hostname; +}; + + +class CERTRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(CERT) + +private: + uint16_t d_type, d_tag; + string d_certificate; + uint8_t d_algorithm; +}; + +class TLSARecordContent : public DNSRecordContent +{ +public: + includeboilerplate(TLSA) + +private: + uint8_t d_certusage, d_selector, d_matchtype; + string d_cert; +}; + +class SMIMEARecordContent : public DNSRecordContent +{ +public: + includeboilerplate(SMIMEA) + +private: + uint8_t d_certusage, d_selector, d_matchtype; + string d_cert; +}; + +class OPENPGPKEYRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(OPENPGPKEY) + +private: + string d_keyring; +}; + + +class RRSIGRecordContent : public DNSRecordContent +{ +public: + RRSIGRecordContent(); + includeboilerplate(RRSIG) + + uint16_t d_type{0}; + uint16_t d_tag{0}; + DNSName d_signer; + string d_signature; + uint32_t d_originalttl{0}, d_sigexpire{0}, d_siginception{0}; + uint8_t d_algorithm{0}, d_labels{0}; +}; + +//namespace { + struct soatimes + { + uint32_t serial; + uint32_t refresh; + uint32_t retry; + uint32_t expire; + uint32_t minimum; + }; +//} + +class RKEYRecordContent : public DNSRecordContent +{ +public: + RKEYRecordContent(); + includeboilerplate(RKEY) + uint16_t d_flags{0}; + uint8_t d_protocol{0}, d_algorithm{0}; + string d_key; +}; + +class SOARecordContent : public DNSRecordContent +{ +public: + includeboilerplate(SOA) + SOARecordContent(const DNSName& mname, const DNSName& rname, const struct soatimes& st); + + struct soatimes d_st; + DNSName d_mname; + DNSName d_rname; +}; + +class NSECRecordContent : public DNSRecordContent +{ +public: + static void report(void); + NSECRecordContent() + {} + NSECRecordContent(const string& content, const string& zone=""); //FIXME400: DNSName& zone? + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation(bool noDot=false) const override; + void toPacket(DNSPacketWriter& pw) override; + uint16_t getType() const override + { + return QType::NSEC; + } + DNSName d_next; + std::set d_set; +private: +}; + +class NSEC3RecordContent : public DNSRecordContent +{ +public: + static void report(void); + NSEC3RecordContent() + {} + NSEC3RecordContent(const string& content, const string& zone=""); //FIXME400: DNSName& zone? + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation(bool noDot=false) const override; + void toPacket(DNSPacketWriter& pw) override; + + uint8_t d_algorithm{0}, d_flags{0}; + uint16_t d_iterations{0}; + string d_salt; + string d_nexthash; + std::set d_set; + + uint16_t getType() const override + { + return QType::NSEC3; + } + + +private: +}; + + +class NSEC3PARAMRecordContent : public DNSRecordContent +{ +public: + static void report(void); + NSEC3PARAMRecordContent() + {} + NSEC3PARAMRecordContent(const string& content, const string& zone=""); // FIXME400: DNSName& zone? + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation(bool noDot=false) const override; + void toPacket(DNSPacketWriter& pw) override; + + uint16_t getType() const override + { + return QType::NSEC3PARAM; + } + + + uint8_t d_algorithm{0}, d_flags{0}; + uint16_t d_iterations{0}; + string d_salt; +}; + + +class LOCRecordContent : public DNSRecordContent +{ +public: + static void report(void); + LOCRecordContent() + {} + LOCRecordContent(const string& content, const string& zone=""); + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation(bool noDot=false) const override; + void toPacket(DNSPacketWriter& pw) override; + + uint8_t d_version{0}, d_size{0}, d_horizpre{0}, d_vertpre{0}; + uint32_t d_latitude{0}, d_longitude{0}, d_altitude{0}; + uint16_t getType() const override + { + return QType::LOC; + } + +private: +}; + + +class WKSRecordContent : public DNSRecordContent +{ +public: + static void report(void); + WKSRecordContent() + {} + WKSRecordContent(const string& content, const string& zone=""); // FIXME400: DNSName& zone? + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation(bool noDot=false) const override; + void toPacket(DNSPacketWriter& pw) override; + + uint32_t d_ip{0}; + std::bitset<65535> d_services; +private: +}; + +class EUI48RecordContent : public DNSRecordContent +{ +public: + EUI48RecordContent() {}; + static void report(void); + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& zone); // FIXME400: DNSName& zone? + string getZoneRepresentation(bool noDot=false) const override; + void toPacket(DNSPacketWriter& pw) override; + uint16_t getType() const override { return QType::EUI48; } +private: + // storage for the bytes + uint8_t d_eui48[6]; +}; + +class EUI64RecordContent : public DNSRecordContent +{ +public: + EUI64RecordContent() {}; + static void report(void); + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& zone); // FIXME400: DNSName& zone? + string getZoneRepresentation(bool noDot=false) const override; + void toPacket(DNSPacketWriter& pw) override; + uint16_t getType() const override { return QType::EUI64; } +private: + // storage for the bytes + uint8_t d_eui64[8]; +}; + +class TKEYRecordContent : public DNSRecordContent +{ +public: + TKEYRecordContent(); + includeboilerplate(TKEY) + + // storage for the bytes + uint16_t d_othersize{0}; + uint16_t d_mode{0}; + uint32_t d_inception{0}; + uint32_t d_expiration{0}; + + DNSName d_algo; + string d_key; + string d_other; + + uint16_t d_error{0}; + uint16_t d_keysize{0}; +private: +}; + +class URIRecordContent : public DNSRecordContent { + public: + includeboilerplate(URI) + private: + uint16_t d_priority, d_weight; + string d_target; +}; + +class CAARecordContent : public DNSRecordContent { + public: + includeboilerplate(CAA) + private: + uint8_t d_flags; + string d_tag, d_value; +}; + +#define boilerplate(RNAME, RTYPE) \ +RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \ +{ \ + return new RNAME##RecordContent(dr, pr); \ +} \ + \ +RNAME##RecordContent::RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr) \ +{ \ + doRecordCheck(dr); \ + xfrPacket(pr); \ +} \ + \ +RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const string& zonedata) \ +{ \ + return new RNAME##RecordContent(zonedata); \ +} \ + \ +void RNAME##RecordContent::toPacket(DNSPacketWriter& pw) \ +{ \ + this->xfrPacket(pw); \ +} \ + \ +void RNAME##RecordContent::report(void) \ +{ \ + regist(1, RTYPE, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME); \ + regist(254, RTYPE, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME); \ +} \ +void RNAME##RecordContent::unreport(void) \ +{ \ + unregist(1, RTYPE); \ + unregist(254, RTYPE); \ +} \ + \ +RNAME##RecordContent::RNAME##RecordContent(const string& zoneData) \ +{ \ + try { \ + RecordTextReader rtr(zoneData); \ + xfrPacket(rtr); \ + } \ + catch(RecordTextException& rtr) { \ + throw MOADNSException("Parsing record content (try 'pdnsutil check-zone'): "+string(rtr.what())); \ + } \ +} \ + \ +string RNAME##RecordContent::getZoneRepresentation(bool noDot) const \ +{ \ + string ret; \ + RecordTextWriter rtw(ret, noDot); \ + const_cast(this)->xfrPacket(rtw); \ + return ret; \ +} + + +#define boilerplate_conv(RNAME, TYPE, CONV) \ +boilerplate(RNAME, TYPE) \ +template \ +void RNAME##RecordContent::xfrPacket(Convertor& conv, bool noDot) \ +{ \ + CONV; \ + if (conv.eof() == false) throw MOADNSException("All data was not consumed"); \ +} \ + +struct EDNSOpts +{ + enum zFlags { DNSSECOK=32768 }; + vector > d_options; + uint16_t d_packetsize{0}; + uint16_t d_Z{0}; + uint8_t d_extRCode, d_version; +}; +//! Convenience function that fills out EDNS0 options, and returns true if there are any + +class MOADNSParser; +bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo); +DNSRecord makeOpt(int udpsize, int extRCode, int Z); +void reportBasicTypes(); +void reportOtherTypes(); +void reportAllTypes(); +ComboAddress getAddr(const DNSRecord& dr, uint16_t defport=0); +#endif diff --git a/dnssecinfra.cc b/dnssecinfra.cc new file mode 100644 index 0000000..315691a --- /dev/null +++ b/dnssecinfra.cc @@ -0,0 +1,755 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "dnsparser.hh" +#include "sstuff.hh" +#include "misc.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" +#ifndef RECURSOR +#include "statbag.hh" +#endif +#include "iputils.hh" + +#include +#include "dnssecinfra.hh" +#include "dnsseckeeper.hh" +#include +#include +#include // for 'operator+=()' +#include +#include "base64.hh" +#include "namespaces.hh" +#ifdef HAVE_P11KIT1 +#include "pkcs11signers.hh" +#endif +#include "gss_context.hh" +#include "misc.hh" + +using namespace boost::assign; + +shared_ptr DNSCryptoKeyEngine::makeFromISCFile(DNSKEYRecordContent& drc, const char* fname) +{ + string sline, isc; + FILE *fp=fopen(fname, "r"); + if(!fp) { + throw runtime_error("Unable to read file '"+string(fname)+"' for generating DNS Private Key"); + } + + while(stringfgets(fp, sline)) { + isc += sline; + } + fclose(fp); + shared_ptr dke = makeFromISCString(drc, isc); + if(!dke->checkKey()) { + throw runtime_error("Invalid DNS Private Key in file '"+string(fname)); + } + return dke; +} + +shared_ptr DNSCryptoKeyEngine::makeFromISCString(DNSKEYRecordContent& drc, const std::string& content) +{ + bool pkcs11=false; + int algorithm = 0; + string sline, key, value, raw; + std::istringstream str(content); + map stormap; + + while(std::getline(str, sline)) { + tie(key,value)=splitField(sline, ':'); + trim(value); + if(pdns_iequals(key,"algorithm")) { + algorithm = pdns_stou(value); + stormap["algorithm"]=std::to_string(algorithm); + continue; + } else if (pdns_iequals(key,"pin")) { + stormap["pin"]=value; + continue; + } else if (pdns_iequals(key,"engine")) { + stormap["engine"]=value; + pkcs11=true; + continue; + } else if (pdns_iequals(key,"slot")) { + stormap["slot"]=value; + continue; + } else if (pdns_iequals(key,"label")) { + stormap["label"]=value; + continue; + } + else if(pdns_iequals(key, "Private-key-format")) + continue; + raw.clear(); + B64Decode(value, raw); + stormap[toLower(key)]=raw; + } + shared_ptr dpk; + + if (pkcs11) { +#ifdef HAVE_P11KIT1 + if (stormap.find("slot") == stormap.end()) + throw PDNSException("Cannot load PKCS#11 key, no Slot specified"); + // we need PIN to be at least empty + if (stormap.find("pin") == stormap.end()) stormap["pin"] = ""; + dpk = PKCS11DNSCryptoKeyEngine::maker(algorithm); +#else + throw PDNSException("Cannot load PKCS#11 key without support for it"); +#endif + } else { + dpk=make(algorithm); + } + dpk->fromISCMap(drc, stormap); + return dpk; +} + +std::string DNSCryptoKeyEngine::convertToISC() const +{ + typedef map stormap_t; + storvector_t stormap = this->convertToISCVector(); + ostringstream ret; + ret<<"Private-key-format: v1.2\n"; + for(const stormap_t::value_type& value : stormap) { + if(value.first != "Algorithm" && value.first != "PIN" && + value.first != "Slot" && value.first != "Engine" && + value.first != "Label") + ret< DNSCryptoKeyEngine::make(unsigned int algo) +{ + const makers_t& makers = getMakers(); + makers_t::const_iterator iter = makers.find(algo); + if(iter != makers.cend()) + return (iter->second)(algo); + else { + throw runtime_error("Request to create key object for unknown algorithm number "+std::to_string(algo)); + } +} + +/** + * Returns the supported DNSSEC algorithms with the name of the Crypto Backend used + * + * @return A vector with pairs of (algorithm-number (int), backend-name (string)) + */ +vector> DNSCryptoKeyEngine::listAllAlgosWithBackend() +{ + vector> ret; + for (auto const& value : getMakers()) { + shared_ptr dcke(value.second(value.first)); + ret.push_back(make_pair(value.first, dcke->getName())); + } + return ret; +} + +void DNSCryptoKeyEngine::report(unsigned int algo, maker_t* maker, bool fallback) +{ + getAllMakers()[algo].push_back(maker); + if(getMakers().count(algo) && fallback) { + return; + } + getMakers()[algo]=maker; +} + +bool DNSCryptoKeyEngine::testAll() +{ + bool ret=true; + + for(const allmakers_t::value_type& value : getAllMakers()) + { + for(maker_t* creator : value.second) { + + for(maker_t* signer : value.second) { + // multi_map bestSigner, bestVerifier; + + for(maker_t* verifier : value.second) { + try { + /* pair res=*/ testMakers(value.first, creator, signer, verifier); + } + catch(std::exception& e) + { + cerr< bestSigner, bestVerifier; + + for(maker_t* verifier : getAllMakers()[algo]) { + try { + /* pair res=*/testMakers(algo, creator, signer, verifier); + } + catch(std::exception& e) + { + cerr< DNSCryptoKeyEngine::testMakers(unsigned int algo, maker_t* creator, maker_t* signer, maker_t* verifier) +{ + shared_ptr dckeCreate(creator(algo)); + shared_ptr dckeSign(signer(algo)); + shared_ptr dckeVerify(verifier(algo)); + + cerr<<"Testing algorithm "<getName()<<"' ->'"<getName()<<"' -> '"<getName()<<"' "; + unsigned int bits; + if(algo <= 10) + bits=1024; + else if(algo == 12 || algo == 13 || algo == 15) // ECC-GOST or ECDSAP256SHA256 or ED25519 + bits=256; + else if(algo == 14) // ECDSAP384SHA384 + bits = 384; + else if(algo == 16) // ED448 + bits = 456; + else + throw runtime_error("Can't guess key size for algorithm "+std::to_string(algo)); + + dckeCreate->create(bits); + + { // FIXME: this block copy/pasted from makeFromISCString + DNSKEYRecordContent dkrc; + int algorithm = 0; + string sline, key, value, raw; + std::istringstream str(dckeCreate->convertToISC()); + map stormap; + + while(std::getline(str, sline)) { + tie(key,value)=splitField(sline, ':'); + trim(value); + if(pdns_iequals(key,"algorithm")) { + algorithm = pdns_stou(value); + stormap["algorithm"]=std::to_string(algorithm); + continue; + } else if (pdns_iequals(key,"pin")) { + stormap["pin"]=value; + continue; + } else if (pdns_iequals(key,"engine")) { + stormap["engine"]=value; + continue; + } else if (pdns_iequals(key,"slot")) { + int slot = std::stoi(value); + stormap["slot"]=std::to_string(slot); + continue; + } else if (pdns_iequals(key,"label")) { + stormap["label"]=value; + continue; + } + else if(pdns_iequals(key, "Private-key-format")) + continue; + raw.clear(); + B64Decode(value, raw); + stormap[toLower(key)]=raw; + } + dckeSign->fromISCMap(dkrc, stormap); + if(!dckeSign->checkKey()) { + throw runtime_error("Verification of key with creator "+dckeCreate->getName()+" with signer "+dckeSign->getName()+" and verifier "+dckeVerify->getName()+" failed"); + } + } + + string message("Hi! How is life?"); + + string signature; + DTime dt; dt.set(); + for(unsigned int n = 0; n < 100; ++n) + signature = dckeSign->sign(message); + unsigned int udiffSign= dt.udiff()/100, udiffVerify; + + dckeVerify->fromPublicKeyString(dckeSign->getPublicKeyString()); + if (dckeVerify->getPublicKeyString().compare(dckeSign->getPublicKeyString())) { + throw runtime_error("Comparison of public key loaded into verifier produced by signer failed"); + } + dt.set(); + if(dckeVerify->verify(message, signature)) { + udiffVerify = dt.udiff(); + cerr<<"Signature & verify ok, signature "<getName()+" with signer "+dckeSign->getName()+" and verifier "+dckeVerify->getName()+" failed"); + } + return make_pair(udiffSign, udiffVerify); +} + +shared_ptr DNSCryptoKeyEngine::makeFromPublicKeyString(unsigned int algorithm, const std::string& content) +{ + shared_ptr dpk=make(algorithm); + dpk->fromPublicKeyString(content); + return dpk; +} + + +shared_ptr DNSCryptoKeyEngine::makeFromPEMString(DNSKEYRecordContent& drc, const std::string& raw) +{ + + for(const makers_t::value_type& val : getMakers()) + { + shared_ptr ret=nullptr; + try { + ret = val.second(val.first); + ret->fromPEMString(drc, raw); + return ret; + } + catch(...) + { + } + } + return 0; +} + + +static bool sharedDNSSECCompare(const shared_ptr& a, const shared_ptr& b) +{ + return a->serialize(g_rootdnsname, true, true) < b->serialize(g_rootdnsname, true, true); +} + +/** + * Returns the string that should be hashed to create/verify the RRSIG content + * + * @param qname DNSName of the RRSIG's owner name. + * @param rrc The RRSIGRecordContent we take the Type Covered and + * original TTL fields from. + * @param signRecords A vector of DNSRecordContent shared_ptr's that are covered + * by the RRSIG, where we get the RDATA from. + * @param processRRSIGLabels A boolean to trigger processing the RRSIG's "Labels" + * field. This is usually only needed for validation + * purposes, as the authoritative server correctly + * sets qname to the wildcard. + */ +string getMessageForRRSET(const DNSName& qname, const RRSIGRecordContent& rrc, vector >& signRecords, bool processRRSIGLabels) +{ + sort(signRecords.begin(), signRecords.end(), sharedDNSSECCompare); + + string toHash; + toHash.append(const_cast(rrc).serialize(g_rootdnsname, true, true)); + toHash.resize(toHash.size() - rrc.d_signature.length()); // chop off the end, don't sign the signature! + + string nameToHash(qname.toDNSStringLC()); + + if (processRRSIGLabels) { + unsigned int rrsig_labels = rrc.d_labels; + unsigned int fqdn_labels = qname.countLabels(); + + if (rrsig_labels < fqdn_labels) { + DNSName choppedQname(qname); + while (choppedQname.countLabels() > rrsig_labels) + choppedQname.chopOff(); + nameToHash = "\x01*" + choppedQname.toDNSStringLC(); + } else if (rrsig_labels > fqdn_labels) { + // The RRSIG Labels field is a lie (or the qname is wrong) and the RRSIG + // can never be valid + return ""; + } + } + + for(shared_ptr& add : signRecords) { + toHash.append(nameToHash); + uint16_t tmp=htons(rrc.d_type); + toHash.append((char*)&tmp, 2); + tmp=htons(1); // class + toHash.append((char*)&tmp, 2); + uint32_t ttl=htonl(rrc.d_originalttl); + toHash.append((char*)&ttl, 4); + // for NSEC signatures, we should not lowercase the rdata section + string rdata=add->serialize(g_rootdnsname, true, (add->getType() == QType::NSEC) ? false : true); // RFC 6840, 5.1 + tmp=htons(rdata.length()); + toHash.append((char*)&tmp, 2); + toHash.append(rdata); + } + + return toHash; +} + +bool DNSCryptoKeyEngine::isAlgorithmSupported(unsigned int algo) +{ + const makers_t& makers = getMakers(); + makers_t::const_iterator iter = makers.find(algo); + return iter != makers.cend(); +} + +static unsigned int digestToAlgorithmNumber(uint8_t digest) +{ + switch(digest) { + case DNSSECKeeper::SHA1: + return DNSSECKeeper::RSASHA1; + case DNSSECKeeper::SHA256: + return DNSSECKeeper::RSASHA256; + case DNSSECKeeper::GOST: + return DNSSECKeeper::ECCGOST; + case DNSSECKeeper::SHA384: + return DNSSECKeeper::ECDSA384; + default: + throw std::runtime_error("Unknown digest type " + std::to_string(digest)); + } + return 0; +} + +bool DNSCryptoKeyEngine::isDigestSupported(uint8_t digest) +{ + try { + unsigned int algo = digestToAlgorithmNumber(digest); + return isAlgorithmSupported(algo); + } + catch(const std::exception& e) { + return false; + } +} + +DSRecordContent makeDSFromDNSKey(const DNSName& qname, const DNSKEYRecordContent& drc, uint8_t digest) +{ + string toHash; + toHash.assign(qname.toDNSStringLC()); + toHash.append(const_cast(drc).serialize(DNSName(), true, true)); + + DSRecordContent dsrc; + try { + unsigned int algo = digestToAlgorithmNumber(digest); + shared_ptr dpk(DNSCryptoKeyEngine::make(algo)); + dsrc.d_digest = dpk->hash(toHash); + } + catch(const std::exception& e) { + throw std::runtime_error("Asked to a DS of unknown digest type " + std::to_string(digest)+"\n"); + } + + dsrc.d_algorithm = drc.d_algorithm; + dsrc.d_digesttype = digest; + dsrc.d_tag = const_cast(drc).getTag(); + + return dsrc; +} + + +static DNSKEYRecordContent makeDNSKEYFromDNSCryptoKeyEngine(const std::shared_ptr pk, uint8_t algorithm, uint16_t flags) +{ + DNSKEYRecordContent drc; + + drc.d_protocol=3; + drc.d_algorithm = algorithm; + + drc.d_flags=flags; + drc.d_key = pk->getPublicKeyString(); + + return drc; +} + +uint32_t getStartOfWeek() +{ + uint32_t now = time(0); + now -= (now % (7*86400)); + return now; +} + +string hashQNameWithSalt(const NSEC3PARAMRecordContent& ns3prc, const DNSName& qname) +{ + return hashQNameWithSalt(ns3prc.d_salt, ns3prc.d_iterations, qname); +} + +string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const DNSName& qname) +{ + unsigned int times = iterations; + unsigned char hash[20]; + string toHash(qname.toDNSStringLC()); + + for(;;) { + toHash.append(salt); + SHA1((unsigned char*)toHash.c_str(), toHash.length(), hash); + toHash.assign((char*)hash, sizeof(hash)); + if(!times--) + break; + } + return toHash; +} + +void incrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-) +{ + if(raw.empty()) + return; + + for(string::size_type pos=raw.size(); pos; ) { + --pos; + unsigned char c = (unsigned char)raw[pos]; + ++c; + raw[pos] = (char) c; + if(c) + break; + } +} + +void decrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-) +{ + if(raw.empty()) + return; + + for(string::size_type pos=raw.size(); pos; ) { + --pos; + unsigned char c = (unsigned char)raw[pos]; + --c; + raw[pos] = (char) c; + if(c != 0xff) + break; + } +} + +DNSKEYRecordContent DNSSECPrivateKey::getDNSKEY() const +{ + return makeDNSKEYFromDNSCryptoKeyEngine(getKey(), d_algorithm, d_flags); +} + +class DEREater +{ +public: + DEREater(const std::string& str) : d_str(str), d_pos(0) + {} + + struct eof{}; + + uint8_t getByte() + { + if(d_pos >= d_str.length()) { + throw eof(); + } + return (uint8_t) d_str[d_pos++]; + } + + uint32_t getLength() + { + uint8_t first = getByte(); + if(first < 0x80) { + return first; + } + first &= ~0x80; + + uint32_t len=0; + for(int n=0; n < first; ++n) { + len *= 0x100; + len += getByte(); + } + return len; + } + + std::string getBytes(unsigned int len) + { + std::string ret; + for(unsigned int n=0; n < len; ++n) + ret.append(1, (char)getByte()); + return ret; + } + + std::string::size_type getOffset() + { + return d_pos; + } +private: + const std::string& d_str; + std::string::size_type d_pos; +}; + +static string calculateHMAC(const std::string& key, const std::string& text, TSIGHashEnum hasher) { + + const EVP_MD* md_type; + unsigned int outlen; + unsigned char hash[EVP_MAX_MD_SIZE]; + switch(hasher) { + case TSIG_MD5: + md_type = EVP_md5(); + break; + case TSIG_SHA1: + md_type = EVP_sha1(); + break; + case TSIG_SHA224: + md_type = EVP_sha224(); + break; + case TSIG_SHA256: + md_type = EVP_sha256(); + break; + case TSIG_SHA384: + md_type = EVP_sha384(); + break; + case TSIG_SHA512: + md_type = EVP_sha512(); + break; + default: + throw PDNSException("Unknown hash algorithm requested from calculateHMAC()"); + } + + unsigned char* out = HMAC(md_type, reinterpret_cast(key.c_str()), key.size(), reinterpret_cast(text.c_str()), text.size(), hash, &outlen); + if (out == NULL || outlen == 0) { + throw PDNSException("HMAC computation failed"); + } + + return string((char*) hash, outlen); +} + +static bool constantTimeStringEquals(const std::string& a, const std::string& b) +{ + if (a.size() != b.size()) { + return false; + } + const size_t size = a.size(); +#if OPENSSL_VERSION_NUMBER >= 0x0090819fL + return CRYPTO_memcmp(a.c_str(), b.c_str(), size) == 0; +#else + const volatile unsigned char *_a = (const volatile unsigned char *) a.c_str(); + const volatile unsigned char *_b = (const volatile unsigned char *) b.c_str(); + unsigned char res = 0; + + for (size_t idx = 0; idx < size; idx++) { + res |= _a[idx] ^ _b[idx]; + } + + return res == 0; +#endif +} + +static string makeTSIGPayload(const string& previous, const char* packetBegin, size_t packetSize, const DNSName& tsigKeyName, const TSIGRecordContent& trc, bool timersonly) +{ + string message; + + if(!previous.empty()) { + uint16_t len = htons(previous.length()); + message.append(reinterpret_cast(&len), sizeof(len)); + message.append(previous); + } + + message.append(packetBegin, packetSize); + + vector signVect; + DNSPacketWriter dw(signVect, DNSName(), 0); + auto pos=signVect.size(); + if(!timersonly) { + dw.xfrName(tsigKeyName, false); + dw.xfr16BitInt(QClass::ANY); // class + dw.xfr32BitInt(0); // TTL + dw.xfrName(trc.d_algoName.makeLowerCase(), false); + } + + uint32_t now = trc.d_time; + dw.xfr48BitInt(now); + dw.xfr16BitInt(trc.d_fudge); // fudge + if(!timersonly) { + dw.xfr16BitInt(trc.d_eRcode); // extended rcode + dw.xfr16BitInt(trc.d_otherData.length()); // length of 'other' data + // dw.xfrBlob(trc->d_otherData); + } + message.append(signVect.begin()+pos, signVect.end()); + return message; +} + +static string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigOffset, const DNSName& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly, unsigned int dnsHeaderOffset=0) +{ + string message; + string packet(opacket); + + packet.resize(tsigOffset); // remove the TSIG record at the end as per RFC2845 3.4.1 + packet[(dnsHeaderOffset + sizeof(struct dnsheader))-1]--; // Decrease ARCOUNT because we removed the TSIG RR in the previous line. + + + // Replace the message ID with the original message ID from the TSIG record. + // This is needed for forwarded DNS Update as they get a new ID when forwarding (section 6.1 of RFC2136). The TSIG record stores the original ID and the + // signature was created with the original ID, so we replace it here to get the originally signed message. + // If the message is not forwarded, we simply override it with the same id. + uint16_t origID = htons(trc.d_origID); + packet.replace(0, 2, (char*)&origID, 2); + + return makeTSIGPayload(previous, packet.data(), packet.size(), keyname, trc, timersonly); +} + +void addTSIG(DNSPacketWriter& pw, TSIGRecordContent& trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly) +{ + TSIGHashEnum algo; + if (!getTSIGHashEnum(trc.d_algoName, algo)) { + throw PDNSException(string("Unsupported TSIG HMAC algorithm ") + trc.d_algoName.toString()); + } + + string toSign = makeTSIGPayload(tsigprevious, reinterpret_cast(pw.getContent().data()), pw.getContent().size(), tsigkeyname, trc, timersonly); + + if (algo == TSIG_GSS) { + if (!gss_add_signature(tsigkeyname, toSign, trc.d_mac)) { + throw PDNSException(string("Could not add TSIG signature with algorithm 'gss-tsig' and key name '")+tsigkeyname.toString()+string("'")); + } + } else { + trc.d_mac = calculateHMAC(tsigsecret, toSign, algo); + // trc.d_mac[0]++; // sabotage + } + pw.startRecord(tsigkeyname, QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false); + trc.toPacket(pw); + pw.commit(); +} + +bool validateTSIG(const std::string& packet, size_t sigPos, const TSIGTriplet& tt, const TSIGRecordContent& trc, const std::string& previousMAC, const std::string& theirMAC, bool timersOnly, unsigned int dnsHeaderOffset) +{ + uint64_t delta = std::abs((int64_t)trc.d_time - (int64_t)time(nullptr)); + if(delta > trc.d_fudge) { + throw std::runtime_error("Invalid TSIG time delta " + std::to_string(delta) + " > fudge " + std::to_string(trc.d_fudge)); + } + + TSIGHashEnum algo; + if (!getTSIGHashEnum(trc.d_algoName, algo)) { + throw std::runtime_error("Unsupported TSIG HMAC algorithm " + trc.d_algoName.toString()); + } + + TSIGHashEnum expectedAlgo; + if (!getTSIGHashEnum(tt.algo, expectedAlgo)) { + throw std::runtime_error("Unsupported TSIG HMAC algorithm expected " + tt.algo.toString()); + } + + if (algo != expectedAlgo) { + throw std::runtime_error("Signature with TSIG key '"+tt.name.toString()+"' does not match the expected algorithm (" + tt.algo.toString() + " / " + trc.d_algoName.toString() + ")"); + } + + string tsigMsg; + tsigMsg = makeTSIGMessageFromTSIGPacket(packet, sigPos, tt.name, trc, previousMAC, timersOnly, dnsHeaderOffset); + + if (algo == TSIG_GSS) { + GssContext gssctx(tt.name); + if (!gss_verify_signature(tt.name, tsigMsg, theirMAC)) { + throw std::runtime_error("Signature with TSIG key '"+tt.name.toString()+"' failed to validate"); + } + } else { + string ourMac = calculateHMAC(tt.secret, tsigMsg, algo); + + if(!constantTimeStringEquals(ourMac, theirMAC)) { + throw std::runtime_error("Signature with TSIG key '"+tt.name.toString()+"' failed to validate"); + } + } + + return true; +} diff --git a/dnssecinfra.hh b/dnssecinfra.hh new file mode 100644 index 0000000..3cf6dd9 --- /dev/null +++ b/dnssecinfra.hh @@ -0,0 +1,170 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_DNSSECINFRA_HH +#define PDNS_DNSSECINFRA_HH + +#include "dnsrecords.hh" + +#include +#include +#include +#include "misc.hh" + +class UeberBackend; + +// rules of the road: Algorithm must be set in 'make' for each KeyEngine, and will NEVER change! + +class DNSCryptoKeyEngine +{ + public: + explicit DNSCryptoKeyEngine(unsigned int algorithm) : d_algorithm(algorithm) {} + virtual ~DNSCryptoKeyEngine() {}; + virtual string getName() const = 0; + + typedef std::map stormap_t; + typedef std::vector > storvector_t; + virtual void create(unsigned int bits)=0; + virtual storvector_t convertToISCVector() const =0; + std::string convertToISC() const ; + virtual std::string sign(const std::string& msg) const =0; + virtual std::string hash(const std::string& msg) const + { + throw std::runtime_error("hash() function not implemented"); + return msg; + } + virtual bool verify(const std::string& msg, const std::string& signature) const =0; + + virtual std::string getPubKeyHash()const =0; + virtual std::string getPublicKeyString()const =0; + virtual int getBits() const =0; + virtual unsigned int getAlgorithm() const + { + return d_algorithm; + } + + virtual void fromISCMap(DNSKEYRecordContent& drc, stormap_t& stormap)=0; + virtual void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) + { + throw std::runtime_error("Can't import from PEM string"); + } + virtual void fromPublicKeyString(const std::string& content) = 0; + virtual bool checkKey() const + { + return true; + } + static shared_ptr makeFromISCFile(DNSKEYRecordContent& drc, const char* fname); + static shared_ptr makeFromISCString(DNSKEYRecordContent& drc, const std::string& content); + static shared_ptr makeFromPEMString(DNSKEYRecordContent& drc, const std::string& raw); + static shared_ptr makeFromPublicKeyString(unsigned int algorithm, const std::string& raw); + static shared_ptr make(unsigned int algorithm); + static bool isAlgorithmSupported(unsigned int algo); + static bool isDigestSupported(uint8_t digest); + + typedef shared_ptr maker_t(unsigned int algorithm); + + static void report(unsigned int algorithm, maker_t* maker, bool fallback=false); + static std::pair testMakers(unsigned int algorithm, maker_t* creator, maker_t* signer, maker_t* verifier); + static vector> listAllAlgosWithBackend(); + static bool testAll(); + static bool testOne(int algo); + private: + + typedef std::map makers_t; + typedef std::map > allmakers_t; + static makers_t& getMakers() + { + static makers_t s_makers; + return s_makers; + } + static allmakers_t& getAllMakers() + { + static allmakers_t s_allmakers; + return s_allmakers; + } + protected: + const unsigned int d_algorithm; +}; + +struct DNSSECPrivateKey +{ + uint16_t getTag() const + { + return getDNSKEY().getTag(); + } + + const shared_ptr getKey() const + { + return d_key; + } + + void setKey(const shared_ptr key) + { + d_key = key; + d_algorithm = key->getAlgorithm(); + } + DNSKEYRecordContent getDNSKEY() const; + + uint16_t d_flags; + uint8_t d_algorithm; + +private: + shared_ptr d_key; +}; + + + +struct CanonicalCompare: public std::binary_function +{ + bool operator()(const std::string& a, const std::string& b) { + std::vector avect, bvect; + + stringtok(avect, a, "."); + stringtok(bvect, b, "."); + + reverse(avect.begin(), avect.end()); + reverse(bvect.begin(), bvect.end()); + + return avect < bvect; + } +}; + +string getMessageForRRSET(const DNSName& qname, const RRSIGRecordContent& rrc, std::vector >& signRecords, bool processRRSIGLabels = false); + +DSRecordContent makeDSFromDNSKey(const DNSName& qname, const DNSKEYRecordContent& drc, uint8_t digest); + +class DNSSECKeeper; + +uint32_t getStartOfWeek(); + +string hashQNameWithSalt(const NSEC3PARAMRecordContent& ns3prc, const DNSName& qname); +string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const DNSName& qname); + +void incrementHash(std::string& raw); +void decrementHash(std::string& raw); + +void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set& authMap, vector& rrs); + +void addTSIG(DNSPacketWriter& pw, TSIGRecordContent& trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly); +bool validateTSIG(const std::string& packet, size_t sigPos, const TSIGTriplet& tt, const TSIGRecordContent& trc, const std::string& previousMAC, const std::string& theirMAC, bool timersOnly, unsigned int dnsHeaderOffset=0); + +uint64_t signatureCacheSize(const std::string& str); +#endif diff --git a/dnsseckeeper.hh b/dnsseckeeper.hh new file mode 100644 index 0000000..61b17ae --- /dev/null +++ b/dnsseckeeper.hh @@ -0,0 +1,308 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dnssecinfra.hh" +#include "dnsrecords.hh" +#include "ueberbackend.hh" + +using namespace ::boost::multi_index; + +class DNSSECKeeper : public boost::noncopyable +{ +public: + enum keytype_t { KSK, ZSK, CSK }; + enum keyalgorithm_t : uint8_t { + RSAMD5=1, + DH=2, + DSA=3, + RSASHA1=5, + DSANSEC3SHA1=6, + RSASHA1NSEC3SHA1=7, + RSASHA256=8, + RSASHA512=10, + ECCGOST=12, + ECDSA256=13, + ECDSA384=14, + ED25519=15, + ED448=16 + }; + + enum dsdigestalgorithm_t : uint8_t { + SHA1=1, + SHA256=2, + GOST=3, + SHA384=4 + }; + + struct KeyMetaData + { + string fname; + unsigned int id; + bool active; + keytype_t keyType; + bool hasSEPBit; + }; + typedef std::pair keymeta_t; + typedef std::vector keyset_t; + + static string keyTypeToString(const keytype_t &keyType) + { + switch(keyType) { + case DNSSECKeeper::KSK: + return("KSK"); + case DNSSECKeeper::ZSK: + return("ZSK"); + case DNSSECKeeper::CSK: + return("CSK"); + default: + return("UNKNOWN"); + } + } + + /* + * Returns the algorithm number based on the mnemonic (or old PowerDNS value of) a string. + * See https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml for the mapping + */ + static int shorthand2algorithm(const string &algorithm) + { + if (pdns_iequals(algorithm, "rsamd5")) return RSAMD5; + if (pdns_iequals(algorithm, "dh")) return DH; + if (pdns_iequals(algorithm, "dsa")) return DSA; + if (pdns_iequals(algorithm, "rsasha1")) return RSASHA1; + if (pdns_iequals(algorithm, "dsa-nsec3-sha1")) return DSANSEC3SHA1; + if (pdns_iequals(algorithm, "rsasha1-nsec3-sha1")) return RSASHA1NSEC3SHA1; + if (pdns_iequals(algorithm, "rsasha256")) return RSASHA256; + if (pdns_iequals(algorithm, "rsasha512")) return RSASHA512; + if (pdns_iequals(algorithm, "ecc-gost")) return ECCGOST; + if (pdns_iequals(algorithm, "gost")) return ECCGOST; + if (pdns_iequals(algorithm, "ecdsa256")) return ECDSA256; + if (pdns_iequals(algorithm, "ecdsap256sha256")) return ECDSA256; + if (pdns_iequals(algorithm, "ecdsa384")) return ECDSA384; + if (pdns_iequals(algorithm, "ecdsap384sha384")) return ECDSA384; + if (pdns_iequals(algorithm, "ed25519")) return ED25519; + if (pdns_iequals(algorithm, "ed448")) return ED448; + if (pdns_iequals(algorithm, "indirect")) return 252; + if (pdns_iequals(algorithm, "privatedns")) return 253; + if (pdns_iequals(algorithm, "privateoid")) return 254; + return -1; + } + + /* + * Returns the mnemonic from https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml + */ + static string algorithm2name(uint8_t algo) { + switch(algo) { + case 0: + case 4: + case 9: + case 11: + return "Reserved"; + case RSAMD5: + return "RSAMD5"; + case DH: + return "DH"; + case DSA: + return "DSA"; + case RSASHA1: + return "RSASHA1"; + case DSANSEC3SHA1: + return "DSA-NSEC3-SHA1"; + case RSASHA1NSEC3SHA1: + return "RSASHA1-NSEC3-SHA1"; + case RSASHA256: + return "RSASHA256"; + case RSASHA512: + return "RSASHA512"; + case ECCGOST: + return "ECC-GOST"; + case ECDSA256: + return "ECDSAP256SHA256"; + case ECDSA384: + return "ECDSAP384SHA384"; + case ED25519: + return "ED25519"; + case ED448: + return "ED448"; + case 252: + return "INDIRECT"; + case 253: + return "PRIVATEDNS"; + case 254: + return "PRIVATEOID"; + default: + return "Unallocated/Reserved"; + } + } + +private: + UeberBackend* d_keymetadb; + bool d_ourDB; + +public: + DNSSECKeeper() : d_keymetadb( new UeberBackend("key-only")), d_ourDB(true) + { + + } + + DNSSECKeeper(UeberBackend* db) : d_keymetadb(db), d_ourDB(false) + { + } + + ~DNSSECKeeper() + { + if(d_ourDB) + delete d_keymetadb; + } + bool doesDNSSEC(); + bool isSecuredZone(const DNSName& zone); + static uint64_t dbdnssecCacheSizes(const std::string& str); + keyset_t getEntryPoints(const DNSName& zname); + keyset_t getKeys(const DNSName& zone, bool useCache = true); + DNSSECPrivateKey getKeyById(const DNSName& zone, unsigned int id); + bool addKey(const DNSName& zname, bool setSEPBit, int algorithm, int64_t& id, int bits=0, bool active=true); + bool addKey(const DNSName& zname, const DNSSECPrivateKey& dpk, int64_t& id, bool active=true); + bool removeKey(const DNSName& zname, unsigned int id); + bool activateKey(const DNSName& zname, unsigned int id); + bool deactivateKey(const DNSName& zname, unsigned int id); + bool checkKeys(const DNSName& zname); + + bool getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* n3p=0, bool* narrow=0); + bool checkNSEC3PARAM(const NSEC3PARAMRecordContent& ns3p, string& msg); + bool setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& n3p, const bool& narrow=false); + bool unsetNSEC3PARAM(const DNSName& zname); + void clearAllCaches(); + void clearCaches(const DNSName& name); + bool getPreRRSIGs(UeberBackend& db, const DNSName& signer, const DNSName& qname, const DNSName& wildcardname, const QType& qtype, DNSResourceRecord::Place, vector& rrsigs, uint32_t signTTL); + bool isPresigned(const DNSName& zname); + bool setPresigned(const DNSName& zname); + bool unsetPresigned(const DNSName& zname); + bool setPublishCDNSKEY(const DNSName& zname); + bool unsetPublishCDNSKEY(const DNSName& zname); + bool setPublishCDS(const DNSName& zname, const string& digestAlgos); + bool unsetPublishCDS(const DNSName& zname); + + bool TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname); + bool getTSIGForAccess(const DNSName& zone, const string& master, DNSName* keyname); + + void startTransaction(const DNSName& zone, int zone_id) + { + (*d_keymetadb->backends.begin())->startTransaction(zone, zone_id); + } + + void commitTransaction() + { + (*d_keymetadb->backends.begin())->commitTransaction(); + } + + void getFromMeta(const DNSName& zname, const std::string& key, std::string& value); + void getSoaEdit(const DNSName& zname, std::string& value); + bool unSecureZone(const DNSName& zone, std::string& error, std::string& info); + bool rectifyZone(const DNSName& zone, std::string& error, std::string& info, bool doTransaction); +private: + + + struct KeyCacheEntry + { + typedef vector keys_t; + + uint32_t getTTD() const + { + return d_ttd; + } + + DNSName d_domain; + mutable keys_t d_keys; + unsigned int d_ttd; + }; + + struct METACacheEntry + { + uint32_t getTTD() const + { + return d_ttd; + } + + DNSName d_domain; + mutable std::string d_key, d_value; + unsigned int d_ttd; + + }; + + + typedef multi_index_container< + KeyCacheEntry, + indexed_by< + ordered_unique >, + sequenced<> + > + > keycache_t; + typedef multi_index_container< + METACacheEntry, + indexed_by< + ordered_unique< + composite_key< + METACacheEntry, + member , + member + >, composite_key_compare, CIStringCompare> >, + sequenced<> + > + > metacache_t; + + void cleanup(); + + static keycache_t s_keycache; + static metacache_t s_metacache; + static pthread_rwlock_t s_metacachelock; + static pthread_rwlock_t s_keycachelock; + static AtomicCounter s_ops; + static time_t s_last_prune; + +public: + void preRemoval(const KeyCacheEntry&) + { + } + void preRemoval(const METACacheEntry&) + { + } +}; + +class DNSPacket; +uint32_t localtime_format_YYYYMMDDSS(time_t t, uint32_t seq); +// for SOA-EDIT +uint32_t calculateEditSOA(const DNSZoneRecord& rr, const string& kind); +uint32_t calculateEditSOA(const SOAData& sd, const string& kind); +bool editSOA(DNSSECKeeper& dk, const DNSName& qname, DNSPacket* dp); +bool editSOARecord(DNSZoneRecord& rr, const string& kind); +// for SOA-EDIT-DNSUPDATE/API +uint32_t calculateIncreaseSOA(SOAData sd, const string& increaseKind, const string& editKind); +bool increaseSOARecord(DNSResourceRecord& rr, const string& increaseKind, const string& editKind); +bool increaseSOARecord(DNSZoneRecord& rr, const string& increaseKind, const string& editKind); diff --git a/dnswriter.cc b/dnswriter.cc new file mode 100644 index 0000000..916a23b --- /dev/null +++ b/dnswriter.cc @@ -0,0 +1,424 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#if BOOST_VERSION >= 105400 +#include +#endif +#include "dnswriter.hh" +#include "misc.hh" +#include "dnsparser.hh" + +#include + +/* d_content: <---- d_stuff ----> + v d_truncatemarker + dnsheader | qname | qtype | qclass | {recordname| dnsrecordheader | record } + ^ d_rollbackmarker ^ d_sor + + +*/ + + +DNSPacketWriter::DNSPacketWriter(vector& content, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode) + : d_content(content), d_qname(qname), d_canonic(false), d_lowerCase(false) +{ + d_content.clear(); + dnsheader dnsheader; + + memset(&dnsheader, 0, sizeof(dnsheader)); + dnsheader.id=0; + dnsheader.qdcount=htons(1); + dnsheader.opcode=opcode; + + const uint8_t* ptr=(const uint8_t*)&dnsheader; + uint32_t len=d_content.size(); + d_content.resize(len + sizeof(dnsheader)); + uint8_t* dptr=(&*d_content.begin()) + len; + + memcpy(dptr, ptr, sizeof(dnsheader)); + d_namepositions.reserve(16); + xfrName(qname, false); + xfr16BitInt(qtype); + xfr16BitInt(qclass); + + d_truncatemarker=d_content.size(); + d_sor = 0; + d_rollbackmarker = 0; +} + +dnsheader* DNSPacketWriter::getHeader() +{ + return reinterpret_cast(&*d_content.begin()); +} + + +void DNSPacketWriter::startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, DNSResourceRecord::Place place, bool compress) +{ + commit(); + d_rollbackmarker=d_content.size(); + + if(compress && !name.empty() && d_qname==name) { // don't do the whole label compression thing if we *know* we can get away with "see question" - except when compressing the root + static unsigned char marker[2]={0xc0, 0x0c}; + d_content.insert(d_content.end(), (const char *) &marker[0], (const char *) &marker[2]); + } + else { + xfrName(name, compress); + } + xfr16BitInt(qtype); + xfr16BitInt(qclass); + xfr32BitInt(ttl); + xfr16BitInt(0); // this will be the record size + d_recordplace = place; + d_sor=d_content.size(); // this will remind us where to stuff the record size +} + +void DNSPacketWriter::addOpt(uint16_t udpsize, int extRCode, int Z, const vector >& options, uint8_t version) +{ + uint32_t ttl=0; + + EDNS0Record stuff; + + stuff.extRCode=extRCode; + stuff.version=version; + stuff.Z=htons(Z); + + static_assert(sizeof(EDNS0Record) == sizeof(ttl), "sizeof(EDNS0Record) must match sizeof(ttl)"); + memcpy(&ttl, &stuff, sizeof(stuff)); + + ttl=ntohl(ttl); // will be reversed later on + + startRecord(g_rootdnsname, QType::OPT, ttl, udpsize, DNSResourceRecord::ADDITIONAL, false); + for(optvect_t::const_iterator iter = options.begin(); iter != options.end(); ++iter) { + xfr16BitInt(iter->first); + xfr16BitInt(iter->second.length()); + xfrBlob(iter->second); + } +} + +void DNSPacketWriter::xfr48BitInt(uint64_t val) +{ + unsigned char bytes[6]; + uint16_t theLeft = htons((val >> 32)&0xffffU); + uint32_t theRight = htonl(val & 0xffffffffU); + memcpy(bytes, (void*)&theLeft, sizeof(theLeft)); + memcpy(bytes+2, (void*)&theRight, sizeof(theRight)); + + d_content.insert(d_content.end(), bytes, bytes + sizeof(bytes)); +} + + +void DNSPacketWriter::xfr32BitInt(uint32_t val) +{ + int rval=htonl(val); + uint8_t* ptr=reinterpret_cast(&rval); + d_content.insert(d_content.end(), ptr, ptr+4); +} + +void DNSPacketWriter::xfr16BitInt(uint16_t val) +{ + uint16_t rval=htons(val); + uint8_t* ptr=reinterpret_cast(&rval); + d_content.insert(d_content.end(), ptr, ptr+2); +} + +void DNSPacketWriter::xfr8BitInt(uint8_t val) +{ + d_content.push_back(val); +} + + +/* input: + if lenField is true + "" -> 0 + "blah" -> 4blah + "blah" "blah" -> output 4blah4blah + "verylongstringlongerthan256....characters" \xffverylongstring\x23characters (autosplit) + "blah\"blah" -> 9blah"blah + "blah\97" -> 5blahb + + if lenField is false + "blah" -> blah + "blah\"blah" -> blah"blah + */ +void DNSPacketWriter::xfrText(const string& text, bool, bool lenField) +{ + if(text.empty()) { + d_content.push_back(0); + return; + } + vector segments = segmentDNSText(text); + for(const string& str : segments) { + if(lenField) + d_content.push_back(str.length()); + d_content.insert(d_content.end(), str.c_str(), str.c_str() + str.length()); + } +} + +void DNSPacketWriter::xfrUnquotedText(const string& text, bool lenField) +{ + if(text.empty()) { + d_content.push_back(0); + return; + } + if(lenField) + d_content.push_back(text.length()); + d_content.insert(d_content.end(), text.c_str(), text.c_str() + text.length()); +} + + +static constexpr bool l_verbose=false; +uint16_t DNSPacketWriter::lookupName(const DNSName& name, uint16_t* matchLen) +{ + // iterate over the written labels, see if we find a match + const auto& raw = name.getStorage(); + + /* name might be a.root-servers.net, we need to be able to benefit from finding: + b.root-servers.net, or even: + b\xc0\x0c + */ + unsigned int bestpos=0; + *matchLen=0; +#if BOOST_VERSION >= 105400 + boost::container::static_vector nvect, pvect; +#else + vector nvect, pvect; +#endif + + try { + for(auto riter= raw.cbegin(); riter < raw.cend(); ) { + if(!*riter) + break; + nvect.push_back(riter - raw.cbegin()); + riter+=*riter+1; + } + } + catch(std::bad_alloc& ba) { + if(l_verbose) + cout<<"Domain "<> 8)); + d_content.push_back((char)(offset & 0xff)); + } + else { + unsigned int pos=d_content.size(); + if(l_verbose) + cout<<"Found nothing, we are at pos "< lc; + if(d_lowerCase) + lc = make_unique(name.makeLowerCase()); + + const DNSName::string_t& raw = (lc ? *lc : name).getStorage(); + if(l_verbose) + cout<<"Writing out the whole thing "<(blob.c_str()); + d_content.insert(d_content.end(), ptr, ptr+blob.size()); +} + +void DNSPacketWriter::xfrBlobNoSpaces(const string& blob, int ) +{ + xfrBlob(blob); +} + +void DNSPacketWriter::xfrHexBlob(const string& blob, bool keepReading) +{ + xfrBlob(blob); +} + +// call __before commit__ +void DNSPacketWriter::getRecordPayload(string& records) +{ + records.assign(d_content.begin() + d_sor, d_content.end()); +} + +uint32_t DNSPacketWriter::size() +{ + return d_content.size(); +} + +void DNSPacketWriter::rollback() +{ + d_content.resize(d_rollbackmarker); + d_sor = 0; +} + +void DNSPacketWriter::truncate() +{ + d_content.resize(d_truncatemarker); + dnsheader* dh=reinterpret_cast( &*d_content.begin()); + dh->ancount = dh->nscount = dh->arcount = 0; +} + +void DNSPacketWriter::commit() +{ + if(!d_sor) + return; + uint16_t rlen = d_content.size() - d_sor; + d_content[d_sor-2]=rlen >> 8; + d_content[d_sor-1]=rlen & 0xff; + d_sor=0; + dnsheader* dh=reinterpret_cast( &*d_content.begin()); + switch(d_recordplace) { + case DNSResourceRecord::QUESTION: + dh->qdcount = htons(ntohs(dh->qdcount) + 1); + break; + case DNSResourceRecord::ANSWER: + dh->ancount = htons(ntohs(dh->ancount) + 1); + break; + case DNSResourceRecord::AUTHORITY: + dh->nscount = htons(ntohs(dh->nscount) + 1); + break; + case DNSResourceRecord::ADDITIONAL: + dh->arcount = htons(ntohs(dh->arcount) + 1); + break; + } + +} diff --git a/dnswriter.hh b/dnswriter.hh new file mode 100644 index 0000000..49cf695 --- /dev/null +++ b/dnswriter.hh @@ -0,0 +1,154 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_DNSWRITER_HH +#define PDNS_DNSWRITER_HH + +#include +#include +#include +#include "dns.hh" +#include "dnsname.hh" +#include "namespaces.hh" +#include + + +/** this class can be used to write DNS packets. It knows about DNS in the sense that it makes + the packet header and record headers. + + The model is: + + packetheader (recordheader recordcontent)* + + The packetheader needs to be updated with the amount of packets of each kind (answer, auth, additional) + + Each recordheader contains the length of a dns record. + + Calling convention: + + vector content; + DNSPacketWriter dpw(content, const string& qname, uint16_t qtype, uint16_t qclass=QClass:IN); // sets the question + dpw.startrecord("this.is.an.ip.address.", ns_t_a); // does nothing, except store qname and qtype + dpw.xfr32BitInt(0x01020304); // adds 4 bytes (0x01020304) to the record buffer + dpw.startrecord("this.is.an.ip.address.", ns_t_a); // aha! writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer, which gets emptied + // new qname and qtype are stored + dpw.xfr32BitInt(0x04030201); // adds 4 bytes (0x04030201) to the record buffer + dpw.commit(); // writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer + + // content now contains the ready packet, with 1 question and 2 answers + +*/ + +class DNSPacketWriter : public boost::noncopyable +{ + +public: + //! Start a DNS Packet in the vector passed, with question qname, qtype and qclass + DNSPacketWriter(vector& content, const DNSName& qname, uint16_t qtype, uint16_t qclass=QClass::IN, uint8_t opcode=0); + + /** Start a new DNS record within this packet for namq, qtype, ttl, class and in the requested place. Note that packets can only be written in natural order - + ANSWER, AUTHORITY, ADDITIONAL */ + void startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=QClass::IN, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, bool compress=true); + + /** Shorthand way to add an Opt-record, for example for EDNS0 purposes */ + typedef vector > optvect_t; + void addOpt(uint16_t udpsize, int extRCode, int Z, const optvect_t& options=optvect_t(), uint8_t version=0); + + /** needs to be called after the last record is added, but can be called again and again later on. Is called internally by startRecord too. + The content of the vector<> passed to the constructor is inconsistent until commit is called. + */ + void commit(); + + uint32_t size(); // needs to be 32 bit because otherwise we don't see the wrap coming when it happened! + + /** Should the packet have grown too big for the writer's liking, rollback removes the record currently being written */ + void rollback(); + + /** Discard all content except the question section */ + void truncate(); + + void xfr48BitInt(uint64_t val); + void xfr32BitInt(uint32_t val); + void xfr16BitInt(uint16_t val); + void xfrType(uint16_t val) + { + xfr16BitInt(val); + } + void xfrIP(const uint32_t& val) + { + xfr32BitInt(htonl(val)); + } + void xfrIP6(const std::string& val) + { + xfrBlob(val,16); + } + void xfrTime(const uint32_t& val) + { + xfr32BitInt(val); + } + + void xfr8BitInt(uint8_t val); + + void xfrName(const DNSName& label, bool compress=false, bool noDot=false); + void xfrText(const string& text, bool multi=false, bool lenField=true); + void xfrUnquotedText(const string& text, bool lenField); + void xfrBlob(const string& blob, int len=-1); + void xfrBlobNoSpaces(const string& blob, int len=-1); + void xfrHexBlob(const string& blob, bool keepReading=false); + + dnsheader* getHeader(); + void getRecordPayload(string& records); // call __before commit__ + + void setCanonic(bool val) + { + d_canonic=val; + } + + void setLowercase(bool val) + { + d_lowerCase=val; + } + vector & getContent() + { + return d_content; + } + bool eof() { return true; } // we don't know how long the record should be + +private: + uint16_t lookupName(const DNSName& name, uint16_t* matchlen); + vector d_namepositions; + // We declare 1 uint_16 in the public section, these 3 align on a 8-byte boundry + uint16_t d_sor; + uint16_t d_rollbackmarker; // start of last complete packet, for rollback + + vector & d_content; + DNSName d_qname; + + uint16_t d_truncatemarker; // end of header, for truncate + DNSResourceRecord::Place d_recordplace; + bool d_canonic, d_lowerCase; +}; + +typedef vector > labelparts_t; +// bool labeltokUnescape(labelparts_t& parts, const DNSName& label); +std::vector segmentDNSText(const string& text); // from dnslabeltext.rl +std::deque segmentDNSName(const string& input ); // from dnslabeltext.rl +#endif diff --git a/ednscookies.cc b/ednscookies.cc new file mode 100644 index 0000000..5e20819 --- /dev/null +++ b/ednscookies.cc @@ -0,0 +1,51 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "ednscookies.hh" + +bool getEDNSCookiesOptFromString(const string& option, EDNSCookiesOpt* eco) +{ + return getEDNSCookiesOptFromString(option.c_str(), option.length(), eco); +} + +bool getEDNSCookiesOptFromString(const char* option, unsigned int len, EDNSCookiesOpt* eco) +{ + if(len != 8 && len < 16) + return false; + eco->client = string(option, 8); + if (len > 8) { + eco->server = string(option + 8, len - 8); + } + return true; +} + +string makeEDNSCookiesOptString(const EDNSCookiesOpt& eco) +{ + string ret; + if (eco.client.length() != 8) + return ret; + if (eco.server.length() != 0 && (eco.server.length() < 8 || eco.server.length() > 32)) + return ret; + ret.assign(eco.client); + if (eco.server.length() != 0) + ret.append(eco.server); + return ret; +} diff --git a/ednscookies.hh b/ednscookies.hh new file mode 100644 index 0000000..7dce62b --- /dev/null +++ b/ednscookies.hh @@ -0,0 +1,36 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_EDNSCOOKIES_HH +#define PDNS_EDNSCOOKIES_HH + +#include "namespaces.hh" + +struct EDNSCookiesOpt +{ + string client; + string server; +}; + +bool getEDNSCookiesOptFromString(const char* option, unsigned int len, EDNSCookiesOpt* eco); +bool getEDNSCookiesOptFromString(const string& option, EDNSCookiesOpt* eco); +string makeEDNSCookiesOptString(const EDNSCookiesOpt& eco); +#endif diff --git a/ednsoptions.cc b/ednsoptions.cc new file mode 100644 index 0000000..eade5df --- /dev/null +++ b/ednsoptions.cc @@ -0,0 +1,115 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "dns.hh" +#include "ednsoptions.hh" +#include "iputils.hh" + +/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */ +int getEDNSOption(char* optRR, const size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize) +{ + assert(optRR != NULL); + assert(optionValue != NULL); + assert(optionValueSize != NULL); + size_t pos = 0; + if (len < DNS_RDLENGTH_SIZE) + return EINVAL; + + const uint16_t rdLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]); + size_t rdPos = 0; + pos += DNS_RDLENGTH_SIZE; + if ((pos + rdLen) > len) { + return EINVAL; + } + + while(len >= (pos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE) && + rdLen >= (rdPos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) { + const uint16_t optionCode = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]); + pos += EDNS_OPTION_CODE_SIZE; + rdPos += EDNS_OPTION_CODE_SIZE; + const uint16_t optionLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]); + pos += EDNS_OPTION_LENGTH_SIZE; + rdPos += EDNS_OPTION_LENGTH_SIZE; + if (optionLen > (rdLen - rdPos) || optionLen > (len - pos)) + return EINVAL; + + if (optionCode == wantedOption) { + *optionValue = optRR + pos - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE); + *optionValueSize = optionLen + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE; + return 0; + } + else { + /* skip this option */ + pos += optionLen; + rdPos += optionLen; + } + } + + return ENOENT; +} + +/* extract all EDNS0 options from a pointer on the beginning rdLen of the OPT RR */ +int getEDNSOptions(const char* optRR, const size_t len, std::map& options) +{ + assert(optRR != NULL); + size_t pos = 0; + if (len < DNS_RDLENGTH_SIZE) + return EINVAL; + + const uint16_t rdLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]); + size_t rdPos = 0; + pos += DNS_RDLENGTH_SIZE; + if ((pos + rdLen) > len) { + return EINVAL; + } + + while(len >= (pos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE) && + rdLen >= (rdPos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) { + const uint16_t optionCode = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]); + pos += EDNS_OPTION_CODE_SIZE; + rdPos += EDNS_OPTION_CODE_SIZE; + const uint16_t optionLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]); + pos += EDNS_OPTION_LENGTH_SIZE; + rdPos += EDNS_OPTION_LENGTH_SIZE; + if (optionLen > (rdLen - rdPos) || optionLen > (len - pos)) + return EINVAL; + + EDNSOptionView view; + view.content = optRR + pos; + view.size = optionLen; + options[optionCode] = view; + + /* skip this option */ + pos += optionLen; + rdPos += optionLen; + } + + return 0; +} + +void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res) +{ + const uint16_t ednsOptionCode = htons(optionCode); + const uint16_t payloadLen = htons(payload.length()); + res.append((const char *) &ednsOptionCode, sizeof ednsOptionCode); + res.append((const char *) &payloadLen, sizeof payloadLen); + res.append(payload); +} diff --git a/ednsoptions.hh b/ednsoptions.hh new file mode 100644 index 0000000..ea0279a --- /dev/null +++ b/ednsoptions.hh @@ -0,0 +1,46 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_EDNSOPTIONS_HH +#define PDNS_EDNSOPTIONS_HH + +#include "namespaces.hh" + +struct EDNSOptionCode +{ + enum EDNSOptionCodeEnum {NSID=3, DAU=4, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13}; +}; + +/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */ +int getEDNSOption(char* optRR, size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize); + +struct EDNSOptionView +{ + const char* content{nullptr}; + uint16_t size{0}; +}; + +/* extract all EDNS0 options from a pointer on the beginning rdLen of the OPT RR */ +int getEDNSOptions(const char* optRR, size_t len, std::map& options); + +void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res); + +#endif diff --git a/ednssubnet.cc b/ednssubnet.cc new file mode 100644 index 0000000..4826f60 --- /dev/null +++ b/ednssubnet.cc @@ -0,0 +1,108 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ednssubnet.hh" +#include "dns.hh" + +namespace { + struct EDNSSubnetOptsWire + { + uint16_t family; + uint8_t sourceMask; + uint8_t scopeMask; + } GCCPACKATTRIBUTE; // BRRRRR + +} + +bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso) +{ + //cerr<<"options.size:"< 0 ? (((esow.sourceMask - 1)>> 3)+1) : 0; + //cerr<<"octetsin:"< sizeof(address.sin4.sin_addr.s_addr)) + return false; + address.reset(); + address.sin4.sin_family = AF_INET; + if(octetsin > 0) + memcpy(&address.sin4.sin_addr.s_addr, options+sizeof(esow), octetsin); + } else if(esow.family == 2) { + if(len != sizeof(esow)+octetsin) + return false; + if(octetsin > sizeof(address.sin6.sin6_addr.s6_addr)) + return false; + + address.reset(); + address.sin4.sin_family = AF_INET6; + if(octetsin > 0) + memcpy(&address.sin6.sin6_addr.s6_addr, options+sizeof(esow), octetsin); + } + else + return false; + //cerr<<"Source address: "<source = Netmask(address, esow.sourceMask); + /* 'address' has more bits set (potentially) than scopeMask. This leads to odd looking netmasks that promise + more precision than they have. For this reason we truncate the address to scopeMask bits */ + + address.truncate(esow.scopeMask); // truncate will not throw for odd scopeMasks + eso->scope = Netmask(address, esow.scopeMask); + + return true; +} + +string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso) +{ + string ret; + EDNSSubnetOptsWire esow; + uint16_t family = htons(eso.source.getNetwork().sin4.sin_family == AF_INET ? 1 : 2); + esow.family = family; + esow.sourceMask = eso.source.getBits(); + esow.scopeMask = eso.scope.getBits(); + ret.assign((const char*)&esow, sizeof(esow)); + int octetsout = ((esow.sourceMask - 1)>> 3)+1; + + ComboAddress src=eso.source.getNetwork(); + src.truncate(esow.sourceMask); + + if(family == htons(1)) + ret.append((const char*) &src.sin4.sin_addr.s_addr, octetsout); + else + ret.append((const char*) &src.sin6.sin6_addr.s6_addr, octetsout); + return ret; +} + diff --git a/ednssubnet.hh b/ednssubnet.hh new file mode 100644 index 0000000..eb87b48 --- /dev/null +++ b/ednssubnet.hh @@ -0,0 +1,38 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_EDNSSUBNET_HH +#define PDNS_EDNSSUBNET_HH + +#include "namespaces.hh" +#include "iputils.hh" +#include "dnsname.hh" + +struct EDNSSubnetOpts +{ + Netmask source; + Netmask scope; +}; + +bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso); +bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso); +string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso); +#endif diff --git a/effective_tld_names.dat b/effective_tld_names.dat new file mode 100644 index 0000000..c75fb5b --- /dev/null +++ b/effective_tld_names.dat @@ -0,0 +1,12661 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, +// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. + +// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. + +// ===BEGIN ICANN DOMAINS=== + +// ac : https://en.wikipedia.org/wiki/.ac +ac +com.ac +edu.ac +gov.ac +net.ac +mil.ac +org.ac + +// ad : https://en.wikipedia.org/wiki/.ad +ad +nom.ad + +// ae : https://en.wikipedia.org/wiki/.ae +// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php +ae +co.ae +net.ae +org.ae +sch.ae +ac.ae +gov.ae +mil.ae + +// aero : see https://www.information.aero/index.php?id=66 +aero +accident-investigation.aero +accident-prevention.aero +aerobatic.aero +aeroclub.aero +aerodrome.aero +agents.aero +aircraft.aero +airline.aero +airport.aero +air-surveillance.aero +airtraffic.aero +air-traffic-control.aero +ambulance.aero +amusement.aero +association.aero +author.aero +ballooning.aero +broker.aero +caa.aero +cargo.aero +catering.aero +certification.aero +championship.aero +charter.aero +civilaviation.aero +club.aero +conference.aero +consultant.aero +consulting.aero +control.aero +council.aero +crew.aero +design.aero +dgca.aero +educator.aero +emergency.aero +engine.aero +engineer.aero +entertainment.aero +equipment.aero +exchange.aero +express.aero +federation.aero +flight.aero +freight.aero +fuel.aero +gliding.aero +government.aero +groundhandling.aero +group.aero +hanggliding.aero +homebuilt.aero +insurance.aero +journal.aero +journalist.aero +leasing.aero +logistics.aero +magazine.aero +maintenance.aero +media.aero +microlight.aero +modelling.aero +navigation.aero +parachuting.aero +paragliding.aero +passenger-association.aero +pilot.aero +press.aero +production.aero +recreation.aero +repbody.aero +res.aero +research.aero +rotorcraft.aero +safety.aero +scientist.aero +services.aero +show.aero +skydiving.aero +software.aero +student.aero +trader.aero +trading.aero +trainer.aero +union.aero +workinggroup.aero +works.aero + +// af : http://www.nic.af/help.jsp +af +gov.af +com.af +org.af +net.af +edu.af + +// ag : http://www.nic.ag/prices.htm +ag +com.ag +org.ag +net.ag +co.ag +nom.ag + +// ai : http://nic.com.ai/ +ai +off.ai +com.ai +net.ai +org.ai + +// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 +al +com.al +edu.al +gov.al +mil.al +net.al +org.al + +// am : https://en.wikipedia.org/wiki/.am +am + +// ao : https://en.wikipedia.org/wiki/.ao +// http://www.dns.ao/REGISTR.DOC +ao +ed.ao +gv.ao +og.ao +co.ao +pb.ao +it.ao + +// aq : https://en.wikipedia.org/wiki/.aq +aq + +// ar : https://nic.ar/nic-argentina/normativa-vigente +ar +com.ar +edu.ar +gob.ar +gov.ar +int.ar +mil.ar +musica.ar +net.ar +org.ar +tur.ar + +// arpa : https://en.wikipedia.org/wiki/.arpa +// Confirmed by registry 2008-06-18 +arpa +e164.arpa +in-addr.arpa +ip6.arpa +iris.arpa +uri.arpa +urn.arpa + +// as : https://en.wikipedia.org/wiki/.as +as +gov.as + +// asia : https://en.wikipedia.org/wiki/.asia +asia + +// at : https://en.wikipedia.org/wiki/.at +// Confirmed by registry 2008-06-17 +at +ac.at +co.at +gv.at +or.at + +// au : https://en.wikipedia.org/wiki/.au +// http://www.auda.org.au/ +au +// 2LDs +com.au +net.au +org.au +edu.au +gov.au +asn.au +id.au +// Historic 2LDs (closed to new registration, but sites still exist) +info.au +conf.au +oz.au +// CGDNs - http://www.cgdn.org.au/ +act.au +nsw.au +nt.au +qld.au +sa.au +tas.au +vic.au +wa.au +// 3LDs +act.edu.au +nsw.edu.au +nt.edu.au +qld.edu.au +sa.edu.au +tas.edu.au +vic.edu.au +wa.edu.au +// act.gov.au Bug 984824 - Removed at request of Greg Tankard +// nsw.gov.au Bug 547985 - Removed at request of +// nt.gov.au Bug 940478 - Removed at request of Greg Connors +qld.gov.au +sa.gov.au +tas.gov.au +vic.gov.au +wa.gov.au + +// aw : https://en.wikipedia.org/wiki/.aw +aw +com.aw + +// ax : https://en.wikipedia.org/wiki/.ax +ax + +// az : https://en.wikipedia.org/wiki/.az +az +com.az +net.az +int.az +gov.az +org.az +edu.az +info.az +pp.az +mil.az +name.az +pro.az +biz.az + +// ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf +ba +com.ba +edu.ba +gov.ba +mil.ba +net.ba +org.ba + +// bb : https://en.wikipedia.org/wiki/.bb +bb +biz.bb +co.bb +com.bb +edu.bb +gov.bb +info.bb +net.bb +org.bb +store.bb +tv.bb + +// bd : https://en.wikipedia.org/wiki/.bd +*.bd + +// be : https://en.wikipedia.org/wiki/.be +// Confirmed by registry 2008-06-08 +be +ac.be + +// bf : https://en.wikipedia.org/wiki/.bf +bf +gov.bf + +// bg : https://en.wikipedia.org/wiki/.bg +// https://www.register.bg/user/static/rules/en/index.html +bg +a.bg +b.bg +c.bg +d.bg +e.bg +f.bg +g.bg +h.bg +i.bg +j.bg +k.bg +l.bg +m.bg +n.bg +o.bg +p.bg +q.bg +r.bg +s.bg +t.bg +u.bg +v.bg +w.bg +x.bg +y.bg +z.bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg + +// bh : https://en.wikipedia.org/wiki/.bh +bh +com.bh +edu.bh +net.bh +org.bh +gov.bh + +// bi : https://en.wikipedia.org/wiki/.bi +// http://whois.nic.bi/ +bi +co.bi +com.bi +edu.bi +or.bi +org.bi + +// biz : https://en.wikipedia.org/wiki/.biz +biz + +// bj : https://en.wikipedia.org/wiki/.bj +bj +asso.bj +barreau.bj +gouv.bj + +// bm : http://www.bermudanic.bm/dnr-text.txt +bm +com.bm +edu.bm +gov.bm +net.bm +org.bm + +// bn : http://www.bnnic.bn/faqs +bn +com.bn +edu.bn +gov.bn +net.bn +org.bn + +// bo : https://nic.bo/delegacion2015.php#h-1.10 +bo +com.bo +edu.bo +gob.bo +int.bo +org.bo +net.bo +mil.bo +tv.bo +web.bo +// Social Domains +academia.bo +agro.bo +arte.bo +blog.bo +bolivia.bo +ciencia.bo +cooperativa.bo +democracia.bo +deporte.bo +ecologia.bo +economia.bo +empresa.bo +indigena.bo +industria.bo +info.bo +medicina.bo +movimiento.bo +musica.bo +natural.bo +nombre.bo +noticias.bo +patria.bo +politica.bo +profesional.bo +plurinacional.bo +pueblo.bo +revista.bo +salud.bo +tecnologia.bo +tksat.bo +transporte.bo +wiki.bo + +// br : http://registro.br/dominio/categoria.html +// Submitted by registry +br +9guacu.br +abc.br +adm.br +adv.br +agr.br +aju.br +am.br +anani.br +aparecida.br +arq.br +art.br +ato.br +b.br +barueri.br +belem.br +bhz.br +bio.br +blog.br +bmd.br +boavista.br +bsb.br +campinagrande.br +campinas.br +caxias.br +cim.br +cng.br +cnt.br +com.br +contagem.br +coop.br +cri.br +cuiaba.br +curitiba.br +def.br +ecn.br +eco.br +edu.br +emp.br +eng.br +esp.br +etc.br +eti.br +far.br +feira.br +flog.br +floripa.br +fm.br +fnd.br +fortal.br +fot.br +foz.br +fst.br +g12.br +ggf.br +goiania.br +gov.br +// gov.br 26 states + df https://en.wikipedia.org/wiki/States_of_Brazil +ac.gov.br +al.gov.br +am.gov.br +ap.gov.br +ba.gov.br +ce.gov.br +df.gov.br +es.gov.br +go.gov.br +ma.gov.br +mg.gov.br +ms.gov.br +mt.gov.br +pa.gov.br +pb.gov.br +pe.gov.br +pi.gov.br +pr.gov.br +rj.gov.br +rn.gov.br +ro.gov.br +rr.gov.br +rs.gov.br +sc.gov.br +se.gov.br +sp.gov.br +to.gov.br +gru.br +imb.br +ind.br +inf.br +jab.br +jampa.br +jdf.br +joinville.br +jor.br +jus.br +leg.br +lel.br +londrina.br +macapa.br +maceio.br +manaus.br +maringa.br +mat.br +med.br +mil.br +morena.br +mp.br +mus.br +natal.br +net.br +niteroi.br +*.nom.br +not.br +ntr.br +odo.br +ong.br +org.br +osasco.br +palmas.br +poa.br +ppg.br +pro.br +psc.br +psi.br +pvh.br +qsl.br +radio.br +rec.br +recife.br +ribeirao.br +rio.br +riobranco.br +riopreto.br +salvador.br +sampa.br +santamaria.br +santoandre.br +saobernardo.br +saogonca.br +sjc.br +slg.br +slz.br +sorocaba.br +srv.br +taxi.br +teo.br +the.br +tmp.br +trd.br +tur.br +tv.br +udi.br +vet.br +vix.br +vlog.br +wiki.br +zlg.br + +// bs : http://www.nic.bs/rules.html +bs +com.bs +net.bs +org.bs +edu.bs +gov.bs + +// bt : https://en.wikipedia.org/wiki/.bt +bt +com.bt +edu.bt +gov.bt +net.bt +org.bt + +// bv : No registrations at this time. +// Submitted by registry +bv + +// bw : https://en.wikipedia.org/wiki/.bw +// http://www.gobin.info/domainname/bw.doc +// list of other 2nd level tlds ? +bw +co.bw +org.bw + +// by : https://en.wikipedia.org/wiki/.by +// http://tld.by/rules_2006_en.html +// list of other 2nd level tlds ? +by +gov.by +mil.by +// Official information does not indicate that com.by is a reserved +// second-level domain, but it's being used as one (see www.google.com.by and +// www.yahoo.com.by, for example), so we list it here for safety's sake. +com.by + +// http://hoster.by/ +of.by + +// bz : https://en.wikipedia.org/wiki/.bz +// http://www.belizenic.bz/ +bz +com.bz +net.bz +org.bz +edu.bz +gov.bz + +// ca : https://en.wikipedia.org/wiki/.ca +ca +// ca geographical names +ab.ca +bc.ca +mb.ca +nb.ca +nf.ca +nl.ca +ns.ca +nt.ca +nu.ca +on.ca +pe.ca +qc.ca +sk.ca +yk.ca +// gc.ca: https://en.wikipedia.org/wiki/.gc.ca +// see also: http://registry.gc.ca/en/SubdomainFAQ +gc.ca + +// cat : https://en.wikipedia.org/wiki/.cat +cat + +// cc : https://en.wikipedia.org/wiki/.cc +cc + +// cd : https://en.wikipedia.org/wiki/.cd +// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 +cd +gov.cd + +// cf : https://en.wikipedia.org/wiki/.cf +cf + +// cg : https://en.wikipedia.org/wiki/.cg +cg + +// ch : https://en.wikipedia.org/wiki/.ch +ch + +// ci : https://en.wikipedia.org/wiki/.ci +// http://www.nic.ci/index.php?page=charte +ci +org.ci +or.ci +com.ci +co.ci +edu.ci +ed.ci +ac.ci +net.ci +go.ci +asso.ci +aéroport.ci +int.ci +presse.ci +md.ci +gouv.ci + +// ck : https://en.wikipedia.org/wiki/.ck +*.ck +!www.ck + +// cl : https://en.wikipedia.org/wiki/.cl +cl +gov.cl +gob.cl +co.cl +mil.cl + +// cm : https://en.wikipedia.org/wiki/.cm plus bug 981927 +cm +co.cm +com.cm +gov.cm +net.cm + +// cn : https://en.wikipedia.org/wiki/.cn +// Submitted by registry +cn +ac.cn +com.cn +edu.cn +gov.cn +net.cn +org.cn +mil.cn +公司.cn +网络.cn +網絡.cn +// cn geographic names +ah.cn +bj.cn +cq.cn +fj.cn +gd.cn +gs.cn +gz.cn +gx.cn +ha.cn +hb.cn +he.cn +hi.cn +hl.cn +hn.cn +jl.cn +js.cn +jx.cn +ln.cn +nm.cn +nx.cn +qh.cn +sc.cn +sd.cn +sh.cn +sn.cn +sx.cn +tj.cn +xj.cn +xz.cn +yn.cn +zj.cn +hk.cn +mo.cn +tw.cn + +// co : https://en.wikipedia.org/wiki/.co +// Submitted by registry +co +arts.co +com.co +edu.co +firm.co +gov.co +info.co +int.co +mil.co +net.co +nom.co +org.co +rec.co +web.co + +// com : https://en.wikipedia.org/wiki/.com +com + +// coop : https://en.wikipedia.org/wiki/.coop +coop + +// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do +cr +ac.cr +co.cr +ed.cr +fi.cr +go.cr +or.cr +sa.cr + +// cu : https://en.wikipedia.org/wiki/.cu +cu +com.cu +edu.cu +org.cu +net.cu +gov.cu +inf.cu + +// cv : https://en.wikipedia.org/wiki/.cv +cv + +// cw : http://www.una.cw/cw_registry/ +// Confirmed by registry 2013-03-26 +cw +com.cw +edu.cw +net.cw +org.cw + +// cx : https://en.wikipedia.org/wiki/.cx +// list of other 2nd level tlds ? +cx +gov.cx + +// cy : http://www.nic.cy/ +// Submitted by registry Panayiotou Fotia +cy +ac.cy +biz.cy +com.cy +ekloges.cy +gov.cy +ltd.cy +name.cy +net.cy +org.cy +parliament.cy +press.cy +pro.cy +tm.cy + +// cz : https://en.wikipedia.org/wiki/.cz +cz + +// de : https://en.wikipedia.org/wiki/.de +// Confirmed by registry (with technical +// reservations) 2008-07-01 +de + +// dj : https://en.wikipedia.org/wiki/.dj +dj + +// dk : https://en.wikipedia.org/wiki/.dk +// Confirmed by registry 2008-06-17 +dk + +// dm : https://en.wikipedia.org/wiki/.dm +dm +com.dm +net.dm +org.dm +edu.dm +gov.dm + +// do : https://en.wikipedia.org/wiki/.do +do +art.do +com.do +edu.do +gob.do +gov.do +mil.do +net.do +org.do +sld.do +web.do + +// dz : https://en.wikipedia.org/wiki/.dz +dz +com.dz +org.dz +net.dz +gov.dz +edu.dz +asso.dz +pol.dz +art.dz + +// ec : http://www.nic.ec/reg/paso1.asp +// Submitted by registry +ec +com.ec +info.ec +net.ec +fin.ec +k12.ec +med.ec +pro.ec +org.ec +edu.ec +gov.ec +gob.ec +mil.ec + +// edu : https://en.wikipedia.org/wiki/.edu +edu + +// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B +ee +edu.ee +gov.ee +riik.ee +lib.ee +med.ee +com.ee +pri.ee +aip.ee +org.ee +fie.ee + +// eg : https://en.wikipedia.org/wiki/.eg +eg +com.eg +edu.eg +eun.eg +gov.eg +mil.eg +name.eg +net.eg +org.eg +sci.eg + +// er : https://en.wikipedia.org/wiki/.er +*.er + +// es : https://www.nic.es/site_ingles/ingles/dominios/index.html +es +com.es +nom.es +org.es +gob.es +edu.es + +// et : https://en.wikipedia.org/wiki/.et +et +com.et +gov.et +org.et +edu.et +biz.et +name.et +info.et +net.et + +// eu : https://en.wikipedia.org/wiki/.eu +eu + +// fi : https://en.wikipedia.org/wiki/.fi +fi +// aland.fi : https://en.wikipedia.org/wiki/.ax +// This domain is being phased out in favor of .ax. As there are still many +// domains under aland.fi, we still keep it on the list until aland.fi is +// completely removed. +// TODO: Check for updates (expected to be phased out around Q1/2009) +aland.fi + +// fj : https://en.wikipedia.org/wiki/.fj +*.fj + +// fk : https://en.wikipedia.org/wiki/.fk +*.fk + +// fm : https://en.wikipedia.org/wiki/.fm +fm + +// fo : https://en.wikipedia.org/wiki/.fo +fo + +// fr : http://www.afnic.fr/ +// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs +fr +com.fr +asso.fr +nom.fr +prd.fr +presse.fr +tm.fr +// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels +aeroport.fr +assedic.fr +avocat.fr +avoues.fr +cci.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +geometre-expert.fr +gouv.fr +greta.fr +huissier-justice.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + +// ga : https://en.wikipedia.org/wiki/.ga +ga + +// gb : This registry is effectively dormant +// Submitted by registry +gb + +// gd : https://en.wikipedia.org/wiki/.gd +gd + +// ge : http://www.nic.net.ge/policy_en.pdf +ge +com.ge +edu.ge +gov.ge +org.ge +mil.ge +net.ge +pvt.ge + +// gf : https://en.wikipedia.org/wiki/.gf +gf + +// gg : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +gg +co.gg +net.gg +org.gg + +// gh : https://en.wikipedia.org/wiki/.gh +// see also: http://www.nic.gh/reg_now.php +// Although domains directly at second level are not possible at the moment, +// they have been possible for some time and may come back. +gh +com.gh +edu.gh +gov.gh +org.gh +mil.gh + +// gi : http://www.nic.gi/rules.html +gi +com.gi +ltd.gi +gov.gi +mod.gi +edu.gi +org.gi + +// gl : https://en.wikipedia.org/wiki/.gl +// http://nic.gl +gl +co.gl +com.gl +edu.gl +net.gl +org.gl + +// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm +gm + +// gn : http://psg.com/dns/gn/gn.txt +// Submitted by registry +gn +ac.gn +com.gn +edu.gn +gov.gn +org.gn +net.gn + +// gov : https://en.wikipedia.org/wiki/.gov +gov + +// gp : http://www.nic.gp/index.php?lang=en +gp +com.gp +net.gp +mobi.gp +edu.gp +org.gp +asso.gp + +// gq : https://en.wikipedia.org/wiki/.gq +gq + +// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html +// Submitted by registry +gr +com.gr +edu.gr +net.gr +org.gr +gov.gr + +// gs : https://en.wikipedia.org/wiki/.gs +gs + +// gt : http://www.gt/politicas_de_registro.html +gt +com.gt +edu.gt +gob.gt +ind.gt +mil.gt +net.gt +org.gt + +// gu : http://gadao.gov.gu/register.html +// University of Guam : https://www.uog.edu +// Submitted by uognoc@triton.uog.edu +gu +com.gu +edu.gu +gov.gu +guam.gu +info.gu +net.gu +org.gu +web.gu + +// gw : https://en.wikipedia.org/wiki/.gw +gw + +// gy : https://en.wikipedia.org/wiki/.gy +// http://registry.gy/ +gy +co.gy +com.gy +edu.gy +gov.gy +net.gy +org.gy + +// hk : https://www.hkirc.hk +// Submitted by registry +hk +com.hk +edu.hk +gov.hk +idv.hk +net.hk +org.hk +公司.hk +教育.hk +敎育.hk +政府.hk +個人.hk +个人.hk +箇人.hk +網络.hk +网络.hk +组織.hk +網絡.hk +网絡.hk +组织.hk +組織.hk +組织.hk + +// hm : https://en.wikipedia.org/wiki/.hm +hm + +// hn : http://www.nic.hn/politicas/ps02,,05.html +hn +com.hn +edu.hn +org.hn +net.hn +mil.hn +gob.hn + +// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf +hr +iz.hr +from.hr +name.hr +com.hr + +// ht : http://www.nic.ht/info/charte.cfm +ht +com.ht +shop.ht +firm.ht +info.ht +adult.ht +net.ht +pro.ht +org.ht +med.ht +art.ht +coop.ht +pol.ht +asso.ht +edu.ht +rel.ht +gouv.ht +perso.ht + +// hu : http://www.domain.hu/domain/English/sld.html +// Confirmed by registry 2008-06-12 +hu +co.hu +info.hu +org.hu +priv.hu +sport.hu +tm.hu +2000.hu +agrar.hu +bolt.hu +casino.hu +city.hu +erotica.hu +erotika.hu +film.hu +forum.hu +games.hu +hotel.hu +ingatlan.hu +jogasz.hu +konyvelo.hu +lakas.hu +media.hu +news.hu +reklam.hu +sex.hu +shop.hu +suli.hu +szex.hu +tozsde.hu +utazas.hu +video.hu + +// id : https://pandi.id/en/domain/registration-requirements/ +id +ac.id +biz.id +co.id +desa.id +go.id +mil.id +my.id +net.id +or.id +ponpes.id +sch.id +web.id + +// ie : https://en.wikipedia.org/wiki/.ie +ie +gov.ie + +// il : http://www.isoc.org.il/domains/ +il +ac.il +co.il +gov.il +idf.il +k12.il +muni.il +net.il +org.il + +// im : https://www.nic.im/ +// Submitted by registry +im +ac.im +co.im +com.im +ltd.co.im +net.im +org.im +plc.co.im +tt.im +tv.im + +// in : https://en.wikipedia.org/wiki/.in +// see also: https://registry.in/Policies +// Please note, that nic.in is not an official eTLD, but used by most +// government institutions. +in +co.in +firm.in +net.in +org.in +gen.in +ind.in +nic.in +ac.in +edu.in +res.in +gov.in +mil.in + +// info : https://en.wikipedia.org/wiki/.info +info + +// int : https://en.wikipedia.org/wiki/.int +// Confirmed by registry 2008-06-18 +int +eu.int + +// io : http://www.nic.io/rules.html +// list of other 2nd level tlds ? +io +com.io + +// iq : http://www.cmc.iq/english/iq/iqregister1.htm +iq +gov.iq +edu.iq +mil.iq +com.iq +org.iq +net.iq + +// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules +// Also see http://www.nic.ir/Internationalized_Domain_Names +// Two .ir entries added at request of , 2010-04-16 +ir +ac.ir +co.ir +gov.ir +id.ir +net.ir +org.ir +sch.ir +// xn--mgba3a4f16a.ir (.ir, Persian YEH) +ایران.ir +// xn--mgba3a4fra.ir (.ir, Arabic YEH) +ايران.ir + +// is : http://www.isnic.is/domain/rules.php +// Confirmed by registry 2008-12-06 +is +net.is +com.is +edu.is +gov.is +org.is +int.is + +// it : https://en.wikipedia.org/wiki/.it +it +gov.it +edu.it +// Reserved geo-names (regions and provinces): +// http://www.nic.it/sites/default/files/docs/Regulation_assignation_v7.1.pdf +// Regions +abr.it +abruzzo.it +aosta-valley.it +aostavalley.it +bas.it +basilicata.it +cal.it +calabria.it +cam.it +campania.it +emilia-romagna.it +emiliaromagna.it +emr.it +friuli-v-giulia.it +friuli-ve-giulia.it +friuli-vegiulia.it +friuli-venezia-giulia.it +friuli-veneziagiulia.it +friuli-vgiulia.it +friuliv-giulia.it +friulive-giulia.it +friulivegiulia.it +friulivenezia-giulia.it +friuliveneziagiulia.it +friulivgiulia.it +fvg.it +laz.it +lazio.it +lig.it +liguria.it +lom.it +lombardia.it +lombardy.it +lucania.it +mar.it +marche.it +mol.it +molise.it +piedmont.it +piemonte.it +pmn.it +pug.it +puglia.it +sar.it +sardegna.it +sardinia.it +sic.it +sicilia.it +sicily.it +taa.it +tos.it +toscana.it +trentin-sud-tirol.it +trentin-süd-tirol.it +trentin-sudtirol.it +trentin-südtirol.it +trentin-sued-tirol.it +trentin-suedtirol.it +trentino-a-adige.it +trentino-aadige.it +trentino-alto-adige.it +trentino-altoadige.it +trentino-s-tirol.it +trentino-stirol.it +trentino-sud-tirol.it +trentino-süd-tirol.it +trentino-sudtirol.it +trentino-südtirol.it +trentino-sued-tirol.it +trentino-suedtirol.it +trentino.it +trentinoa-adige.it +trentinoaadige.it +trentinoalto-adige.it +trentinoaltoadige.it +trentinos-tirol.it +trentinostirol.it +trentinosud-tirol.it +trentinosüd-tirol.it +trentinosudtirol.it +trentinosüdtirol.it +trentinosued-tirol.it +trentinosuedtirol.it +trentinsud-tirol.it +trentinsüd-tirol.it +trentinsudtirol.it +trentinsüdtirol.it +trentinsued-tirol.it +trentinsuedtirol.it +tuscany.it +umb.it +umbria.it +val-d-aosta.it +val-daosta.it +vald-aosta.it +valdaosta.it +valle-aosta.it +valle-d-aosta.it +valle-daosta.it +valleaosta.it +valled-aosta.it +valledaosta.it +vallee-aoste.it +vallée-aoste.it +vallee-d-aoste.it +vallée-d-aoste.it +valleeaoste.it +valléeaoste.it +valleedaoste.it +valléedaoste.it +vao.it +vda.it +ven.it +veneto.it +// Provinces +ag.it +agrigento.it +al.it +alessandria.it +alto-adige.it +altoadige.it +an.it +ancona.it +andria-barletta-trani.it +andria-trani-barletta.it +andriabarlettatrani.it +andriatranibarletta.it +ao.it +aosta.it +aoste.it +ap.it +aq.it +aquila.it +ar.it +arezzo.it +ascoli-piceno.it +ascolipiceno.it +asti.it +at.it +av.it +avellino.it +ba.it +balsan-sudtirol.it +balsan-südtirol.it +balsan-suedtirol.it +balsan.it +bari.it +barletta-trani-andria.it +barlettatraniandria.it +belluno.it +benevento.it +bergamo.it +bg.it +bi.it +biella.it +bl.it +bn.it +bo.it +bologna.it +bolzano-altoadige.it +bolzano.it +bozen-sudtirol.it +bozen-südtirol.it +bozen-suedtirol.it +bozen.it +br.it +brescia.it +brindisi.it +bs.it +bt.it +bulsan-sudtirol.it +bulsan-südtirol.it +bulsan-suedtirol.it +bulsan.it +bz.it +ca.it +cagliari.it +caltanissetta.it +campidano-medio.it +campidanomedio.it +campobasso.it +carbonia-iglesias.it +carboniaiglesias.it +carrara-massa.it +carraramassa.it +caserta.it +catania.it +catanzaro.it +cb.it +ce.it +cesena-forli.it +cesena-forlì.it +cesenaforli.it +cesenaforlì.it +ch.it +chieti.it +ci.it +cl.it +cn.it +co.it +como.it +cosenza.it +cr.it +cremona.it +crotone.it +cs.it +ct.it +cuneo.it +cz.it +dell-ogliastra.it +dellogliastra.it +en.it +enna.it +fc.it +fe.it +fermo.it +ferrara.it +fg.it +fi.it +firenze.it +florence.it +fm.it +foggia.it +forli-cesena.it +forlì-cesena.it +forlicesena.it +forlìcesena.it +fr.it +frosinone.it +ge.it +genoa.it +genova.it +go.it +gorizia.it +gr.it +grosseto.it +iglesias-carbonia.it +iglesiascarbonia.it +im.it +imperia.it +is.it +isernia.it +kr.it +la-spezia.it +laquila.it +laspezia.it +latina.it +lc.it +le.it +lecce.it +lecco.it +li.it +livorno.it +lo.it +lodi.it +lt.it +lu.it +lucca.it +macerata.it +mantova.it +massa-carrara.it +massacarrara.it +matera.it +mb.it +mc.it +me.it +medio-campidano.it +mediocampidano.it +messina.it +mi.it +milan.it +milano.it +mn.it +mo.it +modena.it +monza-brianza.it +monza-e-della-brianza.it +monza.it +monzabrianza.it +monzaebrianza.it +monzaedellabrianza.it +ms.it +mt.it +na.it +naples.it +napoli.it +no.it +novara.it +nu.it +nuoro.it +og.it +ogliastra.it +olbia-tempio.it +olbiatempio.it +or.it +oristano.it +ot.it +pa.it +padova.it +padua.it +palermo.it +parma.it +pavia.it +pc.it +pd.it +pe.it +perugia.it +pesaro-urbino.it +pesarourbino.it +pescara.it +pg.it +pi.it +piacenza.it +pisa.it +pistoia.it +pn.it +po.it +pordenone.it +potenza.it +pr.it +prato.it +pt.it +pu.it +pv.it +pz.it +ra.it +ragusa.it +ravenna.it +rc.it +re.it +reggio-calabria.it +reggio-emilia.it +reggiocalabria.it +reggioemilia.it +rg.it +ri.it +rieti.it +rimini.it +rm.it +rn.it +ro.it +roma.it +rome.it +rovigo.it +sa.it +salerno.it +sassari.it +savona.it +si.it +siena.it +siracusa.it +so.it +sondrio.it +sp.it +sr.it +ss.it +suedtirol.it +südtirol.it +sv.it +ta.it +taranto.it +te.it +tempio-olbia.it +tempioolbia.it +teramo.it +terni.it +tn.it +to.it +torino.it +tp.it +tr.it +trani-andria-barletta.it +trani-barletta-andria.it +traniandriabarletta.it +tranibarlettaandria.it +trapani.it +trento.it +treviso.it +trieste.it +ts.it +turin.it +tv.it +ud.it +udine.it +urbino-pesaro.it +urbinopesaro.it +va.it +varese.it +vb.it +vc.it +ve.it +venezia.it +venice.it +verbania.it +vercelli.it +verona.it +vi.it +vibo-valentia.it +vibovalentia.it +vicenza.it +viterbo.it +vr.it +vs.it +vt.it +vv.it + +// je : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +je +co.je +net.je +org.je + +// jm : http://www.com.jm/register.html +*.jm + +// jo : http://www.dns.jo/Registration_policy.aspx +jo +com.jo +org.jo +net.jo +edu.jo +sch.jo +gov.jo +mil.jo +name.jo + +// jobs : https://en.wikipedia.org/wiki/.jobs +jobs + +// jp : https://en.wikipedia.org/wiki/.jp +// http://jprs.co.jp/en/jpdomain.html +// Submitted by registry +jp +// jp organizational type names +ac.jp +ad.jp +co.jp +ed.jp +go.jp +gr.jp +lg.jp +ne.jp +or.jp +// jp prefecture type names +aichi.jp +akita.jp +aomori.jp +chiba.jp +ehime.jp +fukui.jp +fukuoka.jp +fukushima.jp +gifu.jp +gunma.jp +hiroshima.jp +hokkaido.jp +hyogo.jp +ibaraki.jp +ishikawa.jp +iwate.jp +kagawa.jp +kagoshima.jp +kanagawa.jp +kochi.jp +kumamoto.jp +kyoto.jp +mie.jp +miyagi.jp +miyazaki.jp +nagano.jp +nagasaki.jp +nara.jp +niigata.jp +oita.jp +okayama.jp +okinawa.jp +osaka.jp +saga.jp +saitama.jp +shiga.jp +shimane.jp +shizuoka.jp +tochigi.jp +tokushima.jp +tokyo.jp +tottori.jp +toyama.jp +wakayama.jp +yamagata.jp +yamaguchi.jp +yamanashi.jp +栃木.jp +愛知.jp +愛媛.jp +兵庫.jp +熊本.jp +茨城.jp +北海道.jp +千葉.jp +和歌山.jp +長崎.jp +長野.jp +新潟.jp +青森.jp +静岡.jp +東京.jp +石川.jp +埼玉.jp +三重.jp +京都.jp +佐賀.jp +大分.jp +大阪.jp +奈良.jp +宮城.jp +宮崎.jp +富山.jp +山口.jp +山形.jp +山梨.jp +岩手.jp +岐阜.jp +岡山.jp +å³¶æ ¹.jp +広島.jp +徳島.jp +沖縄.jp +滋賀.jp +神奈川.jp +福井.jp +福岡.jp +福島.jp +秋田.jp +群馬.jp +香川.jp +高知.jp +鳥取.jp +鹿児島.jp +// jp geographic type names +// http://jprs.jp/doc/rule/saisoku-1.html +*.kawasaki.jp +*.kitakyushu.jp +*.kobe.jp +*.nagoya.jp +*.sapporo.jp +*.sendai.jp +*.yokohama.jp +!city.kawasaki.jp +!city.kitakyushu.jp +!city.kobe.jp +!city.nagoya.jp +!city.sapporo.jp +!city.sendai.jp +!city.yokohama.jp +// 4th level registration +aisai.aichi.jp +ama.aichi.jp +anjo.aichi.jp +asuke.aichi.jp +chiryu.aichi.jp +chita.aichi.jp +fuso.aichi.jp +gamagori.aichi.jp +handa.aichi.jp +hazu.aichi.jp +hekinan.aichi.jp +higashiura.aichi.jp +ichinomiya.aichi.jp +inazawa.aichi.jp +inuyama.aichi.jp +isshiki.aichi.jp +iwakura.aichi.jp +kanie.aichi.jp +kariya.aichi.jp +kasugai.aichi.jp +kira.aichi.jp +kiyosu.aichi.jp +komaki.aichi.jp +konan.aichi.jp +kota.aichi.jp +mihama.aichi.jp +miyoshi.aichi.jp +nishio.aichi.jp +nisshin.aichi.jp +obu.aichi.jp +oguchi.aichi.jp +oharu.aichi.jp +okazaki.aichi.jp +owariasahi.aichi.jp +seto.aichi.jp +shikatsu.aichi.jp +shinshiro.aichi.jp +shitara.aichi.jp +tahara.aichi.jp +takahama.aichi.jp +tobishima.aichi.jp +toei.aichi.jp +togo.aichi.jp +tokai.aichi.jp +tokoname.aichi.jp +toyoake.aichi.jp +toyohashi.aichi.jp +toyokawa.aichi.jp +toyone.aichi.jp +toyota.aichi.jp +tsushima.aichi.jp +yatomi.aichi.jp +akita.akita.jp +daisen.akita.jp +fujisato.akita.jp +gojome.akita.jp +hachirogata.akita.jp +happou.akita.jp +higashinaruse.akita.jp +honjo.akita.jp +honjyo.akita.jp +ikawa.akita.jp +kamikoani.akita.jp +kamioka.akita.jp +katagami.akita.jp +kazuno.akita.jp +kitaakita.akita.jp +kosaka.akita.jp +kyowa.akita.jp +misato.akita.jp +mitane.akita.jp +moriyoshi.akita.jp +nikaho.akita.jp +noshiro.akita.jp +odate.akita.jp +oga.akita.jp +ogata.akita.jp +semboku.akita.jp +yokote.akita.jp +yurihonjo.akita.jp +aomori.aomori.jp +gonohe.aomori.jp +hachinohe.aomori.jp +hashikami.aomori.jp +hiranai.aomori.jp +hirosaki.aomori.jp +itayanagi.aomori.jp +kuroishi.aomori.jp +misawa.aomori.jp +mutsu.aomori.jp +nakadomari.aomori.jp +noheji.aomori.jp +oirase.aomori.jp +owani.aomori.jp +rokunohe.aomori.jp +sannohe.aomori.jp +shichinohe.aomori.jp +shingo.aomori.jp +takko.aomori.jp +towada.aomori.jp +tsugaru.aomori.jp +tsuruta.aomori.jp +abiko.chiba.jp +asahi.chiba.jp +chonan.chiba.jp +chosei.chiba.jp +choshi.chiba.jp +chuo.chiba.jp +funabashi.chiba.jp +futtsu.chiba.jp +hanamigawa.chiba.jp +ichihara.chiba.jp +ichikawa.chiba.jp +ichinomiya.chiba.jp +inzai.chiba.jp +isumi.chiba.jp +kamagaya.chiba.jp +kamogawa.chiba.jp +kashiwa.chiba.jp +katori.chiba.jp +katsuura.chiba.jp +kimitsu.chiba.jp +kisarazu.chiba.jp +kozaki.chiba.jp +kujukuri.chiba.jp +kyonan.chiba.jp +matsudo.chiba.jp +midori.chiba.jp +mihama.chiba.jp +minamiboso.chiba.jp +mobara.chiba.jp +mutsuzawa.chiba.jp +nagara.chiba.jp +nagareyama.chiba.jp +narashino.chiba.jp +narita.chiba.jp +noda.chiba.jp +oamishirasato.chiba.jp +omigawa.chiba.jp +onjuku.chiba.jp +otaki.chiba.jp +sakae.chiba.jp +sakura.chiba.jp +shimofusa.chiba.jp +shirako.chiba.jp +shiroi.chiba.jp +shisui.chiba.jp +sodegaura.chiba.jp +sosa.chiba.jp +tako.chiba.jp +tateyama.chiba.jp +togane.chiba.jp +tohnosho.chiba.jp +tomisato.chiba.jp +urayasu.chiba.jp +yachimata.chiba.jp +yachiyo.chiba.jp +yokaichiba.chiba.jp +yokoshibahikari.chiba.jp +yotsukaido.chiba.jp +ainan.ehime.jp +honai.ehime.jp +ikata.ehime.jp +imabari.ehime.jp +iyo.ehime.jp +kamijima.ehime.jp +kihoku.ehime.jp +kumakogen.ehime.jp +masaki.ehime.jp +matsuno.ehime.jp +matsuyama.ehime.jp +namikata.ehime.jp +niihama.ehime.jp +ozu.ehime.jp +saijo.ehime.jp +seiyo.ehime.jp +shikokuchuo.ehime.jp +tobe.ehime.jp +toon.ehime.jp +uchiko.ehime.jp +uwajima.ehime.jp +yawatahama.ehime.jp +echizen.fukui.jp +eiheiji.fukui.jp +fukui.fukui.jp +ikeda.fukui.jp +katsuyama.fukui.jp +mihama.fukui.jp +minamiechizen.fukui.jp +obama.fukui.jp +ohi.fukui.jp +ono.fukui.jp +sabae.fukui.jp +sakai.fukui.jp +takahama.fukui.jp +tsuruga.fukui.jp +wakasa.fukui.jp +ashiya.fukuoka.jp +buzen.fukuoka.jp +chikugo.fukuoka.jp +chikuho.fukuoka.jp +chikujo.fukuoka.jp +chikushino.fukuoka.jp +chikuzen.fukuoka.jp +chuo.fukuoka.jp +dazaifu.fukuoka.jp +fukuchi.fukuoka.jp +hakata.fukuoka.jp +higashi.fukuoka.jp +hirokawa.fukuoka.jp +hisayama.fukuoka.jp +iizuka.fukuoka.jp +inatsuki.fukuoka.jp +kaho.fukuoka.jp +kasuga.fukuoka.jp +kasuya.fukuoka.jp +kawara.fukuoka.jp +keisen.fukuoka.jp +koga.fukuoka.jp +kurate.fukuoka.jp +kurogi.fukuoka.jp +kurume.fukuoka.jp +minami.fukuoka.jp +miyako.fukuoka.jp +miyama.fukuoka.jp +miyawaka.fukuoka.jp +mizumaki.fukuoka.jp +munakata.fukuoka.jp +nakagawa.fukuoka.jp +nakama.fukuoka.jp +nishi.fukuoka.jp +nogata.fukuoka.jp +ogori.fukuoka.jp +okagaki.fukuoka.jp +okawa.fukuoka.jp +oki.fukuoka.jp +omuta.fukuoka.jp +onga.fukuoka.jp +onojo.fukuoka.jp +oto.fukuoka.jp +saigawa.fukuoka.jp +sasaguri.fukuoka.jp +shingu.fukuoka.jp +shinyoshitomi.fukuoka.jp +shonai.fukuoka.jp +soeda.fukuoka.jp +sue.fukuoka.jp +tachiarai.fukuoka.jp +tagawa.fukuoka.jp +takata.fukuoka.jp +toho.fukuoka.jp +toyotsu.fukuoka.jp +tsuiki.fukuoka.jp +ukiha.fukuoka.jp +umi.fukuoka.jp +usui.fukuoka.jp +yamada.fukuoka.jp +yame.fukuoka.jp +yanagawa.fukuoka.jp +yukuhashi.fukuoka.jp +aizubange.fukushima.jp +aizumisato.fukushima.jp +aizuwakamatsu.fukushima.jp +asakawa.fukushima.jp +bandai.fukushima.jp +date.fukushima.jp +fukushima.fukushima.jp +furudono.fukushima.jp +futaba.fukushima.jp +hanawa.fukushima.jp +higashi.fukushima.jp +hirata.fukushima.jp +hirono.fukushima.jp +iitate.fukushima.jp +inawashiro.fukushima.jp +ishikawa.fukushima.jp +iwaki.fukushima.jp +izumizaki.fukushima.jp +kagamiishi.fukushima.jp +kaneyama.fukushima.jp +kawamata.fukushima.jp +kitakata.fukushima.jp +kitashiobara.fukushima.jp +koori.fukushima.jp +koriyama.fukushima.jp +kunimi.fukushima.jp +miharu.fukushima.jp +mishima.fukushima.jp +namie.fukushima.jp +nango.fukushima.jp +nishiaizu.fukushima.jp +nishigo.fukushima.jp +okuma.fukushima.jp +omotego.fukushima.jp +ono.fukushima.jp +otama.fukushima.jp +samegawa.fukushima.jp +shimogo.fukushima.jp +shirakawa.fukushima.jp +showa.fukushima.jp +soma.fukushima.jp +sukagawa.fukushima.jp +taishin.fukushima.jp +tamakawa.fukushima.jp +tanagura.fukushima.jp +tenei.fukushima.jp +yabuki.fukushima.jp +yamato.fukushima.jp +yamatsuri.fukushima.jp +yanaizu.fukushima.jp +yugawa.fukushima.jp +anpachi.gifu.jp +ena.gifu.jp +gifu.gifu.jp +ginan.gifu.jp +godo.gifu.jp +gujo.gifu.jp +hashima.gifu.jp +hichiso.gifu.jp +hida.gifu.jp +higashishirakawa.gifu.jp +ibigawa.gifu.jp +ikeda.gifu.jp +kakamigahara.gifu.jp +kani.gifu.jp +kasahara.gifu.jp +kasamatsu.gifu.jp +kawaue.gifu.jp +kitagata.gifu.jp +mino.gifu.jp +minokamo.gifu.jp +mitake.gifu.jp +mizunami.gifu.jp +motosu.gifu.jp +nakatsugawa.gifu.jp +ogaki.gifu.jp +sakahogi.gifu.jp +seki.gifu.jp +sekigahara.gifu.jp +shirakawa.gifu.jp +tajimi.gifu.jp +takayama.gifu.jp +tarui.gifu.jp +toki.gifu.jp +tomika.gifu.jp +wanouchi.gifu.jp +yamagata.gifu.jp +yaotsu.gifu.jp +yoro.gifu.jp +annaka.gunma.jp +chiyoda.gunma.jp +fujioka.gunma.jp +higashiagatsuma.gunma.jp +isesaki.gunma.jp +itakura.gunma.jp +kanna.gunma.jp +kanra.gunma.jp +katashina.gunma.jp +kawaba.gunma.jp +kiryu.gunma.jp +kusatsu.gunma.jp +maebashi.gunma.jp +meiwa.gunma.jp +midori.gunma.jp +minakami.gunma.jp +naganohara.gunma.jp +nakanojo.gunma.jp +nanmoku.gunma.jp +numata.gunma.jp +oizumi.gunma.jp +ora.gunma.jp +ota.gunma.jp +shibukawa.gunma.jp +shimonita.gunma.jp +shinto.gunma.jp +showa.gunma.jp +takasaki.gunma.jp +takayama.gunma.jp +tamamura.gunma.jp +tatebayashi.gunma.jp +tomioka.gunma.jp +tsukiyono.gunma.jp +tsumagoi.gunma.jp +ueno.gunma.jp +yoshioka.gunma.jp +asaminami.hiroshima.jp +daiwa.hiroshima.jp +etajima.hiroshima.jp +fuchu.hiroshima.jp +fukuyama.hiroshima.jp +hatsukaichi.hiroshima.jp +higashihiroshima.hiroshima.jp +hongo.hiroshima.jp +jinsekikogen.hiroshima.jp +kaita.hiroshima.jp +kui.hiroshima.jp +kumano.hiroshima.jp +kure.hiroshima.jp +mihara.hiroshima.jp +miyoshi.hiroshima.jp +naka.hiroshima.jp +onomichi.hiroshima.jp +osakikamijima.hiroshima.jp +otake.hiroshima.jp +saka.hiroshima.jp +sera.hiroshima.jp +seranishi.hiroshima.jp +shinichi.hiroshima.jp +shobara.hiroshima.jp +takehara.hiroshima.jp +abashiri.hokkaido.jp +abira.hokkaido.jp +aibetsu.hokkaido.jp +akabira.hokkaido.jp +akkeshi.hokkaido.jp +asahikawa.hokkaido.jp +ashibetsu.hokkaido.jp +ashoro.hokkaido.jp +assabu.hokkaido.jp +atsuma.hokkaido.jp +bibai.hokkaido.jp +biei.hokkaido.jp +bifuka.hokkaido.jp +bihoro.hokkaido.jp +biratori.hokkaido.jp +chippubetsu.hokkaido.jp +chitose.hokkaido.jp +date.hokkaido.jp +ebetsu.hokkaido.jp +embetsu.hokkaido.jp +eniwa.hokkaido.jp +erimo.hokkaido.jp +esan.hokkaido.jp +esashi.hokkaido.jp +fukagawa.hokkaido.jp +fukushima.hokkaido.jp +furano.hokkaido.jp +furubira.hokkaido.jp +haboro.hokkaido.jp +hakodate.hokkaido.jp +hamatonbetsu.hokkaido.jp +hidaka.hokkaido.jp +higashikagura.hokkaido.jp +higashikawa.hokkaido.jp +hiroo.hokkaido.jp +hokuryu.hokkaido.jp +hokuto.hokkaido.jp +honbetsu.hokkaido.jp +horokanai.hokkaido.jp +horonobe.hokkaido.jp +ikeda.hokkaido.jp +imakane.hokkaido.jp +ishikari.hokkaido.jp +iwamizawa.hokkaido.jp +iwanai.hokkaido.jp +kamifurano.hokkaido.jp +kamikawa.hokkaido.jp +kamishihoro.hokkaido.jp +kamisunagawa.hokkaido.jp +kamoenai.hokkaido.jp +kayabe.hokkaido.jp +kembuchi.hokkaido.jp +kikonai.hokkaido.jp +kimobetsu.hokkaido.jp +kitahiroshima.hokkaido.jp +kitami.hokkaido.jp +kiyosato.hokkaido.jp +koshimizu.hokkaido.jp +kunneppu.hokkaido.jp +kuriyama.hokkaido.jp +kuromatsunai.hokkaido.jp +kushiro.hokkaido.jp +kutchan.hokkaido.jp +kyowa.hokkaido.jp +mashike.hokkaido.jp +matsumae.hokkaido.jp +mikasa.hokkaido.jp +minamifurano.hokkaido.jp +mombetsu.hokkaido.jp +moseushi.hokkaido.jp +mukawa.hokkaido.jp +muroran.hokkaido.jp +naie.hokkaido.jp +nakagawa.hokkaido.jp +nakasatsunai.hokkaido.jp +nakatombetsu.hokkaido.jp +nanae.hokkaido.jp +nanporo.hokkaido.jp +nayoro.hokkaido.jp +nemuro.hokkaido.jp +niikappu.hokkaido.jp +niki.hokkaido.jp +nishiokoppe.hokkaido.jp +noboribetsu.hokkaido.jp +numata.hokkaido.jp +obihiro.hokkaido.jp +obira.hokkaido.jp +oketo.hokkaido.jp +okoppe.hokkaido.jp +otaru.hokkaido.jp +otobe.hokkaido.jp +otofuke.hokkaido.jp +otoineppu.hokkaido.jp +oumu.hokkaido.jp +ozora.hokkaido.jp +pippu.hokkaido.jp +rankoshi.hokkaido.jp +rebun.hokkaido.jp +rikubetsu.hokkaido.jp +rishiri.hokkaido.jp +rishirifuji.hokkaido.jp +saroma.hokkaido.jp +sarufutsu.hokkaido.jp +shakotan.hokkaido.jp +shari.hokkaido.jp +shibecha.hokkaido.jp +shibetsu.hokkaido.jp +shikabe.hokkaido.jp +shikaoi.hokkaido.jp +shimamaki.hokkaido.jp +shimizu.hokkaido.jp +shimokawa.hokkaido.jp +shinshinotsu.hokkaido.jp +shintoku.hokkaido.jp +shiranuka.hokkaido.jp +shiraoi.hokkaido.jp +shiriuchi.hokkaido.jp +sobetsu.hokkaido.jp +sunagawa.hokkaido.jp +taiki.hokkaido.jp +takasu.hokkaido.jp +takikawa.hokkaido.jp +takinoue.hokkaido.jp +teshikaga.hokkaido.jp +tobetsu.hokkaido.jp +tohma.hokkaido.jp +tomakomai.hokkaido.jp +tomari.hokkaido.jp +toya.hokkaido.jp +toyako.hokkaido.jp +toyotomi.hokkaido.jp +toyoura.hokkaido.jp +tsubetsu.hokkaido.jp +tsukigata.hokkaido.jp +urakawa.hokkaido.jp +urausu.hokkaido.jp +uryu.hokkaido.jp +utashinai.hokkaido.jp +wakkanai.hokkaido.jp +wassamu.hokkaido.jp +yakumo.hokkaido.jp +yoichi.hokkaido.jp +aioi.hyogo.jp +akashi.hyogo.jp +ako.hyogo.jp +amagasaki.hyogo.jp +aogaki.hyogo.jp +asago.hyogo.jp +ashiya.hyogo.jp +awaji.hyogo.jp +fukusaki.hyogo.jp +goshiki.hyogo.jp +harima.hyogo.jp +himeji.hyogo.jp +ichikawa.hyogo.jp +inagawa.hyogo.jp +itami.hyogo.jp +kakogawa.hyogo.jp +kamigori.hyogo.jp +kamikawa.hyogo.jp +kasai.hyogo.jp +kasuga.hyogo.jp +kawanishi.hyogo.jp +miki.hyogo.jp +minamiawaji.hyogo.jp +nishinomiya.hyogo.jp +nishiwaki.hyogo.jp +ono.hyogo.jp +sanda.hyogo.jp +sannan.hyogo.jp +sasayama.hyogo.jp +sayo.hyogo.jp +shingu.hyogo.jp +shinonsen.hyogo.jp +shiso.hyogo.jp +sumoto.hyogo.jp +taishi.hyogo.jp +taka.hyogo.jp +takarazuka.hyogo.jp +takasago.hyogo.jp +takino.hyogo.jp +tamba.hyogo.jp +tatsuno.hyogo.jp +toyooka.hyogo.jp +yabu.hyogo.jp +yashiro.hyogo.jp +yoka.hyogo.jp +yokawa.hyogo.jp +ami.ibaraki.jp +asahi.ibaraki.jp +bando.ibaraki.jp +chikusei.ibaraki.jp +daigo.ibaraki.jp +fujishiro.ibaraki.jp +hitachi.ibaraki.jp +hitachinaka.ibaraki.jp +hitachiomiya.ibaraki.jp +hitachiota.ibaraki.jp +ibaraki.ibaraki.jp +ina.ibaraki.jp +inashiki.ibaraki.jp +itako.ibaraki.jp +iwama.ibaraki.jp +joso.ibaraki.jp +kamisu.ibaraki.jp +kasama.ibaraki.jp +kashima.ibaraki.jp +kasumigaura.ibaraki.jp +koga.ibaraki.jp +miho.ibaraki.jp +mito.ibaraki.jp +moriya.ibaraki.jp +naka.ibaraki.jp +namegata.ibaraki.jp +oarai.ibaraki.jp +ogawa.ibaraki.jp +omitama.ibaraki.jp +ryugasaki.ibaraki.jp +sakai.ibaraki.jp +sakuragawa.ibaraki.jp +shimodate.ibaraki.jp +shimotsuma.ibaraki.jp +shirosato.ibaraki.jp +sowa.ibaraki.jp +suifu.ibaraki.jp +takahagi.ibaraki.jp +tamatsukuri.ibaraki.jp +tokai.ibaraki.jp +tomobe.ibaraki.jp +tone.ibaraki.jp +toride.ibaraki.jp +tsuchiura.ibaraki.jp +tsukuba.ibaraki.jp +uchihara.ibaraki.jp +ushiku.ibaraki.jp +yachiyo.ibaraki.jp +yamagata.ibaraki.jp +yawara.ibaraki.jp +yuki.ibaraki.jp +anamizu.ishikawa.jp +hakui.ishikawa.jp +hakusan.ishikawa.jp +kaga.ishikawa.jp +kahoku.ishikawa.jp +kanazawa.ishikawa.jp +kawakita.ishikawa.jp +komatsu.ishikawa.jp +nakanoto.ishikawa.jp +nanao.ishikawa.jp +nomi.ishikawa.jp +nonoichi.ishikawa.jp +noto.ishikawa.jp +shika.ishikawa.jp +suzu.ishikawa.jp +tsubata.ishikawa.jp +tsurugi.ishikawa.jp +uchinada.ishikawa.jp +wajima.ishikawa.jp +fudai.iwate.jp +fujisawa.iwate.jp +hanamaki.iwate.jp +hiraizumi.iwate.jp +hirono.iwate.jp +ichinohe.iwate.jp +ichinoseki.iwate.jp +iwaizumi.iwate.jp +iwate.iwate.jp +joboji.iwate.jp +kamaishi.iwate.jp +kanegasaki.iwate.jp +karumai.iwate.jp +kawai.iwate.jp +kitakami.iwate.jp +kuji.iwate.jp +kunohe.iwate.jp +kuzumaki.iwate.jp +miyako.iwate.jp +mizusawa.iwate.jp +morioka.iwate.jp +ninohe.iwate.jp +noda.iwate.jp +ofunato.iwate.jp +oshu.iwate.jp +otsuchi.iwate.jp +rikuzentakata.iwate.jp +shiwa.iwate.jp +shizukuishi.iwate.jp +sumita.iwate.jp +tanohata.iwate.jp +tono.iwate.jp +yahaba.iwate.jp +yamada.iwate.jp +ayagawa.kagawa.jp +higashikagawa.kagawa.jp +kanonji.kagawa.jp +kotohira.kagawa.jp +manno.kagawa.jp +marugame.kagawa.jp +mitoyo.kagawa.jp +naoshima.kagawa.jp +sanuki.kagawa.jp +tadotsu.kagawa.jp +takamatsu.kagawa.jp +tonosho.kagawa.jp +uchinomi.kagawa.jp +utazu.kagawa.jp +zentsuji.kagawa.jp +akune.kagoshima.jp +amami.kagoshima.jp +hioki.kagoshima.jp +isa.kagoshima.jp +isen.kagoshima.jp +izumi.kagoshima.jp +kagoshima.kagoshima.jp +kanoya.kagoshima.jp +kawanabe.kagoshima.jp +kinko.kagoshima.jp +kouyama.kagoshima.jp +makurazaki.kagoshima.jp +matsumoto.kagoshima.jp +minamitane.kagoshima.jp +nakatane.kagoshima.jp +nishinoomote.kagoshima.jp +satsumasendai.kagoshima.jp +soo.kagoshima.jp +tarumizu.kagoshima.jp +yusui.kagoshima.jp +aikawa.kanagawa.jp +atsugi.kanagawa.jp +ayase.kanagawa.jp +chigasaki.kanagawa.jp +ebina.kanagawa.jp +fujisawa.kanagawa.jp +hadano.kanagawa.jp +hakone.kanagawa.jp +hiratsuka.kanagawa.jp +isehara.kanagawa.jp +kaisei.kanagawa.jp +kamakura.kanagawa.jp +kiyokawa.kanagawa.jp +matsuda.kanagawa.jp +minamiashigara.kanagawa.jp +miura.kanagawa.jp +nakai.kanagawa.jp +ninomiya.kanagawa.jp +odawara.kanagawa.jp +oi.kanagawa.jp +oiso.kanagawa.jp +sagamihara.kanagawa.jp +samukawa.kanagawa.jp +tsukui.kanagawa.jp +yamakita.kanagawa.jp +yamato.kanagawa.jp +yokosuka.kanagawa.jp +yugawara.kanagawa.jp +zama.kanagawa.jp +zushi.kanagawa.jp +aki.kochi.jp +geisei.kochi.jp +hidaka.kochi.jp +higashitsuno.kochi.jp +ino.kochi.jp +kagami.kochi.jp +kami.kochi.jp +kitagawa.kochi.jp +kochi.kochi.jp +mihara.kochi.jp +motoyama.kochi.jp +muroto.kochi.jp +nahari.kochi.jp +nakamura.kochi.jp +nankoku.kochi.jp +nishitosa.kochi.jp +niyodogawa.kochi.jp +ochi.kochi.jp +okawa.kochi.jp +otoyo.kochi.jp +otsuki.kochi.jp +sakawa.kochi.jp +sukumo.kochi.jp +susaki.kochi.jp +tosa.kochi.jp +tosashimizu.kochi.jp +toyo.kochi.jp +tsuno.kochi.jp +umaji.kochi.jp +yasuda.kochi.jp +yusuhara.kochi.jp +amakusa.kumamoto.jp +arao.kumamoto.jp +aso.kumamoto.jp +choyo.kumamoto.jp +gyokuto.kumamoto.jp +kamiamakusa.kumamoto.jp +kikuchi.kumamoto.jp +kumamoto.kumamoto.jp +mashiki.kumamoto.jp +mifune.kumamoto.jp +minamata.kumamoto.jp +minamioguni.kumamoto.jp +nagasu.kumamoto.jp +nishihara.kumamoto.jp +oguni.kumamoto.jp +ozu.kumamoto.jp +sumoto.kumamoto.jp +takamori.kumamoto.jp +uki.kumamoto.jp +uto.kumamoto.jp +yamaga.kumamoto.jp +yamato.kumamoto.jp +yatsushiro.kumamoto.jp +ayabe.kyoto.jp +fukuchiyama.kyoto.jp +higashiyama.kyoto.jp +ide.kyoto.jp +ine.kyoto.jp +joyo.kyoto.jp +kameoka.kyoto.jp +kamo.kyoto.jp +kita.kyoto.jp +kizu.kyoto.jp +kumiyama.kyoto.jp +kyotamba.kyoto.jp +kyotanabe.kyoto.jp +kyotango.kyoto.jp +maizuru.kyoto.jp +minami.kyoto.jp +minamiyamashiro.kyoto.jp +miyazu.kyoto.jp +muko.kyoto.jp +nagaokakyo.kyoto.jp +nakagyo.kyoto.jp +nantan.kyoto.jp +oyamazaki.kyoto.jp +sakyo.kyoto.jp +seika.kyoto.jp +tanabe.kyoto.jp +uji.kyoto.jp +ujitawara.kyoto.jp +wazuka.kyoto.jp +yamashina.kyoto.jp +yawata.kyoto.jp +asahi.mie.jp +inabe.mie.jp +ise.mie.jp +kameyama.mie.jp +kawagoe.mie.jp +kiho.mie.jp +kisosaki.mie.jp +kiwa.mie.jp +komono.mie.jp +kumano.mie.jp +kuwana.mie.jp +matsusaka.mie.jp +meiwa.mie.jp +mihama.mie.jp +minamiise.mie.jp +misugi.mie.jp +miyama.mie.jp +nabari.mie.jp +shima.mie.jp +suzuka.mie.jp +tado.mie.jp +taiki.mie.jp +taki.mie.jp +tamaki.mie.jp +toba.mie.jp +tsu.mie.jp +udono.mie.jp +ureshino.mie.jp +watarai.mie.jp +yokkaichi.mie.jp +furukawa.miyagi.jp +higashimatsushima.miyagi.jp +ishinomaki.miyagi.jp +iwanuma.miyagi.jp +kakuda.miyagi.jp +kami.miyagi.jp +kawasaki.miyagi.jp +marumori.miyagi.jp +matsushima.miyagi.jp +minamisanriku.miyagi.jp +misato.miyagi.jp +murata.miyagi.jp +natori.miyagi.jp +ogawara.miyagi.jp +ohira.miyagi.jp +onagawa.miyagi.jp +osaki.miyagi.jp +rifu.miyagi.jp +semine.miyagi.jp +shibata.miyagi.jp +shichikashuku.miyagi.jp +shikama.miyagi.jp +shiogama.miyagi.jp +shiroishi.miyagi.jp +tagajo.miyagi.jp +taiwa.miyagi.jp +tome.miyagi.jp +tomiya.miyagi.jp +wakuya.miyagi.jp +watari.miyagi.jp +yamamoto.miyagi.jp +zao.miyagi.jp +aya.miyazaki.jp +ebino.miyazaki.jp +gokase.miyazaki.jp +hyuga.miyazaki.jp +kadogawa.miyazaki.jp +kawaminami.miyazaki.jp +kijo.miyazaki.jp +kitagawa.miyazaki.jp +kitakata.miyazaki.jp +kitaura.miyazaki.jp +kobayashi.miyazaki.jp +kunitomi.miyazaki.jp +kushima.miyazaki.jp +mimata.miyazaki.jp +miyakonojo.miyazaki.jp +miyazaki.miyazaki.jp +morotsuka.miyazaki.jp +nichinan.miyazaki.jp +nishimera.miyazaki.jp +nobeoka.miyazaki.jp +saito.miyazaki.jp +shiiba.miyazaki.jp +shintomi.miyazaki.jp +takaharu.miyazaki.jp +takanabe.miyazaki.jp +takazaki.miyazaki.jp +tsuno.miyazaki.jp +achi.nagano.jp +agematsu.nagano.jp +anan.nagano.jp +aoki.nagano.jp +asahi.nagano.jp +azumino.nagano.jp +chikuhoku.nagano.jp +chikuma.nagano.jp +chino.nagano.jp +fujimi.nagano.jp +hakuba.nagano.jp +hara.nagano.jp +hiraya.nagano.jp +iida.nagano.jp +iijima.nagano.jp +iiyama.nagano.jp +iizuna.nagano.jp +ikeda.nagano.jp +ikusaka.nagano.jp +ina.nagano.jp +karuizawa.nagano.jp +kawakami.nagano.jp +kiso.nagano.jp +kisofukushima.nagano.jp +kitaaiki.nagano.jp +komagane.nagano.jp +komoro.nagano.jp +matsukawa.nagano.jp +matsumoto.nagano.jp +miasa.nagano.jp +minamiaiki.nagano.jp +minamimaki.nagano.jp +minamiminowa.nagano.jp +minowa.nagano.jp +miyada.nagano.jp +miyota.nagano.jp +mochizuki.nagano.jp +nagano.nagano.jp +nagawa.nagano.jp +nagiso.nagano.jp +nakagawa.nagano.jp +nakano.nagano.jp +nozawaonsen.nagano.jp +obuse.nagano.jp +ogawa.nagano.jp +okaya.nagano.jp +omachi.nagano.jp +omi.nagano.jp +ookuwa.nagano.jp +ooshika.nagano.jp +otaki.nagano.jp +otari.nagano.jp +sakae.nagano.jp +sakaki.nagano.jp +saku.nagano.jp +sakuho.nagano.jp +shimosuwa.nagano.jp +shinanomachi.nagano.jp +shiojiri.nagano.jp +suwa.nagano.jp +suzaka.nagano.jp +takagi.nagano.jp +takamori.nagano.jp +takayama.nagano.jp +tateshina.nagano.jp +tatsuno.nagano.jp +togakushi.nagano.jp +togura.nagano.jp +tomi.nagano.jp +ueda.nagano.jp +wada.nagano.jp +yamagata.nagano.jp +yamanouchi.nagano.jp +yasaka.nagano.jp +yasuoka.nagano.jp +chijiwa.nagasaki.jp +futsu.nagasaki.jp +goto.nagasaki.jp +hasami.nagasaki.jp +hirado.nagasaki.jp +iki.nagasaki.jp +isahaya.nagasaki.jp +kawatana.nagasaki.jp +kuchinotsu.nagasaki.jp +matsuura.nagasaki.jp +nagasaki.nagasaki.jp +obama.nagasaki.jp +omura.nagasaki.jp +oseto.nagasaki.jp +saikai.nagasaki.jp +sasebo.nagasaki.jp +seihi.nagasaki.jp +shimabara.nagasaki.jp +shinkamigoto.nagasaki.jp +togitsu.nagasaki.jp +tsushima.nagasaki.jp +unzen.nagasaki.jp +ando.nara.jp +gose.nara.jp +heguri.nara.jp +higashiyoshino.nara.jp +ikaruga.nara.jp +ikoma.nara.jp +kamikitayama.nara.jp +kanmaki.nara.jp +kashiba.nara.jp +kashihara.nara.jp +katsuragi.nara.jp +kawai.nara.jp +kawakami.nara.jp +kawanishi.nara.jp +koryo.nara.jp +kurotaki.nara.jp +mitsue.nara.jp +miyake.nara.jp +nara.nara.jp +nosegawa.nara.jp +oji.nara.jp +ouda.nara.jp +oyodo.nara.jp +sakurai.nara.jp +sango.nara.jp +shimoichi.nara.jp +shimokitayama.nara.jp +shinjo.nara.jp +soni.nara.jp +takatori.nara.jp +tawaramoto.nara.jp +tenkawa.nara.jp +tenri.nara.jp +uda.nara.jp +yamatokoriyama.nara.jp +yamatotakada.nara.jp +yamazoe.nara.jp +yoshino.nara.jp +aga.niigata.jp +agano.niigata.jp +gosen.niigata.jp +itoigawa.niigata.jp +izumozaki.niigata.jp +joetsu.niigata.jp +kamo.niigata.jp +kariwa.niigata.jp +kashiwazaki.niigata.jp +minamiuonuma.niigata.jp +mitsuke.niigata.jp +muika.niigata.jp +murakami.niigata.jp +myoko.niigata.jp +nagaoka.niigata.jp +niigata.niigata.jp +ojiya.niigata.jp +omi.niigata.jp +sado.niigata.jp +sanjo.niigata.jp +seiro.niigata.jp +seirou.niigata.jp +sekikawa.niigata.jp +shibata.niigata.jp +tagami.niigata.jp +tainai.niigata.jp +tochio.niigata.jp +tokamachi.niigata.jp +tsubame.niigata.jp +tsunan.niigata.jp +uonuma.niigata.jp +yahiko.niigata.jp +yoita.niigata.jp +yuzawa.niigata.jp +beppu.oita.jp +bungoono.oita.jp +bungotakada.oita.jp +hasama.oita.jp +hiji.oita.jp +himeshima.oita.jp +hita.oita.jp +kamitsue.oita.jp +kokonoe.oita.jp +kuju.oita.jp +kunisaki.oita.jp +kusu.oita.jp +oita.oita.jp +saiki.oita.jp +taketa.oita.jp +tsukumi.oita.jp +usa.oita.jp +usuki.oita.jp +yufu.oita.jp +akaiwa.okayama.jp +asakuchi.okayama.jp +bizen.okayama.jp +hayashima.okayama.jp +ibara.okayama.jp +kagamino.okayama.jp +kasaoka.okayama.jp +kibichuo.okayama.jp +kumenan.okayama.jp +kurashiki.okayama.jp +maniwa.okayama.jp +misaki.okayama.jp +nagi.okayama.jp +niimi.okayama.jp +nishiawakura.okayama.jp +okayama.okayama.jp +satosho.okayama.jp +setouchi.okayama.jp +shinjo.okayama.jp +shoo.okayama.jp +soja.okayama.jp +takahashi.okayama.jp +tamano.okayama.jp +tsuyama.okayama.jp +wake.okayama.jp +yakage.okayama.jp +aguni.okinawa.jp +ginowan.okinawa.jp +ginoza.okinawa.jp +gushikami.okinawa.jp +haebaru.okinawa.jp +higashi.okinawa.jp +hirara.okinawa.jp +iheya.okinawa.jp +ishigaki.okinawa.jp +ishikawa.okinawa.jp +itoman.okinawa.jp +izena.okinawa.jp +kadena.okinawa.jp +kin.okinawa.jp +kitadaito.okinawa.jp +kitanakagusuku.okinawa.jp +kumejima.okinawa.jp +kunigami.okinawa.jp +minamidaito.okinawa.jp +motobu.okinawa.jp +nago.okinawa.jp +naha.okinawa.jp +nakagusuku.okinawa.jp +nakijin.okinawa.jp +nanjo.okinawa.jp +nishihara.okinawa.jp +ogimi.okinawa.jp +okinawa.okinawa.jp +onna.okinawa.jp +shimoji.okinawa.jp +taketomi.okinawa.jp +tarama.okinawa.jp +tokashiki.okinawa.jp +tomigusuku.okinawa.jp +tonaki.okinawa.jp +urasoe.okinawa.jp +uruma.okinawa.jp +yaese.okinawa.jp +yomitan.okinawa.jp +yonabaru.okinawa.jp +yonaguni.okinawa.jp +zamami.okinawa.jp +abeno.osaka.jp +chihayaakasaka.osaka.jp +chuo.osaka.jp +daito.osaka.jp +fujiidera.osaka.jp +habikino.osaka.jp +hannan.osaka.jp +higashiosaka.osaka.jp +higashisumiyoshi.osaka.jp +higashiyodogawa.osaka.jp +hirakata.osaka.jp +ibaraki.osaka.jp +ikeda.osaka.jp +izumi.osaka.jp +izumiotsu.osaka.jp +izumisano.osaka.jp +kadoma.osaka.jp +kaizuka.osaka.jp +kanan.osaka.jp +kashiwara.osaka.jp +katano.osaka.jp +kawachinagano.osaka.jp +kishiwada.osaka.jp +kita.osaka.jp +kumatori.osaka.jp +matsubara.osaka.jp +minato.osaka.jp +minoh.osaka.jp +misaki.osaka.jp +moriguchi.osaka.jp +neyagawa.osaka.jp +nishi.osaka.jp +nose.osaka.jp +osakasayama.osaka.jp +sakai.osaka.jp +sayama.osaka.jp +sennan.osaka.jp +settsu.osaka.jp +shijonawate.osaka.jp +shimamoto.osaka.jp +suita.osaka.jp +tadaoka.osaka.jp +taishi.osaka.jp +tajiri.osaka.jp +takaishi.osaka.jp +takatsuki.osaka.jp +tondabayashi.osaka.jp +toyonaka.osaka.jp +toyono.osaka.jp +yao.osaka.jp +ariake.saga.jp +arita.saga.jp +fukudomi.saga.jp +genkai.saga.jp +hamatama.saga.jp +hizen.saga.jp +imari.saga.jp +kamimine.saga.jp +kanzaki.saga.jp +karatsu.saga.jp +kashima.saga.jp +kitagata.saga.jp +kitahata.saga.jp +kiyama.saga.jp +kouhoku.saga.jp +kyuragi.saga.jp +nishiarita.saga.jp +ogi.saga.jp +omachi.saga.jp +ouchi.saga.jp +saga.saga.jp +shiroishi.saga.jp +taku.saga.jp +tara.saga.jp +tosu.saga.jp +yoshinogari.saga.jp +arakawa.saitama.jp +asaka.saitama.jp +chichibu.saitama.jp +fujimi.saitama.jp +fujimino.saitama.jp +fukaya.saitama.jp +hanno.saitama.jp +hanyu.saitama.jp +hasuda.saitama.jp +hatogaya.saitama.jp +hatoyama.saitama.jp +hidaka.saitama.jp +higashichichibu.saitama.jp +higashimatsuyama.saitama.jp +honjo.saitama.jp +ina.saitama.jp +iruma.saitama.jp +iwatsuki.saitama.jp +kamiizumi.saitama.jp +kamikawa.saitama.jp +kamisato.saitama.jp +kasukabe.saitama.jp +kawagoe.saitama.jp +kawaguchi.saitama.jp +kawajima.saitama.jp +kazo.saitama.jp +kitamoto.saitama.jp +koshigaya.saitama.jp +kounosu.saitama.jp +kuki.saitama.jp +kumagaya.saitama.jp +matsubushi.saitama.jp +minano.saitama.jp +misato.saitama.jp +miyashiro.saitama.jp +miyoshi.saitama.jp +moroyama.saitama.jp +nagatoro.saitama.jp +namegawa.saitama.jp +niiza.saitama.jp +ogano.saitama.jp +ogawa.saitama.jp +ogose.saitama.jp +okegawa.saitama.jp +omiya.saitama.jp +otaki.saitama.jp +ranzan.saitama.jp +ryokami.saitama.jp +saitama.saitama.jp +sakado.saitama.jp +satte.saitama.jp +sayama.saitama.jp +shiki.saitama.jp +shiraoka.saitama.jp +soka.saitama.jp +sugito.saitama.jp +toda.saitama.jp +tokigawa.saitama.jp +tokorozawa.saitama.jp +tsurugashima.saitama.jp +urawa.saitama.jp +warabi.saitama.jp +yashio.saitama.jp +yokoze.saitama.jp +yono.saitama.jp +yorii.saitama.jp +yoshida.saitama.jp +yoshikawa.saitama.jp +yoshimi.saitama.jp +aisho.shiga.jp +gamo.shiga.jp +higashiomi.shiga.jp +hikone.shiga.jp +koka.shiga.jp +konan.shiga.jp +kosei.shiga.jp +koto.shiga.jp +kusatsu.shiga.jp +maibara.shiga.jp +moriyama.shiga.jp +nagahama.shiga.jp +nishiazai.shiga.jp +notogawa.shiga.jp +omihachiman.shiga.jp +otsu.shiga.jp +ritto.shiga.jp +ryuoh.shiga.jp +takashima.shiga.jp +takatsuki.shiga.jp +torahime.shiga.jp +toyosato.shiga.jp +yasu.shiga.jp +akagi.shimane.jp +ama.shimane.jp +gotsu.shimane.jp +hamada.shimane.jp +higashiizumo.shimane.jp +hikawa.shimane.jp +hikimi.shimane.jp +izumo.shimane.jp +kakinoki.shimane.jp +masuda.shimane.jp +matsue.shimane.jp +misato.shimane.jp +nishinoshima.shimane.jp +ohda.shimane.jp +okinoshima.shimane.jp +okuizumo.shimane.jp +shimane.shimane.jp +tamayu.shimane.jp +tsuwano.shimane.jp +unnan.shimane.jp +yakumo.shimane.jp +yasugi.shimane.jp +yatsuka.shimane.jp +arai.shizuoka.jp +atami.shizuoka.jp +fuji.shizuoka.jp +fujieda.shizuoka.jp +fujikawa.shizuoka.jp +fujinomiya.shizuoka.jp +fukuroi.shizuoka.jp +gotemba.shizuoka.jp +haibara.shizuoka.jp +hamamatsu.shizuoka.jp +higashiizu.shizuoka.jp +ito.shizuoka.jp +iwata.shizuoka.jp +izu.shizuoka.jp +izunokuni.shizuoka.jp +kakegawa.shizuoka.jp +kannami.shizuoka.jp +kawanehon.shizuoka.jp +kawazu.shizuoka.jp +kikugawa.shizuoka.jp +kosai.shizuoka.jp +makinohara.shizuoka.jp +matsuzaki.shizuoka.jp +minamiizu.shizuoka.jp +mishima.shizuoka.jp +morimachi.shizuoka.jp +nishiizu.shizuoka.jp +numazu.shizuoka.jp +omaezaki.shizuoka.jp +shimada.shizuoka.jp +shimizu.shizuoka.jp +shimoda.shizuoka.jp +shizuoka.shizuoka.jp +susono.shizuoka.jp +yaizu.shizuoka.jp +yoshida.shizuoka.jp +ashikaga.tochigi.jp +bato.tochigi.jp +haga.tochigi.jp +ichikai.tochigi.jp +iwafune.tochigi.jp +kaminokawa.tochigi.jp +kanuma.tochigi.jp +karasuyama.tochigi.jp +kuroiso.tochigi.jp +mashiko.tochigi.jp +mibu.tochigi.jp +moka.tochigi.jp +motegi.tochigi.jp +nasu.tochigi.jp +nasushiobara.tochigi.jp +nikko.tochigi.jp +nishikata.tochigi.jp +nogi.tochigi.jp +ohira.tochigi.jp +ohtawara.tochigi.jp +oyama.tochigi.jp +sakura.tochigi.jp +sano.tochigi.jp +shimotsuke.tochigi.jp +shioya.tochigi.jp +takanezawa.tochigi.jp +tochigi.tochigi.jp +tsuga.tochigi.jp +ujiie.tochigi.jp +utsunomiya.tochigi.jp +yaita.tochigi.jp +aizumi.tokushima.jp +anan.tokushima.jp +ichiba.tokushima.jp +itano.tokushima.jp +kainan.tokushima.jp +komatsushima.tokushima.jp +matsushige.tokushima.jp +mima.tokushima.jp +minami.tokushima.jp +miyoshi.tokushima.jp +mugi.tokushima.jp +nakagawa.tokushima.jp +naruto.tokushima.jp +sanagochi.tokushima.jp +shishikui.tokushima.jp +tokushima.tokushima.jp +wajiki.tokushima.jp +adachi.tokyo.jp +akiruno.tokyo.jp +akishima.tokyo.jp +aogashima.tokyo.jp +arakawa.tokyo.jp +bunkyo.tokyo.jp +chiyoda.tokyo.jp +chofu.tokyo.jp +chuo.tokyo.jp +edogawa.tokyo.jp +fuchu.tokyo.jp +fussa.tokyo.jp +hachijo.tokyo.jp +hachioji.tokyo.jp +hamura.tokyo.jp +higashikurume.tokyo.jp +higashimurayama.tokyo.jp +higashiyamato.tokyo.jp +hino.tokyo.jp +hinode.tokyo.jp +hinohara.tokyo.jp +inagi.tokyo.jp +itabashi.tokyo.jp +katsushika.tokyo.jp +kita.tokyo.jp +kiyose.tokyo.jp +kodaira.tokyo.jp +koganei.tokyo.jp +kokubunji.tokyo.jp +komae.tokyo.jp +koto.tokyo.jp +kouzushima.tokyo.jp +kunitachi.tokyo.jp +machida.tokyo.jp +meguro.tokyo.jp +minato.tokyo.jp +mitaka.tokyo.jp +mizuho.tokyo.jp +musashimurayama.tokyo.jp +musashino.tokyo.jp +nakano.tokyo.jp +nerima.tokyo.jp +ogasawara.tokyo.jp +okutama.tokyo.jp +ome.tokyo.jp +oshima.tokyo.jp +ota.tokyo.jp +setagaya.tokyo.jp +shibuya.tokyo.jp +shinagawa.tokyo.jp +shinjuku.tokyo.jp +suginami.tokyo.jp +sumida.tokyo.jp +tachikawa.tokyo.jp +taito.tokyo.jp +tama.tokyo.jp +toshima.tokyo.jp +chizu.tottori.jp +hino.tottori.jp +kawahara.tottori.jp +koge.tottori.jp +kotoura.tottori.jp +misasa.tottori.jp +nanbu.tottori.jp +nichinan.tottori.jp +sakaiminato.tottori.jp +tottori.tottori.jp +wakasa.tottori.jp +yazu.tottori.jp +yonago.tottori.jp +asahi.toyama.jp +fuchu.toyama.jp +fukumitsu.toyama.jp +funahashi.toyama.jp +himi.toyama.jp +imizu.toyama.jp +inami.toyama.jp +johana.toyama.jp +kamiichi.toyama.jp +kurobe.toyama.jp +nakaniikawa.toyama.jp +namerikawa.toyama.jp +nanto.toyama.jp +nyuzen.toyama.jp +oyabe.toyama.jp +taira.toyama.jp +takaoka.toyama.jp +tateyama.toyama.jp +toga.toyama.jp +tonami.toyama.jp +toyama.toyama.jp +unazuki.toyama.jp +uozu.toyama.jp +yamada.toyama.jp +arida.wakayama.jp +aridagawa.wakayama.jp +gobo.wakayama.jp +hashimoto.wakayama.jp +hidaka.wakayama.jp +hirogawa.wakayama.jp +inami.wakayama.jp +iwade.wakayama.jp +kainan.wakayama.jp +kamitonda.wakayama.jp +katsuragi.wakayama.jp +kimino.wakayama.jp +kinokawa.wakayama.jp +kitayama.wakayama.jp +koya.wakayama.jp +koza.wakayama.jp +kozagawa.wakayama.jp +kudoyama.wakayama.jp +kushimoto.wakayama.jp +mihama.wakayama.jp +misato.wakayama.jp +nachikatsuura.wakayama.jp +shingu.wakayama.jp +shirahama.wakayama.jp +taiji.wakayama.jp +tanabe.wakayama.jp +wakayama.wakayama.jp +yuasa.wakayama.jp +yura.wakayama.jp +asahi.yamagata.jp +funagata.yamagata.jp +higashine.yamagata.jp +iide.yamagata.jp +kahoku.yamagata.jp +kaminoyama.yamagata.jp +kaneyama.yamagata.jp +kawanishi.yamagata.jp +mamurogawa.yamagata.jp +mikawa.yamagata.jp +murayama.yamagata.jp +nagai.yamagata.jp +nakayama.yamagata.jp +nanyo.yamagata.jp +nishikawa.yamagata.jp +obanazawa.yamagata.jp +oe.yamagata.jp +oguni.yamagata.jp +ohkura.yamagata.jp +oishida.yamagata.jp +sagae.yamagata.jp +sakata.yamagata.jp +sakegawa.yamagata.jp +shinjo.yamagata.jp +shirataka.yamagata.jp +shonai.yamagata.jp +takahata.yamagata.jp +tendo.yamagata.jp +tozawa.yamagata.jp +tsuruoka.yamagata.jp +yamagata.yamagata.jp +yamanobe.yamagata.jp +yonezawa.yamagata.jp +yuza.yamagata.jp +abu.yamaguchi.jp +hagi.yamaguchi.jp +hikari.yamaguchi.jp +hofu.yamaguchi.jp +iwakuni.yamaguchi.jp +kudamatsu.yamaguchi.jp +mitou.yamaguchi.jp +nagato.yamaguchi.jp +oshima.yamaguchi.jp +shimonoseki.yamaguchi.jp +shunan.yamaguchi.jp +tabuse.yamaguchi.jp +tokuyama.yamaguchi.jp +toyota.yamaguchi.jp +ube.yamaguchi.jp +yuu.yamaguchi.jp +chuo.yamanashi.jp +doshi.yamanashi.jp +fuefuki.yamanashi.jp +fujikawa.yamanashi.jp +fujikawaguchiko.yamanashi.jp +fujiyoshida.yamanashi.jp +hayakawa.yamanashi.jp +hokuto.yamanashi.jp +ichikawamisato.yamanashi.jp +kai.yamanashi.jp +kofu.yamanashi.jp +koshu.yamanashi.jp +kosuge.yamanashi.jp +minami-alps.yamanashi.jp +minobu.yamanashi.jp +nakamichi.yamanashi.jp +nanbu.yamanashi.jp +narusawa.yamanashi.jp +nirasaki.yamanashi.jp +nishikatsura.yamanashi.jp +oshino.yamanashi.jp +otsuki.yamanashi.jp +showa.yamanashi.jp +tabayama.yamanashi.jp +tsuru.yamanashi.jp +uenohara.yamanashi.jp +yamanakako.yamanashi.jp +yamanashi.yamanashi.jp + +// ke : http://www.kenic.or.ke/index.php/en/ke-domains/ke-domains +ke +ac.ke +co.ke +go.ke +info.ke +me.ke +mobi.ke +ne.ke +or.ke +sc.ke + +// kg : http://www.domain.kg/dmn_n.html +kg +org.kg +net.kg +com.kg +edu.kg +gov.kg +mil.kg + +// kh : http://www.mptc.gov.kh/dns_registration.htm +*.kh + +// ki : http://www.ki/dns/index.html +ki +edu.ki +biz.ki +net.ki +org.ki +gov.ki +info.ki +com.ki + +// km : https://en.wikipedia.org/wiki/.km +// http://www.domaine.km/documents/charte.doc +km +org.km +nom.km +gov.km +prd.km +tm.km +edu.km +mil.km +ass.km +com.km +// These are only mentioned as proposed suggestions at domaine.km, but +// https://en.wikipedia.org/wiki/.km says they're available for registration: +coop.km +asso.km +presse.km +medecin.km +notaires.km +pharmaciens.km +veterinaire.km +gouv.km + +// kn : https://en.wikipedia.org/wiki/.kn +// http://www.dot.kn/domainRules.html +kn +net.kn +org.kn +edu.kn +gov.kn + +// kp : http://www.kcce.kp/en_index.php +kp +com.kp +edu.kp +gov.kp +org.kp +rep.kp +tra.kp + +// kr : https://en.wikipedia.org/wiki/.kr +// see also: http://domain.nida.or.kr/eng/registration.jsp +kr +ac.kr +co.kr +es.kr +go.kr +hs.kr +kg.kr +mil.kr +ms.kr +ne.kr +or.kr +pe.kr +re.kr +sc.kr +// kr geographical names +busan.kr +chungbuk.kr +chungnam.kr +daegu.kr +daejeon.kr +gangwon.kr +gwangju.kr +gyeongbuk.kr +gyeonggi.kr +gyeongnam.kr +incheon.kr +jeju.kr +jeonbuk.kr +jeonnam.kr +seoul.kr +ulsan.kr + +// kw : https://www.nic.kw/policies/ +// Confirmed by registry +kw +com.kw +edu.kw +emb.kw +gov.kw +ind.kw +net.kw +org.kw + +// ky : http://www.icta.ky/da_ky_reg_dom.php +// Confirmed by registry 2008-06-17 +ky +edu.ky +gov.ky +com.ky +org.ky +net.ky + +// kz : https://en.wikipedia.org/wiki/.kz +// see also: http://www.nic.kz/rules/index.jsp +kz +org.kz +edu.kz +net.kz +gov.kz +mil.kz +com.kz + +// la : https://en.wikipedia.org/wiki/.la +// Submitted by registry +la +int.la +net.la +info.la +edu.la +gov.la +per.la +com.la +org.la + +// lb : https://en.wikipedia.org/wiki/.lb +// Submitted by registry +lb +com.lb +edu.lb +gov.lb +net.lb +org.lb + +// lc : https://en.wikipedia.org/wiki/.lc +// see also: http://www.nic.lc/rules.htm +lc +com.lc +net.lc +co.lc +org.lc +edu.lc +gov.lc + +// li : https://en.wikipedia.org/wiki/.li +li + +// lk : http://www.nic.lk/seclevpr.html +lk +gov.lk +sch.lk +net.lk +int.lk +com.lk +org.lk +edu.lk +ngo.lk +soc.lk +web.lk +ltd.lk +assn.lk +grp.lk +hotel.lk +ac.lk + +// lr : http://psg.com/dns/lr/lr.txt +// Submitted by registry +lr +com.lr +edu.lr +gov.lr +org.lr +net.lr + +// ls : https://en.wikipedia.org/wiki/.ls +ls +co.ls +org.ls + +// lt : https://en.wikipedia.org/wiki/.lt +lt +// gov.lt : http://www.gov.lt/index_en.php +gov.lt + +// lu : http://www.dns.lu/en/ +lu + +// lv : http://www.nic.lv/DNS/En/generic.php +lv +com.lv +edu.lv +gov.lv +org.lv +mil.lv +id.lv +net.lv +asn.lv +conf.lv + +// ly : http://www.nic.ly/regulations.php +ly +com.ly +net.ly +gov.ly +plc.ly +edu.ly +sch.ly +med.ly +org.ly +id.ly + +// ma : https://en.wikipedia.org/wiki/.ma +// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf +ma +co.ma +net.ma +gov.ma +org.ma +ac.ma +press.ma + +// mc : http://www.nic.mc/ +mc +tm.mc +asso.mc + +// md : https://en.wikipedia.org/wiki/.md +md + +// me : https://en.wikipedia.org/wiki/.me +me +co.me +net.me +org.me +edu.me +ac.me +gov.me +its.me +priv.me + +// mg : http://nic.mg/nicmg/?page_id=39 +mg +org.mg +nom.mg +gov.mg +prd.mg +tm.mg +edu.mg +mil.mg +com.mg +co.mg + +// mh : https://en.wikipedia.org/wiki/.mh +mh + +// mil : https://en.wikipedia.org/wiki/.mil +mil + +// mk : https://en.wikipedia.org/wiki/.mk +// see also: http://dns.marnet.net.mk/postapka.php +mk +com.mk +org.mk +net.mk +edu.mk +gov.mk +inf.mk +name.mk + +// ml : http://www.gobin.info/domainname/ml-template.doc +// see also: https://en.wikipedia.org/wiki/.ml +ml +com.ml +edu.ml +gouv.ml +gov.ml +net.ml +org.ml +presse.ml + +// mm : https://en.wikipedia.org/wiki/.mm +*.mm + +// mn : https://en.wikipedia.org/wiki/.mn +mn +gov.mn +edu.mn +org.mn + +// mo : http://www.monic.net.mo/ +mo +com.mo +net.mo +org.mo +edu.mo +gov.mo + +// mobi : https://en.wikipedia.org/wiki/.mobi +mobi + +// mp : http://www.dot.mp/ +// Confirmed by registry 2008-06-17 +mp + +// mq : https://en.wikipedia.org/wiki/.mq +mq + +// mr : https://en.wikipedia.org/wiki/.mr +mr +gov.mr + +// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf +ms +com.ms +edu.ms +gov.ms +net.ms +org.ms + +// mt : https://www.nic.org.mt/go/policy +// Submitted by registry +mt +com.mt +edu.mt +net.mt +org.mt + +// mu : https://en.wikipedia.org/wiki/.mu +mu +com.mu +net.mu +org.mu +gov.mu +ac.mu +co.mu +or.mu + +// museum : http://about.museum/naming/ +// http://index.museum/ +museum +academy.museum +agriculture.museum +air.museum +airguard.museum +alabama.museum +alaska.museum +amber.museum +ambulance.museum +american.museum +americana.museum +americanantiques.museum +americanart.museum +amsterdam.museum +and.museum +annefrank.museum +anthro.museum +anthropology.museum +antiques.museum +aquarium.museum +arboretum.museum +archaeological.museum +archaeology.museum +architecture.museum +art.museum +artanddesign.museum +artcenter.museum +artdeco.museum +arteducation.museum +artgallery.museum +arts.museum +artsandcrafts.museum +asmatart.museum +assassination.museum +assisi.museum +association.museum +astronomy.museum +atlanta.museum +austin.museum +australia.museum +automotive.museum +aviation.museum +axis.museum +badajoz.museum +baghdad.museum +bahn.museum +bale.museum +baltimore.museum +barcelona.museum +baseball.museum +basel.museum +baths.museum +bauern.museum +beauxarts.museum +beeldengeluid.museum +bellevue.museum +bergbau.museum +berkeley.museum +berlin.museum +bern.museum +bible.museum +bilbao.museum +bill.museum +birdart.museum +birthplace.museum +bonn.museum +boston.museum +botanical.museum +botanicalgarden.museum +botanicgarden.museum +botany.museum +brandywinevalley.museum +brasil.museum +bristol.museum +british.museum +britishcolumbia.museum +broadcast.museum +brunel.museum +brussel.museum +brussels.museum +bruxelles.museum +building.museum +burghof.museum +bus.museum +bushey.museum +cadaques.museum +california.museum +cambridge.museum +can.museum +canada.museum +capebreton.museum +carrier.museum +cartoonart.museum +casadelamoneda.museum +castle.museum +castres.museum +celtic.museum +center.museum +chattanooga.museum +cheltenham.museum +chesapeakebay.museum +chicago.museum +children.museum +childrens.museum +childrensgarden.museum +chiropractic.museum +chocolate.museum +christiansburg.museum +cincinnati.museum +cinema.museum +circus.museum +civilisation.museum +civilization.museum +civilwar.museum +clinton.museum +clock.museum +coal.museum +coastaldefence.museum +cody.museum +coldwar.museum +collection.museum +colonialwilliamsburg.museum +coloradoplateau.museum +columbia.museum +columbus.museum +communication.museum +communications.museum +community.museum +computer.museum +computerhistory.museum +comunicações.museum +contemporary.museum +contemporaryart.museum +convent.museum +copenhagen.museum +corporation.museum +correios-e-telecomunicações.museum +corvette.museum +costume.museum +countryestate.museum +county.museum +crafts.museum +cranbrook.museum +creation.museum +cultural.museum +culturalcenter.museum +culture.museum +cyber.museum +cymru.museum +dali.museum +dallas.museum +database.museum +ddr.museum +decorativearts.museum +delaware.museum +delmenhorst.museum +denmark.museum +depot.museum +design.museum +detroit.museum +dinosaur.museum +discovery.museum +dolls.museum +donostia.museum +durham.museum +eastafrica.museum +eastcoast.museum +education.museum +educational.museum +egyptian.museum +eisenbahn.museum +elburg.museum +elvendrell.museum +embroidery.museum +encyclopedic.museum +england.museum +entomology.museum +environment.museum +environmentalconservation.museum +epilepsy.museum +essex.museum +estate.museum +ethnology.museum +exeter.museum +exhibition.museum +family.museum +farm.museum +farmequipment.museum +farmers.museum +farmstead.museum +field.museum +figueres.museum +filatelia.museum +film.museum +fineart.museum +finearts.museum +finland.museum +flanders.museum +florida.museum +force.museum +fortmissoula.museum +fortworth.museum +foundation.museum +francaise.museum +frankfurt.museum +franziskaner.museum +freemasonry.museum +freiburg.museum +fribourg.museum +frog.museum +fundacio.museum +furniture.museum +gallery.museum +garden.museum +gateway.museum +geelvinck.museum +gemological.museum +geology.museum +georgia.museum +giessen.museum +glas.museum +glass.museum +gorge.museum +grandrapids.museum +graz.museum +guernsey.museum +halloffame.museum +hamburg.museum +handson.museum +harvestcelebration.museum +hawaii.museum +health.museum +heimatunduhren.museum +hellas.museum +helsinki.museum +hembygdsforbund.museum +heritage.museum +histoire.museum +historical.museum +historicalsociety.museum +historichouses.museum +historisch.museum +historisches.museum +history.museum +historyofscience.museum +horology.museum +house.museum +humanities.museum +illustration.museum +imageandsound.museum +indian.museum +indiana.museum +indianapolis.museum +indianmarket.museum +intelligence.museum +interactive.museum +iraq.museum +iron.museum +isleofman.museum +jamison.museum +jefferson.museum +jerusalem.museum +jewelry.museum +jewish.museum +jewishart.museum +jfk.museum +journalism.museum +judaica.museum +judygarland.museum +juedisches.museum +juif.museum +karate.museum +karikatur.museum +kids.museum +koebenhavn.museum +koeln.museum +kunst.museum +kunstsammlung.museum +kunstunddesign.museum +labor.museum +labour.museum +lajolla.museum +lancashire.museum +landes.museum +lans.museum +läns.museum +larsson.museum +lewismiller.museum +lincoln.museum +linz.museum +living.museum +livinghistory.museum +localhistory.museum +london.museum +losangeles.museum +louvre.museum +loyalist.museum +lucerne.museum +luxembourg.museum +luzern.museum +mad.museum +madrid.museum +mallorca.museum +manchester.museum +mansion.museum +mansions.museum +manx.museum +marburg.museum +maritime.museum +maritimo.museum +maryland.museum +marylhurst.museum +media.museum +medical.museum +medizinhistorisches.museum +meeres.museum +memorial.museum +mesaverde.museum +michigan.museum +midatlantic.museum +military.museum +mill.museum +miners.museum +mining.museum +minnesota.museum +missile.museum +missoula.museum +modern.museum +moma.museum +money.museum +monmouth.museum +monticello.museum +montreal.museum +moscow.museum +motorcycle.museum +muenchen.museum +muenster.museum +mulhouse.museum +muncie.museum +museet.museum +museumcenter.museum +museumvereniging.museum +music.museum +national.museum +nationalfirearms.museum +nationalheritage.museum +nativeamerican.museum +naturalhistory.museum +naturalhistorymuseum.museum +naturalsciences.museum +nature.museum +naturhistorisches.museum +natuurwetenschappen.museum +naumburg.museum +naval.museum +nebraska.museum +neues.museum +newhampshire.museum +newjersey.museum +newmexico.museum +newport.museum +newspaper.museum +newyork.museum +niepce.museum +norfolk.museum +north.museum +nrw.museum +nuernberg.museum +nuremberg.museum +nyc.museum +nyny.museum +oceanographic.museum +oceanographique.museum +omaha.museum +online.museum +ontario.museum +openair.museum +oregon.museum +oregontrail.museum +otago.museum +oxford.museum +pacific.museum +paderborn.museum +palace.museum +paleo.museum +palmsprings.museum +panama.museum +paris.museum +pasadena.museum +pharmacy.museum +philadelphia.museum +philadelphiaarea.museum +philately.museum +phoenix.museum +photography.museum +pilots.museum +pittsburgh.museum +planetarium.museum +plantation.museum +plants.museum +plaza.museum +portal.museum +portland.museum +portlligat.museum +posts-and-telecommunications.museum +preservation.museum +presidio.museum +press.museum +project.museum +public.museum +pubol.museum +quebec.museum +railroad.museum +railway.museum +research.museum +resistance.museum +riodejaneiro.museum +rochester.museum +rockart.museum +roma.museum +russia.museum +saintlouis.museum +salem.museum +salvadordali.museum +salzburg.museum +sandiego.museum +sanfrancisco.museum +santabarbara.museum +santacruz.museum +santafe.museum +saskatchewan.museum +satx.museum +savannahga.museum +schlesisches.museum +schoenbrunn.museum +schokoladen.museum +school.museum +schweiz.museum +science.museum +scienceandhistory.museum +scienceandindustry.museum +sciencecenter.museum +sciencecenters.museum +science-fiction.museum +sciencehistory.museum +sciences.museum +sciencesnaturelles.museum +scotland.museum +seaport.museum +settlement.museum +settlers.museum +shell.museum +sherbrooke.museum +sibenik.museum +silk.museum +ski.museum +skole.museum +society.museum +sologne.museum +soundandvision.museum +southcarolina.museum +southwest.museum +space.museum +spy.museum +square.museum +stadt.museum +stalbans.museum +starnberg.museum +state.museum +stateofdelaware.museum +station.museum +steam.museum +steiermark.museum +stjohn.museum +stockholm.museum +stpetersburg.museum +stuttgart.museum +suisse.museum +surgeonshall.museum +surrey.museum +svizzera.museum +sweden.museum +sydney.museum +tank.museum +tcm.museum +technology.museum +telekommunikation.museum +television.museum +texas.museum +textile.museum +theater.museum +time.museum +timekeeping.museum +topology.museum +torino.museum +touch.museum +town.museum +transport.museum +tree.museum +trolley.museum +trust.museum +trustee.museum +uhren.museum +ulm.museum +undersea.museum +university.museum +usa.museum +usantiques.museum +usarts.museum +uscountryestate.museum +usculture.museum +usdecorativearts.museum +usgarden.museum +ushistory.museum +ushuaia.museum +uslivinghistory.museum +utah.museum +uvic.museum +valley.museum +vantaa.museum +versailles.museum +viking.museum +village.museum +virginia.museum +virtual.museum +virtuel.museum +vlaanderen.museum +volkenkunde.museum +wales.museum +wallonie.museum +war.museum +washingtondc.museum +watchandclock.museum +watch-and-clock.museum +western.museum +westfalen.museum +whaling.museum +wildlife.museum +williamsburg.museum +windmill.museum +workshop.museum +york.museum +yorkshire.museum +yosemite.museum +youth.museum +zoological.museum +zoology.museum +ירושלים.museum +иком.museum + +// mv : https://en.wikipedia.org/wiki/.mv +// "mv" included because, contra Wikipedia, google.mv exists. +mv +aero.mv +biz.mv +com.mv +coop.mv +edu.mv +gov.mv +info.mv +int.mv +mil.mv +museum.mv +name.mv +net.mv +org.mv +pro.mv + +// mw : http://www.registrar.mw/ +mw +ac.mw +biz.mw +co.mw +com.mw +coop.mw +edu.mw +gov.mw +int.mw +museum.mw +net.mw +org.mw + +// mx : http://www.nic.mx/ +// Submitted by registry +mx +com.mx +org.mx +gob.mx +edu.mx +net.mx + +// my : http://www.mynic.net.my/ +my +com.my +net.my +org.my +gov.my +edu.my +mil.my +name.my + +// mz : http://www.uem.mz/ +// Submitted by registry +mz +ac.mz +adv.mz +co.mz +edu.mz +gov.mz +mil.mz +net.mz +org.mz + +// na : http://www.na-nic.com.na/ +// http://www.info.na/domain/ +na +info.na +pro.na +name.na +school.na +or.na +dr.na +us.na +mx.na +ca.na +in.na +cc.na +tv.na +ws.na +mobi.na +co.na +com.na +org.na + +// name : has 2nd-level tlds, but there's no list of them +name + +// nc : http://www.cctld.nc/ +nc +asso.nc +nom.nc + +// ne : https://en.wikipedia.org/wiki/.ne +ne + +// net : https://en.wikipedia.org/wiki/.net +net + +// nf : https://en.wikipedia.org/wiki/.nf +nf +com.nf +net.nf +per.nf +rec.nf +web.nf +arts.nf +firm.nf +info.nf +other.nf +store.nf + +// ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds +ng +com.ng +edu.ng +gov.ng +i.ng +mil.ng +mobi.ng +name.ng +net.ng +org.ng +sch.ng + +// ni : http://www.nic.ni/ +ni +ac.ni +biz.ni +co.ni +com.ni +edu.ni +gob.ni +in.ni +info.ni +int.ni +mil.ni +net.ni +nom.ni +org.ni +web.ni + +// nl : https://en.wikipedia.org/wiki/.nl +// https://www.sidn.nl/ +// ccTLD for the Netherlands +nl + +// BV.nl will be a registry for dutch BV's (besloten vennootschap) +bv.nl + +// no : http://www.norid.no/regelverk/index.en.html +// The Norwegian registry has declined to notify us of updates. The web pages +// referenced below are the official source of the data. There is also an +// announce mailing list: +// https://postlister.uninett.no/sympa/info/norid-diskusjon +no +// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html +fhs.no +vgs.no +fylkesbibl.no +folkebibl.no +museum.no +idrett.no +priv.no +// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html +mil.no +stat.no +dep.no +kommune.no +herad.no +// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html +// counties +aa.no +ah.no +bu.no +fm.no +hl.no +hm.no +jan-mayen.no +mr.no +nl.no +nt.no +of.no +ol.no +oslo.no +rl.no +sf.no +st.no +svalbard.no +tm.no +tr.no +va.no +vf.no +// primary and lower secondary schools per county +gs.aa.no +gs.ah.no +gs.bu.no +gs.fm.no +gs.hl.no +gs.hm.no +gs.jan-mayen.no +gs.mr.no +gs.nl.no +gs.nt.no +gs.of.no +gs.ol.no +gs.oslo.no +gs.rl.no +gs.sf.no +gs.st.no +gs.svalbard.no +gs.tm.no +gs.tr.no +gs.va.no +gs.vf.no +// cities +akrehamn.no +Ã¥krehamn.no +algard.no +Ã¥lgÃ¥rd.no +arna.no +brumunddal.no +bryne.no +bronnoysund.no +brønnøysund.no +drobak.no +drøbak.no +egersund.no +fetsund.no +floro.no +florø.no +fredrikstad.no +hokksund.no +honefoss.no +hønefoss.no +jessheim.no +jorpeland.no +jørpeland.no +kirkenes.no +kopervik.no +krokstadelva.no +langevag.no +langevÃ¥g.no +leirvik.no +mjondalen.no +mjøndalen.no +mo-i-rana.no +mosjoen.no +mosjøen.no +nesoddtangen.no +orkanger.no +osoyro.no +osøyro.no +raholt.no +rÃ¥holt.no +sandnessjoen.no +sandnessjøen.no +skedsmokorset.no +slattum.no +spjelkavik.no +stathelle.no +stavern.no +stjordalshalsen.no +stjørdalshalsen.no +tananger.no +tranby.no +vossevangen.no +// communities +afjord.no +Ã¥fjord.no +agdenes.no +al.no +Ã¥l.no +alesund.no +Ã¥lesund.no +alstahaug.no +alta.no +áltá.no +alaheadju.no +álaheadju.no +alvdal.no +amli.no +Ã¥mli.no +amot.no +Ã¥mot.no +andebu.no +andoy.no +andøy.no +andasuolo.no +ardal.no +Ã¥rdal.no +aremark.no +arendal.no +Ã¥s.no +aseral.no +Ã¥seral.no +asker.no +askim.no +askvoll.no +askoy.no +askøy.no +asnes.no +Ã¥snes.no +audnedaln.no +aukra.no +aure.no +aurland.no +aurskog-holand.no +aurskog-høland.no +austevoll.no +austrheim.no +averoy.no +averøy.no +balestrand.no +ballangen.no +balat.no +bálát.no +balsfjord.no +bahccavuotna.no +báhccavuotna.no +bamble.no +bardu.no +beardu.no +beiarn.no +bajddar.no +bájddar.no +baidar.no +báidár.no +berg.no +bergen.no +berlevag.no +berlevÃ¥g.no +bearalvahki.no +bearalváhki.no +bindal.no +birkenes.no +bjarkoy.no +bjarkøy.no +bjerkreim.no +bjugn.no +bodo.no +bodø.no +badaddja.no +bÃ¥dÃ¥ddjÃ¥.no +budejju.no +bokn.no +bremanger.no +bronnoy.no +brønnøy.no +bygland.no +bykle.no +barum.no +bærum.no +bo.telemark.no +bø.telemark.no +bo.nordland.no +bø.nordland.no +bievat.no +bievát.no +bomlo.no +bømlo.no +batsfjord.no +bÃ¥tsfjord.no +bahcavuotna.no +báhcavuotna.no +dovre.no +drammen.no +drangedal.no +dyroy.no +dyrøy.no +donna.no +dønna.no +eid.no +eidfjord.no +eidsberg.no +eidskog.no +eidsvoll.no +eigersund.no +elverum.no +enebakk.no +engerdal.no +etne.no +etnedal.no +evenes.no +evenassi.no +evenášši.no +evje-og-hornnes.no +farsund.no +fauske.no +fuossko.no +fuoisku.no +fedje.no +fet.no +finnoy.no +finnøy.no +fitjar.no +fjaler.no +fjell.no +flakstad.no +flatanger.no +flekkefjord.no +flesberg.no +flora.no +fla.no +flÃ¥.no +folldal.no +forsand.no +fosnes.no +frei.no +frogn.no +froland.no +frosta.no +frana.no +fræna.no +froya.no +frøya.no +fusa.no +fyresdal.no +forde.no +førde.no +gamvik.no +gangaviika.no +gáŋgaviika.no +gaular.no +gausdal.no +gildeskal.no +gildeskÃ¥l.no +giske.no +gjemnes.no +gjerdrum.no +gjerstad.no +gjesdal.no +gjovik.no +gjøvik.no +gloppen.no +gol.no +gran.no +grane.no +granvin.no +gratangen.no +grimstad.no +grong.no +kraanghke.no +krÃ¥anghke.no +grue.no +gulen.no +hadsel.no +halden.no +halsa.no +hamar.no +hamaroy.no +habmer.no +hábmer.no +hapmir.no +hápmir.no +hammerfest.no +hammarfeasta.no +hámmárfeasta.no +haram.no +hareid.no +harstad.no +hasvik.no +aknoluokta.no +ákŋoluokta.no +hattfjelldal.no +aarborte.no +haugesund.no +hemne.no +hemnes.no +hemsedal.no +heroy.more-og-romsdal.no +herøy.møre-og-romsdal.no +heroy.nordland.no +herøy.nordland.no +hitra.no +hjartdal.no +hjelmeland.no +hobol.no +hobøl.no +hof.no +hol.no +hole.no +holmestrand.no +holtalen.no +holtÃ¥len.no +hornindal.no +horten.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no +hagebostad.no +hægebostad.no +hoyanger.no +høyanger.no +hoylandet.no +høylandet.no +ha.no +hÃ¥.no +ibestad.no +inderoy.no +inderøy.no +iveland.no +jevnaker.no +jondal.no +jolster.no +jølster.no +karasjok.no +karasjohka.no +kárášjohka.no +karlsoy.no +galsa.no +gálsá.no +karmoy.no +karmøy.no +kautokeino.no +guovdageaidnu.no +klepp.no +klabu.no +klæbu.no +kongsberg.no +kongsvinger.no +kragero.no +kragerø.no +kristiansand.no +kristiansund.no +krodsherad.no +krødsherad.no +kvalsund.no +rahkkeravju.no +ráhkkerávju.no +kvam.no +kvinesdal.no +kvinnherad.no +kviteseid.no +kvitsoy.no +kvitsøy.no +kvafjord.no +kvæfjord.no +giehtavuoatna.no +kvanangen.no +kvænangen.no +navuotna.no +návuotna.no +kafjord.no +kÃ¥fjord.no +gaivuotna.no +gáivuotna.no +larvik.no +lavangen.no +lavagis.no +loabat.no +loabát.no +lebesby.no +davvesiida.no +leikanger.no +leirfjord.no +leka.no +leksvik.no +lenvik.no +leangaviika.no +leaŋgaviika.no +lesja.no +levanger.no +lier.no +lierne.no +lillehammer.no +lillesand.no +lindesnes.no +lindas.no +lindÃ¥s.no +lom.no +loppa.no +lahppi.no +láhppi.no +lund.no +lunner.no +luroy.no +lurøy.no +luster.no +lyngdal.no +lyngen.no +ivgu.no +lardal.no +lerdal.no +lærdal.no +lodingen.no +lødingen.no +lorenskog.no +lørenskog.no +loten.no +løten.no +malvik.no +masoy.no +mÃ¥søy.no +muosat.no +muosát.no +mandal.no +marker.no +marnardal.no +masfjorden.no +meland.no +meldal.no +melhus.no +meloy.no +meløy.no +meraker.no +merÃ¥ker.no +moareke.no +moÃ¥reke.no +midsund.no +midtre-gauldal.no +modalen.no +modum.no +molde.no +moskenes.no +moss.no +mosvik.no +malselv.no +mÃ¥lselv.no +malatvuopmi.no +málatvuopmi.no +namdalseid.no +aejrie.no +namsos.no +namsskogan.no +naamesjevuemie.no +nååmesjevuemie.no +laakesvuemie.no +nannestad.no +narvik.no +narviika.no +naustdal.no +nedre-eiker.no +nes.akershus.no +nes.buskerud.no +nesna.no +nesodden.no +nesseby.no +unjarga.no +unjárga.no +nesset.no +nissedal.no +nittedal.no +nord-aurdal.no +nord-fron.no +nord-odal.no +norddal.no +nordkapp.no +davvenjarga.no +davvenjárga.no +nordre-land.no +nordreisa.no +raisa.no +ráisa.no +nore-og-uvdal.no +notodden.no +naroy.no +nærøy.no +notteroy.no +nøtterøy.no +odda.no +oksnes.no +øksnes.no +oppdal.no +oppegard.no +oppegÃ¥rd.no +orkdal.no +orland.no +ørland.no +orskog.no +ørskog.no +orsta.no +ørsta.no +os.hedmark.no +os.hordaland.no +osen.no +osteroy.no +osterøy.no +ostre-toten.no +østre-toten.no +overhalla.no +ovre-eiker.no +øvre-eiker.no +oyer.no +øyer.no +oygarden.no +øygarden.no +oystre-slidre.no +øystre-slidre.no +porsanger.no +porsangu.no +porsáŋgu.no +porsgrunn.no +radoy.no +radøy.no +rakkestad.no +rana.no +ruovat.no +randaberg.no +rauma.no +rendalen.no +rennebu.no +rennesoy.no +rennesøy.no +rindal.no +ringebu.no +ringerike.no +ringsaker.no +rissa.no +risor.no +risør.no +roan.no +rollag.no +rygge.no +ralingen.no +rælingen.no +rodoy.no +rødøy.no +romskog.no +rømskog.no +roros.no +røros.no +rost.no +røst.no +royken.no +røyken.no +royrvik.no +røyrvik.no +rade.no +rÃ¥de.no +salangen.no +siellak.no +saltdal.no +salat.no +sálát.no +sálat.no +samnanger.no +sande.more-og-romsdal.no +sande.møre-og-romsdal.no +sande.vestfold.no +sandefjord.no +sandnes.no +sandoy.no +sandøy.no +sarpsborg.no +sauda.no +sauherad.no +sel.no +selbu.no +selje.no +seljord.no +sigdal.no +siljan.no +sirdal.no +skaun.no +skedsmo.no +ski.no +skien.no +skiptvet.no +skjervoy.no +skjervøy.no +skierva.no +skiervá.no +skjak.no +skjÃ¥k.no +skodje.no +skanland.no +skÃ¥nland.no +skanit.no +skánit.no +smola.no +smøla.no +snillfjord.no +snasa.no +snÃ¥sa.no +snoasa.no +snaase.no +snÃ¥ase.no +sogndal.no +sokndal.no +sola.no +solund.no +songdalen.no +sortland.no +spydeberg.no +stange.no +stavanger.no +steigen.no +steinkjer.no +stjordal.no +stjørdal.no +stokke.no +stor-elvdal.no +stord.no +stordal.no +storfjord.no +omasvuotna.no +strand.no +stranda.no +stryn.no +sula.no +suldal.no +sund.no +sunndal.no +surnadal.no +sveio.no +svelvik.no +sykkylven.no +sogne.no +søgne.no +somna.no +sømna.no +sondre-land.no +søndre-land.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +matta-varjjat.no +mátta-várjjat.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no +sorum.no +sørum.no +tana.no +deatnu.no +time.no +tingvoll.no +tinn.no +tjeldsund.no +dielddanuorri.no +tjome.no +tjøme.no +tokke.no +tolga.no +torsken.no +tranoy.no +tranøy.no +tromso.no +tromsø.no +tromsa.no +romsa.no +trondheim.no +troandin.no +trysil.no +trana.no +træna.no +trogstad.no +trøgstad.no +tvedestrand.no +tydal.no +tynset.no +tysfjord.no +divtasvuodna.no +divttasvuotna.no +tysnes.no +tysvar.no +tysvær.no +tonsberg.no +tønsberg.no +ullensaker.no +ullensvang.no +ulvik.no +utsira.no +vadso.no +vadsø.no +cahcesuolo.no +čáhcesuolo.no +vaksdal.no +valle.no +vang.no +vanylven.no +vardo.no +vardø.no +varggat.no +várggát.no +vefsn.no +vaapste.no +vega.no +vegarshei.no +vegÃ¥rshei.no +vennesla.no +verdal.no +verran.no +vestby.no +vestnes.no +vestre-slidre.no +vestre-toten.no +vestvagoy.no +vestvÃ¥gøy.no +vevelstad.no +vik.no +vikna.no +vindafjord.no +volda.no +voss.no +varoy.no +værøy.no +vagan.no +vÃ¥gan.no +voagat.no +vagsoy.no +vÃ¥gsøy.no +vaga.no +vÃ¥gÃ¥.no +valer.ostfold.no +vÃ¥ler.østfold.no +valer.hedmark.no +vÃ¥ler.hedmark.no + +// np : http://www.mos.com.np/register.html +*.np + +// nr : http://cenpac.net.nr/dns/index.html +// Submitted by registry +nr +biz.nr +info.nr +gov.nr +edu.nr +org.nr +net.nr +com.nr + +// nu : https://en.wikipedia.org/wiki/.nu +nu + +// nz : https://en.wikipedia.org/wiki/.nz +// Submitted by registry +nz +ac.nz +co.nz +cri.nz +geek.nz +gen.nz +govt.nz +health.nz +iwi.nz +kiwi.nz +maori.nz +mil.nz +māori.nz +net.nz +org.nz +parliament.nz +school.nz + +// om : https://en.wikipedia.org/wiki/.om +om +co.om +com.om +edu.om +gov.om +med.om +museum.om +net.om +org.om +pro.om + +// onion : https://tools.ietf.org/html/rfc7686 +onion + +// org : https://en.wikipedia.org/wiki/.org +org + +// pa : http://www.nic.pa/ +// Some additional second level "domains" resolve directly as hostnames, such as +// pannet.pa, so we add a rule for "pa". +pa +ac.pa +gob.pa +com.pa +org.pa +sld.pa +edu.pa +net.pa +ing.pa +abo.pa +med.pa +nom.pa + +// pe : https://www.nic.pe/InformeFinalComision.pdf +pe +edu.pe +gob.pe +nom.pe +mil.pe +org.pe +com.pe +net.pe + +// pf : http://www.gobin.info/domainname/formulaire-pf.pdf +pf +com.pf +org.pf +edu.pf + +// pg : https://en.wikipedia.org/wiki/.pg +*.pg + +// ph : http://www.domains.ph/FAQ2.asp +// Submitted by registry +ph +com.ph +net.ph +org.ph +gov.ph +edu.ph +ngo.ph +mil.ph +i.ph + +// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +pk +com.pk +net.pk +edu.pk +org.pk +fam.pk +biz.pk +web.pk +gov.pk +gob.pk +gok.pk +gon.pk +gop.pk +gos.pk +info.pk + +// pl http://www.dns.pl/english/index.html +// Submitted by registry +pl +com.pl +net.pl +org.pl +// pl functional domains (http://www.dns.pl/english/index.html) +aid.pl +agro.pl +atm.pl +auto.pl +biz.pl +edu.pl +gmina.pl +gsm.pl +info.pl +mail.pl +miasta.pl +media.pl +mil.pl +nieruchomosci.pl +nom.pl +pc.pl +powiat.pl +priv.pl +realestate.pl +rel.pl +sex.pl +shop.pl +sklep.pl +sos.pl +szkola.pl +targi.pl +tm.pl +tourism.pl +travel.pl +turystyka.pl +// Government domains +gov.pl +ap.gov.pl +ic.gov.pl +is.gov.pl +us.gov.pl +kmpsp.gov.pl +kppsp.gov.pl +kwpsp.gov.pl +psp.gov.pl +wskr.gov.pl +kwp.gov.pl +mw.gov.pl +ug.gov.pl +um.gov.pl +umig.gov.pl +ugim.gov.pl +upow.gov.pl +uw.gov.pl +starostwo.gov.pl +pa.gov.pl +po.gov.pl +psse.gov.pl +pup.gov.pl +rzgw.gov.pl +sa.gov.pl +so.gov.pl +sr.gov.pl +wsa.gov.pl +sko.gov.pl +uzs.gov.pl +wiih.gov.pl +winb.gov.pl +pinb.gov.pl +wios.gov.pl +witd.gov.pl +wzmiuw.gov.pl +piw.gov.pl +wiw.gov.pl +griw.gov.pl +wif.gov.pl +oum.gov.pl +sdn.gov.pl +zp.gov.pl +uppo.gov.pl +mup.gov.pl +wuoz.gov.pl +konsulat.gov.pl +oirm.gov.pl +// pl regional domains (http://www.dns.pl/english/index.html) +augustow.pl +babia-gora.pl +bedzin.pl +beskidy.pl +bialowieza.pl +bialystok.pl +bielawa.pl +bieszczady.pl +boleslawiec.pl +bydgoszcz.pl +bytom.pl +cieszyn.pl +czeladz.pl +czest.pl +dlugoleka.pl +elblag.pl +elk.pl +glogow.pl +gniezno.pl +gorlice.pl +grajewo.pl +ilawa.pl +jaworzno.pl +jelenia-gora.pl +jgora.pl +kalisz.pl +kazimierz-dolny.pl +karpacz.pl +kartuzy.pl +kaszuby.pl +katowice.pl +kepno.pl +ketrzyn.pl +klodzko.pl +kobierzyce.pl +kolobrzeg.pl +konin.pl +konskowola.pl +kutno.pl +lapy.pl +lebork.pl +legnica.pl +lezajsk.pl +limanowa.pl +lomza.pl +lowicz.pl +lubin.pl +lukow.pl +malbork.pl +malopolska.pl +mazowsze.pl +mazury.pl +mielec.pl +mielno.pl +mragowo.pl +naklo.pl +nowaruda.pl +nysa.pl +olawa.pl +olecko.pl +olkusz.pl +olsztyn.pl +opoczno.pl +opole.pl +ostroda.pl +ostroleka.pl +ostrowiec.pl +ostrowwlkp.pl +pila.pl +pisz.pl +podhale.pl +podlasie.pl +polkowice.pl +pomorze.pl +pomorskie.pl +prochowice.pl +pruszkow.pl +przeworsk.pl +pulawy.pl +radom.pl +rawa-maz.pl +rybnik.pl +rzeszow.pl +sanok.pl +sejny.pl +slask.pl +slupsk.pl +sosnowiec.pl +stalowa-wola.pl +skoczow.pl +starachowice.pl +stargard.pl +suwalki.pl +swidnica.pl +swiebodzin.pl +swinoujscie.pl +szczecin.pl +szczytno.pl +tarnobrzeg.pl +tgory.pl +turek.pl +tychy.pl +ustka.pl +walbrzych.pl +warmia.pl +warszawa.pl +waw.pl +wegrow.pl +wielun.pl +wlocl.pl +wloclawek.pl +wodzislaw.pl +wolomin.pl +wroclaw.pl +zachpomor.pl +zagan.pl +zarow.pl +zgora.pl +zgorzelec.pl + +// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +pm + +// pn : http://www.government.pn/PnRegistry/policies.htm +pn +gov.pn +co.pn +org.pn +edu.pn +net.pn + +// post : https://en.wikipedia.org/wiki/.post +post + +// pr : http://www.nic.pr/index.asp?f=1 +pr +com.pr +net.pr +org.pr +gov.pr +edu.pr +isla.pr +pro.pr +biz.pr +info.pr +name.pr +// these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr +est.pr +prof.pr +ac.pr + +// pro : http://registry.pro/get-pro +pro +aaa.pro +aca.pro +acct.pro +avocat.pro +bar.pro +cpa.pro +eng.pro +jur.pro +law.pro +med.pro +recht.pro + +// ps : https://en.wikipedia.org/wiki/.ps +// http://www.nic.ps/registration/policy.html#reg +ps +edu.ps +gov.ps +sec.ps +plo.ps +com.ps +org.ps +net.ps + +// pt : http://online.dns.pt/dns/start_dns +pt +net.pt +gov.pt +org.pt +edu.pt +int.pt +publ.pt +com.pt +nome.pt + +// pw : https://en.wikipedia.org/wiki/.pw +pw +co.pw +ne.pw +or.pw +ed.pw +go.pw +belau.pw + +// py : http://www.nic.py/pautas.html#seccion_9 +// Submitted by registry +py +com.py +coop.py +edu.py +gov.py +mil.py +net.py +org.py + +// qa : http://domains.qa/en/ +qa +com.qa +edu.qa +gov.qa +mil.qa +name.qa +net.qa +org.qa +sch.qa + +// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs +re +asso.re +com.re +nom.re + +// ro : http://www.rotld.ro/ +ro +arts.ro +com.ro +firm.ro +info.ro +nom.ro +nt.ro +org.ro +rec.ro +store.ro +tm.ro +www.ro + +// rs : https://www.rnids.rs/en/domains/national-domains +rs +ac.rs +co.rs +edu.rs +gov.rs +in.rs +org.rs + +// ru : https://cctld.ru/en/domains/domens_ru/reserved/ +ru +ac.ru +edu.ru +gov.ru +int.ru +mil.ru +test.ru + +// rw : http://www.nic.rw/cgi-bin/policy.pl +rw +gov.rw +net.rw +edu.rw +ac.rw +com.rw +co.rw +int.rw +mil.rw +gouv.rw + +// sa : http://www.nic.net.sa/ +sa +com.sa +net.sa +org.sa +gov.sa +med.sa +pub.sa +edu.sa +sch.sa + +// sb : http://www.sbnic.net.sb/ +// Submitted by registry +sb +com.sb +edu.sb +gov.sb +net.sb +org.sb + +// sc : http://www.nic.sc/ +sc +com.sc +gov.sc +net.sc +org.sc +edu.sc + +// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm +// Submitted by registry +sd +com.sd +net.sd +org.sd +edu.sd +med.sd +tv.sd +gov.sd +info.sd + +// se : https://en.wikipedia.org/wiki/.se +// Submitted by registry +se +a.se +ac.se +b.se +bd.se +brand.se +c.se +d.se +e.se +f.se +fh.se +fhsk.se +fhv.se +g.se +h.se +i.se +k.se +komforb.se +kommunalforbund.se +komvux.se +l.se +lanbib.se +m.se +n.se +naturbruksgymn.se +o.se +org.se +p.se +parti.se +pp.se +press.se +r.se +s.se +t.se +tm.se +u.se +w.se +x.se +y.se +z.se + +// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines +sg +com.sg +net.sg +org.sg +gov.sg +edu.sg +per.sg + +// sh : http://www.nic.sh/registrar.html +sh +com.sh +net.sh +gov.sh +org.sh +mil.sh + +// si : https://en.wikipedia.org/wiki/.si +si + +// sj : No registrations at this time. +// Submitted by registry +sj + +// sk : https://en.wikipedia.org/wiki/.sk +// list of 2nd level domains ? +sk + +// sl : http://www.nic.sl +// Submitted by registry +sl +com.sl +net.sl +edu.sl +gov.sl +org.sl + +// sm : https://en.wikipedia.org/wiki/.sm +sm + +// sn : https://en.wikipedia.org/wiki/.sn +sn +art.sn +com.sn +edu.sn +gouv.sn +org.sn +perso.sn +univ.sn + +// so : http://www.soregistry.com/ +so +com.so +net.so +org.so + +// sr : https://en.wikipedia.org/wiki/.sr +sr + +// st : http://www.nic.st/html/policyrules/ +st +co.st +com.st +consulado.st +edu.st +embaixada.st +gov.st +mil.st +net.st +org.st +principe.st +saotome.st +store.st + +// su : https://en.wikipedia.org/wiki/.su +su + +// sv : http://www.svnet.org.sv/niveldos.pdf +sv +com.sv +edu.sv +gob.sv +org.sv +red.sv + +// sx : https://en.wikipedia.org/wiki/.sx +// Submitted by registry +sx +gov.sx + +// sy : https://en.wikipedia.org/wiki/.sy +// see also: http://www.gobin.info/domainname/sy.doc +sy +edu.sy +gov.sy +net.sy +mil.sy +com.sy +org.sy + +// sz : https://en.wikipedia.org/wiki/.sz +// http://www.sispa.org.sz/ +sz +co.sz +ac.sz +org.sz + +// tc : https://en.wikipedia.org/wiki/.tc +tc + +// td : https://en.wikipedia.org/wiki/.td +td + +// tel: https://en.wikipedia.org/wiki/.tel +// http://www.telnic.org/ +tel + +// tf : https://en.wikipedia.org/wiki/.tf +tf + +// tg : https://en.wikipedia.org/wiki/.tg +// http://www.nic.tg/ +tg + +// th : https://en.wikipedia.org/wiki/.th +// Submitted by registry +th +ac.th +co.th +go.th +in.th +mi.th +net.th +or.th + +// tj : http://www.nic.tj/policy.html +tj +ac.tj +biz.tj +co.tj +com.tj +edu.tj +go.tj +gov.tj +int.tj +mil.tj +name.tj +net.tj +nic.tj +org.tj +test.tj +web.tj + +// tk : https://en.wikipedia.org/wiki/.tk +tk + +// tl : https://en.wikipedia.org/wiki/.tl +tl +gov.tl + +// tm : http://www.nic.tm/local.html +tm +com.tm +co.tm +org.tm +net.tm +nom.tm +gov.tm +mil.tm +edu.tm + +// tn : https://en.wikipedia.org/wiki/.tn +// http://whois.ati.tn/ +tn +com.tn +ens.tn +fin.tn +gov.tn +ind.tn +intl.tn +nat.tn +net.tn +org.tn +info.tn +perso.tn +tourism.tn +edunet.tn +rnrt.tn +rns.tn +rnu.tn +mincom.tn +agrinet.tn +defense.tn +turen.tn + +// to : https://en.wikipedia.org/wiki/.to +// Submitted by registry +to +com.to +gov.to +net.to +org.to +edu.to +mil.to + +// subTLDs: https://www.nic.tr/forms/eng/policies.pdf +// and: https://www.nic.tr/forms/politikalar.pdf +// Submitted by +tr +com.tr +info.tr +biz.tr +net.tr +org.tr +web.tr +gen.tr +tv.tr +av.tr +dr.tr +bbs.tr +name.tr +tel.tr +gov.tr +bel.tr +pol.tr +mil.tr +k12.tr +edu.tr +kep.tr + +// Used by Northern Cyprus +nc.tr + +// Used by government agencies of Northern Cyprus +gov.nc.tr + +// tt : http://www.nic.tt/ +tt +co.tt +com.tt +org.tt +net.tt +biz.tt +info.tt +pro.tt +int.tt +coop.tt +jobs.tt +mobi.tt +travel.tt +museum.tt +aero.tt +name.tt +gov.tt +edu.tt + +// tv : https://en.wikipedia.org/wiki/.tv +// Not listing any 2LDs as reserved since none seem to exist in practice, +// Wikipedia notwithstanding. +tv + +// tw : https://en.wikipedia.org/wiki/.tw +tw +edu.tw +gov.tw +mil.tw +com.tw +net.tw +org.tw +idv.tw +game.tw +ebiz.tw +club.tw +網路.tw +組織.tw +商業.tw + +// tz : http://www.tznic.or.tz/index.php/domains +// Submitted by registry +tz +ac.tz +co.tz +go.tz +hotel.tz +info.tz +me.tz +mil.tz +mobi.tz +ne.tz +or.tz +sc.tz +tv.tz + +// ua : https://hostmaster.ua/policy/?ua +// Submitted by registry +ua +// ua 2LD +com.ua +edu.ua +gov.ua +in.ua +net.ua +org.ua +// ua geographic names +// https://hostmaster.ua/2ld/ +cherkassy.ua +cherkasy.ua +chernigov.ua +chernihiv.ua +chernivtsi.ua +chernovtsy.ua +ck.ua +cn.ua +cr.ua +crimea.ua +cv.ua +dn.ua +dnepropetrovsk.ua +dnipropetrovsk.ua +dominic.ua +donetsk.ua +dp.ua +if.ua +ivano-frankivsk.ua +kh.ua +kharkiv.ua +kharkov.ua +kherson.ua +khmelnitskiy.ua +khmelnytskyi.ua +kiev.ua +kirovograd.ua +km.ua +kr.ua +krym.ua +ks.ua +kv.ua +kyiv.ua +lg.ua +lt.ua +lugansk.ua +lutsk.ua +lv.ua +lviv.ua +mk.ua +mykolaiv.ua +nikolaev.ua +od.ua +odesa.ua +odessa.ua +pl.ua +poltava.ua +rivne.ua +rovno.ua +rv.ua +sb.ua +sebastopol.ua +sevastopol.ua +sm.ua +sumy.ua +te.ua +ternopil.ua +uz.ua +uzhgorod.ua +vinnica.ua +vinnytsia.ua +vn.ua +volyn.ua +yalta.ua +zaporizhzhe.ua +zaporizhzhia.ua +zhitomir.ua +zhytomyr.ua +zp.ua +zt.ua + +// ug : https://www.registry.co.ug/ +ug +co.ug +or.ug +ac.ug +sc.ug +go.ug +ne.ug +com.ug +org.ug + +// uk : https://en.wikipedia.org/wiki/.uk +// Submitted by registry +uk +ac.uk +co.uk +gov.uk +ltd.uk +me.uk +net.uk +nhs.uk +org.uk +plc.uk +police.uk +*.sch.uk + +// us : https://en.wikipedia.org/wiki/.us +us +dni.us +fed.us +isa.us +kids.us +nsn.us +// us geographic names +ak.us +al.us +ar.us +as.us +az.us +ca.us +co.us +ct.us +dc.us +de.us +fl.us +ga.us +gu.us +hi.us +ia.us +id.us +il.us +in.us +ks.us +ky.us +la.us +ma.us +md.us +me.us +mi.us +mn.us +mo.us +ms.us +mt.us +nc.us +nd.us +ne.us +nh.us +nj.us +nm.us +nv.us +ny.us +oh.us +ok.us +or.us +pa.us +pr.us +ri.us +sc.us +sd.us +tn.us +tx.us +ut.us +vi.us +vt.us +va.us +wa.us +wi.us +wv.us +wy.us +// The registrar notes several more specific domains available in each state, +// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat +// haphazard; in some states these domains resolve as addresses, while in others +// only subdomains are available, or even nothing at all. We include the +// most common ones where it's clear that different sites are different +// entities. +k12.ak.us +k12.al.us +k12.ar.us +k12.as.us +k12.az.us +k12.ca.us +k12.co.us +k12.ct.us +k12.dc.us +k12.de.us +k12.fl.us +k12.ga.us +k12.gu.us +// k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login +k12.ia.us +k12.id.us +k12.il.us +k12.in.us +k12.ks.us +k12.ky.us +k12.la.us +k12.ma.us +k12.md.us +k12.me.us +k12.mi.us +k12.mn.us +k12.mo.us +k12.ms.us +k12.mt.us +k12.nc.us +// k12.nd.us Bug 1028347 - Removed at request of Travis Rosso +k12.ne.us +k12.nh.us +k12.nj.us +k12.nm.us +k12.nv.us +k12.ny.us +k12.oh.us +k12.ok.us +k12.or.us +k12.pa.us +k12.pr.us +k12.ri.us +k12.sc.us +// k12.sd.us Bug 934131 - Removed at request of James Booze +k12.tn.us +k12.tx.us +k12.ut.us +k12.vi.us +k12.vt.us +k12.va.us +k12.wa.us +k12.wi.us +// k12.wv.us Bug 947705 - Removed at request of Verne Britton +k12.wy.us +cc.ak.us +cc.al.us +cc.ar.us +cc.as.us +cc.az.us +cc.ca.us +cc.co.us +cc.ct.us +cc.dc.us +cc.de.us +cc.fl.us +cc.ga.us +cc.gu.us +cc.hi.us +cc.ia.us +cc.id.us +cc.il.us +cc.in.us +cc.ks.us +cc.ky.us +cc.la.us +cc.ma.us +cc.md.us +cc.me.us +cc.mi.us +cc.mn.us +cc.mo.us +cc.ms.us +cc.mt.us +cc.nc.us +cc.nd.us +cc.ne.us +cc.nh.us +cc.nj.us +cc.nm.us +cc.nv.us +cc.ny.us +cc.oh.us +cc.ok.us +cc.or.us +cc.pa.us +cc.pr.us +cc.ri.us +cc.sc.us +cc.sd.us +cc.tn.us +cc.tx.us +cc.ut.us +cc.vi.us +cc.vt.us +cc.va.us +cc.wa.us +cc.wi.us +cc.wv.us +cc.wy.us +lib.ak.us +lib.al.us +lib.ar.us +lib.as.us +lib.az.us +lib.ca.us +lib.co.us +lib.ct.us +lib.dc.us +// lib.de.us Issue #243 - Moved to Private section at request of Ed Moore +lib.fl.us +lib.ga.us +lib.gu.us +lib.hi.us +lib.ia.us +lib.id.us +lib.il.us +lib.in.us +lib.ks.us +lib.ky.us +lib.la.us +lib.ma.us +lib.md.us +lib.me.us +lib.mi.us +lib.mn.us +lib.mo.us +lib.ms.us +lib.mt.us +lib.nc.us +lib.nd.us +lib.ne.us +lib.nh.us +lib.nj.us +lib.nm.us +lib.nv.us +lib.ny.us +lib.oh.us +lib.ok.us +lib.or.us +lib.pa.us +lib.pr.us +lib.ri.us +lib.sc.us +lib.sd.us +lib.tn.us +lib.tx.us +lib.ut.us +lib.vi.us +lib.vt.us +lib.va.us +lib.wa.us +lib.wi.us +// lib.wv.us Bug 941670 - Removed at request of Larry W Arnold +lib.wy.us +// k12.ma.us contains school districts in Massachusetts. The 4LDs are +// managed independently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated directly to the +// 5LD operators. +pvt.k12.ma.us +chtr.k12.ma.us +paroch.k12.ma.us +// Merit Network, Inc. maintains the registry for =~ /(k12|cc|lib).mi.us/ and the following +// see also: http://domreg.merit.edu +// see also: whois -h whois.domreg.merit.edu help +ann-arbor.mi.us +cog.mi.us +dst.mi.us +eaton.mi.us +gen.mi.us +mus.mi.us +tec.mi.us +washtenaw.mi.us + +// uy : http://www.nic.org.uy/ +uy +com.uy +edu.uy +gub.uy +mil.uy +net.uy +org.uy + +// uz : http://www.reg.uz/ +uz +co.uz +com.uz +net.uz +org.uz + +// va : https://en.wikipedia.org/wiki/.va +va + +// vc : https://en.wikipedia.org/wiki/.vc +// Submitted by registry +vc +com.vc +net.vc +org.vc +gov.vc +mil.vc +edu.vc + +// ve : https://registro.nic.ve/ +// Submitted by registry +ve +arts.ve +co.ve +com.ve +e12.ve +edu.ve +firm.ve +gob.ve +gov.ve +info.ve +int.ve +mil.ve +net.ve +org.ve +rec.ve +store.ve +tec.ve +web.ve + +// vg : https://en.wikipedia.org/wiki/.vg +vg + +// vi : http://www.nic.vi/newdomainform.htm +// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other +// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they +// are available for registration (which they do not seem to be). +vi +co.vi +com.vi +k12.vi +net.vi +org.vi + +// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +vn +com.vn +net.vn +org.vn +edu.vn +gov.vn +int.vn +ac.vn +biz.vn +info.vn +name.vn +pro.vn +health.vn + +// vu : https://en.wikipedia.org/wiki/.vu +// http://www.vunic.vu/ +vu +com.vu +edu.vu +net.vu +org.vu + +// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +wf + +// ws : https://en.wikipedia.org/wiki/.ws +// http://samoanic.ws/index.dhtml +ws +com.ws +net.ws +org.ws +gov.ws +edu.ws + +// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +yt + +// IDN ccTLDs +// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then +// U-label, and follow this format: +// // A-Label ("", [, variant info]) : +// // [sponsoring org] +// U-Label + +// xn--mgbaam7a8h ("Emerat", Arabic) : AE +// http://nic.ae/english/arabicdomain/rules.jsp +امارات + +// xn--y9a3aq ("hye", Armenian) : AM +// ISOC AM (operated by .am Registry) +Õ°Õ¡Õµ + +// xn--54b7fta0cc ("Bangla", Bangla) : BD +বাংলা + +// xn--90ae ("bg", Bulgarian) : BG +бг + +// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY +// Operated by .by registry +бел + +// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中国 + +// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中國 + +// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ +الجزائر + +// xn--wgbh1c ("Egypt/Masr", Arabic) : EG +// http://www.dotmasr.eg/ +مصر + +// xn--e1a4c ("eu", Cyrillic) : EU +ею + +// xn--node ("ge", Georgian Mkhedruli) : GE +გე + +// xn--qxam ("el", Greek) : GR +// Hellenic Ministry of Infrastructure, Transport, and Networks +ελ + +// xn--j6w193g ("Hong Kong", Chinese) : HK +// https://www.hkirc.hk +// Submitted by registry +// https://www.hkirc.hk/content.jsp?id=30#!/34 +香港 +公司.香港 +教育.香港 +政府.香港 +個人.香港 +網絡.香港 +組織.香港 + +// xn--2scrj9c ("Bharat", Kannada) : IN +// India +ಭಾರತ + +// xn--3hcrj9c ("Bharat", Oriya) : IN +// India +ଭାରତ + +// xn--45br5cyl ("Bharatam", Assamese) : IN +// India +ভাৰত + +// xn--h2breg3eve ("Bharatam", Sanskrit) : IN +// India +भारतम् + +// xn--h2brj9c8c ("Bharot", Santali) : IN +// India +भारोत + +// xn--mgbgu82a ("Bharat", Sindhi) : IN +// India +ڀارت + +// xn--rvc1e0am3e ("Bharatam", Malayalam) : IN +// India +ഭാരതം + +// xn--h2brj9c ("Bharat", Devanagari) : IN +// India +भारत + +// xn--mgbbh1a ("Bharat", Kashmiri) : IN +// India +بارت + +// xn--mgbbh1a71e ("Bharat", Arabic) : IN +// India +بھارت + +// xn--fpcrj9c3d ("Bharat", Telugu) : IN +// India +భారత్ + +// xn--gecrj9c ("Bharat", Gujarati) : IN +// India +ભારત + +// xn--s9brj9c ("Bharat", Gurmukhi) : IN +// India +ਭਾਰਤ + +// xn--45brj9c ("Bharat", Bengali) : IN +// India +ভারত + +// xn--xkc2dl3a5ee0h ("India", Tamil) : IN +// India +இந்தியா + +// xn--mgba3a4f16a ("Iran", Persian) : IR +ایران + +// xn--mgba3a4fra ("Iran", Arabic) : IR +ايران + +// xn--mgbtx2b ("Iraq", Arabic) : IQ +// Communications and Media Commission +عراق + +// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO +// National Information Technology Center (NITC) +// Royal Scientific Society, Al-Jubeiha +الاردن + +// xn--3e0b707e ("Republic of Korea", Hangul) : KR +한국 + +// xn--80ao21a ("Kaz", Kazakh) : KZ +қаз + +// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK +// http://nic.lk +ලංකා + +// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK +// http://nic.lk +இலங்கை + +// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA +المغرب + +// xn--d1alf ("mkd", Macedonian) : MK +// MARnet +мкд + +// xn--l1acc ("mon", Mongolian) : MN +мон + +// xn--mix891f ("Macao", Chinese, Traditional) : MO +// MONIC / HNET Asia (Registry Operator for .mo) +澳門 + +// xn--mix082f ("Macao", Chinese, Simplified) : MO +澳门 + +// xn--mgbx4cd0ab ("Malaysia", Malay) : MY +مليسيا + +// xn--mgb9awbf ("Oman", Arabic) : OM +عمان + +// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK +پاکستان + +// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK +پاكستان + +// xn--ygbi2ammx ("Falasteen", Arabic) : PS +// The Palestinian National Internet Naming Authority (PNINA) +// http://www.pnina.ps +فلسطين + +// xn--90a3ac ("srb", Cyrillic) : RS +// https://www.rnids.rs/en/domains/national-domains +срб +пр.срб +орг.срб +обр.срб +од.срб +упр.срб +ак.срб + +// xn--p1ai ("rf", Russian-Cyrillic) : RU +// http://www.cctld.ru/en/docs/rulesrf.php +рф + +// xn--wgbl6a ("Qatar", Arabic) : QA +// http://www.ict.gov.qa/ +قطر + +// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA +// http://www.nic.net.sa/ +السعودية + +// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA +السعودیة + +// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA +السعودیۃ + +// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA +السعوديه + +// xn--mgbpl2fh ("sudan", Arabic) : SD +// Operated by .sd registry +سودان + +// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG +新加坡 + +// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG +சிங்கப்பூர் + +// xn--ogbpf8fl ("Syria", Arabic) : SY +سورية + +// xn--mgbtf8fl ("Syria", Arabic, variant) : SY +سوريا + +// xn--o3cw4h ("Thai", Thai) : TH +// http://www.thnic.co.th +ไทย +ศึกษา.ไทย +ธุรกิจ.ไทย +รัฐบาล.ไทย +ทหาร.ไทย +เน็ต.ไทย +องค์กร.ไทย + +// xn--pgbs0dh ("Tunisia", Arabic) : TN +// http://nic.tn +تونس + +// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台灣 + +// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台湾 + +// xn--nnx388a ("Taiwan", Chinese, variant) : TW +臺灣 + +// xn--j1amh ("ukr", Cyrillic) : UA +укр + +// xn--mgb2ddes ("AlYemen", Arabic) : YE +اليمن + +// xxx : http://icmregistry.com +xxx + +// ye : http://www.y.net.ye/services/domain_name.htm +*.ye + +// za : http://www.zadna.org.za/content/page/domain-information +ac.za +agric.za +alt.za +co.za +edu.za +gov.za +grondar.za +law.za +mil.za +net.za +ngo.za +nis.za +nom.za +org.za +school.za +tm.za +web.za + +// zm : https://zicta.zm/ +// Submitted by registry +zm +ac.zm +biz.zm +co.zm +com.zm +edu.zm +gov.zm +info.zm +mil.zm +net.zm +org.zm +sch.zm + +// zw : https://www.potraz.gov.zw/ +// Confirmed by registry 2017-01-25 +zw +ac.zw +co.zw +gov.zw +mil.zw +org.zw + + +// newGTLDs +// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2018-05-08T19:40:37Z +// This list is auto-generated, don't edit it manually. + +// aaa : 2015-02-26 American Automobile Association, Inc. +aaa + +// aarp : 2015-05-21 AARP +aarp + +// abarth : 2015-07-30 Fiat Chrysler Automobiles N.V. +abarth + +// abb : 2014-10-24 ABB Ltd +abb + +// abbott : 2014-07-24 Abbott Laboratories, Inc. +abbott + +// abbvie : 2015-07-30 AbbVie Inc. +abbvie + +// abc : 2015-07-30 Disney Enterprises, Inc. +abc + +// able : 2015-06-25 Able Inc. +able + +// abogado : 2014-04-24 Minds + Machines Group Limited +abogado + +// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre +abudhabi + +// academy : 2013-11-07 Binky Moon, LLC +academy + +// accenture : 2014-08-15 Accenture plc +accenture + +// accountant : 2014-11-20 dot Accountant Limited +accountant + +// accountants : 2014-03-20 Binky Moon, LLC +accountants + +// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +aco + +// active : 2014-05-01 Active Network, LLC +active + +// actor : 2013-12-12 United TLD Holdco Ltd. +actor + +// adac : 2015-07-16 Allgemeiner Deutscher Automobil-Club e.V. (ADAC) +adac + +// ads : 2014-12-04 Charleston Road Registry Inc. +ads + +// adult : 2014-10-16 ICM Registry AD LLC +adult + +// aeg : 2015-03-19 Aktiebolaget Electrolux +aeg + +// aetna : 2015-05-21 Aetna Life Insurance Company +aetna + +// afamilycompany : 2015-07-23 Johnson Shareholdings, Inc. +afamilycompany + +// afl : 2014-10-02 Australian Football League +afl + +// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa +africa + +// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +agakhan + +// agency : 2013-11-14 Binky Moon, LLC +agency + +// aig : 2014-12-18 American International Group, Inc. +aig + +// aigo : 2015-08-06 aigo Digital Technology Co,Ltd. +aigo + +// airbus : 2015-07-30 Airbus S.A.S. +airbus + +// airforce : 2014-03-06 United TLD Holdco Ltd. +airforce + +// airtel : 2014-10-24 Bharti Airtel Limited +airtel + +// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +akdn + +// alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V. +alfaromeo + +// alibaba : 2015-01-15 Alibaba Group Holding Limited +alibaba + +// alipay : 2015-01-15 Alibaba Group Holding Limited +alipay + +// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +allfinanz + +// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company +allstate + +// ally : 2015-06-18 Ally Financial Inc. +ally + +// alsace : 2014-07-02 Region Grand Est +alsace + +// alstom : 2015-07-30 ALSTOM +alstom + +// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc. +americanexpress + +// americanfamily : 2015-07-23 AmFam, Inc. +americanfamily + +// amex : 2015-07-31 American Express Travel Related Services Company, Inc. +amex + +// amfam : 2015-07-23 AmFam, Inc. +amfam + +// amica : 2015-05-28 Amica Mutual Insurance Company +amica + +// amsterdam : 2014-07-24 Gemeente Amsterdam +amsterdam + +// analytics : 2014-12-18 Campus IP LLC +analytics + +// android : 2014-08-07 Charleston Road Registry Inc. +android + +// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +anquan + +// anz : 2015-07-31 Australia and New Zealand Banking Group Limited +anz + +// aol : 2015-09-17 Oath Inc. +aol + +// apartments : 2014-12-11 Binky Moon, LLC +apartments + +// app : 2015-05-14 Charleston Road Registry Inc. +app + +// apple : 2015-05-14 Apple Inc. +apple + +// aquarelle : 2014-07-24 Aquarelle.com +aquarelle + +// arab : 2015-11-12 League of Arab States +arab + +// aramco : 2014-11-20 Aramco Services Company +aramco + +// archi : 2014-02-06 Afilias plc +archi + +// army : 2014-03-06 United TLD Holdco Ltd. +army + +// art : 2016-03-24 UK Creative Ideas Limited +art + +// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. +arte + +// asda : 2015-07-31 Wal-Mart Stores, Inc. +asda + +// associates : 2014-03-06 Binky Moon, LLC +associates + +// athleta : 2015-07-30 The Gap, Inc. +athleta + +// attorney : 2014-03-20 United TLD Holdco Ltd. +attorney + +// auction : 2014-03-20 United TLD Holdco Ltd. +auction + +// audi : 2015-05-21 AUDI Aktiengesellschaft +audi + +// audible : 2015-06-25 Amazon Registry Services, Inc. +audible + +// audio : 2014-03-20 Uniregistry, Corp. +audio + +// auspost : 2015-08-13 Australian Postal Corporation +auspost + +// author : 2014-12-18 Amazon Registry Services, Inc. +author + +// auto : 2014-11-13 Cars Registry Limited +auto + +// autos : 2014-01-09 DERAutos, LLC +autos + +// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca +avianca + +// aws : 2015-06-25 Amazon Registry Services, Inc. +aws + +// axa : 2013-12-19 AXA SA +axa + +// azure : 2014-12-18 Microsoft Corporation +azure + +// baby : 2015-04-09 Johnson & Johnson Services, Inc. +baby + +// baidu : 2015-01-08 Baidu, Inc. +baidu + +// banamex : 2015-07-30 Citigroup Inc. +banamex + +// bananarepublic : 2015-07-31 The Gap, Inc. +bananarepublic + +// band : 2014-06-12 United TLD Holdco Ltd. +band + +// bank : 2014-09-25 fTLD Registry Services LLC +bank + +// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +bar + +// barcelona : 2014-07-24 Municipi de Barcelona +barcelona + +// barclaycard : 2014-11-20 Barclays Bank PLC +barclaycard + +// barclays : 2014-11-20 Barclays Bank PLC +barclays + +// barefoot : 2015-06-11 Gallo Vineyards, Inc. +barefoot + +// bargains : 2013-11-14 Binky Moon, LLC +bargains + +// baseball : 2015-10-29 MLB Advanced Media DH, LLC +baseball + +// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA) +basketball + +// bauhaus : 2014-04-17 Werkhaus GmbH +bauhaus + +// bayern : 2014-01-23 Bayern Connect GmbH +bayern + +// bbc : 2014-12-18 British Broadcasting Corporation +bbc + +// bbt : 2015-07-23 BB&T Corporation +bbt + +// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +bbva + +// bcg : 2015-04-02 The Boston Consulting Group, Inc. +bcg + +// bcn : 2014-07-24 Municipi de Barcelona +bcn + +// beats : 2015-05-14 Beats Electronics, LLC +beats + +// beauty : 2015-12-03 L'Oréal +beauty + +// beer : 2014-01-09 Minds + Machines Group Limited +beer + +// bentley : 2014-12-18 Bentley Motors Limited +bentley + +// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG +berlin + +// best : 2013-12-19 BestTLD Pty Ltd +best + +// bestbuy : 2015-07-31 BBY Solutions, Inc. +bestbuy + +// bet : 2015-05-07 Afilias plc +bet + +// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited +bharti + +// bible : 2014-06-19 American Bible Society +bible + +// bid : 2013-12-19 dot Bid Limited +bid + +// bike : 2013-08-27 Binky Moon, LLC +bike + +// bing : 2014-12-18 Microsoft Corporation +bing + +// bingo : 2014-12-04 Binky Moon, LLC +bingo + +// bio : 2014-03-06 Afilias plc +bio + +// black : 2014-01-16 Afilias plc +black + +// blackfriday : 2014-01-16 Uniregistry, Corp. +blackfriday + +// blanco : 2015-07-16 BLANCO GmbH + Co KG +blanco + +// blockbuster : 2015-07-30 Dish DBS Corporation +blockbuster + +// blog : 2015-05-14 Knock Knock WHOIS There, LLC +blog + +// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC +bloomberg + +// blue : 2013-11-07 Afilias plc +blue + +// bms : 2014-10-30 Bristol-Myers Squibb Company +bms + +// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +bmw + +// bnl : 2014-07-24 Banca Nazionale del Lavoro +bnl + +// bnpparibas : 2014-05-29 BNP Paribas +bnpparibas + +// boats : 2014-12-04 DERBoats, LLC +boats + +// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH +boehringer + +// bofa : 2015-07-31 Bank of America Corporation +bofa + +// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +bom + +// bond : 2014-06-05 Bond University Limited +bond + +// boo : 2014-01-30 Charleston Road Registry Inc. +boo + +// book : 2015-08-27 Amazon Registry Services, Inc. +book + +// booking : 2015-07-16 Booking.com B.V. +booking + +// bosch : 2015-06-18 Robert Bosch GMBH +bosch + +// bostik : 2015-05-28 Bostik SA +bostik + +// boston : 2015-12-10 Boston TLD Management, LLC +boston + +// bot : 2014-12-18 Amazon Registry Services, Inc. +bot + +// boutique : 2013-11-14 Binky Moon, LLC +boutique + +// box : 2015-11-12 NS1 Limited +box + +// bradesco : 2014-12-18 Banco Bradesco S.A. +bradesco + +// bridgestone : 2014-12-18 Bridgestone Corporation +bridgestone + +// broadway : 2014-12-22 Celebrate Broadway, Inc. +broadway + +// broker : 2014-12-11 Dotbroker Registry Limited +broker + +// brother : 2015-01-29 Brother Industries, Ltd. +brother + +// brussels : 2014-02-06 DNS.be vzw +brussels + +// budapest : 2013-11-21 Minds + Machines Group Limited +budapest + +// bugatti : 2015-07-23 Bugatti International SA +bugatti + +// build : 2013-11-07 Plan Bee LLC +build + +// builders : 2013-11-07 Binky Moon, LLC +builders + +// business : 2013-11-07 Binky Moon, LLC +business + +// buy : 2014-12-18 Amazon Registry Services, Inc. +buy + +// buzz : 2013-10-02 DOTSTRATEGY CO. +buzz + +// bzh : 2014-02-27 Association www.bzh +bzh + +// cab : 2013-10-24 Binky Moon, LLC +cab + +// cafe : 2015-02-11 Binky Moon, LLC +cafe + +// cal : 2014-07-24 Charleston Road Registry Inc. +cal + +// call : 2014-12-18 Amazon Registry Services, Inc. +call + +// calvinklein : 2015-07-30 PVH gTLD Holdings LLC +calvinklein + +// cam : 2016-04-21 AC Webconnecting Holding B.V. +cam + +// camera : 2013-08-27 Binky Moon, LLC +camera + +// camp : 2013-11-07 Binky Moon, LLC +camp + +// cancerresearch : 2014-05-15 Australian Cancer Research Foundation +cancerresearch + +// canon : 2014-09-12 Canon Inc. +canon + +// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +capetown + +// capital : 2014-03-06 Binky Moon, LLC +capital + +// capitalone : 2015-08-06 Capital One Financial Corporation +capitalone + +// car : 2015-01-22 Cars Registry Limited +car + +// caravan : 2013-12-12 Caravan International, Inc. +caravan + +// cards : 2013-12-05 Binky Moon, LLC +cards + +// care : 2014-03-06 Binky Moon, LLC +care + +// career : 2013-10-09 dotCareer LLC +career + +// careers : 2013-10-02 Binky Moon, LLC +careers + +// cars : 2014-11-13 Cars Registry Limited +cars + +// cartier : 2014-06-23 Richemont DNS Inc. +cartier + +// casa : 2013-11-21 Minds + Machines Group Limited +casa + +// case : 2015-09-03 CNH Industrial N.V. +case + +// caseih : 2015-09-03 CNH Industrial N.V. +caseih + +// cash : 2014-03-06 Binky Moon, LLC +cash + +// casino : 2014-12-18 Binky Moon, LLC +casino + +// catering : 2013-12-05 Binky Moon, LLC +catering + +// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +catholic + +// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +cba + +// cbn : 2014-08-22 The Christian Broadcasting Network, Inc. +cbn + +// cbre : 2015-07-02 CBRE, Inc. +cbre + +// cbs : 2015-08-06 CBS Domains Inc. +cbs + +// ceb : 2015-04-09 The Corporate Executive Board Company +ceb + +// center : 2013-11-07 Binky Moon, LLC +center + +// ceo : 2013-11-07 CEOTLD Pty Ltd +ceo + +// cern : 2014-06-05 European Organization for Nuclear Research ("CERN") +cern + +// cfa : 2014-08-28 CFA Institute +cfa + +// cfd : 2014-12-11 DotCFD Registry Limited +cfd + +// chanel : 2015-04-09 Chanel International B.V. +chanel + +// channel : 2014-05-08 Charleston Road Registry Inc. +channel + +// charity : 2018-04-11 Corn Lake, LLC +charity + +// chase : 2015-04-30 JPMorgan Chase Bank, National Association +chase + +// chat : 2014-12-04 Binky Moon, LLC +chat + +// cheap : 2013-11-14 Binky Moon, LLC +cheap + +// chintai : 2015-06-11 CHINTAI Corporation +chintai + +// christmas : 2013-11-21 Uniregistry, Corp. +christmas + +// chrome : 2014-07-24 Charleston Road Registry Inc. +chrome + +// chrysler : 2015-07-30 FCA US LLC. +chrysler + +// church : 2014-02-06 Binky Moon, LLC +church + +// cipriani : 2015-02-19 Hotel Cipriani Srl +cipriani + +// circle : 2014-12-18 Amazon Registry Services, Inc. +circle + +// cisco : 2014-12-22 Cisco Technology, Inc. +cisco + +// citadel : 2015-07-23 Citadel Domain LLC +citadel + +// citi : 2015-07-30 Citigroup Inc. +citi + +// citic : 2014-01-09 CITIC Group Corporation +citic + +// city : 2014-05-29 Binky Moon, LLC +city + +// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. +cityeats + +// claims : 2014-03-20 Binky Moon, LLC +claims + +// cleaning : 2013-12-05 Binky Moon, LLC +cleaning + +// click : 2014-06-05 Uniregistry, Corp. +click + +// clinic : 2014-03-20 Binky Moon, LLC +clinic + +// clinique : 2015-10-01 The Estée Lauder Companies Inc. +clinique + +// clothing : 2013-08-27 Binky Moon, LLC +clothing + +// cloud : 2015-04-16 Aruba PEC S.p.A. +cloud + +// club : 2013-11-08 .CLUB DOMAINS, LLC +club + +// clubmed : 2015-06-25 Club Méditerranée S.A. +clubmed + +// coach : 2014-10-09 Binky Moon, LLC +coach + +// codes : 2013-10-31 Binky Moon, LLC +codes + +// coffee : 2013-10-17 Binky Moon, LLC +coffee + +// college : 2014-01-16 XYZ.COM LLC +college + +// cologne : 2014-02-05 punkt.wien GmbH +cologne + +// comcast : 2015-07-23 Comcast IP Holdings I, LLC +comcast + +// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +commbank + +// community : 2013-12-05 Binky Moon, LLC +community + +// company : 2013-11-07 Binky Moon, LLC +company + +// compare : 2015-10-08 iSelect Ltd +compare + +// computer : 2013-10-24 Binky Moon, LLC +computer + +// comsec : 2015-01-08 VeriSign, Inc. +comsec + +// condos : 2013-12-05 Binky Moon, LLC +condos + +// construction : 2013-09-16 Binky Moon, LLC +construction + +// consulting : 2013-12-05 United TLD Holdco Ltd. +consulting + +// contact : 2015-01-08 Top Level Spectrum, Inc. +contact + +// contractors : 2013-09-10 Binky Moon, LLC +contractors + +// cooking : 2013-11-21 Minds + Machines Group Limited +cooking + +// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +cookingchannel + +// cool : 2013-11-14 Binky Moon, LLC +cool + +// corsica : 2014-09-25 Collectivité de Corse +corsica + +// country : 2013-12-19 DotCountry LLC +country + +// coupon : 2015-02-26 Amazon Registry Services, Inc. +coupon + +// coupons : 2015-03-26 Binky Moon, LLC +coupons + +// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD +courses + +// credit : 2014-03-20 Binky Moon, LLC +credit + +// creditcard : 2014-03-20 Binky Moon, LLC +creditcard + +// creditunion : 2015-01-22 CUNA Performance Resources, LLC +creditunion + +// cricket : 2014-10-09 dot Cricket Limited +cricket + +// crown : 2014-10-24 Crown Equipment Corporation +crown + +// crs : 2014-04-03 Federated Co-operatives Limited +crs + +// cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd. +cruise + +// cruises : 2013-12-05 Binky Moon, LLC +cruises + +// csc : 2014-09-25 Alliance-One Services, Inc. +csc + +// cuisinella : 2014-04-03 SALM S.A.S. +cuisinella + +// cymru : 2014-05-08 Nominet UK +cymru + +// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd. +cyou + +// dabur : 2014-02-06 Dabur India Limited +dabur + +// dad : 2014-01-23 Charleston Road Registry Inc. +dad + +// dance : 2013-10-24 United TLD Holdco Ltd. +dance + +// data : 2016-06-02 Dish DBS Corporation +data + +// date : 2014-11-20 dot Date Limited +date + +// dating : 2013-12-05 Binky Moon, LLC +dating + +// datsun : 2014-03-27 NISSAN MOTOR CO., LTD. +datsun + +// day : 2014-01-30 Charleston Road Registry Inc. +day + +// dclk : 2014-11-20 Charleston Road Registry Inc. +dclk + +// dds : 2015-05-07 Minds + Machines Group Limited +dds + +// deal : 2015-06-25 Amazon Registry Services, Inc. +deal + +// dealer : 2014-12-22 Dealer Dot Com, Inc. +dealer + +// deals : 2014-05-22 Binky Moon, LLC +deals + +// degree : 2014-03-06 United TLD Holdco Ltd. +degree + +// delivery : 2014-09-11 Binky Moon, LLC +delivery + +// dell : 2014-10-24 Dell Inc. +dell + +// deloitte : 2015-07-31 Deloitte Touche Tohmatsu +deloitte + +// delta : 2015-02-19 Delta Air Lines, Inc. +delta + +// democrat : 2013-10-24 United TLD Holdco Ltd. +democrat + +// dental : 2014-03-20 Binky Moon, LLC +dental + +// dentist : 2014-03-20 United TLD Holdco Ltd. +dentist + +// desi : 2013-11-14 Desi Networks LLC +desi + +// design : 2014-11-07 Top Level Design, LLC +design + +// dev : 2014-10-16 Charleston Road Registry Inc. +dev + +// dhl : 2015-07-23 Deutsche Post AG +dhl + +// diamonds : 2013-09-22 Binky Moon, LLC +diamonds + +// diet : 2014-06-26 Uniregistry, Corp. +diet + +// digital : 2014-03-06 Binky Moon, LLC +digital + +// direct : 2014-04-10 Binky Moon, LLC +direct + +// directory : 2013-09-20 Binky Moon, LLC +directory + +// discount : 2014-03-06 Binky Moon, LLC +discount + +// discover : 2015-07-23 Discover Financial Services +discover + +// dish : 2015-07-30 Dish DBS Corporation +dish + +// diy : 2015-11-05 Lifestyle Domain Holdings, Inc. +diy + +// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. +dnp + +// docs : 2014-10-16 Charleston Road Registry Inc. +docs + +// doctor : 2016-06-02 Binky Moon, LLC +doctor + +// dodge : 2015-07-30 FCA US LLC. +dodge + +// dog : 2014-12-04 Binky Moon, LLC +dog + +// doha : 2014-09-18 Communications Regulatory Authority (CRA) +doha + +// domains : 2013-10-17 Binky Moon, LLC +domains + +// dot : 2015-05-21 Dish DBS Corporation +dot + +// download : 2014-11-20 dot Support Limited +download + +// drive : 2015-03-05 Charleston Road Registry Inc. +drive + +// dtv : 2015-06-04 Dish DBS Corporation +dtv + +// dubai : 2015-01-01 Dubai Smart Government Department +dubai + +// duck : 2015-07-23 Johnson Shareholdings, Inc. +duck + +// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company +dunlop + +// duns : 2015-08-06 The Dun & Bradstreet Corporation +duns + +// dupont : 2015-06-25 E. I. du Pont de Nemours and Company +dupont + +// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +durban + +// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +dvag + +// dvr : 2016-05-26 Hughes Satellite Systems Corporation +dvr + +// earth : 2014-12-04 Interlink Co., Ltd. +earth + +// eat : 2014-01-23 Charleston Road Registry Inc. +eat + +// eco : 2016-07-08 Big Room Inc. +eco + +// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. +edeka + +// education : 2013-11-07 Binky Moon, LLC +education + +// email : 2013-10-31 Binky Moon, LLC +email + +// emerck : 2014-04-03 Merck KGaA +emerck + +// energy : 2014-09-11 Binky Moon, LLC +energy + +// engineer : 2014-03-06 United TLD Holdco Ltd. +engineer + +// engineering : 2014-03-06 Binky Moon, LLC +engineering + +// enterprises : 2013-09-20 Binky Moon, LLC +enterprises + +// epost : 2015-07-23 Deutsche Post AG +epost + +// epson : 2014-12-04 Seiko Epson Corporation +epson + +// equipment : 2013-08-27 Binky Moon, LLC +equipment + +// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson +ericsson + +// erni : 2014-04-03 ERNI Group Holding AG +erni + +// esq : 2014-05-08 Charleston Road Registry Inc. +esq + +// estate : 2013-08-27 Binky Moon, LLC +estate + +// esurance : 2015-07-23 Esurance Insurance Company +esurance + +// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +etisalat + +// eurovision : 2014-04-24 European Broadcasting Union (EBU) +eurovision + +// eus : 2013-12-12 Puntueus Fundazioa +eus + +// events : 2013-12-05 Binky Moon, LLC +events + +// everbank : 2014-05-15 EverBank +everbank + +// exchange : 2014-03-06 Binky Moon, LLC +exchange + +// expert : 2013-11-21 Binky Moon, LLC +expert + +// exposed : 2013-12-05 Binky Moon, LLC +exposed + +// express : 2015-02-11 Binky Moon, LLC +express + +// extraspace : 2015-05-14 Extra Space Storage LLC +extraspace + +// fage : 2014-12-18 Fage International S.A. +fage + +// fail : 2014-03-06 Binky Moon, LLC +fail + +// fairwinds : 2014-11-13 FairWinds Partners, LLC +fairwinds + +// faith : 2014-11-20 dot Faith Limited +faith + +// family : 2015-04-02 United TLD Holdco Ltd. +family + +// fan : 2014-03-06 Asiamix Digital Limited +fan + +// fans : 2014-11-07 Asiamix Digital Limited +fans + +// farm : 2013-11-07 Binky Moon, LLC +farm + +// farmers : 2015-07-09 Farmers Insurance Exchange +farmers + +// fashion : 2014-07-03 Minds + Machines Group Limited +fashion + +// fast : 2014-12-18 Amazon Registry Services, Inc. +fast + +// fedex : 2015-08-06 Federal Express Corporation +fedex + +// feedback : 2013-12-19 Top Level Spectrum, Inc. +feedback + +// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V. +ferrari + +// ferrero : 2014-12-18 Ferrero Trading Lux S.A. +ferrero + +// fiat : 2015-07-31 Fiat Chrysler Automobiles N.V. +fiat + +// fidelity : 2015-07-30 Fidelity Brokerage Services LLC +fidelity + +// fido : 2015-08-06 Rogers Communications Canada Inc. +fido + +// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +film + +// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +final + +// finance : 2014-03-20 Binky Moon, LLC +finance + +// financial : 2014-03-06 Binky Moon, LLC +financial + +// fire : 2015-06-25 Amazon Registry Services, Inc. +fire + +// firestone : 2014-12-18 Bridgestone Licensing Services, Inc +firestone + +// firmdale : 2014-03-27 Firmdale Holdings Limited +firmdale + +// fish : 2013-12-12 Binky Moon, LLC +fish + +// fishing : 2013-11-21 Minds + Machines Group Limited +fishing + +// fit : 2014-11-07 Minds + Machines Group Limited +fit + +// fitness : 2014-03-06 Binky Moon, LLC +fitness + +// flickr : 2015-04-02 Yahoo! Domain Services Inc. +flickr + +// flights : 2013-12-05 Binky Moon, LLC +flights + +// flir : 2015-07-23 FLIR Systems, Inc. +flir + +// florist : 2013-11-07 Binky Moon, LLC +florist + +// flowers : 2014-10-09 Uniregistry, Corp. +flowers + +// fly : 2014-05-08 Charleston Road Registry Inc. +fly + +// foo : 2014-01-23 Charleston Road Registry Inc. +foo + +// food : 2016-04-21 Lifestyle Domain Holdings, Inc. +food + +// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc. +foodnetwork + +// football : 2014-12-18 Binky Moon, LLC +football + +// ford : 2014-11-13 Ford Motor Company +ford + +// forex : 2014-12-11 Dotforex Registry Limited +forex + +// forsale : 2014-05-22 United TLD Holdco Ltd. +forsale + +// forum : 2015-04-02 Fegistry, LLC +forum + +// foundation : 2013-12-05 Binky Moon, LLC +foundation + +// fox : 2015-09-11 FOX Registry, LLC +fox + +// free : 2015-12-10 Amazon Registry Services, Inc. +free + +// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH +fresenius + +// frl : 2014-05-15 FRLregistry B.V. +frl + +// frogans : 2013-12-19 OP3FT +frogans + +// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc. +frontdoor + +// frontier : 2015-02-05 Frontier Communications Corporation +frontier + +// ftr : 2015-07-16 Frontier Communications Corporation +ftr + +// fujitsu : 2015-07-30 Fujitsu Limited +fujitsu + +// fujixerox : 2015-07-23 Xerox DNHC LLC +fujixerox + +// fun : 2016-01-14 DotSpace Inc. +fun + +// fund : 2014-03-20 Binky Moon, LLC +fund + +// furniture : 2014-03-20 Binky Moon, LLC +furniture + +// futbol : 2013-09-20 United TLD Holdco Ltd. +futbol + +// fyi : 2015-04-02 Binky Moon, LLC +fyi + +// gal : 2013-11-07 Asociación puntoGAL +gal + +// gallery : 2013-09-13 Binky Moon, LLC +gallery + +// gallo : 2015-06-11 Gallo Vineyards, Inc. +gallo + +// gallup : 2015-02-19 Gallup, Inc. +gallup + +// game : 2015-05-28 Uniregistry, Corp. +game + +// games : 2015-05-28 United TLD Holdco Ltd. +games + +// gap : 2015-07-31 The Gap, Inc. +gap + +// garden : 2014-06-26 Minds + Machines Group Limited +garden + +// gbiz : 2014-07-17 Charleston Road Registry Inc. +gbiz + +// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" +gdn + +// gea : 2014-12-04 GEA Group Aktiengesellschaft +gea + +// gent : 2014-01-23 COMBELL NV +gent + +// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +genting + +// george : 2015-07-31 Wal-Mart Stores, Inc. +george + +// ggee : 2014-01-09 GMO Internet, Inc. +ggee + +// gift : 2013-10-17 DotGift, LLC +gift + +// gifts : 2014-07-03 Binky Moon, LLC +gifts + +// gives : 2014-03-06 United TLD Holdco Ltd. +gives + +// giving : 2014-11-13 Giving Limited +giving + +// glade : 2015-07-23 Johnson Shareholdings, Inc. +glade + +// glass : 2013-11-07 Binky Moon, LLC +glass + +// gle : 2014-07-24 Charleston Road Registry Inc. +gle + +// global : 2014-04-17 Dot Global Domain Registry Limited +global + +// globo : 2013-12-19 Globo Comunicação e Participações S.A +globo + +// gmail : 2014-05-01 Charleston Road Registry Inc. +gmail + +// gmbh : 2016-01-29 Binky Moon, LLC +gmbh + +// gmo : 2014-01-09 GMO Internet Pte. Ltd. +gmo + +// gmx : 2014-04-24 1&1 Mail & Media GmbH +gmx + +// godaddy : 2015-07-23 Go Daddy East, LLC +godaddy + +// gold : 2015-01-22 Binky Moon, LLC +gold + +// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +goldpoint + +// golf : 2014-12-18 Binky Moon, LLC +golf + +// goo : 2014-12-18 NTT Resonant Inc. +goo + +// goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company +goodhands + +// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company +goodyear + +// goog : 2014-11-20 Charleston Road Registry Inc. +goog + +// google : 2014-07-24 Charleston Road Registry Inc. +google + +// gop : 2014-01-16 Republican State Leadership Committee, Inc. +gop + +// got : 2014-12-18 Amazon Registry Services, Inc. +got + +// grainger : 2015-05-07 Grainger Registry Services, LLC +grainger + +// graphics : 2013-09-13 Binky Moon, LLC +graphics + +// gratis : 2014-03-20 Binky Moon, LLC +gratis + +// green : 2014-05-08 Afilias plc +green + +// gripe : 2014-03-06 Binky Moon, LLC +gripe + +// grocery : 2016-06-16 Wal-Mart Stores, Inc. +grocery + +// group : 2014-08-15 Binky Moon, LLC +group + +// guardian : 2015-07-30 The Guardian Life Insurance Company of America +guardian + +// gucci : 2014-11-13 Guccio Gucci S.p.a. +gucci + +// guge : 2014-08-28 Charleston Road Registry Inc. +guge + +// guide : 2013-09-13 Binky Moon, LLC +guide + +// guitars : 2013-11-14 Uniregistry, Corp. +guitars + +// guru : 2013-08-27 Binky Moon, LLC +guru + +// hair : 2015-12-03 L'Oréal +hair + +// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH +hamburg + +// hangout : 2014-11-13 Charleston Road Registry Inc. +hangout + +// haus : 2013-12-05 United TLD Holdco Ltd. +haus + +// hbo : 2015-07-30 HBO Registry Services, Inc. +hbo + +// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED +hdfc + +// hdfcbank : 2015-02-12 HDFC Bank Limited +hdfcbank + +// health : 2015-02-11 DotHealth, LLC +health + +// healthcare : 2014-06-12 Binky Moon, LLC +healthcare + +// help : 2014-06-26 Uniregistry, Corp. +help + +// helsinki : 2015-02-05 City of Helsinki +helsinki + +// here : 2014-02-06 Charleston Road Registry Inc. +here + +// hermes : 2014-07-10 HERMES INTERNATIONAL +hermes + +// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. +hgtv + +// hiphop : 2014-03-06 Uniregistry, Corp. +hiphop + +// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. +hisamitsu + +// hitachi : 2014-10-31 Hitachi, Ltd. +hitachi + +// hiv : 2014-03-13 Uniregistry, Corp. +hiv + +// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited +hkt + +// hockey : 2015-03-19 Binky Moon, LLC +hockey + +// holdings : 2013-08-27 Binky Moon, LLC +holdings + +// holiday : 2013-11-07 Binky Moon, LLC +holiday + +// homedepot : 2015-04-02 Home Depot Product Authority, LLC +homedepot + +// homegoods : 2015-07-16 The TJX Companies, Inc. +homegoods + +// homes : 2014-01-09 DERHomes, LLC +homes + +// homesense : 2015-07-16 The TJX Companies, Inc. +homesense + +// honda : 2014-12-18 Honda Motor Co., Ltd. +honda + +// honeywell : 2015-07-23 Honeywell GTLD LLC +honeywell + +// horse : 2013-11-21 Minds + Machines Group Limited +horse + +// hospital : 2016-10-20 Binky Moon, LLC +hospital + +// host : 2014-04-17 DotHost Inc. +host + +// hosting : 2014-05-29 Uniregistry, Corp. +hosting + +// hot : 2015-08-27 Amazon Registry Services, Inc. +hot + +// hoteles : 2015-03-05 Travel Reservations SRL +hoteles + +// hotels : 2016-04-07 Booking.com B.V. +hotels + +// hotmail : 2014-12-18 Microsoft Corporation +hotmail + +// house : 2013-11-07 Binky Moon, LLC +house + +// how : 2014-01-23 Charleston Road Registry Inc. +how + +// hsbc : 2014-10-24 HSBC Global Services (UK) Limited +hsbc + +// hughes : 2015-07-30 Hughes Satellite Systems Corporation +hughes + +// hyatt : 2015-07-30 Hyatt GTLD, L.L.C. +hyatt + +// hyundai : 2015-07-09 Hyundai Motor Company +hyundai + +// ibm : 2014-07-31 International Business Machines Corporation +ibm + +// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited +icbc + +// ice : 2014-10-30 IntercontinentalExchange, Inc. +ice + +// icu : 2015-01-08 ShortDot SA +icu + +// ieee : 2015-07-23 IEEE Global LLC +ieee + +// ifm : 2014-01-30 ifm electronic gmbh +ifm + +// ikano : 2015-07-09 Ikano S.A. +ikano + +// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +imamat + +// imdb : 2015-06-25 Amazon Registry Services, Inc. +imdb + +// immo : 2014-07-10 Binky Moon, LLC +immo + +// immobilien : 2013-11-07 United TLD Holdco Ltd. +immobilien + +// inc : 2018-03-10 GTLD Limited +inc + +// industries : 2013-12-05 Binky Moon, LLC +industries + +// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. +infiniti + +// ing : 2014-01-23 Charleston Road Registry Inc. +ing + +// ink : 2013-12-05 Top Level Design, LLC +ink + +// institute : 2013-11-07 Binky Moon, LLC +institute + +// insurance : 2015-02-19 fTLD Registry Services LLC +insurance + +// insure : 2014-03-20 Binky Moon, LLC +insure + +// intel : 2015-08-06 Intel Corporation +intel + +// international : 2013-11-07 Binky Moon, LLC +international + +// intuit : 2015-07-30 Intuit Administrative Services, Inc. +intuit + +// investments : 2014-03-20 Binky Moon, LLC +investments + +// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. +ipiranga + +// irish : 2014-08-07 Binky Moon, LLC +irish + +// iselect : 2015-02-11 iSelect Ltd +iselect + +// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +ismaili + +// ist : 2014-08-28 Istanbul Metropolitan Municipality +ist + +// istanbul : 2014-08-28 Istanbul Metropolitan Municipality +istanbul + +// itau : 2014-10-02 Itau Unibanco Holding S.A. +itau + +// itv : 2015-07-09 ITV Services Limited +itv + +// iveco : 2015-09-03 CNH Industrial N.V. +iveco + +// jaguar : 2014-11-13 Jaguar Land Rover Ltd +jaguar + +// java : 2014-06-19 Oracle Corporation +java + +// jcb : 2014-11-20 JCB Co., Ltd. +jcb + +// jcp : 2015-04-23 JCP Media, Inc. +jcp + +// jeep : 2015-07-30 FCA US LLC. +jeep + +// jetzt : 2014-01-09 Binky Moon, LLC +jetzt + +// jewelry : 2015-03-05 Binky Moon, LLC +jewelry + +// jio : 2015-04-02 Reliance Industries Limited +jio + +// jlc : 2014-12-04 Richemont DNS Inc. +jlc + +// jll : 2015-04-02 Jones Lang LaSalle Incorporated +jll + +// jmp : 2015-03-26 Matrix IP LLC +jmp + +// jnj : 2015-06-18 Johnson & Johnson Services, Inc. +jnj + +// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +joburg + +// jot : 2014-12-18 Amazon Registry Services, Inc. +jot + +// joy : 2014-12-18 Amazon Registry Services, Inc. +joy + +// jpmorgan : 2015-04-30 JPMorgan Chase Bank, National Association +jpmorgan + +// jprs : 2014-09-18 Japan Registry Services Co., Ltd. +jprs + +// juegos : 2014-03-20 Uniregistry, Corp. +juegos + +// juniper : 2015-07-30 JUNIPER NETWORKS, INC. +juniper + +// kaufen : 2013-11-07 United TLD Holdco Ltd. +kaufen + +// kddi : 2014-09-12 KDDI CORPORATION +kddi + +// kerryhotels : 2015-04-30 Kerry Trading Co. Limited +kerryhotels + +// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited +kerrylogistics + +// kerryproperties : 2015-04-09 Kerry Trading Co. Limited +kerryproperties + +// kfh : 2014-12-04 Kuwait Finance House +kfh + +// kia : 2015-07-09 KIA MOTORS CORPORATION +kia + +// kim : 2013-09-23 Afilias plc +kim + +// kinder : 2014-11-07 Ferrero Trading Lux S.A. +kinder + +// kindle : 2015-06-25 Amazon Registry Services, Inc. +kindle + +// kitchen : 2013-09-20 Binky Moon, LLC +kitchen + +// kiwi : 2013-09-20 DOT KIWI LIMITED +kiwi + +// koeln : 2014-01-09 punkt.wien GmbH +koeln + +// komatsu : 2015-01-08 Komatsu Ltd. +komatsu + +// kosher : 2015-08-20 Kosher Marketing Assets LLC +kosher + +// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) +kpmg + +// kpn : 2015-01-08 Koninklijke KPN N.V. +kpn + +// krd : 2013-12-05 KRG Department of Information Technology +krd + +// kred : 2013-12-19 KredTLD Pty Ltd +kred + +// kuokgroup : 2015-04-09 Kerry Trading Co. Limited +kuokgroup + +// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen +kyoto + +// lacaixa : 2014-01-09 Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” +lacaixa + +// ladbrokes : 2015-08-06 LADBROKES INTERNATIONAL PLC +ladbrokes + +// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A. +lamborghini + +// lamer : 2015-10-01 The Estée Lauder Companies Inc. +lamer + +// lancaster : 2015-02-12 LANCASTER +lancaster + +// lancia : 2015-07-31 Fiat Chrysler Automobiles N.V. +lancia + +// lancome : 2015-07-23 L'Oréal +lancome + +// land : 2013-09-10 Binky Moon, LLC +land + +// landrover : 2014-11-13 Jaguar Land Rover Ltd +landrover + +// lanxess : 2015-07-30 LANXESS Corporation +lanxess + +// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +lasalle + +// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico +lat + +// latino : 2015-07-30 Dish DBS Corporation +latino + +// latrobe : 2014-06-16 La Trobe University +latrobe + +// law : 2015-01-22 Minds + Machines Group Limited +law + +// lawyer : 2014-03-20 United TLD Holdco Ltd. +lawyer + +// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant") +lds + +// lease : 2014-03-06 Binky Moon, LLC +lease + +// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +leclerc + +// lefrak : 2015-07-16 LeFrak Organization, Inc. +lefrak + +// legal : 2014-10-16 Binky Moon, LLC +legal + +// lego : 2015-07-16 LEGO Juris A/S +lego + +// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION +lexus + +// lgbt : 2014-05-08 Afilias plc +lgbt + +// liaison : 2014-10-02 Liaison Technologies, Incorporated +liaison + +// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +lidl + +// life : 2014-02-06 Binky Moon, LLC +life + +// lifeinsurance : 2015-01-15 American Council of Life Insurers +lifeinsurance + +// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. +lifestyle + +// lighting : 2013-08-27 Binky Moon, LLC +lighting + +// like : 2014-12-18 Amazon Registry Services, Inc. +like + +// lilly : 2015-07-31 Eli Lilly and Company +lilly + +// limited : 2014-03-06 Binky Moon, LLC +limited + +// limo : 2013-10-17 Binky Moon, LLC +limo + +// lincoln : 2014-11-13 Ford Motor Company +lincoln + +// linde : 2014-12-04 Linde Aktiengesellschaft +linde + +// link : 2013-11-14 Uniregistry, Corp. +link + +// lipsy : 2015-06-25 Lipsy Ltd +lipsy + +// live : 2014-12-04 United TLD Holdco Ltd. +live + +// living : 2015-07-30 Lifestyle Domain Holdings, Inc. +living + +// lixil : 2015-03-19 LIXIL Group Corporation +lixil + +// llc : 2017-12-14 Afilias plc +llc + +// loan : 2014-11-20 dot Loan Limited +loan + +// loans : 2014-03-20 Binky Moon, LLC +loans + +// locker : 2015-06-04 Dish DBS Corporation +locker + +// locus : 2015-06-25 Locus Analytics LLC +locus + +// loft : 2015-07-30 Annco, Inc. +loft + +// lol : 2015-01-30 Uniregistry, Corp. +lol + +// london : 2013-11-14 Dot London Domains Limited +london + +// lotte : 2014-11-07 Lotte Holdings Co., Ltd. +lotte + +// lotto : 2014-04-10 Afilias plc +lotto + +// love : 2014-12-22 Merchant Law Group LLP +love + +// lpl : 2015-07-30 LPL Holdings, Inc. +lpl + +// lplfinancial : 2015-07-30 LPL Holdings, Inc. +lplfinancial + +// ltd : 2014-09-25 Binky Moon, LLC +ltd + +// ltda : 2014-04-17 InterNetX, Corp +ltda + +// lundbeck : 2015-08-06 H. Lundbeck A/S +lundbeck + +// lupin : 2014-11-07 LUPIN LIMITED +lupin + +// luxe : 2014-01-09 Minds + Machines Group Limited +luxe + +// luxury : 2013-10-17 Luxury Partners, LLC +luxury + +// macys : 2015-07-31 Macys, Inc. +macys + +// madrid : 2014-05-01 Comunidad de Madrid +madrid + +// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) +maif + +// maison : 2013-12-05 Binky Moon, LLC +maison + +// makeup : 2015-01-15 L'Oréal +makeup + +// man : 2014-12-04 MAN SE +man + +// management : 2013-11-07 Binky Moon, LLC +management + +// mango : 2013-10-24 PUNTO FA S.L. +mango + +// map : 2016-06-09 Charleston Road Registry Inc. +map + +// market : 2014-03-06 United TLD Holdco Ltd. +market + +// marketing : 2013-11-07 Binky Moon, LLC +marketing + +// markets : 2014-12-11 Dotmarkets Registry Limited +markets + +// marriott : 2014-10-09 Marriott Worldwide Corporation +marriott + +// marshalls : 2015-07-16 The TJX Companies, Inc. +marshalls + +// maserati : 2015-07-31 Fiat Chrysler Automobiles N.V. +maserati + +// mattel : 2015-08-06 Mattel Sites, Inc. +mattel + +// mba : 2015-04-02 Binky Moon, LLC +mba + +// mckinsey : 2015-07-31 McKinsey Holdings, Inc. +mckinsey + +// med : 2015-08-06 Medistry LLC +med + +// media : 2014-03-06 Binky Moon, LLC +media + +// meet : 2014-01-16 Charleston Road Registry Inc. +meet + +// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +melbourne + +// meme : 2014-01-30 Charleston Road Registry Inc. +meme + +// memorial : 2014-10-16 Dog Beach, LLC +memorial + +// men : 2015-02-26 Exclusive Registry Limited +men + +// menu : 2013-09-11 Wedding TLD2, LLC +menu + +// merckmsd : 2016-07-14 MSD Registry Holdings, Inc. +merckmsd + +// metlife : 2015-05-07 MetLife Services and Solutions, LLC +metlife + +// miami : 2013-12-19 Minds + Machines Group Limited +miami + +// microsoft : 2014-12-18 Microsoft Corporation +microsoft + +// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +mini + +// mint : 2015-07-30 Intuit Administrative Services, Inc. +mint + +// mit : 2015-07-02 Massachusetts Institute of Technology +mit + +// mitsubishi : 2015-07-23 Mitsubishi Corporation +mitsubishi + +// mlb : 2015-05-21 MLB Advanced Media DH, LLC +mlb + +// mls : 2015-04-23 The Canadian Real Estate Association +mls + +// mma : 2014-11-07 MMA IARD +mma + +// mobile : 2016-06-02 Dish DBS Corporation +mobile + +// mobily : 2014-12-18 GreenTech Consultancy Company W.L.L. +mobily + +// moda : 2013-11-07 United TLD Holdco Ltd. +moda + +// moe : 2013-11-13 Interlink Co., Ltd. +moe + +// moi : 2014-12-18 Amazon Registry Services, Inc. +moi + +// mom : 2015-04-16 Uniregistry, Corp. +mom + +// monash : 2013-09-30 Monash University +monash + +// money : 2014-10-16 Binky Moon, LLC +money + +// monster : 2015-09-11 Monster Worldwide, Inc. +monster + +// mopar : 2015-07-30 FCA US LLC. +mopar + +// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant") +mormon + +// mortgage : 2014-03-20 United TLD Holdco Ltd. +mortgage + +// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +moscow + +// moto : 2015-06-04 Motorola Trademark Holdings, LLC +moto + +// motorcycles : 2014-01-09 DERMotorcycles, LLC +motorcycles + +// mov : 2014-01-30 Charleston Road Registry Inc. +mov + +// movie : 2015-02-05 Binky Moon, LLC +movie + +// movistar : 2014-10-16 Telefónica S.A. +movistar + +// msd : 2015-07-23 MSD Registry Holdings, Inc. +msd + +// mtn : 2014-12-04 MTN Dubai Limited +mtn + +// mtr : 2015-03-12 MTR Corporation Limited +mtr + +// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC +mutual + +// nab : 2015-08-20 National Australia Bank Limited +nab + +// nadex : 2014-12-11 Nadex Domains, Inc. +nadex + +// nagoya : 2013-10-24 GMO Registry, Inc. +nagoya + +// nationwide : 2015-07-23 Nationwide Mutual Insurance Company +nationwide + +// natura : 2015-03-12 NATURA COSMÉTICOS S.A. +natura + +// navy : 2014-03-06 United TLD Holdco Ltd. +navy + +// nba : 2015-07-31 NBA REGISTRY, LLC +nba + +// nec : 2015-01-08 NEC Corporation +nec + +// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +netbank + +// netflix : 2015-06-18 Netflix, Inc. +netflix + +// network : 2013-11-14 Binky Moon, LLC +network + +// neustar : 2013-12-05 Registry Services, LLC +neustar + +// new : 2014-01-30 Charleston Road Registry Inc. +new + +// newholland : 2015-09-03 CNH Industrial N.V. +newholland + +// news : 2014-12-18 United TLD Holdco Ltd. +news + +// next : 2015-06-18 Next plc +next + +// nextdirect : 2015-06-18 Next plc +nextdirect + +// nexus : 2014-07-24 Charleston Road Registry Inc. +nexus + +// nfl : 2015-07-23 NFL Reg Ops LLC +nfl + +// ngo : 2014-03-06 Public Interest Registry +ngo + +// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) +nhk + +// nico : 2014-12-04 DWANGO Co., Ltd. +nico + +// nike : 2015-07-23 NIKE, Inc. +nike + +// nikon : 2015-05-21 NIKON CORPORATION +nikon + +// ninja : 2013-11-07 United TLD Holdco Ltd. +ninja + +// nissan : 2014-03-27 NISSAN MOTOR CO., LTD. +nissan + +// nissay : 2015-10-29 Nippon Life Insurance Company +nissay + +// nokia : 2015-01-08 Nokia Corporation +nokia + +// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC +northwesternmutual + +// norton : 2014-12-04 Symantec Corporation +norton + +// now : 2015-06-25 Amazon Registry Services, Inc. +now + +// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +nowruz + +// nowtv : 2015-05-14 Starbucks (HK) Limited +nowtv + +// nra : 2014-05-22 NRA Holdings Company, INC. +nra + +// nrw : 2013-11-21 Minds + Machines GmbH +nrw + +// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION +ntt + +// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications +nyc + +// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA +obi + +// observer : 2015-04-30 Top Level Spectrum, Inc. +observer + +// off : 2015-07-23 Johnson Shareholdings, Inc. +off + +// office : 2015-03-12 Microsoft Corporation +office + +// okinawa : 2013-12-05 BRregistry, Inc. +okinawa + +// olayan : 2015-05-14 Crescent Holding GmbH +olayan + +// olayangroup : 2015-05-14 Crescent Holding GmbH +olayangroup + +// oldnavy : 2015-07-31 The Gap, Inc. +oldnavy + +// ollo : 2015-06-04 Dish DBS Corporation +ollo + +// omega : 2015-01-08 The Swatch Group Ltd +omega + +// one : 2014-11-07 One.com A/S +one + +// ong : 2014-03-06 Public Interest Registry +ong + +// onl : 2013-09-16 I-Registry Ltd. +onl + +// online : 2015-01-15 DotOnline Inc. +online + +// onyourside : 2015-07-23 Nationwide Mutual Insurance Company +onyourside + +// ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED +ooo + +// open : 2015-07-31 American Express Travel Related Services Company, Inc. +open + +// oracle : 2014-06-19 Oracle Corporation +oracle + +// orange : 2015-03-12 Orange Brand Services Limited +orange + +// organic : 2014-03-27 Afilias plc +organic + +// origins : 2015-10-01 The Estée Lauder Companies Inc. +origins + +// osaka : 2014-09-04 Osaka Registry Co., Ltd. +osaka + +// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. +otsuka + +// ott : 2015-06-04 Dish DBS Corporation +ott + +// ovh : 2014-01-16 OVH SAS +ovh + +// page : 2014-12-04 Charleston Road Registry Inc. +page + +// panasonic : 2015-07-30 Panasonic Corporation +panasonic + +// panerai : 2014-11-07 Richemont DNS Inc. +panerai + +// paris : 2014-01-30 City of Paris +paris + +// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +pars + +// partners : 2013-12-05 Binky Moon, LLC +partners + +// parts : 2013-12-05 Binky Moon, LLC +parts + +// party : 2014-09-11 Blue Sky Registry Limited +party + +// passagens : 2015-03-05 Travel Reservations SRL +passagens + +// pay : 2015-08-27 Amazon Registry Services, Inc. +pay + +// pccw : 2015-05-14 PCCW Enterprises Limited +pccw + +// pet : 2015-05-07 Afilias plc +pet + +// pfizer : 2015-09-11 Pfizer Inc. +pfizer + +// pharmacy : 2014-06-19 National Association of Boards of Pharmacy +pharmacy + +// phd : 2016-07-28 Charleston Road Registry Inc. +phd + +// philips : 2014-11-07 Koninklijke Philips N.V. +philips + +// phone : 2016-06-02 Dish DBS Corporation +phone + +// photo : 2013-11-14 Uniregistry, Corp. +photo + +// photography : 2013-09-20 Binky Moon, LLC +photography + +// photos : 2013-10-17 Binky Moon, LLC +photos + +// physio : 2014-05-01 PhysBiz Pty Ltd +physio + +// piaget : 2014-10-16 Richemont DNS Inc. +piaget + +// pics : 2013-11-14 Uniregistry, Corp. +pics + +// pictet : 2014-06-26 Pictet Europe S.A. +pictet + +// pictures : 2014-03-06 Binky Moon, LLC +pictures + +// pid : 2015-01-08 Top Level Spectrum, Inc. +pid + +// pin : 2014-12-18 Amazon Registry Services, Inc. +pin + +// ping : 2015-06-11 Ping Registry Provider, Inc. +ping + +// pink : 2013-10-01 Afilias plc +pink + +// pioneer : 2015-07-16 Pioneer Corporation +pioneer + +// pizza : 2014-06-26 Binky Moon, LLC +pizza + +// place : 2014-04-24 Binky Moon, LLC +place + +// play : 2015-03-05 Charleston Road Registry Inc. +play + +// playstation : 2015-07-02 Sony Computer Entertainment Inc. +playstation + +// plumbing : 2013-09-10 Binky Moon, LLC +plumbing + +// plus : 2015-02-05 Binky Moon, LLC +plus + +// pnc : 2015-07-02 PNC Domain Co., LLC +pnc + +// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +pohl + +// poker : 2014-07-03 Afilias plc +poker + +// politie : 2015-08-20 Politie Nederland +politie + +// porn : 2014-10-16 ICM Registry PN LLC +porn + +// pramerica : 2015-07-30 Prudential Financial, Inc. +pramerica + +// praxi : 2013-12-05 Praxi S.p.A. +praxi + +// press : 2014-04-03 DotPress Inc. +press + +// prime : 2015-06-25 Amazon Registry Services, Inc. +prime + +// prod : 2014-01-23 Charleston Road Registry Inc. +prod + +// productions : 2013-12-05 Binky Moon, LLC +productions + +// prof : 2014-07-24 Charleston Road Registry Inc. +prof + +// progressive : 2015-07-23 Progressive Casualty Insurance Company +progressive + +// promo : 2014-12-18 Afilias plc +promo + +// properties : 2013-12-05 Binky Moon, LLC +properties + +// property : 2014-05-22 Uniregistry, Corp. +property + +// protection : 2015-04-23 XYZ.COM LLC +protection + +// pru : 2015-07-30 Prudential Financial, Inc. +pru + +// prudential : 2015-07-30 Prudential Financial, Inc. +prudential + +// pub : 2013-12-12 United TLD Holdco Ltd. +pub + +// pwc : 2015-10-29 PricewaterhouseCoopers LLP +pwc + +// qpon : 2013-11-14 dotCOOL, Inc. +qpon + +// quebec : 2013-12-19 PointQuébec Inc +quebec + +// quest : 2015-03-26 Quest ION Limited +quest + +// qvc : 2015-07-30 QVC, Inc. +qvc + +// racing : 2014-12-04 Premier Registry Limited +racing + +// radio : 2016-07-21 European Broadcasting Union (EBU) +radio + +// raid : 2015-07-23 Johnson Shareholdings, Inc. +raid + +// read : 2014-12-18 Amazon Registry Services, Inc. +read + +// realestate : 2015-09-11 dotRealEstate LLC +realestate + +// realtor : 2014-05-29 Real Estate Domains LLC +realtor + +// realty : 2015-03-19 Fegistry, LLC +realty + +// recipes : 2013-10-17 Binky Moon, LLC +recipes + +// red : 2013-11-07 Afilias plc +red + +// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. +redstone + +// redumbrella : 2015-03-26 Travelers TLD, LLC +redumbrella + +// rehab : 2014-03-06 United TLD Holdco Ltd. +rehab + +// reise : 2014-03-13 Binky Moon, LLC +reise + +// reisen : 2014-03-06 Binky Moon, LLC +reisen + +// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. +reit + +// reliance : 2015-04-02 Reliance Industries Limited +reliance + +// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd. +ren + +// rent : 2014-12-04 XYZ.COM LLC +rent + +// rentals : 2013-12-05 Binky Moon, LLC +rentals + +// repair : 2013-11-07 Binky Moon, LLC +repair + +// report : 2013-12-05 Binky Moon, LLC +report + +// republican : 2014-03-20 United TLD Holdco Ltd. +republican + +// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +rest + +// restaurant : 2014-07-03 Binky Moon, LLC +restaurant + +// review : 2014-11-20 dot Review Limited +review + +// reviews : 2013-09-13 United TLD Holdco Ltd. +reviews + +// rexroth : 2015-06-18 Robert Bosch GMBH +rexroth + +// rich : 2013-11-21 I-Registry Ltd. +rich + +// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited +richardli + +// ricoh : 2014-11-20 Ricoh Company, Ltd. +ricoh + +// rightathome : 2015-07-23 Johnson Shareholdings, Inc. +rightathome + +// ril : 2015-04-02 Reliance Industries Limited +ril + +// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO +rio + +// rip : 2014-07-10 United TLD Holdco Ltd. +rip + +// rmit : 2015-11-19 Royal Melbourne Institute of Technology +rmit + +// rocher : 2014-12-18 Ferrero Trading Lux S.A. +rocher + +// rocks : 2013-11-14 United TLD Holdco Ltd. +rocks + +// rodeo : 2013-12-19 Minds + Machines Group Limited +rodeo + +// rogers : 2015-08-06 Rogers Communications Canada Inc. +rogers + +// room : 2014-12-18 Amazon Registry Services, Inc. +room + +// rsvp : 2014-05-08 Charleston Road Registry Inc. +rsvp + +// rugby : 2016-12-15 World Rugby Strategic Developments Limited +rugby + +// ruhr : 2013-10-02 regiodot GmbH & Co. KG +ruhr + +// run : 2015-03-19 Binky Moon, LLC +run + +// rwe : 2015-04-02 RWE AG +rwe + +// ryukyu : 2014-01-09 BRregistry, Inc. +ryukyu + +// saarland : 2013-12-12 dotSaarland GmbH +saarland + +// safe : 2014-12-18 Amazon Registry Services, Inc. +safe + +// safety : 2015-01-08 Safety Registry Services, LLC. +safety + +// sakura : 2014-12-18 SAKURA Internet Inc. +sakura + +// sale : 2014-10-16 United TLD Holdco Ltd. +sale + +// salon : 2014-12-11 Binky Moon, LLC +salon + +// samsclub : 2015-07-31 Wal-Mart Stores, Inc. +samsclub + +// samsung : 2014-04-03 SAMSUNG SDS CO., LTD +samsung + +// sandvik : 2014-11-13 Sandvik AB +sandvik + +// sandvikcoromant : 2014-11-07 Sandvik AB +sandvikcoromant + +// sanofi : 2014-10-09 Sanofi +sanofi + +// sap : 2014-03-27 SAP AG +sap + +// sarl : 2014-07-03 Binky Moon, LLC +sarl + +// sas : 2015-04-02 Research IP LLC +sas + +// save : 2015-06-25 Amazon Registry Services, Inc. +save + +// saxo : 2014-10-31 Saxo Bank A/S +saxo + +// sbi : 2015-03-12 STATE BANK OF INDIA +sbi + +// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION +sbs + +// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) +sca + +// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") +scb + +// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG +schaeffler + +// schmidt : 2014-04-03 SALM S.A.S. +schmidt + +// scholarships : 2014-04-24 Scholarships.com, LLC +scholarships + +// school : 2014-12-18 Binky Moon, LLC +school + +// schule : 2014-03-06 Binky Moon, LLC +schule + +// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +schwarz + +// science : 2014-09-11 dot Science Limited +science + +// scjohnson : 2015-07-23 Johnson Shareholdings, Inc. +scjohnson + +// scor : 2014-10-31 SCOR SE +scor + +// scot : 2014-01-23 Dot Scot Registry Limited +scot + +// search : 2016-06-09 Charleston Road Registry Inc. +search + +// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) +seat + +// secure : 2015-08-27 Amazon Registry Services, Inc. +secure + +// security : 2015-05-14 XYZ.COM LLC +security + +// seek : 2014-12-04 Seek Limited +seek + +// select : 2015-10-08 iSelect Ltd +select + +// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. +sener + +// services : 2014-02-27 Binky Moon, LLC +services + +// ses : 2015-07-23 SES +ses + +// seven : 2015-08-06 Seven West Media Ltd +seven + +// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG +sew + +// sex : 2014-11-13 ICM Registry SX LLC +sex + +// sexy : 2013-09-11 Uniregistry, Corp. +sexy + +// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR +sfr + +// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited +shangrila + +// sharp : 2014-05-01 Sharp Corporation +sharp + +// shaw : 2015-04-23 Shaw Cablesystems G.P. +shaw + +// shell : 2015-07-30 Shell Information Technology International Inc +shell + +// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +shia + +// shiksha : 2013-11-14 Afilias plc +shiksha + +// shoes : 2013-10-02 Binky Moon, LLC +shoes + +// shop : 2016-04-08 GMO Registry, Inc. +shop + +// shopping : 2016-03-31 Binky Moon, LLC +shopping + +// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +shouji + +// show : 2015-03-05 Binky Moon, LLC +show + +// showtime : 2015-08-06 CBS Domains Inc. +showtime + +// shriram : 2014-01-23 Shriram Capital Ltd. +shriram + +// silk : 2015-06-25 Amazon Registry Services, Inc. +silk + +// sina : 2015-03-12 Sina Corporation +sina + +// singles : 2013-08-27 Binky Moon, LLC +singles + +// site : 2015-01-15 DotSite Inc. +site + +// ski : 2015-04-09 Afilias plc +ski + +// skin : 2015-01-15 L'Oréal +skin + +// sky : 2014-06-19 Sky International AG +sky + +// skype : 2014-12-18 Microsoft Corporation +skype + +// sling : 2015-07-30 Hughes Satellite Systems Corporation +sling + +// smart : 2015-07-09 Smart Communications, Inc. (SMART) +smart + +// smile : 2014-12-18 Amazon Registry Services, Inc. +smile + +// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F +sncf + +// soccer : 2015-03-26 Binky Moon, LLC +soccer + +// social : 2013-11-07 United TLD Holdco Ltd. +social + +// softbank : 2015-07-02 SoftBank Corp. +softbank + +// software : 2014-03-20 United TLD Holdco Ltd. +software + +// sohu : 2013-12-19 Sohu.com Limited +sohu + +// solar : 2013-11-07 Binky Moon, LLC +solar + +// solutions : 2013-11-07 Binky Moon, LLC +solutions + +// song : 2015-02-26 Amazon Registry Services, Inc. +song + +// sony : 2015-01-08 Sony Corporation +sony + +// soy : 2014-01-23 Charleston Road Registry Inc. +soy + +// space : 2014-04-03 DotSpace Inc. +space + +// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG +spiegel + +// sport : 2017-11-16 Global Association of International Sports Federations (GAISF) +sport + +// spot : 2015-02-26 Amazon Registry Services, Inc. +spot + +// spreadbetting : 2014-12-11 Dotspreadbetting Registry Limited +spreadbetting + +// srl : 2015-05-07 InterNetX, Corp +srl + +// srt : 2015-07-30 FCA US LLC. +srt + +// stada : 2014-11-13 STADA Arzneimittel AG +stada + +// staples : 2015-07-30 Staples, Inc. +staples + +// star : 2015-01-08 Star India Private Limited +star + +// starhub : 2015-02-05 StarHub Ltd +starhub + +// statebank : 2015-03-12 STATE BANK OF INDIA +statebank + +// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company +statefarm + +// statoil : 2014-12-04 Statoil ASA +statoil + +// stc : 2014-10-09 Saudi Telecom Company +stc + +// stcgroup : 2014-10-09 Saudi Telecom Company +stcgroup + +// stockholm : 2014-12-18 Stockholms kommun +stockholm + +// storage : 2014-12-22 XYZ.COM LLC +storage + +// store : 2015-04-09 DotStore Inc. +store + +// stream : 2016-01-08 dot Stream Limited +stream + +// studio : 2015-02-11 United TLD Holdco Ltd. +studio + +// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD +study + +// style : 2014-12-04 Binky Moon, LLC +style + +// sucks : 2014-12-22 Vox Populi Registry Ltd. +sucks + +// supplies : 2013-12-19 Binky Moon, LLC +supplies + +// supply : 2013-12-19 Binky Moon, LLC +supply + +// support : 2013-10-24 Binky Moon, LLC +support + +// surf : 2014-01-09 Minds + Machines Group Limited +surf + +// surgery : 2014-03-20 Binky Moon, LLC +surgery + +// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION +suzuki + +// swatch : 2015-01-08 The Swatch Group Ltd +swatch + +// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited +swiftcover + +// swiss : 2014-10-16 Swiss Confederation +swiss + +// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet +sydney + +// symantec : 2014-12-04 Symantec Corporation +symantec + +// systems : 2013-11-07 Binky Moon, LLC +systems + +// tab : 2014-12-04 Tabcorp Holdings Limited +tab + +// taipei : 2014-07-10 Taipei City Government +taipei + +// talk : 2015-04-09 Amazon Registry Services, Inc. +talk + +// taobao : 2015-01-15 Alibaba Group Holding Limited +taobao + +// target : 2015-07-31 Target Domain Holdings, LLC +target + +// tatamotors : 2015-03-12 Tata Motors Ltd +tatamotors + +// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +tatar + +// tattoo : 2013-08-30 Uniregistry, Corp. +tattoo + +// tax : 2014-03-20 Binky Moon, LLC +tax + +// taxi : 2015-03-19 Binky Moon, LLC +taxi + +// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +tci + +// tdk : 2015-06-11 TDK Corporation +tdk + +// team : 2015-03-05 Binky Moon, LLC +team + +// tech : 2015-01-30 Personals TLD Inc. +tech + +// technology : 2013-09-13 Binky Moon, LLC +technology + +// telecity : 2015-02-19 TelecityGroup International Limited +telecity + +// telefonica : 2014-10-16 Telefónica S.A. +telefonica + +// temasek : 2014-08-07 Temasek Holdings (Private) Limited +temasek + +// tennis : 2014-12-04 Binky Moon, LLC +tennis + +// teva : 2015-07-02 Teva Pharmaceutical Industries Limited +teva + +// thd : 2015-04-02 Home Depot Product Authority, LLC +thd + +// theater : 2015-03-19 Binky Moon, LLC +theater + +// theatre : 2015-05-07 XYZ.COM LLC +theatre + +// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America +tiaa + +// tickets : 2015-02-05 Accent Media Limited +tickets + +// tienda : 2013-11-14 Binky Moon, LLC +tienda + +// tiffany : 2015-01-30 Tiffany and Company +tiffany + +// tips : 2013-09-20 Binky Moon, LLC +tips + +// tires : 2014-11-07 Binky Moon, LLC +tires + +// tirol : 2014-04-24 punkt Tirol GmbH +tirol + +// tjmaxx : 2015-07-16 The TJX Companies, Inc. +tjmaxx + +// tjx : 2015-07-16 The TJX Companies, Inc. +tjx + +// tkmaxx : 2015-07-16 The TJX Companies, Inc. +tkmaxx + +// tmall : 2015-01-15 Alibaba Group Holding Limited +tmall + +// today : 2013-09-20 Binky Moon, LLC +today + +// tokyo : 2013-11-13 GMO Registry, Inc. +tokyo + +// tools : 2013-11-21 Binky Moon, LLC +tools + +// top : 2014-03-20 .TOP Registry +top + +// toray : 2014-12-18 Toray Industries, Inc. +toray + +// toshiba : 2014-04-10 TOSHIBA Corporation +toshiba + +// total : 2015-08-06 Total SA +total + +// tours : 2015-01-22 Binky Moon, LLC +tours + +// town : 2014-03-06 Binky Moon, LLC +town + +// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION +toyota + +// toys : 2014-03-06 Binky Moon, LLC +toys + +// trade : 2014-01-23 Elite Registry Limited +trade + +// trading : 2014-12-11 Dottrading Registry Limited +trading + +// training : 2013-11-07 Binky Moon, LLC +training + +// travel : Dog Beach, LLC +travel + +// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +travelchannel + +// travelers : 2015-03-26 Travelers TLD, LLC +travelers + +// travelersinsurance : 2015-03-26 Travelers TLD, LLC +travelersinsurance + +// trust : 2014-10-16 NCC Group Inc. +trust + +// trv : 2015-03-26 Travelers TLD, LLC +trv + +// tube : 2015-06-11 Latin American Telecom LLC +tube + +// tui : 2014-07-03 TUI AG +tui + +// tunes : 2015-02-26 Amazon Registry Services, Inc. +tunes + +// tushu : 2014-12-18 Amazon Registry Services, Inc. +tushu + +// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED +tvs + +// ubank : 2015-08-20 National Australia Bank Limited +ubank + +// ubs : 2014-12-11 UBS AG +ubs + +// uconnect : 2015-07-30 FCA US LLC. +uconnect + +// unicom : 2015-10-15 China United Network Communications Corporation Limited +unicom + +// university : 2014-03-06 Binky Moon, LLC +university + +// uno : 2013-09-11 Dot Latin LLC +uno + +// uol : 2014-05-01 UBN INTERNET LTDA. +uol + +// ups : 2015-06-25 UPS Market Driver, Inc. +ups + +// vacations : 2013-12-05 Binky Moon, LLC +vacations + +// vana : 2014-12-11 Lifestyle Domain Holdings, Inc. +vana + +// vanguard : 2015-09-03 The Vanguard Group, Inc. +vanguard + +// vegas : 2014-01-16 Dot Vegas, Inc. +vegas + +// ventures : 2013-08-27 Binky Moon, LLC +ventures + +// verisign : 2015-08-13 VeriSign, Inc. +verisign + +// versicherung : 2014-03-20 TLD-BOX Registrydienstleistungen GmbH +versicherung + +// vet : 2014-03-06 United TLD Holdco Ltd. +vet + +// viajes : 2013-10-17 Binky Moon, LLC +viajes + +// video : 2014-10-16 United TLD Holdco Ltd. +video + +// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +vig + +// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +viking + +// villas : 2013-12-05 Binky Moon, LLC +villas + +// vin : 2015-06-18 Binky Moon, LLC +vin + +// vip : 2015-01-22 Minds + Machines Group Limited +vip + +// virgin : 2014-09-25 Virgin Enterprises Limited +virgin + +// visa : 2015-07-30 Visa Worldwide Pte. Limited +visa + +// vision : 2013-12-05 Binky Moon, LLC +vision + +// vista : 2014-09-18 Vistaprint Limited +vista + +// vistaprint : 2014-09-18 Vistaprint Limited +vistaprint + +// viva : 2014-11-07 Saudi Telecom Company +viva + +// vivo : 2015-07-31 Telefonica Brasil S.A. +vivo + +// vlaanderen : 2014-02-06 DNS.be vzw +vlaanderen + +// vodka : 2013-12-19 Minds + Machines Group Limited +vodka + +// volkswagen : 2015-05-14 Volkswagen Group of America Inc. +volkswagen + +// volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag +volvo + +// vote : 2013-11-21 Monolith Registry LLC +vote + +// voting : 2013-11-13 Valuetainment Corp. +voting + +// voto : 2013-11-21 Monolith Registry LLC +voto + +// voyage : 2013-08-27 Binky Moon, LLC +voyage + +// vuelos : 2015-03-05 Travel Reservations SRL +vuelos + +// wales : 2014-05-08 Nominet UK +wales + +// walmart : 2015-07-31 Wal-Mart Stores, Inc. +walmart + +// walter : 2014-11-13 Sandvik AB +walter + +// wang : 2013-10-24 Zodiac Wang Limited +wang + +// wanggou : 2014-12-18 Amazon Registry Services, Inc. +wanggou + +// warman : 2015-06-18 Weir Group IP Limited +warman + +// watch : 2013-11-14 Binky Moon, LLC +watch + +// watches : 2014-12-22 Richemont DNS Inc. +watches + +// weather : 2015-01-08 International Business Machines Corporation +weather + +// weatherchannel : 2015-03-12 International Business Machines Corporation +weatherchannel + +// webcam : 2014-01-23 dot Webcam Limited +webcam + +// weber : 2015-06-04 Saint-Gobain Weber SA +weber + +// website : 2014-04-03 DotWebsite Inc. +website + +// wed : 2013-10-01 Atgron, Inc. +wed + +// wedding : 2014-04-24 Minds + Machines Group Limited +wedding + +// weibo : 2015-03-05 Sina Corporation +weibo + +// weir : 2015-01-29 Weir Group IP Limited +weir + +// whoswho : 2014-02-20 Who's Who Registry +whoswho + +// wien : 2013-10-28 punkt.wien GmbH +wien + +// wiki : 2013-11-07 Top Level Design, LLC +wiki + +// williamhill : 2014-03-13 William Hill Organization Limited +williamhill + +// win : 2014-11-20 First Registry Limited +win + +// windows : 2014-12-18 Microsoft Corporation +windows + +// wine : 2015-06-18 Binky Moon, LLC +wine + +// winners : 2015-07-16 The TJX Companies, Inc. +winners + +// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC +wme + +// wolterskluwer : 2015-08-06 Wolters Kluwer N.V. +wolterskluwer + +// woodside : 2015-07-09 Woodside Petroleum Limited +woodside + +// work : 2013-12-19 Minds + Machines Group Limited +work + +// works : 2013-11-14 Binky Moon, LLC +works + +// world : 2014-06-12 Binky Moon, LLC +world + +// wow : 2015-10-08 Amazon Registry Services, Inc. +wow + +// wtc : 2013-12-19 World Trade Centers Association, Inc. +wtc + +// wtf : 2014-03-06 Binky Moon, LLC +wtf + +// xbox : 2014-12-18 Microsoft Corporation +xbox + +// xerox : 2014-10-24 Xerox DNHC LLC +xerox + +// xfinity : 2015-07-09 Comcast IP Holdings I, LLC +xfinity + +// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +xihuan + +// xin : 2014-12-11 Elegant Leader Limited +xin + +// xn--11b4c3d : 2015-01-15 VeriSign Sarl +कॉम + +// xn--1ck2e1b : 2015-02-26 Amazon Registry Services, Inc. +セール + +// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. +佛山 + +// xn--30rr7y : 2014-06-12 Excellent First Limited +慈善 + +// xn--3bst00m : 2013-09-13 Eagle Horizon Limited +集团 + +// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED +在线 + +// xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd. +大众汽车 + +// xn--3pxu8k : 2015-01-15 VeriSign Sarl +点看 + +// xn--42c2d9a : 2015-01-15 VeriSign Sarl +คอม + +// xn--45q11c : 2013-11-21 Zodiac Gemini Ltd +八卦 + +// xn--4gbrim : 2013-10-04 Suhub Electronic Establishment +موقع + +// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center +公益 + +// xn--55qx5d : 2013-11-14 China Internet Network Information Center (CNNIC) +公司 + +// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited +香格里拉 + +// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +网站 + +// xn--6frz82g : 2013-09-23 Afilias plc +移动 + +// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited +我爱你 + +// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +москва + +// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +католик + +// xn--80asehdb : 2013-07-14 CORE Association +онлайн + +// xn--80aswg : 2013-07-14 CORE Association +сайт + +// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +联通 + +// xn--9dbq2a : 2015-01-15 VeriSign Sarl +קום + +// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED +时尚 + +// xn--9krt00a : 2015-03-12 Sina Corporation +微博 + +// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited +淡马锡 + +// xn--bck1b9a5dre4c : 2015-02-26 Amazon Registry Services, Inc. +ファッション + +// xn--c1avg : 2013-11-14 Public Interest Registry +орг + +// xn--c2br7g : 2015-01-15 VeriSign Sarl +नेट + +// xn--cck2b3b : 2015-02-26 Amazon Registry Services, Inc. +ストア + +// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD +삼성 + +// xn--czr694b : 2014-01-16 Dot Trademark TLD Holding Company Limited +商标 + +// xn--czrs0t : 2013-12-19 Binky Moon, LLC +商店 + +// xn--czru2d : 2013-11-21 Zodiac Aquarius Limited +商城 + +// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” +дети + +// xn--eckvdtc9d : 2014-12-18 Amazon Registry Services, Inc. +ポイント + +// xn--efvy88h : 2014-08-22 Guangzhou YU Wei Information Technology Co., Ltd. +新闻 + +// xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited +工行 + +// xn--fct429k : 2015-04-09 Amazon Registry Services, Inc. +家電 + +// xn--fhbei : 2015-01-15 VeriSign Sarl +كوم + +// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED +中文网 + +// xn--fiq64b : 2013-10-14 CITIC Group Corporation +中信 + +// xn--fjq720a : 2014-05-22 Binky Moon, LLC +娱乐 + +// xn--flw351e : 2014-07-31 Charleston Road Registry Inc. +谷歌 + +// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited +電訊盈科 + +// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited +购物 + +// xn--gckr3f0f : 2015-02-26 Amazon Registry Services, Inc. +クラウド + +// xn--gk3at1e : 2015-10-08 Amazon Registry Services, Inc. +通販 + +// xn--hxt814e : 2014-05-15 Zodiac Taurus Limited +网店 + +// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry +संगठन + +// xn--imr513n : 2014-12-11 Dot Trademark TLD Holding Company Limited +餐厅 + +// xn--io0a7i : 2013-11-14 China Internet Network Information Center (CNNIC) +网络 + +// xn--j1aef : 2015-01-15 VeriSign Sarl +ком + +// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation +诺基亚 + +// xn--jvr189m : 2015-02-26 Amazon Registry Services, Inc. +食品 + +// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. +飞利浦 + +// xn--kpu716f : 2014-12-22 Richemont DNS Inc. +手表 + +// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd +手机 + +// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company +ارامكو + +// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH +العليان + +// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +اتصالات + +// xn--mgbab2bd : 2013-10-31 CORE Association +بازار + +// xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L. +موبايلي + +// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre +ابوظبي + +// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +كاثوليك + +// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +همراه + +// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +닷컴 + +// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. +政府 + +// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. +شبكة + +// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House +بيتك + +// xn--ngbrx : 2015-11-12 League of Arab States +عرب + +// xn--nqv7f : 2013-11-14 Public Interest Registry +机构 + +// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry +组织机构 + +// xn--nyqy26a : 2014-11-07 Stable Tone Limited +健康 + +// xn--otu796d : 2017-08-06 Dot Trademark TLD Holding Company Limited +招聘 + +// xn--p1acf : 2013-12-12 Rusnames Limited +рус + +// xn--pbt977c : 2014-12-22 Richemont DNS Inc. +珠宝 + +// xn--pssy2u : 2015-01-15 VeriSign Sarl +大拿 + +// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. +みんな + +// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. +グーグル + +// xn--rhqv96g : 2013-09-11 Stable Tone Limited +世界 + +// xn--rovu88b : 2015-02-26 Amazon Registry Services, Inc. +書籍 + +// xn--ses554g : 2014-01-16 KNET Co., Ltd. +网址 + +// xn--t60b56a : 2015-01-15 VeriSign Sarl +닷넷 + +// xn--tckwe : 2015-01-15 VeriSign Sarl +コム + +// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +天主教 + +// xn--unup4y : 2013-07-14 Binky Moon, LLC +游戏 + +// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberater + +// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberatung + +// xn--vhquv : 2013-08-27 Binky Moon, LLC +企业 + +// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. +信息 + +// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited +嘉里大酒店 + +// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited +嘉里 + +// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. +广东 + +// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center +政务 + +// xyz : 2013-12-05 XYZ.COM LLC +xyz + +// yachts : 2014-01-09 DERYachts, LLC +yachts + +// yahoo : 2015-04-02 Yahoo! Domain Services Inc. +yahoo + +// yamaxun : 2014-12-18 Amazon Registry Services, Inc. +yamaxun + +// yandex : 2014-04-10 YANDEX, LLC +yandex + +// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +yodobashi + +// yoga : 2014-05-29 Minds + Machines Group Limited +yoga + +// yokohama : 2013-12-12 GMO Registry, Inc. +yokohama + +// you : 2015-04-09 Amazon Registry Services, Inc. +you + +// youtube : 2014-05-01 Charleston Road Registry Inc. +youtube + +// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +yun + +// zappos : 2015-06-25 Amazon Registry Services, Inc. +zappos + +// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) +zara + +// zero : 2014-12-18 Amazon Registry Services, Inc. +zero + +// zip : 2014-05-08 Charleston Road Registry Inc. +zip + +// zippo : 2015-07-02 Zadco Company +zippo + +// zone : 2013-11-14 Binky Moon, LLC +zone + +// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) +zuerich + + +// ===END ICANN DOMAINS=== +// ===BEGIN PRIVATE DOMAINS=== +// (Note: these are in alphabetical order by company name) + +// 1GB LLC : https://www.1gb.ua/ +// Submitted by 1GB LLC +cc.ua +inf.ua +ltd.ua + +// Agnat sp. z o.o. : https://domena.pl +// Submitted by Przemyslaw Plewa +beep.pl + +// Alces Software Ltd : http://alces-software.com +// Submitted by Mark J. Titorenko +*.compute.estate +*.alces.network + +// alwaysdata : https://www.alwaysdata.com +// Submitted by Cyril +alwaysdata.net + +// Amazon CloudFront : https://aws.amazon.com/cloudfront/ +// Submitted by Donavan Miller +cloudfront.net + +// Amazon Elastic Compute Cloud : https://aws.amazon.com/ec2/ +// Submitted by Luke Wells +*.compute.amazonaws.com +*.compute-1.amazonaws.com +*.compute.amazonaws.com.cn +us-east-1.amazonaws.com + +// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/ +// Submitted by Luke Wells +cn-north-1.eb.amazonaws.com.cn +cn-northwest-1.eb.amazonaws.com.cn +elasticbeanstalk.com +ap-northeast-1.elasticbeanstalk.com +ap-northeast-2.elasticbeanstalk.com +ap-northeast-3.elasticbeanstalk.com +ap-south-1.elasticbeanstalk.com +ap-southeast-1.elasticbeanstalk.com +ap-southeast-2.elasticbeanstalk.com +ca-central-1.elasticbeanstalk.com +eu-central-1.elasticbeanstalk.com +eu-west-1.elasticbeanstalk.com +eu-west-2.elasticbeanstalk.com +eu-west-3.elasticbeanstalk.com +sa-east-1.elasticbeanstalk.com +us-east-1.elasticbeanstalk.com +us-east-2.elasticbeanstalk.com +us-gov-west-1.elasticbeanstalk.com +us-west-1.elasticbeanstalk.com +us-west-2.elasticbeanstalk.com + +// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/ +// Submitted by Luke Wells +*.elb.amazonaws.com +*.elb.amazonaws.com.cn + +// Amazon S3 : https://aws.amazon.com/s3/ +// Submitted by Luke Wells +s3.amazonaws.com +s3-ap-northeast-1.amazonaws.com +s3-ap-northeast-2.amazonaws.com +s3-ap-south-1.amazonaws.com +s3-ap-southeast-1.amazonaws.com +s3-ap-southeast-2.amazonaws.com +s3-ca-central-1.amazonaws.com +s3-eu-central-1.amazonaws.com +s3-eu-west-1.amazonaws.com +s3-eu-west-2.amazonaws.com +s3-eu-west-3.amazonaws.com +s3-external-1.amazonaws.com +s3-fips-us-gov-west-1.amazonaws.com +s3-sa-east-1.amazonaws.com +s3-us-gov-west-1.amazonaws.com +s3-us-east-2.amazonaws.com +s3-us-west-1.amazonaws.com +s3-us-west-2.amazonaws.com +s3.ap-northeast-2.amazonaws.com +s3.ap-south-1.amazonaws.com +s3.cn-north-1.amazonaws.com.cn +s3.ca-central-1.amazonaws.com +s3.eu-central-1.amazonaws.com +s3.eu-west-2.amazonaws.com +s3.eu-west-3.amazonaws.com +s3.us-east-2.amazonaws.com +s3.dualstack.ap-northeast-1.amazonaws.com +s3.dualstack.ap-northeast-2.amazonaws.com +s3.dualstack.ap-south-1.amazonaws.com +s3.dualstack.ap-southeast-1.amazonaws.com +s3.dualstack.ap-southeast-2.amazonaws.com +s3.dualstack.ca-central-1.amazonaws.com +s3.dualstack.eu-central-1.amazonaws.com +s3.dualstack.eu-west-1.amazonaws.com +s3.dualstack.eu-west-2.amazonaws.com +s3.dualstack.eu-west-3.amazonaws.com +s3.dualstack.sa-east-1.amazonaws.com +s3.dualstack.us-east-1.amazonaws.com +s3.dualstack.us-east-2.amazonaws.com +s3-website-us-east-1.amazonaws.com +s3-website-us-west-1.amazonaws.com +s3-website-us-west-2.amazonaws.com +s3-website-ap-northeast-1.amazonaws.com +s3-website-ap-southeast-1.amazonaws.com +s3-website-ap-southeast-2.amazonaws.com +s3-website-eu-west-1.amazonaws.com +s3-website-sa-east-1.amazonaws.com +s3-website.ap-northeast-2.amazonaws.com +s3-website.ap-south-1.amazonaws.com +s3-website.ca-central-1.amazonaws.com +s3-website.eu-central-1.amazonaws.com +s3-website.eu-west-2.amazonaws.com +s3-website.eu-west-3.amazonaws.com +s3-website.us-east-2.amazonaws.com + +// Amune : https://amune.org/ +// Submitted by Team Amune +t3l3p0rt.net +tele.amune.org + +// Aptible : https://www.aptible.com/ +// Submitted by Thomas Orozco +on-aptible.com + +// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/ +// Submitted by Hector Martin +user.party.eus + +// Association potager.org : https://potager.org/ +// Submitted by Lunar +pimienta.org +poivron.org +potager.org +sweetpepper.org + +// ASUSTOR Inc. : http://www.asustor.com +// Submitted by Vincent Tseng +myasustor.com + +// AVM : https://avm.de +// Submitted by Andreas Weise +myfritz.net + +// AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com +// Submitted by James Kennedy +*.awdev.ca +*.advisor.ws + +// backplane : https://www.backplane.io +// Submitted by Anthony Voutas +backplaneapp.io + +// BetaInABox +// Submitted by Adrian +betainabox.com + +// BinaryLane : http://www.binarylane.com +// Submitted by Nathan O'Sullivan +bnr.la + +// Blackbaud, Inc. : https://www.blackbaud.com +// Submitted by Paul Crowder +blackbaudcdn.net + +// Boomla : https://boomla.com +// Submitted by Tibor Halter +boomla.net + +// Boxfuse : https://boxfuse.com +// Submitted by Axel Fontaine +boxfuse.io + +// bplaced : https://www.bplaced.net/ +// Submitted by Miroslav Bozic +square7.ch +bplaced.com +bplaced.de +square7.de +bplaced.net +square7.net + +// BrowserSafetyMark +// Submitted by Dave Tharp +browsersafetymark.io + +// callidomus : https://www.callidomus.com/ +// Submitted by Marcus Popp +mycd.eu + +// CentralNic : http://www.centralnic.com/names/domains +// Submitted by registry +ae.org +ar.com +br.com +cn.com +com.de +com.se +de.com +eu.com +gb.com +gb.net +hu.com +hu.net +jp.net +jpn.com +kr.com +mex.com +no.com +qc.com +ru.com +sa.com +se.net +uk.com +uk.net +us.com +uy.com +za.bz +za.com + +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown +africa.com + +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown +gr.com + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown +in.net + +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown +us.org + +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown +co.com + +// c.la : http://www.c.la/ +c.la + +// certmgr.org : https://certmgr.org +// Submitted by B. Blechschmidt +certmgr.org + +// Citrix : https://citrix.com +// Submitted by Alex Stoddard +xenapponazure.com + +// ClearVox : http://www.clearvox.nl/ +// Submitted by Leon Rowland +virtueeldomein.nl + +// Clever Cloud : https://www.clever-cloud.com/ +// Submitted by Quentin Adam +cleverapps.io + +// Cloud66 : https://www.cloud66.com/ +// Submitted by Khash Sajadi +c66.me +cloud66.ws + +// CloudAccess.net : https://www.cloudaccess.net/ +// Submitted by Pawel Panek +jdevcloud.com +wpdevcloud.com +cloudaccess.host +freesite.host +cloudaccess.net + +// cloudControl : https://www.cloudcontrol.com/ +// Submitted by Tobias Wilken +cloudcontrolled.com +cloudcontrolapp.com + +// co.ca : http://registry.co.ca/ +co.ca + +// Co & Co : https://co-co.nl/ +// Submitted by Govert Versluis +*.otap.co + +// i-registry s.r.o. : http://www.i-registry.cz/ +// Submitted by Martin Semrad +co.cz + +// CDN77.com : http://www.cdn77.com +// Submitted by Jan Krpes +c.cdn77.org +cdn77-ssl.net +r.cdn77.net +rsc.cdn77.org +ssl.origin.cdn77-secure.org + +// Cloud DNS Ltd : http://www.cloudns.net +// Submitted by Aleksander Hristov +cloudns.asia +cloudns.biz +cloudns.club +cloudns.cc +cloudns.eu +cloudns.in +cloudns.info +cloudns.org +cloudns.pro +cloudns.pw +cloudns.us + +// Cloudeity Inc : https://cloudeity.com +// Submitted by Stefan Dimitrov +cloudeity.net + +// CNPY : https://cnpy.gdn +// Submitted by Angelo Gladding +cnpy.gdn + +// CoDNS B.V. +co.nl +co.no + +// Combell.com : https://www.combell.com +// Submitted by Thomas Wouters +webhosting.be +hosting-cluster.nl + +// COSIMO GmbH : http://www.cosimo.de +// Submitted by Rene Marticke +dyn.cosidns.de +dynamisches-dns.de +dnsupdater.de +internet-dns.de +l-o-g-i-n.de +dynamic-dns.info +feste-ip.net +knx-server.net +static-access.net + +// Craynic, s.r.o. : http://www.craynic.com/ +// Submitted by Ales Krajnik +realm.cz + +// Cryptonomic : https://cryptonomic.net/ +// Submitted by Andrew Cady +*.cryptonomic.net + +// Cupcake : https://cupcake.io/ +// Submitted by Jonathan Rudenberg +cupcake.is + +// cyon GmbH : https://www.cyon.ch/ +// Submitted by Dominic Luechinger +cyon.link +cyon.site + +// Daplie, Inc : https://daplie.com +// Submitted by AJ ONeal +daplie.me +localhost.daplie.me + +// Datto, Inc. : https://www.datto.com/ +// Submitted by Philipp Heckel +dattolocal.com +dattorelay.com +dattoweb.com +mydatto.com +dattolocal.net +mydatto.net + +// Dansk.net : http://www.dansk.net/ +// Submitted by Anani Voule +biz.dk +co.dk +firm.dk +reg.dk +store.dk + +// Debian : https://www.debian.org/ +// Submitted by Peter Palfrader / Debian Sysadmin Team +debian.net + +// deSEC : https://desec.io/ +// Submitted by Peter Thomassen +dedyn.io + +// DNShome : https://www.dnshome.de/ +// Submitted by Norbert Auler +dnshome.de + +// DrayTek Corp. : https://www.draytek.com/ +// Submitted by Paul Fang +drayddns.com + +// DreamHost : http://www.dreamhost.com/ +// Submitted by Andrew Farmer +dreamhosters.com + +// Drobo : http://www.drobo.com/ +// Submitted by Ricardo Padilha +mydrobo.com + +// Drud Holdings, LLC. : https://www.drud.com/ +// Submitted by Kevin Bridges +drud.io +drud.us + +// DuckDNS : http://www.duckdns.org/ +// Submitted by Richard Harper +duckdns.org + +// dy.fi : http://dy.fi/ +// Submitted by Heikki Hannikainen +dy.fi +tunk.org + +// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ +dyndns-at-home.com +dyndns-at-work.com +dyndns-blog.com +dyndns-free.com +dyndns-home.com +dyndns-ip.com +dyndns-mail.com +dyndns-office.com +dyndns-pics.com +dyndns-remote.com +dyndns-server.com +dyndns-web.com +dyndns-wiki.com +dyndns-work.com +dyndns.biz +dyndns.info +dyndns.org +dyndns.tv +at-band-camp.net +ath.cx +barrel-of-knowledge.info +barrell-of-knowledge.info +better-than.tv +blogdns.com +blogdns.net +blogdns.org +blogsite.org +boldlygoingnowhere.org +broke-it.net +buyshouses.net +cechire.com +dnsalias.com +dnsalias.net +dnsalias.org +dnsdojo.com +dnsdojo.net +dnsdojo.org +does-it.net +doesntexist.com +doesntexist.org +dontexist.com +dontexist.net +dontexist.org +doomdns.com +doomdns.org +dvrdns.org +dyn-o-saur.com +dynalias.com +dynalias.net +dynalias.org +dynathome.net +dyndns.ws +endofinternet.net +endofinternet.org +endoftheinternet.org +est-a-la-maison.com +est-a-la-masion.com +est-le-patron.com +est-mon-blogueur.com +for-better.biz +for-more.biz +for-our.info +for-some.biz +for-the.biz +forgot.her.name +forgot.his.name +from-ak.com +from-al.com +from-ar.com +from-az.net +from-ca.com +from-co.net +from-ct.com +from-dc.com +from-de.com +from-fl.com +from-ga.com +from-hi.com +from-ia.com +from-id.com +from-il.com +from-in.com +from-ks.com +from-ky.com +from-la.net +from-ma.com +from-md.com +from-me.org +from-mi.com +from-mn.com +from-mo.com +from-ms.com +from-mt.com +from-nc.com +from-nd.com +from-ne.com +from-nh.com +from-nj.com +from-nm.com +from-nv.com +from-ny.net +from-oh.com +from-ok.com +from-or.com +from-pa.com +from-pr.com +from-ri.com +from-sc.com +from-sd.com +from-tn.com +from-tx.com +from-ut.com +from-va.com +from-vt.com +from-wa.com +from-wi.com +from-wv.com +from-wy.com +ftpaccess.cc +fuettertdasnetz.de +game-host.org +game-server.cc +getmyip.com +gets-it.net +go.dyndns.org +gotdns.com +gotdns.org +groks-the.info +groks-this.info +ham-radio-op.net +here-for-more.info +hobby-site.com +hobby-site.org +home.dyndns.org +homedns.org +homeftp.net +homeftp.org +homeip.net +homelinux.com +homelinux.net +homelinux.org +homeunix.com +homeunix.net +homeunix.org +iamallama.com +in-the-band.net +is-a-anarchist.com +is-a-blogger.com +is-a-bookkeeper.com +is-a-bruinsfan.org +is-a-bulls-fan.com +is-a-candidate.org +is-a-caterer.com +is-a-celticsfan.org +is-a-chef.com +is-a-chef.net +is-a-chef.org +is-a-conservative.com +is-a-cpa.com +is-a-cubicle-slave.com +is-a-democrat.com +is-a-designer.com +is-a-doctor.com +is-a-financialadvisor.com +is-a-geek.com +is-a-geek.net +is-a-geek.org +is-a-green.com +is-a-guru.com +is-a-hard-worker.com +is-a-hunter.com +is-a-knight.org +is-a-landscaper.com +is-a-lawyer.com +is-a-liberal.com +is-a-libertarian.com +is-a-linux-user.org +is-a-llama.com +is-a-musician.com +is-a-nascarfan.com +is-a-nurse.com +is-a-painter.com +is-a-patsfan.org +is-a-personaltrainer.com +is-a-photographer.com +is-a-player.com +is-a-republican.com +is-a-rockstar.com +is-a-socialist.com +is-a-soxfan.org +is-a-student.com +is-a-teacher.com +is-a-techie.com +is-a-therapist.com +is-an-accountant.com +is-an-actor.com +is-an-actress.com +is-an-anarchist.com +is-an-artist.com +is-an-engineer.com +is-an-entertainer.com +is-by.us +is-certified.com +is-found.org +is-gone.com +is-into-anime.com +is-into-cars.com +is-into-cartoons.com +is-into-games.com +is-leet.com +is-lost.org +is-not-certified.com +is-saved.org +is-slick.com +is-uberleet.com +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +is-with-theband.com +isa-geek.com +isa-geek.net +isa-geek.org +isa-hockeynut.com +issmarterthanyou.com +isteingeek.de +istmein.de +kicks-ass.net +kicks-ass.org +knowsitall.info +land-4-sale.us +lebtimnetz.de +leitungsen.de +likes-pie.com +likescandy.com +merseine.nu +mine.nu +misconfused.org +mypets.ws +myphotos.cc +neat-url.com +office-on-the.net +on-the-web.tv +podzone.net +podzone.org +readmyblog.org +saves-the-whales.com +scrapper-site.net +scrapping.cc +selfip.biz +selfip.com +selfip.info +selfip.net +selfip.org +sells-for-less.com +sells-for-u.com +sells-it.net +sellsyourhome.org +servebbs.com +servebbs.net +servebbs.org +serveftp.net +serveftp.org +servegame.org +shacknet.nu +simple-url.com +space-to-rent.com +stuff-4-sale.org +stuff-4-sale.us +teaches-yoga.com +thruhere.net +traeumtgerade.de +webhop.biz +webhop.info +webhop.net +webhop.org +worse-than.tv +writesthisblog.com + +// ddnss.de : https://www.ddnss.de/ +// Submitted by Robert Niedziela +ddnss.de +dyn.ddnss.de +dyndns.ddnss.de +dyndns1.de +dyn-ip24.de +home-webserver.de +dyn.home-webserver.de +myhome-server.de +ddnss.org + +// Definima : http://www.definima.com/ +// Submitted by Maxence Bitterli +definima.net +definima.io + +// dnstrace.pro : https://dnstrace.pro/ +// Submitted by Chris Partridge +bci.dnstrace.pro + +// Dynu.com : https://www.dynu.com/ +// Submitted by Sue Ye +ddnsfree.com +ddnsgeek.com +giize.com +gleeze.com +kozow.com +loseyourip.com +ooguy.com +theworkpc.com +casacam.net +dynu.net +accesscam.org +camdvr.org +freeddns.org +mywire.org +webredirect.org +myddns.rocks +blogsite.xyz + +// dynv6 : https://dynv6.com +// Submitted by Dominik Menke +dynv6.net + +// E4YOU spol. s.r.o. : https://e4you.cz/ +// Submitted by Vladimir Dudr +e4.cz + +// Enalean SAS: https://www.enalean.com +// Submitted by Thomas Cottier +mytuleap.com + +// Enonic : http://enonic.com/ +// Submitted by Erik Kaareng-Sunde +enonic.io +customer.enonic.io + +// EU.org https://eu.org/ +// Submitted by Pierre Beyssac +eu.org +al.eu.org +asso.eu.org +at.eu.org +au.eu.org +be.eu.org +bg.eu.org +ca.eu.org +cd.eu.org +ch.eu.org +cn.eu.org +cy.eu.org +cz.eu.org +de.eu.org +dk.eu.org +edu.eu.org +ee.eu.org +es.eu.org +fi.eu.org +fr.eu.org +gr.eu.org +hr.eu.org +hu.eu.org +ie.eu.org +il.eu.org +in.eu.org +int.eu.org +is.eu.org +it.eu.org +jp.eu.org +kr.eu.org +lt.eu.org +lu.eu.org +lv.eu.org +mc.eu.org +me.eu.org +mk.eu.org +mt.eu.org +my.eu.org +net.eu.org +ng.eu.org +nl.eu.org +no.eu.org +nz.eu.org +paris.eu.org +pl.eu.org +pt.eu.org +q-a.eu.org +ro.eu.org +ru.eu.org +se.eu.org +si.eu.org +sk.eu.org +tr.eu.org +uk.eu.org +us.eu.org + +// Evennode : http://www.evennode.com/ +// Submitted by Michal Kralik +eu-1.evennode.com +eu-2.evennode.com +eu-3.evennode.com +eu-4.evennode.com +us-1.evennode.com +us-2.evennode.com +us-3.evennode.com +us-4.evennode.com + +// eDirect Corp. : https://hosting.url.com.tw/ +// Submitted by C.S. chang +twmail.cc +twmail.net +twmail.org +mymailer.com.tw +url.tw + +// Facebook, Inc. +// Submitted by Peter Ruibal +apps.fbsbx.com + +// FAITID : https://faitid.org/ +// Submitted by Maxim Alzoba +// https://www.flexireg.net/stat_info +ru.net +adygeya.ru +bashkiria.ru +bir.ru +cbg.ru +com.ru +dagestan.ru +grozny.ru +kalmykia.ru +kustanai.ru +marine.ru +mordovia.ru +msk.ru +mytis.ru +nalchik.ru +nov.ru +pyatigorsk.ru +spb.ru +vladikavkaz.ru +vladimir.ru +abkhazia.su +adygeya.su +aktyubinsk.su +arkhangelsk.su +armenia.su +ashgabad.su +azerbaijan.su +balashov.su +bashkiria.su +bryansk.su +bukhara.su +chimkent.su +dagestan.su +east-kazakhstan.su +exnet.su +georgia.su +grozny.su +ivanovo.su +jambyl.su +kalmykia.su +kaluga.su +karacol.su +karaganda.su +karelia.su +khakassia.su +krasnodar.su +kurgan.su +kustanai.su +lenug.su +mangyshlak.su +mordovia.su +msk.su +murmansk.su +nalchik.su +navoi.su +north-kazakhstan.su +nov.su +obninsk.su +penza.su +pokrovsk.su +sochi.su +spb.su +tashkent.su +termez.su +togliatti.su +troitsk.su +tselinograd.su +tula.su +tuva.su +vladikavkaz.su +vladimir.su +vologda.su + +// Fancy Bits, LLC : http://getchannels.com +// Submitted by Aman Gupta +channelsdvr.net + +// Fastly Inc. : http://www.fastly.com/ +// Submitted by Fastly Security +fastlylb.net +map.fastlylb.net +freetls.fastly.net +map.fastly.net +a.prod.fastly.net +global.prod.fastly.net +a.ssl.fastly.net +b.ssl.fastly.net +global.ssl.fastly.net + +// FASTVPS EESTI OU : https://fastvps.ru/ +// Submitted by Likhachev Vasiliy +fastpanel.direct +fastvps-server.com + +// Featherhead : https://featherhead.xyz/ +// Submitted by Simon Menke +fhapp.xyz + +// Fedora : https://fedoraproject.org/ +// submitted by Patrick Uiterwijk +fedorainfracloud.org +fedorapeople.org +cloud.fedoraproject.org +app.os.fedoraproject.org +app.os.stg.fedoraproject.org + +// Filegear Inc. : https://www.filegear.com +// Submitted by Jason Zhu +filegear.me + +// Firebase, Inc. +// Submitted by Chris Raynor +firebaseapp.com + +// Flynn : https://flynn.io +// Submitted by Jonathan Rudenberg +flynnhub.com +flynnhosting.net + +// Freebox : http://www.freebox.fr +// Submitted by Romain Fliedel +freebox-os.com +freeboxos.com +fbx-os.fr +fbxos.fr +freebox-os.fr +freeboxos.fr + +// freedesktop.org : https://www.freedesktop.org +// Submitted by Daniel Stone +freedesktop.org + +// Futureweb OG : http://www.futureweb.at +// Submitted by Andreas Schnederle-Wagner +*.futurecms.at +*.ex.futurecms.at +*.in.futurecms.at +futurehosting.at +futuremailing.at +*.ex.ortsinfo.at +*.kunden.ortsinfo.at +*.statics.cloud + +// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains +// Submitted by David Illsley +service.gov.uk + +// GitHub, Inc. +// Submitted by Patrick Toomey +github.io +githubusercontent.com + +// GitLab, Inc. +// Submitted by Alex Hanselka +gitlab.io + +// UKHomeOffice : https://www.gov.uk/government/organisations/home-office +// Submitted by Jon Shanks +homeoffice.gov.uk + +// GlobeHosting, Inc. +// Submitted by Zoltan Egresi +ro.im +shop.ro + +// GoIP DNS Services : http://www.goip.de +// Submitted by Christian Poulter +goip.de + +// Google, Inc. +// Submitted by Eduardo Vela +*.0emm.com +appspot.com +blogspot.ae +blogspot.al +blogspot.am +blogspot.ba +blogspot.be +blogspot.bg +blogspot.bj +blogspot.ca +blogspot.cf +blogspot.ch +blogspot.cl +blogspot.co.at +blogspot.co.id +blogspot.co.il +blogspot.co.ke +blogspot.co.nz +blogspot.co.uk +blogspot.co.za +blogspot.com +blogspot.com.ar +blogspot.com.au +blogspot.com.br +blogspot.com.by +blogspot.com.co +blogspot.com.cy +blogspot.com.ee +blogspot.com.eg +blogspot.com.es +blogspot.com.mt +blogspot.com.ng +blogspot.com.tr +blogspot.com.uy +blogspot.cv +blogspot.cz +blogspot.de +blogspot.dk +blogspot.fi +blogspot.fr +blogspot.gr +blogspot.hk +blogspot.hr +blogspot.hu +blogspot.ie +blogspot.in +blogspot.is +blogspot.it +blogspot.jp +blogspot.kr +blogspot.li +blogspot.lt +blogspot.lu +blogspot.md +blogspot.mk +blogspot.mr +blogspot.mx +blogspot.my +blogspot.nl +blogspot.no +blogspot.pe +blogspot.pt +blogspot.qa +blogspot.re +blogspot.ro +blogspot.rs +blogspot.ru +blogspot.se +blogspot.sg +blogspot.si +blogspot.sk +blogspot.sn +blogspot.td +blogspot.tw +blogspot.ug +blogspot.vn +cloudfunctions.net +cloud.goog +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +publishproxy.com +withgoogle.com +withyoutube.com + +// Hashbang : https://hashbang.sh +hashbang.sh + +// Hasura : https://hasura.io +// Submitted by Shahidh K Muhammed +hasura.app +hasura-app.io + +// Hepforge : https://www.hepforge.org +// Submitted by David Grellscheid +hepforge.org + +// Heroku : https://www.heroku.com/ +// Submitted by Tom Maher +herokuapp.com +herokussl.com + +// Hibernating Rhinos +// Submitted by Oren Eini +myravendb.com +ravendb.community +ravendb.me +development.run +ravendb.run + +// Ici la Lune : http://www.icilalune.com/ +// Submitted by Simon Morvan +moonscale.net + +// iki.fi +// Submitted by Hannu Aronsson +iki.fi + +// info.at : http://www.info.at/ +biz.at +info.at + +// info.cx : http://info.cx +// Submitted by Jacob Slater +info.cx + +// Interlegis : http://www.interlegis.leg.br +// Submitted by Gabriel Ferreira +ac.leg.br +al.leg.br +am.leg.br +ap.leg.br +ba.leg.br +ce.leg.br +df.leg.br +es.leg.br +go.leg.br +ma.leg.br +mg.leg.br +ms.leg.br +mt.leg.br +pa.leg.br +pb.leg.br +pe.leg.br +pi.leg.br +pr.leg.br +rj.leg.br +rn.leg.br +ro.leg.br +rr.leg.br +rs.leg.br +sc.leg.br +se.leg.br +sp.leg.br +to.leg.br + +// intermetrics GmbH : https://pixolino.com/ +// Submitted by Wolfgang Schwarz +pixolino.com + +// IPiFony Systems, Inc. : https://www.ipifony.com/ +// Submitted by Matthew Hardeman +ipifony.net + +// IServ GmbH : https://iserv.eu +// Submitted by Kim-Alexander Brodowski +mein-iserv.de +test-iserv.de + +// Jino : https://www.jino.ru +// Submitted by Sergey Ulyashin +myjino.ru +*.hosting.myjino.ru +*.landing.myjino.ru +*.spectrum.myjino.ru +*.vps.myjino.ru + +// Joyent : https://www.joyent.com/ +// Submitted by Brian Bennett +*.triton.zone +*.cns.joyent.com + +// JS.ORG : http://dns.js.org +// Submitted by Stefan Keim +js.org + +// Keyweb AG : https://www.keyweb.de +// Submitted by Martin Dannehl +keymachine.de + +// KnightPoint Systems, LLC : http://www.knightpoint.com/ +// Submitted by Roy Keene +knightpoint.systems + +// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf +co.krd +edu.krd + +// LCube - Professional hosting e.K. : https://www.lcube-webhosting.de +// Submitted by Lars Laehn +git-repos.de +lcube-server.de +svn-repos.de + +// Lightmaker Property Manager, Inc. : https://app.lmpm.com/ +// Submitted by Greg Holland +app.lmpm.com + +// Linki Tools UG : https://linki.tools +// Submitted by Paulo Matos +linkitools.space + +// linkyard ldt: https://www.linkyard.ch/ +// Submitted by Mario Siegenthaler +linkyard.cloud +linkyard-cloud.ch + +// LiquidNet Ltd : http://www.liquidnetlimited.com/ +// Submitted by Victor Velchev +we.bs + +// Lug.org.uk : https://lug.org.uk +// Submitted by Jon Spriggs +uklugs.org +glug.org.uk +lug.org.uk +lugs.org.uk + +// Lukanet Ltd : https://lukanet.com +// Submitted by Anton Avramov +barsy.bg +barsy.co.uk +barsyonline.co.uk +barsycenter.com +barsyonline.com +barsy.club +barsy.de +barsy.eu +barsy.in +barsy.info +barsy.io +barsy.me +barsy.menu +barsy.mobi +barsy.net +barsy.online +barsy.org +barsy.pro +barsy.pub +barsy.shop +barsy.site +barsy.support +barsy.uk + +// Magento Commerce +// Submitted by Damien Tournoud +*.magentosite.cloud + +// May First - People Link : https://mayfirst.org/ +// Submitted by Jamie McClelland +mayfirst.info +mayfirst.org + +// Mail.Ru Group : https://hb.cldmail.ru +// Submitted by Ilya Zaretskiy +hb.cldmail.ru + +// Memset hosting : https://www.memset.com +// Submitted by Tom Whitwell +miniserver.com +memset.net + +// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ +// Submitted by Zdeněk Å ustr +cloud.metacentrum.cz +custom.metacentrum.cz + +// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ +// Submitted by Radim Janča +flt.cloud.muni.cz +usr.cloud.muni.cz + +// Meteor Development Group : https://www.meteor.com/hosting +// Submitted by Pierre Carrier +meteorapp.com +eu.meteorapp.com + +// Michau Enterprises Limited : http://www.co.pl/ +co.pl + +// Microsoft Corporation : http://microsoft.com +// Submitted by Justin Luk +azurecontainer.io +azurewebsites.net +azure-mobile.net +cloudapp.net + +// Mozilla Corporation : https://mozilla.com +// Submitted by Ben Francis +mozilla-iot.org + +// Mozilla Foundation : https://mozilla.org/ +// Submitted by glob +bmoattachments.org + +// MSK-IX : https://www.msk-ix.ru/ +// Submitted by Khannanov Roman +net.ru +org.ru +pp.ru + +// Netlify : https://www.netlify.com +// Submitted by Jessica Parsons +bitballoon.com +netlify.com + +// Neustar Inc. +// Submitted by Trung Tran +4u.com + +// ngrok : https://ngrok.com/ +// Submitted by Alan Shreve +ngrok.io + +// Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ +// Submitted by Nicholas Ford +nh-serv.co.uk + +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse +nfshost.com + +// Now-DNS : https://now-dns.com +// Submitted by Steve Russell +dnsking.ch +mypi.co +n4t.co +001www.com +ddnslive.com +myiphost.com +forumz.info +16-b.it +32-b.it +64-b.it +soundcast.me +tcp4.me +dnsup.net +hicam.net +now-dns.net +ownip.net +vpndns.net +dynserv.org +now-dns.org +x443.pw +now-dns.top +ntdll.top +freeddns.us +crafting.xyz +zapto.xyz + +// nsupdate.info : https://www.nsupdate.info/ +// Submitted by Thomas Waldmann +nsupdate.info +nerdpol.ovh + +// No-IP.com : https://noip.com/ +// Submitted by Deven Reza +blogsyte.com +brasilia.me +cable-modem.org +ciscofreak.com +collegefan.org +couchpotatofries.org +damnserver.com +ddns.me +ditchyourip.com +dnsfor.me +dnsiskinky.com +dvrcam.info +dynns.com +eating-organic.net +fantasyleague.cc +geekgalaxy.com +golffan.us +health-carereform.com +homesecuritymac.com +homesecuritypc.com +hopto.me +ilovecollege.info +loginto.me +mlbfan.org +mmafan.biz +myactivedirectory.com +mydissent.net +myeffect.net +mymediapc.net +mypsx.net +mysecuritycamera.com +mysecuritycamera.net +mysecuritycamera.org +net-freaks.com +nflfan.org +nhlfan.net +no-ip.ca +no-ip.co.uk +no-ip.net +noip.us +onthewifi.com +pgafan.net +point2this.com +pointto.us +privatizehealthinsurance.net +quicksytes.com +read-books.org +securitytactics.com +serveexchange.com +servehumour.com +servep2p.com +servesarcasm.com +stufftoread.com +ufcfan.org +unusualperson.com +workisboring.com +3utilities.com +bounceme.net +ddns.net +ddnsking.com +gotdns.ch +hopto.org +myftp.biz +myftp.org +myvnc.com +no-ip.biz +no-ip.info +no-ip.org +noip.me +redirectme.net +servebeer.com +serveblog.net +servecounterstrike.com +serveftp.com +servegame.com +servehalflife.com +servehttp.com +serveirc.com +serveminecraft.net +servemp3.com +servepics.com +servequake.com +sytes.net +webhop.me +zapto.org + +// NodeArt : https://nodeart.io +// Submitted by Konstantin Nosov +stage.nodeart.io + +// Nodum B.V. : https://nodum.io/ +// Submitted by Wietse Wind +nodum.co +nodum.io + +// Nucleos Inc. : https://nucleos.com +// Submitted by Piotr Zduniak +pcloud.host + +// NYC.mn : http://www.information.nyc.mn +// Submitted by Matthew Brown +nyc.mn + +// NymNom : https://nymnom.com/ +// Submitted by Dave McCormack +nom.ae +nom.af +nom.ai +nom.al +nym.by +nym.bz +nom.cl +nom.gd +nom.ge +nom.gl +nym.gr +nom.gt +nym.gy +nom.hn +nym.ie +nom.im +nom.ke +nym.kz +nym.la +nym.lc +nom.li +nym.li +nym.lt +nym.lu +nym.me +nom.mk +nym.mn +nym.mx +nom.nu +nym.nz +nym.pe +nym.pt +nom.pw +nom.qa +nym.ro +nom.rs +nom.si +nym.sk +nom.st +nym.su +nym.sx +nom.tj +nym.tw +nom.ug +nom.uy +nom.vc +nom.vg + +// Octopodal Solutions, LLC. : https://ulterius.io/ +// Submitted by Andrew Sampson +cya.gg + +// Omnibond Systems, LLC. : https://www.omnibond.com +// Submitted by Cole Estep +cloudycluster.net + +// One Fold Media : http://www.onefoldmedia.com/ +// Submitted by Eddie Jones +nid.io + +// OpenCraft GmbH : http://opencraft.com/ +// Submitted by Sven Marnach +opencraft.hosting + +// Opera Software, A.S.A. +// Submitted by Yngve Pettersen +operaunite.com + +// OutSystems +// Submitted by Duarte Santos +outsystemscloud.com + +// OwnProvider GmbH: http://www.ownprovider.com +// Submitted by Jan Moennich +ownprovider.com +own.pm + +// OX : http://www.ox.rs +// Submitted by Adam Grand +ox.rs + +// oy.lc +// Submitted by Charly Coste +oy.lc + +// Pagefog : https://pagefog.com/ +// Submitted by Derek Myers +pgfog.com + +// Pagefront : https://www.pagefronthq.com/ +// Submitted by Jason Kriss +pagefrontapp.com + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// Pantheon Systems, Inc. : https://pantheon.io/ +// Submitted by Gary Dylina +pantheonsite.io +gotpantheon.com + +// Peplink | Pepwave : http://peplink.com/ +// Submitted by Steve Leung +mypep.link + +// Planet-Work : https://www.planet-work.com/ +// Submitted by Frédéric VANNIÈRE +on-web.fr + +// Platform.sh : https://platform.sh +// Submitted by Nikola Kotur +*.platform.sh +*.platformsh.site + +// prgmr.com : https://prgmr.com/ +// Submitted by Sarah Newman +xen.prgmr.com + +// priv.at : http://www.nic.priv.at/ +// Submitted by registry +priv.at + +// Protonet GmbH : http://protonet.io +// Submitted by Martin Meier +protonet.io + +// Publication Presse Communication SARL : https://ppcom.fr +// Submitted by Yaacov Akiba Slama +chirurgiens-dentistes-en-france.fr +byen.site + +// Russian Academy of Sciences +// Submitted by Tech Support +ras.ru + +// QA2 +// Submitted by Daniel Dent (https://www.danieldent.com/) +qa2.com + +// QNAP System Inc : https://www.qnap.com +// Submitted by Nick Chang +dev-myqnapcloud.com +alpha-myqnapcloud.com +myqnapcloud.com + +// Quip : https://quip.com +// Submitted by Patrick Linehan +*.quipelements.com + +// Qutheory LLC : http://qutheory.io +// Submitted by Jonas Schwartz +vapor.cloud +vaporcloud.io + +// Rackmaze LLC : https://www.rackmaze.com +// Submitted by Kirill Pertsev +rackmaze.com +rackmaze.net + +// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ +// Submitted by Tim Kramer +rhcloud.com + +// Resin.io : https://resin.io +// Submitted by Tim Perry +resindevice.io +devices.resinstaging.io + +// RethinkDB : https://www.rethinkdb.com/ +// Submitted by Chris Kastorff +hzc.io + +// Revitalised Limited : http://www.revitalised.co.uk +// Submitted by Jack Price +wellbeingzone.eu +ptplus.fit +wellbeingzone.co.uk + +// Sandstorm Development Group, Inc. : https://sandcats.io/ +// Submitted by Asheesh Laroia +sandcats.io + +// SBE network solutions GmbH : https://www.sbe.de/ +// Submitted by Norman Meilick +logoip.de +logoip.com + +// schokokeks.org GbR : https://schokokeks.org/ +// Submitted by Hanno Böck +schokokeks.net + +// Scry Security : http://www.scrysec.com +// Submitted by Shante Adam +scrysec.com + +// Securepoint GmbH : https://www.securepoint.de +// Submitted by Erik Anders +firewall-gateway.com +firewall-gateway.de +my-gateway.de +my-router.de +spdns.de +spdns.eu +firewall-gateway.net +my-firewall.org +myfirewall.org +spdns.org + +// SensioLabs, SAS : https://sensiolabs.com/ +// Submitted by Fabien Potencier +*.s5y.io +*.sensiosite.cloud + +// Service Online LLC : http://drs.ua/ +// Submitted by Serhii Bulakh +biz.ua +co.ua +pp.ua + +// ShiftEdit : https://shiftedit.net/ +// Submitted by Adam Jimenez +shiftedit.io + +// Shopblocks : http://www.shopblocks.com/ +// Submitted by Alex Bowers +myshopblocks.com + +// SinaAppEngine : http://sae.sina.com.cn/ +// Submitted by SinaAppEngine +1kapp.com +appchizi.com +applinzi.com +sinaapp.com +vipsinaapp.com + +// Skyhat : http://www.skyhat.io +// Submitted by Shante Adam +bounty-full.com +alpha.bounty-full.com +beta.bounty-full.com + +// staticland : https://static.land +// Submitted by Seth Vincent +static.land +dev.static.land +sites.static.land + +// SourceLair PC : https://www.sourcelair.com +// Submitted by Antonis Kalipetis +apps.lair.io +*.stolos.io + +// SpaceKit : https://www.spacekit.io/ +// Submitted by Reza Akhavan +spacekit.io + +// SpeedPartner GmbH: https://www.speedpartner.de/ +// Submitted by Stefan Neufeind +customer.speedpartner.de + +// Storj Labs Inc. : https://storj.io/ +// Submitted by Philip Hutchins +storj.farm + +// Studenten Net Twente : http://www.snt.utwente.nl/ +// Submitted by Silke Hofstra +utwente.io + +// Sub 6 Limited: http://www.sub6.com +// Submitted by Dan Miller +temp-dns.com + +// Synology, Inc. : https://www.synology.com/ +// Submitted by Rony Weng +diskstation.me +dscloud.biz +dscloud.me +dscloud.mobi +dsmynas.com +dsmynas.net +dsmynas.org +familyds.com +familyds.net +familyds.org +i234.me +myds.me +synology.me +vpnplus.to + +// TAIFUN Software AG : http://taifun-software.de +// Submitted by Bjoern Henke +taifun-dns.de + +// TASK geographical domains (www.task.gda.pl/uslugi/dns) +gda.pl +gdansk.pl +gdynia.pl +med.pl +sopot.pl + +// The Gwiddle Foundation : https://gwiddlefoundation.org.uk +// Submitted by Joshua Bayfield +gwiddle.co.uk + +// Thingdust AG : https://thingdust.com/ +// Submitted by Adrian Imboden +cust.dev.thingdust.io +cust.disrec.thingdust.io +cust.prod.thingdust.io +cust.testing.thingdust.io + +// TownNews.com : http://www.townnews.com +// Submitted by Dustin Ward +bloxcms.com +townnews-staging.com + +// TrafficPlex GmbH : https://www.trafficplex.de/ +// Submitted by Phillipp Röll +12hp.at +2ix.at +4lima.at +lima-city.at +12hp.ch +2ix.ch +4lima.ch +lima-city.ch +trafficplex.cloud +de.cool +12hp.de +2ix.de +4lima.de +lima-city.de +1337.pictures +clan.rip +lima-city.rocks +webspace.rocks +lima.zone + +// TransIP : https://www.transip.nl +// Submitted by Rory Breuk +*.transurl.be +*.transurl.eu +*.transurl.nl + +// TuxFamily : http://tuxfamily.org +// Submitted by TuxFamily administrators +tuxfamily.org + +// TwoDNS : https://www.twodns.de/ +// Submitted by TwoDNS-Support +dd-dns.de +diskstation.eu +diskstation.org +dray-dns.de +draydns.de +dyn-vpn.de +dynvpn.de +mein-vigor.de +my-vigor.de +my-wan.de +syno-ds.de +synology-diskstation.de +synology-ds.de + +// Uberspace : https://uberspace.de +// Submitted by Moritz Werner +uber.space +*.uberspace.de + +// UDR Limited : http://www.udr.hk.com +// Submitted by registry +hk.com +hk.org +ltd.hk +inc.hk + +// United Gameserver GmbH : https://united-gameserver.de +// Submitted by Stefan Schwarz +virtualuser.de +virtual-user.de + +// .US +// Submitted by Ed Moore +lib.de.us + +// VeryPositive SIA : http://very.lv +// Submitted by Danko Aleksejevs +2038.io + +// Viprinet Europe GmbH : http://www.viprinet.com +// Submitted by Simon Kissel +router.management + +// Virtual-Info : https://www.virtual-info.info/ +// Submitted by Adnan RIHAN +v-info.info + +// WeDeploy by Liferay, Inc. : https://www.wedeploy.com +// Submitted by Henrique Vicente +wedeploy.io +wedeploy.me +wedeploy.sh + +// Western Digital Technologies, Inc : https://www.wdc.com +// Submitted by Jung Jin +remotewd.com + +// Wikimedia Labs : https://wikitech.wikimedia.org +// Submitted by Yuvi Panda +wmflabs.org + +// XenonCloud GbR: https://xenoncloud.net +// Submitted by Julian Uphoff +half.host + +// XnBay Technology : http://www.xnbay.com/ +// Submitted by XnBay Developer +xnbay.com +u2.xnbay.com +u2-local.xnbay.com + +// XS4ALL Internet bv : https://www.xs4all.nl/ +// Submitted by Daniel Mostertman +cistron.nl +demon.nl +xs4all.space + +// YesCourse Pty Ltd : https://yescourse.com +// Submitted by Atul Bhouraskar +official.academy + +// Yola : https://www.yola.com/ +// Submitted by Stefano Rivera +yolasite.com + +// Yombo : https://yombo.net +// Submitted by Mitch Schwenk +ybo.faith +yombo.me +homelink.one +ybo.party +ybo.review +ybo.science +ybo.trade + +// Yunohost : https://yunohost.org +// Submitted by Valentin Grimaud +nohost.me +noho.st + +// ZaNiC : http://www.za.net/ +// Submitted by registry +za.net +za.org + +// Zeit, Inc. : https://zeit.domains/ +// Submitted by Olli Vanhoja +now.sh + +// Zone.id : https://zone.id/ +// Submitted by Su Hendro +zone.id + +// ===END PRIVATE DOMAINS=== diff --git a/epollmplexer.cc b/epollmplexer.cc new file mode 100644 index 0000000..2deae83 --- /dev/null +++ b/epollmplexer.cc @@ -0,0 +1,190 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include +#include "misc.hh" +#ifdef __linux__ +#include +#endif + +#include "namespaces.hh" + +class EpollFDMultiplexer : public FDMultiplexer +{ +public: + EpollFDMultiplexer(); + virtual ~EpollFDMultiplexer() + { + close(d_epollfd); + } + + virtual int run(struct timeval* tv, int timeout=500); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "epoll"; + } +private: + int d_epollfd; + boost::shared_array d_eevents; + static int s_maxevents; // not a hard maximum +}; + + +static FDMultiplexer* makeEpoll() +{ + return new EpollFDMultiplexer(); +} + +static struct EpollRegisterOurselves +{ + EpollRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makeEpoll)); // priority 0! + } +} doItEpoll; + + +int EpollFDMultiplexer::s_maxevents=1024; +EpollFDMultiplexer::EpollFDMultiplexer() : d_eevents(new epoll_event[s_maxevents]) +{ + d_epollfd=epoll_create(s_maxevents); // not hard max + if(d_epollfd < 0) + throw FDMultiplexerException("Setting up epoll: "+stringerror()); + int fd=socket(AF_INET, SOCK_DGRAM, 0); // for self-test + if(fd < 0) + return; + try { + addReadFD(fd, 0); + removeReadFD(fd); + close(fd); + return; + } + catch(FDMultiplexerException &fe) { + close(fd); + close(d_epollfd); + throw FDMultiplexerException("epoll multiplexer failed self-test: "+string(fe.what())); + } + +} + +void EpollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + struct epoll_event eevent; + + eevent.events = (&cbmap == &d_readCallbacks) ? EPOLLIN : EPOLLOUT; + + eevent.data.u64=0; // placate valgrind (I love it so much) + eevent.data.fd=fd; + + if(epoll_ctl(d_epollfd, EPOLL_CTL_ADD, fd, &eevent) < 0) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to epoll set: "+stringerror()); + } +} + +void EpollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); + + struct epoll_event dummy; + dummy.events = 0; + dummy.data.u64 = 0; + + if(epoll_ctl(d_epollfd, EPOLL_CTL_DEL, fd, &dummy) < 0) + throw FDMultiplexerException("Removing fd from epoll set: "+stringerror()); +} + +int EpollFDMultiplexer::run(struct timeval* now, int timeout) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + + int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, timeout); + gettimeofday(now,0); // MANDATORY + + if(ret < 0 && errno!=EINTR) + throw FDMultiplexerException("epoll returned error: "+stringerror()); + + if(ret < 1) // thanks AB! + return 0; + + d_inrun=true; + for(int n=0; n < ret; ++n) { + d_iter=d_readCallbacks.find(d_eevents[n].data.fd); + + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + continue; // so we don't refind ourselves as writable! + } + d_iter=d_writeCallbacks.find(d_eevents[n].data.fd); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + } + } + d_inrun=false; + return ret; +} + +#if 0 +void acceptData(int fd, funcparam_t& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "<&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 = ext +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/m4/boost.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)/m4/pdns_check_clock_gettime.m4 \ + $(top_srcdir)/m4/pdns_check_curl.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ + $(top_srcdir)/m4/pdns_check_libdecaf.m4 \ + $(top_srcdir)/m4/pdns_check_libsodium.m4 \ + $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ + $(top_srcdir)/m4/pdns_check_network_libs.m4 \ + $(top_srcdir)/m4/pdns_check_os.m4 \ + $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ + $(top_srcdir)/m4/pdns_check_ragel.m4 \ + $(top_srcdir)/m4/pdns_check_virtualenv.m4 \ + $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ + $(top_srcdir)/m4/pdns_enable_botan.m4 \ + $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ + $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ + $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ + $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ + $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ + $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ + $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ + $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ + $(top_srcdir)/m4/pdns_stack_protector.m4 \ + $(top_srcdir)/m4/pdns_with_lua.m4 \ + $(top_srcdir)/m4/pdns_with_luajit.m4 \ + $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ + $(top_srcdir)/m4/pdns_with_protobuf.m4 \ + $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +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" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ +BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ +BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_LDPATH = @BOOST_LDPATH@ +BOOST_ROOT = @BOOST_ROOT@ +BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ +BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ +BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ +BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ +BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ +BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ +BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ +BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ +BOTAN_CFLAGS = @BOTAN_CFLAGS@ +BOTAN_LIBS = @BOTAN_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CURL = @CURL@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DYNLINKFLAGS = @DYNLINKFLAGS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ +LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBDECAF_LIBS = @LIBDECAF_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NET_SNMP_CFLAGS = @NET_SNMP_CFLAGS@ +NET_SNMP_LIBS = @NET_SNMP_LIBS@ +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@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ +PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@ +PROTOBUF_LIBS = @PROTOBUF_LIBS@ +PROTOC = @PROTOC@ +RAGEL = @RAGEL@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RT_LIBS = @RT_LIBS@ +SANITIZER_FLAGS = @SANITIZER_FLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ +THREADFLAGS = @THREADFLAGS@ +VERSION = @VERSION@ +VIRTUALENV = @VIRTUALENV@ +WARN_CFLAGS = @WARN_CFLAGS@ +YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ +YAHTTP_LIBS = @YAHTTP_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +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@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pdns_configure_args = @pdns_configure_args@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +socketdir = @socketdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemd = @systemd@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = \ + yahttp \ + json11 + +DIST_SUBDIRS = \ + yahttp \ + json11 + +EXTRA_DIST = \ + luawrapper/include/LuaContext.hpp \ + yahttp/LICENSE \ + json11/LICENSE.txt incbin/incbin.h + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(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) --foreign ext/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign ext/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: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(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 + +# 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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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 +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +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 Makefile +distclean-am: clean-am distclean-generic 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 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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic 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-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-am 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/ext/incbin/incbin.h b/ext/incbin/incbin.h new file mode 100644 index 0000000..c10e247 --- /dev/null +++ b/ext/incbin/incbin.h @@ -0,0 +1,223 @@ +/** + * @file incbin.h + * @author Dale Weiler + * @brief Utility for including binary files + * + * Facilities for including binary files into the current translation unit and + * making use from them externally in other translation units. + */ +#ifndef INCBIN_HDR +#define INCBIN_HDR +#include + +#if defined(__SSE__) || defined(__neon__) +# define INCBIN_ALIGNMENT_INDEX 4 +#elif defined(__AVX__) +# define INCBIN_ALIGNMENT_INDEX 5 +#else +# if ULONG_MAX == 0xffffffffu +# define INCBIN_ALIGNMENT_INDEX 2 +# else +# define INCBIN_ALIGNMENT_INDEX 3 +# endif +#endif + +/* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */ +#define INCBIN_ALIGN_SHIFT_0 1 +#define INCBIN_ALIGN_SHIFT_1 2 +#define INCBIN_ALIGN_SHIFT_2 4 +#define INCBIN_ALIGN_SHIFT_3 8 +#define INCBIN_ALIGN_SHIFT_4 16 +#define INCBIN_ALIGN_SHIFT_5 32 + +/* Common preprocessor utilities */ +#define INCBIN_STR(X) #X +#define INCBIN_STRINGIZE(X) INCBIN_STR(X) + +#define INCBIN_CAT(X, Y) X ## Y +#define INCBIN_CONCATENATE(X, Y) INCBIN_CAT(X, Y) + +#define INCBIN_ALIGNMENT \ + INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT_, INCBIN_ALIGNMENT_INDEX) + +/* Green Hills uses a different directive for including binary data */ +#if defined(__ghs__) +# define INCBIN_MACRO "\tINCBIN" +#else +# define INCBIN_MACRO ".incbin" +#endif + +#ifndef _MSC_VER +# define INCBIN_ALIGN \ + __attribute__((aligned(INCBIN_ALIGNMENT))) +#else +# define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT)) +#endif + +#if defined(__arm__) || /* GNU C and RealView */ \ + defined(__arm) || /* Diab */ \ + defined(_ARM) /* ImageCraft */ +# define INCBIN_ARM +#endif + +#ifdef __GNUC__ +/* Utilize .balign where supported */ +# define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" +# define INCBIN_ALIGN_BYTE ".balign 1\n" +#elif defined(INCBIN_ARM) +/* + * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is + * the shift count. This is the value passed to `.align' + */ +# define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n" +# define INCBIN_ALIGN_BYTE ".align 0\n" +#else +/* We assume other inline assembler's treat `.align' as `.balign' */ +# define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" +# define INCBIN_ALIGN_BYTE ".align 1\n" +#endif + +/* INCBIN_CONST is used by incbin.c generated files */ +#if defined(__cplusplus) +# define INCBIN_EXTERNAL extern "C" +# define INCBIN_CONST extern const +#else +# define INCBIN_EXTERNAL extern +# define INCBIN_CONST const +#endif + +#if defined(__APPLE__) +/* The directives are different for Apple branded compilers */ +# define INCBIN_SECTION ".const_data\n" +# define INCBIN_GLOBAL(NAME) ".globl " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" +# define INCBIN_INT ".long " +# define INCBIN_MANGLE "_" +# define INCBIN_BYTE ".byte " +# define INCBIN_TYPE(...) +#else +# define INCBIN_SECTION ".section .rodata\n" +# define INCBIN_GLOBAL(NAME) ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" +# define INCBIN_INT ".int " +# if defined(__USER_LABEL_PREFIX__) +# define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__) +# else +# define INCBIN_MANGLE "" +# endif +# if defined(INCBIN_ARM) +/* On arm assemblers, `@' is used as a line comment token */ +# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n" +# else +/* It's safe to use `@' on other architectures */ +# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n" +# endif +# define INCBIN_BYTE ".byte " +#endif + +/** + * @breif Specify the prefix to use for symbol names. + * + * By default this is `g', producing symbols of the form: + * @code + * #include "incbin.h" + * INCBIN(Foo, "foo.txt"); + * + * // Now you have the following symbols: + * // const unsigned char gFooData[]; + * // const unsigned char *gFooEnd; + * // const unsigned int gFooSize; + * @endcode + * + * If however you specify a prefix before including: e.g: + * @code + * #define INCBIN_PREFIX incbin + * #include "incbin.h" + * INCBIN(Foo, "foo.txt"); + * + * // Now you have the following symbols instead: + * // const unsigned char incbinFooData[]; + * // const unsigned char *incbinFooEnd; + * // const unsigned int incbinFooSize; + * @endcode + */ +#if !defined(INCBIN_PREFIX) +# define INCBIN_PREFIX g +#endif + +/** + * @brief Externally reference binary data included in another translation unit. + * + * Produces three external symbols that reference the binary data included in + * another translation unit. + * + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with + * "Data", as well as "End" and "Size" after. An example is provided below. + * + * @param NAME The name given for the binary data + * + * @code + * INCBIN_EXTERN(Foo); + * + * // Now you have the following symbols: + * // extern const unsigned char FooData[]; + * // extern const unsigned char *FooEnd; + * // extern const unsigned int FooSize; + * @endcode + */ +#define INCBIN_EXTERN(NAME) \ + INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char INCBIN_CONCATENATE(INCBIN_PREFIX, NAME ## Data)[]; \ + INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *INCBIN_CONCATENATE(INCBIN_PREFIX, NAME ## End); \ + INCBIN_EXTERNAL const unsigned int INCBIN_CONCATENATE(INCBIN_PREFIX, NAME ## Size) + +/** + * @brief Include a binary file into the current translation unit. + * + * Includes a binary file into the current translation unit, producing three symbols + * for objects that encode the data and size respectively. + * + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with + * "Data", as well as "End" and "Size" after. An example is provided below. + * + * @param NAME The name to associate with this binary data (as an identifier.) + * @param FILENAME The file to include (as a string literal.) + * + * @code + * INCBIN(Icon, "icon.png"); + * + * // Now you have the following symbols: + * // const unsigned char IconData[]; + * // const unsigned char *IconEnd; + * // const unsigned int IconSize; + * @endcode + * + * @warning This must be used in global scope + * + * To externally reference the data included by this in another translation unit + * please @see INCBIN_EXTERN. + */ +#ifdef _MSC_VER +#define INCBIN(NAME, FILENAME) \ + INCBIN_EXTERN(NAME) +#else +#define INCBIN(NAME, FILENAME) \ + __asm__(INCBIN_SECTION \ + INCBIN_GLOBAL(NAME ## Data) \ + INCBIN_TYPE(NAME ## Data) \ + INCBIN_ALIGN_HOST \ + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "Data:\n" \ + INCBIN_MACRO " \"" FILENAME "\"\n" \ + INCBIN_GLOBAL(NAME ## End) \ + INCBIN_TYPE(NAME ## End) \ + INCBIN_ALIGN_BYTE \ + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "End:\n" \ + INCBIN_BYTE "1\n" \ + INCBIN_GLOBAL(NAME ## Size) \ + INCBIN_TYPE(NAME ## Size) \ + INCBIN_ALIGN_HOST \ + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "Size:\n" \ + INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "End - " \ + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "Data\n" \ + ); \ + INCBIN_EXTERN(NAME) + +#endif +#endif diff --git a/ext/json11/LICENSE.txt b/ext/json11/LICENSE.txt new file mode 100644 index 0000000..691742e --- /dev/null +++ b/ext/json11/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2013 Dropbox, Inc. + +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. diff --git a/ext/json11/Makefile.am b/ext/json11/Makefile.am new file mode 100644 index 0000000..df5f856 --- /dev/null +++ b/ext/json11/Makefile.am @@ -0,0 +1,2 @@ +noinst_LTLIBRARIES = libjson11.la +libjson11_la_SOURCES = json11.cpp json11.hpp diff --git a/ext/json11/Makefile.in b/ext/json11/Makefile.in new file mode 100644 index 0000000..f6e9708 --- /dev/null +++ b/ext/json11/Makefile.in @@ -0,0 +1,683 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 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@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 = ext/json11 +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/build-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/m4/boost.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)/m4/pdns_check_clock_gettime.m4 \ + $(top_srcdir)/m4/pdns_check_curl.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ + $(top_srcdir)/m4/pdns_check_libdecaf.m4 \ + $(top_srcdir)/m4/pdns_check_libsodium.m4 \ + $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ + $(top_srcdir)/m4/pdns_check_network_libs.m4 \ + $(top_srcdir)/m4/pdns_check_os.m4 \ + $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ + $(top_srcdir)/m4/pdns_check_ragel.m4 \ + $(top_srcdir)/m4/pdns_check_virtualenv.m4 \ + $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ + $(top_srcdir)/m4/pdns_enable_botan.m4 \ + $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ + $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ + $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ + $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ + $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ + $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ + $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ + $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ + $(top_srcdir)/m4/pdns_stack_protector.m4 \ + $(top_srcdir)/m4/pdns_with_lua.m4 \ + $(top_srcdir)/m4/pdns_with_luajit.m4 \ + $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ + $(top_srcdir)/m4/pdns_with_protobuf.m4 \ + $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libjson11_la_LIBADD = +am_libjson11_la_OBJECTS = json11.lo +libjson11_la_OBJECTS = $(am_libjson11_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libjson11_la_SOURCES) +DIST_SOURCES = $(libjson11_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ +BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ +BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_LDPATH = @BOOST_LDPATH@ +BOOST_ROOT = @BOOST_ROOT@ +BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ +BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ +BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ +BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ +BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ +BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ +BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ +BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ +BOTAN_CFLAGS = @BOTAN_CFLAGS@ +BOTAN_LIBS = @BOTAN_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CURL = @CURL@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DYNLINKFLAGS = @DYNLINKFLAGS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ +LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBDECAF_LIBS = @LIBDECAF_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NET_SNMP_CFLAGS = @NET_SNMP_CFLAGS@ +NET_SNMP_LIBS = @NET_SNMP_LIBS@ +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@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ +PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@ +PROTOBUF_LIBS = @PROTOBUF_LIBS@ +PROTOC = @PROTOC@ +RAGEL = @RAGEL@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RT_LIBS = @RT_LIBS@ +SANITIZER_FLAGS = @SANITIZER_FLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ +THREADFLAGS = @THREADFLAGS@ +VERSION = @VERSION@ +VIRTUALENV = @VIRTUALENV@ +WARN_CFLAGS = @WARN_CFLAGS@ +YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ +YAHTTP_LIBS = @YAHTTP_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +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@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pdns_configure_args = @pdns_configure_args@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +socketdir = @socketdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemd = @systemd@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libjson11.la +libjson11_la_SOURCES = json11.cpp json11.hpp +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(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) --foreign ext/json11/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign ext/json11/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: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libjson11.la: $(libjson11_la_OBJECTS) $(libjson11_la_DEPENDENCIES) $(EXTRA_libjson11_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libjson11_la_OBJECTS) $(libjson11_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json11.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +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 $(LTLIBRARIES) +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +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-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +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 -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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + 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-man install-pdf install-pdf-am \ + install-ps install-ps-am 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 tags-am 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/ext/json11/json11.cpp b/ext/json11/json11.cpp new file mode 100644 index 0000000..f48833b --- /dev/null +++ b/ext/json11/json11.cpp @@ -0,0 +1,784 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * 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. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* Helper for representing null - just a do-nothing struct, plus comparison + * operators so the helpers in JsonValue work. We can't use nullptr_t because + * it may not be orderable. + */ +struct NullStruct { + bool operator==(NullStruct) const { return true; } + bool operator<(NullStruct) const { return false; } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(NullStruct, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; + snprintf(buf, sizeof buf, "%.17g", value); + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; + snprintf(buf, sizeof buf, "%d", value); + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; + snprintf(buf, sizeof buf, "\\u%04x", ch); + out += buf; + } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80 + && static_cast(value[i+2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80 + && static_cast(value[i+2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + + // Constructors + explicit Value(const T &value) : m_value(value) {} + explicit Value(T &&value) : m_value(move(value)) {} + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue * other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue * other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { json11::dump(m_value, out); } +}; + +class JsonDouble final : public Value { + double number_value() const override { return m_value; } + int int_value() const override { return static_cast(m_value); } + bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } + bool less(const JsonValue * other) const override { return m_value < other->number_value(); } +public: + explicit JsonDouble(double value) : Value(value) {} +}; + +class JsonInt final : public Value { + double number_value() const override { return m_value; } + int int_value() const override { return m_value; } + bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } + bool less(const JsonValue * other) const override { return m_value < other->number_value(); } +public: + explicit JsonInt(int value) : Value(value) {} +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { return m_value; } +public: + explicit JsonBoolean(bool value) : Value(value) {} +}; + +class JsonString final : public Value { + const string &string_value() const override { return m_value; } +public: + explicit JsonString(const string &value) : Value(value) {} + explicit JsonString(string &&value) : Value(move(value)) {} +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { return m_value; } + const Json & operator[](size_t i) const override; +public: + explicit JsonArray(const Json::array &value) : Value(value) {} + explicit JsonArray(Json::array &&value) : Value(move(value)) {} +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { return m_value; } + const Json & operator[](const string &key) const override; +public: + explicit JsonObject(const Json::object &value) : Value(value) {} + explicit JsonObject(Json::object &&value) : Value(move(value)) {} +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value({}) {} +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() {} +}; + +static const Statics & statics() { + static const Statics s {}; + return s; +} + +static const Json & static_null() { + // This has to be separate, not in Statics, because Json() accesses statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() noexcept : m_ptr(statics().null) {} +Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {} +Json::Json(double value) : m_ptr(make_shared(value)) {} +Json::Json(int value) : m_ptr(make_shared(value)) {} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {} +Json::Json(const string &value) : m_ptr(make_shared(value)) {} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) {} +Json::Json(const char * value) : m_ptr(make_shared(value)) {} +Json::Json(const Json::array &values) : m_ptr(make_shared(values)) {} +Json::Json(Json::array &&values) : m_ptr(make_shared(move(values))) {} +Json::Json(const Json::object &values) : m_ptr(make_shared(values)) {} +Json::Json(Json::object &&values) : m_ptr(make_shared(move(values))) {} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { return m_ptr->type(); } +double Json::number_value() const { return m_ptr->number_value(); } +int Json::int_value() const { return m_ptr->int_value(); } +bool Json::bool_value() const { return m_ptr->bool_value(); } +const string & Json::string_value() const { return m_ptr->string_value(); } +const vector & Json::array_items() const { return m_ptr->array_items(); } +const map & Json::object_items() const { return m_ptr->object_items(); } +const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; } +const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; } + +double JsonValue::number_value() const { return 0; } +int JsonValue::int_value() const { return 0; } +bool JsonValue::bool_value() const { return false; } +const string & JsonValue::string_value() const { return statics().empty_string; } +const vector & JsonValue::array_items() const { return statics().empty_vector; } +const map & JsonValue::object_items() const { return statics().empty_map; } +const Json & JsonValue::operator[] (size_t) const { return static_null(); } +const Json & JsonValue::operator[] (const string &) const { return static_null(); } + +const Json & JsonObject::operator[] (const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json & JsonArray::operator[] (size_t i) const { + if (i >= m_value.size()) return static_null(); + else return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator== (const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator< (const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); + } else { + snprintf(buf, sizeof buf, "(%d)", c); + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +namespace { +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser final { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", false); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", false); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", false); + } + comment_found = true; + } + else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size()-2) + return fail("unexpected end of input inside multi-line comment", false); + // advance until closing tokens + while (!(str[i] == '*' && str[i+1] == '/')) { + i++; + if (i > str.size()-2) + return fail( + "unexpected end of input inside multi-line comment", false); + } + i += 2; + if (i == str.size()) + return fail( + "unexpected end of input inside multi-line comment", false); + comment_found = true; + } + else + return fail("malformed comment", false); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if(strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } + while(comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", (char)0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string & out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (size_t j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') + && !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair components. Check + // whether we're in the middle of such a beast: the previous codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) + && in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) + | (codepoint - 0xDC00)) + 0x10000, out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' + && (i - start_pos) <= static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; +}//namespace { + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser { in, 0, err, false, strategy }; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, + std::string::size_type &parser_stop_pos, + string &err, + JsonParse strategy) { + JsonParser parser { in, 0, err, false, strategy }; + parser_stop_pos = 0; + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + if (!parser.failed) + parser_stop_pos = parser.i; + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape & types, string & err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto & item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/ext/json11/json11.hpp b/ext/json11/json11.hpp new file mode 100644 index 0000000..a68394b --- /dev/null +++ b/ext/json11/json11.hpp @@ -0,0 +1,232 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. + * + * The core object provided by the library is json11::Json. A Json object represents any JSON + * value: null, bool, number (int or double), string (std::string), array (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but not its semantics, + * so some JSON implementations distinguish between integers and floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON implementations (namely + * JavaScript itself) treat all numbers as the same type, distinguishing the two leads + * to JSON that will be *silently* changed by a round-trip through those implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #if _MSC_VER <= 1800 // VS 2013 + #ifndef noexcept + #define noexcept throw() + #endif + + #ifndef snprintf + #define snprintf _snprintf_s + #endif + #endif +#endif + +namespace json11 { + +enum JsonParse { + STANDARD, COMMENTS +}; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + Json() noexcept; // NUL + Json(std::nullptr_t) noexcept; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char * value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T & t) : Json(t.to_json()) {} + + // Implicit constructor: map-like objects (std::map, std::unordered_map, etc) + template ::value + && std::is_constructible::value, + int>::type = 0> + Json(const M & m) : Json(object(m.begin(), m.end())) {} + + // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) + template ::value, + int>::type = 0> + Json(const V & v) : Json(array(v.begin(), v.end())) {} + + // This prevents Json(some_pointer) from accidentally producing a bool. Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { return type() == NUL; } + bool is_number() const { return type() == NUMBER; } + bool is_bool() const { return type() == BOOL; } + bool is_string() const { return type() == STRING; } + bool is_array() const { return type() == ARRAY; } + bool is_object() const { return type() == OBJECT; } + + // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not + // distinguish between integer and non-integer numbers - number_value() and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json & operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json & operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to err. + static Json parse(const std::string & in, + std::string & err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char * in, + std::string & err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector parse_multi( + const std::string & in, + std::string::size_type & parser_stop_pos, + std::string & err, + JsonParse strategy = JsonParse::STANDARD); + + static inline std::vector parse_multi( + const std::string & in, + std::string & err, + JsonParse strategy = JsonParse::STANDARD) { + std::string::size_type parser_stop_pos; + return parse_multi(in, parser_stop_pos, err, strategy); + } + + bool operator== (const Json &rhs) const; + bool operator< (const Json &rhs) const; + bool operator!= (const Json &rhs) const { return !(*this == rhs); } + bool operator<= (const Json &rhs) const { return !(rhs < *this); } + bool operator> (const Json &rhs) const { return (rhs < *this); } + bool operator>= (const Json &rhs) const { return !(*this < rhs); } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has a field of + * the given type. If not, return false and set err to a descriptive message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape & types, std::string & err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue * other) const = 0; + virtual bool less(const JsonValue * other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() {} +}; + +} // namespace json11 diff --git a/ext/luawrapper/include/LuaContext.hpp b/ext/luawrapper/include/LuaContext.hpp new file mode 100644 index 0000000..d0ffe6f --- /dev/null +++ b/ext/luawrapper/include/LuaContext.hpp @@ -0,0 +1,2832 @@ +/* +Copyright (c) 2013, Pierre KRIEGER +All rights reserved. + +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 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 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 INCLUDE_LUACONTEXT_HPP +#define INCLUDE_LUACONTEXT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1900 +# include "misc/exception.hpp" +#endif + +#ifdef __GNUC__ +# define ATTR_UNUSED __attribute__((unused)) +#else +# define ATTR_UNUSED +#endif + +/** + * Defines a Lua context + * A Lua context is used to interpret Lua code. Since everything in Lua is a variable (including functions), + * we only provide few functions like readVariable and writeVariable. + * + * You can also write variables with C++ functions so that they are callable by Lua. Note however that you HAVE TO convert + * your function to std::function (not directly std::bind or a lambda function) so the class can detect which argument types + * it wants. These arguments may only be of basic types (int, float, etc.) or std::string. + */ +class LuaContext { + struct ValueInRegistry; + template struct Binder; + template struct IsOptional; + enum Globals_t { Globals }; // tag for "global variables" +public: + /** + * @param openDefaultLibs True if luaL_openlibs should be called + */ + explicit LuaContext(bool openDefaultLibs = true) + { + // luaL_newstate can return null if allocation failed + mState = luaL_newstate(); + if (mState == nullptr) + throw std::bad_alloc(); + + // setting the panic function + lua_atpanic(mState, [](lua_State* state) -> int { + const std::string str = lua_tostring(state, -1); + lua_pop(state, 1); + assert(false && "lua_atpanic triggered"); + exit(0); + }); + + // opening default library if required to do so + if (openDefaultLibs) + luaL_openlibs(mState); + } + + /** + * Move constructor + */ + LuaContext(LuaContext&& s) : + mState(s.mState) + { + s.mState = luaL_newstate(); + } + + /** + * Move operator + */ + LuaContext& operator=(LuaContext&& s) noexcept + { + std::swap(mState, s.mState); + return *this; + } + + /** + * Copy is forbidden + */ + LuaContext(const LuaContext&) = delete; + + /** + * Copy is forbidden + */ + LuaContext& operator=(const LuaContext&) = delete; + + /** + * Destructor + */ + ~LuaContext() noexcept + { + assert(mState); + lua_close(mState); + } + + /** + * Thrown when an error happens during execution of lua code (like not enough parameters for a function) + */ + class ExecutionErrorException : public std::runtime_error + { + public: + ExecutionErrorException(const std::string& msg) : + std::runtime_error(msg) + { + } + }; + + /** + * Thrown when a syntax error happens in a lua script + */ + class SyntaxErrorException : public std::runtime_error + { + public: + SyntaxErrorException(const std::string& msg) : + std::runtime_error(msg) + { + } + }; + + /** + * Thrown when trying to cast a Lua variable to an unvalid type, eg. trying to read a number when the variable is a string + */ + class WrongTypeException : public std::runtime_error + { + public: + WrongTypeException(std::string luaType_, const std::type_info& destination_) : + std::runtime_error("Trying to cast a lua variable from \"" + luaType_ + "\" to \"" + destination_.name() + "\""), + luaType(luaType_), + destination(destination_) + { + } + + std::string luaType; + const std::type_info& destination; + }; + + /** + * Function object that can call a function stored by Lua + * This type is copiable and movable, but not constructible. It can only be created through readVariable. + * @tparam TFunctionType Function type (eg. "int (int, bool)") + */ + template + class LuaFunctionCaller; + + /** + * Opaque type that identifies a Lua object + */ + struct LuaObject { + LuaObject() = default; + LuaObject(lua_State* state, int index=-1) { + this->objectInRegistry = std::make_shared(state, index); + } + std::shared_ptr objectInRegistry; + }; + + /** + * Opaque type that identifies a Lua thread + */ + struct ThreadID { + ThreadID() = default; + ThreadID(ThreadID&& o) : state(o.state), threadInRegistry(std::move(o.threadInRegistry)) { } + ThreadID& operator=(ThreadID&& o) { std::swap(state, o.state); std::swap(threadInRegistry, o.threadInRegistry); return *this; } + public: + friend LuaContext; + lua_State* state; + std::unique_ptr threadInRegistry; + }; + + /** + * Type that is considered as an empty array + */ + enum EmptyArray_t { EmptyArray }; + + /** + * Type for a metatable + */ + enum Metatable_t { Metatable }; + + /** + * Executes lua code from the stream + * @param code A stream that Lua will read its code from + */ + void executeCode(std::istream& code) + { + auto toCall = load(mState, code); + call>(mState, std::move(toCall)); + } + + /** + * Executes lua code from the stream and returns a value + * @param code A stream that Lua will read its code from + * @tparam TType The type that the executing code should return + */ + template + auto executeCode(std::istream& code) + -> TType + { + auto toCall = load(mState, code); + return call(mState, std::move(toCall)); + } + + /** + * Executes lua code given as parameter + * @param code A string containing code that will be executed by Lua + */ + void executeCode(const std::string& code) + { + executeCode(code.c_str()); + } + + /* + * Executes Lua code from the stream and returns a value + * @param code A string containing code that will be executed by Lua + * @tparam TType The type that the executing code should return + */ + template + auto executeCode(const std::string& code) + -> TType + { + return executeCode(code.c_str()); + } + + /** + * Executes Lua code + * @param code A string containing code that will be executed by Lua + */ + void executeCode(const char* code) + { + auto toCall = load(mState, code); + call>(mState, std::move(toCall)); + } + + /* + * Executes Lua code from the stream and returns a value + * @param code A string containing code that will be executed by Lua + * @tparam TType The type that the executing code should return + */ + template + auto executeCode(const char* code) + -> TType + { + auto toCall = load(mState, code); + return call(mState, std::move(toCall)); + } + + /** + * Executes lua code from the stream + * @param code A stream that Lua will read its code from + */ + void executeCode(const ThreadID& thread, std::istream& code) + { + auto toCall = load(thread.state, code); + call>(thread.state, std::move(toCall)); + } + + /** + * Executes lua code from the stream and returns a value + * @param code A stream that Lua will read its code from + * @tparam TType The type that the executing code should return + */ + template + auto executeCode(const ThreadID& thread, std::istream& code) + -> TType + { + auto toCall = load(thread.state, code); + return call(thread.state, std::move(toCall)); + } + + /** + * Executes lua code given as parameter + * @param code A string containing code that will be executed by Lua + */ + void executeCode(const ThreadID& thread, const std::string& code) + { + executeCode(thread, code.c_str()); + } + + /* + * Executes Lua code from the stream and returns a value + * @param code A string containing code that will be executed by Lua + * @tparam TType The type that the executing code should return + */ + template + auto executeCode(const ThreadID& thread, const std::string& code) + -> TType + { + return executeCode(thread, code.c_str()); + } + + /** + * Executes Lua code + * @param code A string containing code that will be executed by Lua + */ + void executeCode(const ThreadID& thread, const char* code) + { + auto toCall = load(thread.state, code); + call>(thread.state, std::move(toCall)); + } + + /* + * Executes Lua code from the stream and returns a value + * @param code A string containing code that will be executed by Lua + * @tparam TType The type that the executing code should return + */ + template + auto executeCode(const ThreadID& thread, const char* code) + -> TType + { + auto toCall = load(thread.state, code); + return call(thread.state, std::move(toCall)); + } + + /** + * Tells that Lua will be allowed to access an object's function + * This is the version "registerFunction(name, &Foo::function)" + */ + template + auto registerFunction(const std::string& name, TPointerToMemberFunction pointer) + -> typename std::enable_if::value>::type + { + registerFunctionImpl(name, std::mem_fn(pointer), tag{}); + } + + /** + * Tells that Lua will be allowed to access an object's function + * This is the version with an explicit template parameter: "registerFunction(name, [](Foo&) { })" + * @param fn Function object which takes as first parameter a reference to the object + * @tparam TFunctionType Pointer-to-member function type + */ + template + void registerFunction(const std::string& functionName, TType fn) + { + static_assert(std::is_member_function_pointer::value, "registerFunction must take a member function pointer type as template parameter"); + registerFunctionImpl(functionName, std::move(fn), tag{}); + } + + /** + * Tells that Lua will be allowed to access an object's function + * This is the alternative version with an explicit template parameter: "registerFunction(name, [](Foo&) { })" + * @param fn Function object which takes as first parameter a reference to the object + * @tparam TObject Object to register this function to + * @tparam TFunctionType Function type + */ + template + void registerFunction(const std::string& functionName, TType fn) + { + static_assert(std::is_function::value, "registerFunction must take a function type as template parameter"); + registerFunctionImpl(functionName, std::move(fn), tag{}, tag{}); + } + + /** + * Inverse operation of registerFunction + * @tparam TType Type whose function belongs to + */ + template + void unregisterFunction(const std::string& /*functionName*/) + { + lua_pushlightuserdata(mState, const_cast(&typeid(TType))); + lua_pushnil(mState); + lua_settable(mState, LUA_REGISTRYINDEX); + checkTypeRegistration(mState, &typeid(TType)); + + lua_pushlightuserdata(mState, const_cast(&typeid(TType*))); + lua_pushnil(mState); + lua_settable(mState, LUA_REGISTRYINDEX); + checkTypeRegistration(mState, &typeid(TType*)); + + lua_pushlightuserdata(mState, const_cast(&typeid(std::shared_ptr))); + lua_pushnil(mState); + lua_settable(mState, LUA_REGISTRYINDEX); + checkTypeRegistration(mState, &typeid(std::shared_ptr)); + } + + /** + * Registers a member variable + * This is the version "registerMember(name, &Foo::member)" + */ + template + void registerMember(const std::string& name, TVarType TObject::*member) + { + // implementation simply calls the custom member with getter and setter + const auto getter = [=](const TObject& obj) -> TVarType { return obj.*member; }; + const auto setter = [=](TObject& obj, const TVarType& value) { obj.*member = value; }; + registerMember(name, getter, setter); + } + + /** + * Registers a member variable + * This is the version "registerMember(name, getter, setter)" + * @tparam TObject Type to register the member to + * @tparam TVarType Type of the member + * @param name Name of the member to register + * @param readFunction Function of type "TVarType (const TObject&)" + * @param writeFunction_ Function of type "void (TObject&, const TVarType&)" + */ + template + void registerMember(const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction_) + { + registerMemberImpl(name, std::move(readFunction), std::move(writeFunction_)); + } + + /** + * Registers a member variable + * This is the version "registerMember(name, getter, setter)" + * @tparam TMemberType Pointer to member object representing the type + * @param name Name of the member to register + * @param readFunction Function of type "TVarType (const TObject&)" + * @param writeFunction_ Function of type "void (TObject&, const TVarType&)" + */ + template + void registerMember(const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction_) + { + static_assert(std::is_member_object_pointer::value, "registerMember must take a member object pointer type as template parameter"); + registerMemberImpl(tag{}, name, std::move(readFunction), std::move(writeFunction_)); + } + + /** + * Registers a non-modifiable member variable + * This is the version "registerMember(name, getter)" + * @tparam TObject Type to register the member to + * @tparam TVarType Type of the member + * @param name Name of the member to register + * @param readFunction Function of type "TVarType (const TObject&)" + */ + template + void registerMember(const std::string& name, TReadFunction readFunction) + { + registerMemberImpl(name, std::move(readFunction)); + } + + /** + * Registers a non-modifiable member variable + * This is the version "registerMember(name, getter)" + * @tparam TMemberType Pointer to member object representing the type + * @param name Name of the member to register + * @param readFunction Function of type "TVarType (const TObject&)" + */ + template + void registerMember(const std::string& name, TReadFunction readFunction) + { + static_assert(std::is_member_object_pointer::value, "registerMember must take a member object pointer type as template parameter"); + registerMemberImpl(tag{}, name, std::move(readFunction)); + } + + /** + * Registers a dynamic member variable + * This is the version "registerMember(getter, setter)" + * @tparam TObject Type to register the member to + * @tparam TVarType Type of the member + * @param readFunction Function of type "TVarType (const TObject&, const std::string&)" + * @param writeFunction_ Function of type "void (TObject&, const std::string&, const TVarType&)" + */ + template + void registerMember(TReadFunction readFunction, TWriteFunction writeFunction_) + { + registerMemberImpl(std::move(readFunction), std::move(writeFunction_)); + } + + /** + * Registers a dynamic member variable + * This is the version "registerMember(getter, setter)" + * @tparam TMemberType Pointer to member object representing the type + * @param readFunction Function of type "TVarType (const TObject&, const std::string&)" + * @param writeFunction_ Function of type "void (TObject&, const std::string&, const TVarType&)" + */ + template + void registerMember(TReadFunction readFunction, TWriteFunction writeFunction_) + { + static_assert(std::is_member_object_pointer::value, "registerMember must take a member object pointer type as template parameter"); + registerMemberImpl(tag{}, std::move(readFunction), std::move(writeFunction_)); + } + + /** + * Registers a dynamic non-modifiable member variable + * This is the version "registerMember(getter)" + * @tparam TObject Type to register the member to + * @tparam TVarType Type of the member + * @param readFunction Function of type "TVarType (const TObject&, const std::string&)" + */ + template + void registerMember(TReadFunction readFunction) + { + registerMemberImpl(std::move(readFunction)); + } + + /** + * Registers a dynamic non-modifiable member variable + * This is the version "registerMember(getter)" + * @tparam TMemberType Pointer to member object representing the type + * @param readFunction Function of type "TVarType (const TObject&, const std::string&)" + */ + template + void registerMember(TReadFunction readFunction) + { + static_assert(std::is_member_object_pointer::value, "registerMember must take a member object pointer type as template parameter"); + registerMemberImpl(tag{}, std::move(readFunction)); + } + + /** + * Creates a new thread + * A Lua thread is not really a thread, but rather an "execution stack". + * You can destroy the thread by calling destroyThread + * @sa destroyThread + */ + auto createThread() + -> ThreadID + { + ThreadID result; + + result.state = lua_newthread(mState); + result.threadInRegistry = std::unique_ptr(new ValueInRegistry(mState)); + lua_pop(mState, 1); + + return result; + } + + /** + * Destroys a thread created with createThread + * @sa createThread + */ + void destroyThread(ThreadID& id) + { + id.threadInRegistry.reset(); + } + + /** + * Reads the content of a Lua variable + * + * @tparam TType Type requested for the read + * @throw WrongTypeException When the variable is not convertible to the requested type + * @sa writeVariable + * + * Readable types are all types accepted by writeVariable except nullptr, std::unique_ptr and function pointers + * Additionally supported: + * - LuaFunctionCaller, which is an alternative to std::function + * - references to custom objects, in which case it will return the object in-place + * + * After the variable name, you can add other parameters. + * If the variable is an array, it will instead get the element of that array whose offset is the second parameter. + * Same applies for third, fourth, etc. parameters. + */ + template + TType readVariable(const std::string& name, TTypes&&... elements) const + { + lua_getglobal(mState, name.c_str()); + lookIntoStackTop(mState, std::forward(elements)...); + return readTopAndPop(mState, PushedObject{mState, 1}); + } + + /** + * @sa readVariable + */ + template + TType readVariable(const char* name, TTypes&&... elements) const + { + lua_getglobal(mState, name); + lookIntoStackTop(mState, std::forward(elements)...); + return readTopAndPop(mState, PushedObject{mState, 1}); + } + + /** + * @sa readVariable + */ + template + TType readVariable(const ThreadID& thread, const std::string& name, TTypes&&... elements) const + { + lua_getglobal(thread.state, name.c_str()); + lookIntoStackTop(thread.state, std::forward(elements)...); + return readTopAndPop(thread.state, PushedObject{thread.state, 1}); + } + + /** + * @sa readVariable + */ + template + TType readVariable(const ThreadID& thread, const char* name, TTypes&&... elements) const + { + lua_getglobal(thread.state, name); + lookIntoStackTop(thread.state, std::forward(elements)...); + return readTopAndPop(thread.state, PushedObject{thread.state, 1}); + } + + /** + * Changes the content of a Lua variable + * + * Accepted values are: + * - all base types (char, short, int, float, double, bool) + * - std::string + * - enums + * - std::vector<> + * - std::vector>, std::map<> and std::unordered_map<> (the key and value must also be accepted values) + * - std::function<> (all parameters must be accepted values, and return type must be either an accepted value for readVariable or a tuple) + * - std::shared_ptr<> (std::unique_ptr<> are converted to std::shared_ptr<>) + * - nullptr (writes nil) + * - any object + * + * All objects are passed by copy and destroyed by the garbage collector if necessary. + */ + template + void writeVariable(TData&&... data) noexcept { + static_assert(sizeof...(TData) >= 2, "You must pass at least a variable name and a value to writeVariable"); + typedef typename std::decay>::type>::type + RealDataType; + static_assert(!std::is_same::type,RealDataType>::value, "Error: you can't use LuaContext::writeVariable with a tuple"); + + setTable(mState, Globals, std::forward(data)...); + } + + /** + * Equivalent to writeVariable(varName, ..., std::function(data)); + * This version is more efficient than writeVariable if you want to write functions + */ + template + void writeFunction(TData&&... data) noexcept { + static_assert(sizeof...(TData) >= 2, "You must pass at least a variable name and a value to writeFunction"); + + setTable(mState, Globals, std::forward(data)...); + } + + /** + * Same as the other writeFunction, except that the template parameter is automatically detected + * This only works if the data is either a native function pointer, or contains one operator() (this is the case for lambdas) + */ + template + void writeFunction(TData&&... data) noexcept { + static_assert(sizeof...(TData) >= 2, "You must pass at least a variable name and a value to writeFunction"); + typedef typename std::decay>::type>::type + RealDataType; + typedef typename FunctionTypeDetector::type + DetectedFunctionType; + + return writeFunction(std::forward(data)...); + } + + +private: + // the state is the most important variable in the class since it is our interface with Lua + // - registered members and functions are stored in tables at offset &typeid(type) of the registry + // each table has its getter functions at offset 0, getter members at offset 1, default getter at offset 2 + // offset 3 is unused, setter members at offset 4, default setter at offset 5 + lua_State* mState; + + + /**************************************************/ + /* PUSH OBJECT */ + /**************************************************/ + struct PushedObject { + PushedObject(lua_State* state_, int num_ = 1) : state(state_), num(num_) {} + ~PushedObject() { assert(lua_gettop(state) >= num); if (num >= 1) lua_pop(state, num); } + + PushedObject& operator=(const PushedObject&) = delete; + PushedObject(const PushedObject&) = delete; + PushedObject& operator=(PushedObject&& other) { std::swap(state, other.state); std::swap(num, other.num); return *this; } + PushedObject(PushedObject&& other) : state(other.state), num(other.num) { other.num = 0; } + + PushedObject operator+(PushedObject&& other) && { PushedObject obj(state, num + other.num); num = 0; other.num = 0; return obj; } + void operator+=(PushedObject&& other) { assert(state == other.state); num += other.num; other.num = 0; } + + auto getState() const -> lua_State* { return state; } + auto getNum() const -> int { return num; } + + int release() { const auto n = num; num = 0; return n; } + void pop() { if (num >= 1) lua_pop(state, num); num = 0; } + void pop(int n) { assert(num >= n); lua_pop(state, n); num -= n; } + + private: + lua_State* state; + int num = 0; + }; + + + /**************************************************/ + /* MISC */ + /**************************************************/ + // type used as a tag + template + struct tag {}; + + // tag for "the registry" + enum RegistryTag { Registry }; + + // this function takes a value representing the offset to look into + // it will look into the top element of the stack and replace the element by its content at the given index + template + static void lookIntoStackTop(lua_State* state, OffsetType1&& offset1, OffsetTypeOthers&&... offsetOthers) { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + auto p1 = Pusher::type>::push(state, offset1); + lua_gettable(state, -2); + lua_remove(state, -2); + p1.release(); + + lookIntoStackTop(state, std::forward(offsetOthers)...); + } + + template + static void lookIntoStackTop(lua_State* state, Metatable_t, OffsetTypeOthers&&... offsetOthers) { + lua_getmetatable(state, -1); + lua_remove(state, -2); + + lookIntoStackTop(state, std::forward(offsetOthers)...); + } + + static void lookIntoStackTop(lua_State*) { + } + + // equivalent of lua_settable with t[k]=n, where t is the value at the index in the template parameter, k is the second parameter, n is the last parameter, and n is pushed by the function in the first parameter + // if there are more than 3 parameters, parameters 3 to n-1 are considered as sub-indices into the array + // the dataPusher MUST push only one thing on the stack + // TTableIndex must be either LUA_REGISTRYINDEX, LUA_GLOBALSINDEX, LUA_ENVINDEX, or the position of the element on the stack + template + static void setTable(lua_State* state, const PushedObject&, TIndex&& index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, index); + auto p2 = Pusher::type>::push(state, std::forward(data)); + + lua_settable(state, -3); + p1.release(); + p2.release(); + } + + template + static void setTable(lua_State* state, const PushedObject&, const std::string& index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, std::forward(data)); + lua_setfield(state, -2, index.c_str()); + p1.release(); + } + + template + static void setTable(lua_State* state, const PushedObject&, const char* index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, std::forward(data)); + lua_setfield(state, -2, index); + p1.release(); + } + + template + static void setTable(lua_State* state, const PushedObject&, Metatable_t, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, std::forward(data)); + lua_setmetatable(state, -2); + p1.release(); + } + + template + static auto setTable(lua_State* state, PushedObject&, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + -> typename std::enable_if::type, Metatable_t>::value>::type + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + + auto p1 = Pusher::type>::push(state, std::forward(index1)); + lua_gettable(state, -2); + + setTable(state, std::move(p1), std::forward(index2), std::forward(index3), std::forward(indices)...); + } + + template + static auto setTable(lua_State* state, PushedObject&& pushedTable, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + -> typename std::enable_if::type, Metatable_t>::value>::type + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + + auto p1 = Pusher::type>::push(state, std::forward(index1)) + std::move(pushedTable); + lua_gettable(state, -2); + + setTable(state, std::move(p1), std::forward(index2), std::forward(index3), std::forward(indices)...); + } + + template + static void setTable(lua_State* state, PushedObject& pushedObject, Metatable_t, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + { + if (lua_getmetatable(state, -1) == 0) + { + lua_newtable(state); + PushedObject p1{state, 1}; + + setTable(state, p1, std::forward(index2), std::forward(index3), std::forward(indices)...); + + lua_setmetatable(state, -2); + p1.release(); + } + else + { + setTable(state, pushedObject, std::forward(index2), std::forward(index3), std::forward(indices)...); + } + } + + template + static void setTable(lua_State* state, PushedObject&& pushedObject, Metatable_t, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + { + if (lua_getmetatable(state, -1) == 0) + { + lua_newtable(state); + PushedObject p1{state, 1}; + + setTable(state, p1, std::forward(index2), std::forward(index3), std::forward(indices)...); + + lua_setmetatable(state, -2); + p1.release(); + } + else + { + setTable(state, std::move(pushedObject), std::forward(index2), std::forward(index3), std::forward(indices)...); + } + } + + template + static void setTable(lua_State* state, RegistryTag, TIndex&& index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, index); + auto p2 = Pusher::type>::push(state, std::forward(data)); + + lua_settable(state, LUA_REGISTRYINDEX); + p1.release(); + p2.release(); + } + + template + static void setTable(lua_State* state, RegistryTag, const std::string& index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, std::forward(data)); + lua_setfield(state, LUA_REGISTRYINDEX, index.c_str()); + p1.release(); + } + + template + static void setTable(lua_State* state, RegistryTag, const char* index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, std::forward(data)); + lua_setfield(state, LUA_REGISTRYINDEX, index); + p1.release(); + } + + template + static void setTable(lua_State* state, RegistryTag, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + + auto p1 = Pusher::type>::push(state, std::forward(index1)); + lua_gettable(state, LUA_REGISTRYINDEX); + + setTable(state, std::move(p1), std::forward(index2), std::forward(index3), std::forward(indices)...); + } + + template + static void setTable(lua_State* state, Globals_t, TIndex&& index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + +# if LUA_VERSION_NUM >= 502 + + lua_pushglobaltable(state); + PushedObject p3{state, 1}; + auto p1 = Pusher::type>::push(state, index); + auto p2 = Pusher::type>::push(state, std::forward(data)); + lua_settable(state, -3); + +# else + + auto p1 = Pusher::type>::push(state, index); + auto p2 = Pusher::type>::push(state, std::forward(data)); + lua_settable(state, LUA_GLOBALSINDEX); + +# endif + + p1.release(); + p2.release(); + } + + template + static void setTable(lua_State* state, Globals_t, const std::string& index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, std::forward(data)); + lua_setglobal(state, index.c_str()); + p1.release(); + } + + template + static void setTable(lua_State* state, Globals_t, const char* index, TData&& data) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values data"); + + auto p1 = Pusher::type>::push(state, std::forward(data)); + lua_setglobal(state, index); + p1.release(); + } + + template + static void setTable(lua_State* state, Globals_t, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Impossible to have a multiple-values index"); + +# if LUA_VERSION_NUM >= 502 + + lua_pushglobaltable(state); + auto p1 = Pusher::type>::push(state, std::forward(index1)) + PushedObject{state, 1}; + lua_gettable(state, -2); + +# else + + auto p1 = Pusher::type>::push(state, std::forward(index1)); + lua_gettable(state, LUA_GLOBALSINDEX); + +# endif + + setTable(state, std::move(p1), std::forward(index2), std::forward(index3), std::forward(indices)...); + } + + // TODO: g++ reports "ambiguous overload" + /*template + static void setTable(lua_State* state, Globals_t, const char* index, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + { + lua_getglobal(state, index); + PushedObject p1{state, 1}; + + setTable(state, std::move(p1), std::forward(index2), std::forward(index3), std::forward(indices)...); + } + + template + static void setTable(lua_State* state, Globals_t, const std::string& index, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept + { + lua_getglobal(state, index.c_str()); + PushedObject p1{state, 1}; + + setTable(state, std::move(p1), std::forward(index2), std::forward(index3), std::forward(indices)...); + }*/ + + // simple function that reads the "nb" first top elements of the stack, pops them, and returns the value + // warning: first parameter is the number of parameters, not the parameter index + // if read generates an exception, stack is poped anyway + template + static auto readTopAndPop(lua_State* state, PushedObject object) + -> TReturnType + { + auto val = Reader::type>::read(state, -object.getNum()); + if (!val.is_initialized()) + throw WrongTypeException{lua_typename(state, lua_type(state, -object.getNum())), typeid(TReturnType)}; + return val.get(); + } + + // checks that the offsets for a type's registrations are set in the registry + static void checkTypeRegistration(lua_State* state, const std::type_info* type) + { + lua_pushlightuserdata(state, const_cast(type)); + lua_gettable(state, LUA_REGISTRYINDEX); + if (!lua_isnil(state, -1)) { + lua_pop(state, 1); + return; + } + lua_pop(state, 1); + + lua_pushlightuserdata(state, const_cast(type)); + lua_newtable(state); + + lua_pushinteger(state, 0); + lua_newtable(state); + lua_settable(state, -3); + + lua_pushinteger(state, 1); + lua_newtable(state); + lua_settable(state, -3); + + lua_pushinteger(state, 3); + lua_newtable(state); + lua_settable(state, -3); + + lua_pushinteger(state, 4); + lua_newtable(state); + lua_settable(state, -3); + + lua_settable(state, LUA_REGISTRYINDEX); + } + + // +# ifdef _MSC_VER + __declspec(noreturn) +# else + [[noreturn]] +# endif + static void luaError(lua_State* state) + { + lua_error(state); + assert(false); + std::terminate(); // removes compilation warning + } + + + /**************************************************/ + /* FUNCTIONS REGISTRATION */ + /**************************************************/ + // the "registerFunction" public functions call this one + template + void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag, tag) + { + static_assert(std::is_class::value || std::is_pointer::value || std::is_union::value , "registerFunction can only be used for a class a union or a pointer"); + + checkTypeRegistration(mState, &typeid(TObject)); + setTable(mState, Registry, &typeid(TObject), 0, functionName, std::move(function)); + + checkTypeRegistration(mState, &typeid(TObject*)); + setTable(mState, Registry, &typeid(TObject*), 0, functionName, [=](TObject* obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward(rest)...); }); + + checkTypeRegistration(mState, &typeid(std::shared_ptr)); + setTable, TOtherParams...)>(mState, Registry, &typeid(std::shared_ptr), 0, functionName, [=](const std::shared_ptr& obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward(rest)...); }); + } + + template + void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag, tag fTypeTag) + { + registerFunctionImpl(functionName, function, tag{}, fTypeTag); + + checkTypeRegistration(mState, &typeid(TObject const*)); + setTable(mState, Registry, &typeid(TObject const*), 0, functionName, [=](TObject const* obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward(rest)...); }); + + checkTypeRegistration(mState, &typeid(std::shared_ptr)); + setTable, TOtherParams...)>(mState, Registry, &typeid(std::shared_ptr), 0, functionName, [=](const std::shared_ptr& obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward(rest)...); }); + } + + template + void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag) + { + registerFunctionImpl(functionName, std::move(function), tag{}, tag{}); + } + + template + void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag) + { + registerFunctionImpl(functionName, std::move(function), tag{}, tag{}); + } + + template + void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag) + { + registerFunctionImpl(functionName, std::move(function), tag{}, tag{}); + } + + template + void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag) + { + registerFunctionImpl(functionName, std::move(function), tag{}, tag{}); + } + + // the "registerMember" public functions call this one + template + void registerMemberImpl(const std::string& name, TReadFunction readFunction) + { + static_assert(std::is_class::value || std::is_pointer::value, "registerMember can only be called on a class or a pointer"); + + checkTypeRegistration(mState, &typeid(TObject)); + setTable(mState, Registry, &typeid(TObject), 1, name, [readFunction](TObject const& object) { + return readFunction(object); + }); + + checkTypeRegistration(mState, &typeid(TObject*)); + setTable(mState, Registry, &typeid(TObject*), 1, name, [readFunction](TObject const* object) { + assert(object); + return readFunction(*object); + }); + + checkTypeRegistration(mState, &typeid(TObject const*)); + setTable(mState, Registry, &typeid(TObject const*), 1, name, [readFunction](TObject const* object) { + assert(object); + return readFunction(*object); + }); + + checkTypeRegistration(mState, &typeid(std::shared_ptr)); + setTable)>(mState, Registry, &typeid(std::shared_ptr), 1, name, [readFunction](const std::shared_ptr& object) { + assert(object); + return readFunction(*object); + }); + + checkTypeRegistration(mState, &typeid(std::shared_ptr)); + setTable)>(mState, Registry, &typeid(std::shared_ptr), 1, name, [readFunction](const std::shared_ptr& object) { + assert(object); + return readFunction(*object); + }); + } + + template + void registerMemberImpl(const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction_) + { + registerMemberImpl(name, readFunction); + + setTable(mState, Registry, &typeid(TObject), 4, name, [writeFunction_](TObject& object, const TVarType& value) { + writeFunction_(object, value); + }); + + setTable(mState, Registry, &typeid(TObject*), 4, name, [writeFunction_](TObject* object, const TVarType& value) { + assert(object); + writeFunction_(*object, value); + }); + + setTable, TVarType)>(mState, Registry, &typeid(std::shared_ptr), 4, name, [writeFunction_](std::shared_ptr object, const TVarType& value) { + assert(object); + writeFunction_(*object, value); + }); + } + + template + void registerMemberImpl(tag, const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction_) + { + registerMemberImpl(name, std::move(readFunction), std::move(writeFunction_)); + } + + template + void registerMemberImpl(tag, const std::string& name, TReadFunction readFunction) + { + registerMemberImpl(name, std::move(readFunction)); + } + + // the "registerMember" public functions call this one + template + void registerMemberImpl(TReadFunction readFunction) + { + checkTypeRegistration(mState, &typeid(TObject)); + setTable(mState, Registry, &typeid(TObject), 2, [readFunction](TObject const& object, const std::string& name) { + return readFunction(object, name); + }); + + checkTypeRegistration(mState, &typeid(TObject*)); + setTable(mState, Registry, &typeid(TObject*), 2, [readFunction](TObject const* object, const std::string& name) { + assert(object); + return readFunction(*object, name); + }); + + checkTypeRegistration(mState, &typeid(TObject const*)); + setTable(mState, Registry, &typeid(TObject const*), 2, [readFunction](TObject const* object, const std::string& name) { + assert(object); + return readFunction(*object, name); + }); + + checkTypeRegistration(mState, &typeid(std::shared_ptr)); + setTable, std::string)>(mState, Registry, &typeid(std::shared_ptr), 2, [readFunction](const std::shared_ptr& object, const std::string& name) { + assert(object); + return readFunction(*object, name); + }); + + checkTypeRegistration(mState, &typeid(std::shared_ptr)); + setTable, std::string)>(mState, Registry, &typeid(std::shared_ptr), 2, [readFunction](const std::shared_ptr& object, const std::string& name) { + assert(object); + return readFunction(*object, name); + }); + } + + template + void registerMemberImpl(TReadFunction readFunction, TWriteFunction writeFunction_) + { + registerMemberImpl(readFunction); + + setTable(mState, Registry, &typeid(TObject), 5, [writeFunction_](TObject& object, const std::string& name, const TVarType& value) { + writeFunction_(object, name, value); + }); + + setTable(mState, Registry, &typeid(TObject*), 2, [writeFunction_](TObject* object, const std::string& name, const TVarType& value) { + assert(object); + writeFunction_(*object, name, value); + }); + + setTable, std::string, TVarType)>(mState, Registry, &typeid(std::shared_ptr), 2, [writeFunction_](const std::shared_ptr& object, const std::string& name, const TVarType& value) { + assert(object); + writeFunction_(*object, name, value); + }); + } + + template + void registerMemberImpl(tag, TReadFunction readFunction, TWriteFunction writeFunction_) + { + registerMemberImpl(std::move(readFunction), std::move(writeFunction_)); + } + + template + void registerMemberImpl(tag, TReadFunction readFunction) + { + registerMemberImpl(std::move(readFunction)); + } + + + /**************************************************/ + /* LOADING AND CALLING */ + /**************************************************/ + // this function loads data from the stream and pushes a function at the top of the stack + // throws in case of syntax error + static PushedObject load(lua_State* state, std::istream& code) { + // since the lua_load function requires a static function, we use this structure + // the Reader structure is at the same time an object storing an istream and a buffer, + // and a static function provider + struct Reader { + Reader(std::istream& str) : stream(str) {} + std::istream& stream; + std::array buffer; + + // read function ; "data" must be an instance of Reader + static const char* read(lua_State* /*l*/, void* data, size_t* size) { + assert(size != nullptr); + assert(data != nullptr); + Reader& me = *static_cast(data); + if (me.stream.eof()) { *size = 0; return nullptr; } + + me.stream.read(me.buffer.data(), me.buffer.size()); + *size = static_cast(me.stream.gcount()); // gcount could return a value larger than a size_t, but its maximum is me.buffer.size() so there's no problem + return me.buffer.data(); + } + }; + + // we create an instance of Reader, and we call lua_load + Reader reader{code}; + const auto loadReturnValue = lua_load(state, &Reader::read, &reader, "chunk" +# if LUA_VERSION_NUM >= 502 + , nullptr +# endif + ); + + // now we have to check return value + if (loadReturnValue != 0) { + // there was an error during loading, an error message was pushed on the stack + const std::string errorMsg = lua_tostring(state, -1); + lua_pop(state, 1); + if (loadReturnValue == LUA_ERRMEM) + throw std::bad_alloc(); + else if (loadReturnValue == LUA_ERRSYNTAX) + throw SyntaxErrorException{errorMsg}; + throw std::runtime_error("Error while calling lua_load: " + errorMsg); + } + + return PushedObject{state, 1}; + } + + // this function loads data and pushes a function at the top of the stack + // throws in case of syntax error + static PushedObject load(lua_State* state, const char* code) { + auto loadReturnValue = luaL_loadstring(state, code); + + // now we have to check return value + if (loadReturnValue != 0) { + // there was an error during loading, an error message was pushed on the stack + const std::string errorMsg = lua_tostring(state, -1); + lua_pop(state, 1); + if (loadReturnValue == LUA_ERRMEM) + throw std::bad_alloc(); + else if (loadReturnValue == LUA_ERRSYNTAX) + throw SyntaxErrorException{errorMsg}; + throw std::runtime_error("Error while calling lua_load: " + errorMsg); + } + + return PushedObject{state, 1}; + } + + // this function calls what is on the top of the stack and removes it (just like lua_call) + // if an exception is triggered, the top of the stack will be removed anyway + template + static auto call(lua_State* state, PushedObject toCall, TParameters&&... input) + -> TReturnType + { + typedef typename Tupleizer::type + RealReturnType; + + // we push the parameters on the stack + auto inArguments = Pusher>::push(state, std::forward_as_tuple(std::forward(input)...)); + + // + const int outArgumentsCount = std::tuple_size::value; + auto outArguments = callRaw(state, std::move(toCall) + std::move(inArguments), outArgumentsCount); + + // pcall succeeded, we pop the returned values and return them + return readTopAndPop(state, std::move(outArguments)); + } + + // this function just calls lua_pcall and checks for errors + static PushedObject callRaw(lua_State* state, PushedObject functionAndArguments, const int outArguments) + { + // calling pcall automatically pops the parameters and pushes output + const auto pcallReturnValue = lua_pcall(state, functionAndArguments.getNum() - 1, outArguments, 0); + functionAndArguments.release(); + + // if pcall failed, analyzing the problem and throwing + if (pcallReturnValue != 0) { + PushedObject errorCode{state, 1}; + + // an error occured during execution, either an error message or a std::exception_ptr was pushed on the stack + if (pcallReturnValue == LUA_ERRMEM) { + throw std::bad_alloc{}; + + } else if (pcallReturnValue == LUA_ERRRUN) { + if (lua_isstring(state, 1)) { + // the error is a string + const auto str = readTopAndPop(state, std::move(errorCode)); + throw ExecutionErrorException{str}; + + } else { + // an exception_ptr was pushed on the stack + // rethrowing it with an additional ExecutionErrorException + try { + if (const auto exp = readTopAndPop(state, std::move(errorCode))) { + std::rethrow_exception(exp); + } + } catch(...) { + std::throw_with_nested(ExecutionErrorException{"Exception thrown by a callback function called by Lua"}); + } + throw ExecutionErrorException{"Unknown Lua error"}; + } + } + } + + return PushedObject{state, outArguments}; + } + + + /**************************************************/ + /* PUSH FUNCTIONS */ + /**************************************************/ + template + static PushedObject push(lua_State* state, T&& value) + { + return Pusher::type>::push(state, std::forward(value)); + } + + // the Pusher structures allow you to push a value on the stack + // - static const int minSize : minimum size on the stack that the value can have + // - static const int maxSize : maximum size on the stack that the value can have + // - static int push(const LuaContext&, ValueType) : pushes the value on the stack and returns the size on the stack + + // implementation for custom objects + template + struct Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + template + static PushedObject push(lua_State* state, TType2&& value) noexcept { + // this function is called when lua's garbage collector wants to destroy our object + // we simply call its destructor + const auto garbageCallbackFunction = [](lua_State* lua) -> int { + assert(lua_gettop(lua) == 1); + TType* ptr = static_cast(lua_touserdata(lua, 1)); + assert(ptr); + ptr->~TType(); + return 0; + }; + + // this function will be stored in __index in the metatable + const auto indexFunction = [](lua_State* lua) -> int { + try { + assert(lua_gettop(lua) == 2); + assert(lua_isuserdata(lua, 1)); + + // searching for a handler + lua_pushlightuserdata(lua, const_cast(&typeid(TType))); + lua_gettable(lua, LUA_REGISTRYINDEX); + assert(!lua_isnil(lua, -1)); + + // looking into getter functions + lua_pushinteger(lua, 0); + lua_gettable(lua, -2); + lua_pushvalue(lua, 2); + lua_gettable(lua, -2); + if (!lua_isnil(lua, -1)) + return 1; + lua_pop(lua, 2); + + // looking into getter members + lua_pushinteger(lua, 1); + lua_gettable(lua, -2); + lua_pushvalue(lua, 2); + lua_gettable(lua, -2); + if (!lua_isnil(lua, -1)) { + lua_pushvalue(lua, 1); + return callRaw(lua, PushedObject{lua, 2}, 1).release(); + } + lua_pop(lua, 2); + + // looking into default getter + lua_pushinteger(lua, 2); + lua_gettable(lua, -2); + if (lua_isnil(lua, -1)) + return 1; + lua_pushvalue(lua, 1); + lua_pushvalue(lua, 2); + return callRaw(lua, PushedObject{lua, 3}, 1).release(); + + } catch (...) { + Pusher::push(lua, std::current_exception()).release(); + luaError(lua); + } + }; + + // this function will be stored in __newindex in the metatable + const auto newIndexFunction = [](lua_State* lua) -> int { + try { + assert(lua_gettop(lua) == 3); + assert(lua_isuserdata(lua, 1)); + + // searching for a handler + lua_pushlightuserdata(lua, const_cast(&typeid(TType))); + lua_rawget(lua, LUA_REGISTRYINDEX); + assert(!lua_isnil(lua, -1)); + + // looking into setter members + lua_pushinteger(lua, 4); + lua_rawget(lua, -2); + lua_pushvalue(lua, 2); + lua_rawget(lua, -2); + if (!lua_isnil(lua, -1)) { + lua_pushvalue(lua, 1); + lua_pushvalue(lua, 3); + callRaw(lua, PushedObject{lua, 3}, 0); + lua_pop(lua, 2); + return 0; + } + lua_pop(lua, 2); + + // looking into default setter + lua_pushinteger(lua, 5); + lua_rawget(lua, -2); + if (lua_isnil(lua, -1)) + { + lua_pop(lua, 2); + lua_pushstring(lua, "No setter found"); + luaError(lua); + } + lua_pushvalue(lua, 1); + lua_pushvalue(lua, 2); + lua_pushvalue(lua, 3); + callRaw(lua, PushedObject{lua, 4}, 0); + lua_pop(lua, 1); + return 0; + + } catch (...) { + Pusher::push(lua, std::current_exception()).release(); + luaError(lua); + } + }; + + // writing structure for this type into the registry + checkTypeRegistration(state, &typeid(TType)); + + // creating the object + // lua_newuserdata allocates memory in the internals of the lua library and returns it so we can fill it + // and that's what we do with placement-new + const auto pointerLocation = static_cast(lua_newuserdata(state, sizeof(TType))); + new (pointerLocation) TType(std::forward(value)); + PushedObject obj{state, 1}; + + // creating the metatable (over the object on the stack) + // lua_settable pops the key and value we just pushed, so stack management is easy + // all that remains on the stack after these function calls is the metatable + lua_newtable(state); + PushedObject pushedTable{state, 1}; + + // using the garbage collecting function we created above + if (!boost::has_trivial_destructor::value) + { + lua_pushstring(state, "__gc"); + lua_pushcfunction(state, garbageCallbackFunction); + lua_settable(state, -3); + } + + // the _typeid index of the metatable will store the type_info* + lua_pushstring(state, "_typeid"); + lua_pushlightuserdata(state, const_cast(&typeid(TType))); + lua_settable(state, -3); + + // using the index function we created above + lua_pushstring(state, "__index"); + lua_pushcfunction(state, indexFunction); + lua_settable(state, -3); + + // using the newindex function we created above + lua_pushstring(state, "__newindex"); + lua_pushcfunction(state, newIndexFunction); + lua_settable(state, -3); + + // at this point, the stack contains the object at offset -2 and the metatable at offset -1 + // lua_setmetatable will bind the two together and pop the metatable + // our custom type remains on the stack (and that's what we want since this is a push function) + lua_setmetatable(state, -2); + pushedTable.release(); + + return obj; + } + }; + + // this structure has a "size" int static member which is equal to the total of the push min size of all the types + template + struct PusherTotalMinSize; + + // this structure has a "size" int static member which is equal to the total of the push max size of all the types + template + struct PusherTotalMaxSize; + + // this structure has a "size" int static member which is equal to the maximum size of the push of all the types + template + struct PusherMinSize; + + // this structure has a "size" int static member which is equal to the maximum size of the push of all the types + template + struct PusherMaxSize; + + + /**************************************************/ + /* READ FUNCTIONS */ + /**************************************************/ + // the "Reader" structures allow to read data from the stack + // - the "ReturnType" type is what is returned by the reader, and can be different than the template parameter (especially with references and constness) + // - the "read" static function will check and read at the same time, returning an empty optional if it is the wrong type + + template + struct Reader { + typedef typename std::conditional::value, TType, TType&>::type + ReturnType; + + static auto read(lua_State* state, int index) + -> boost::optional + { + if (!test(state, index)) + return boost::none; + return boost::optional(*static_cast(lua_touserdata(state, index))); + } + + private: + static bool test(lua_State* state, int index) + { + if (!lua_isuserdata(state, index)) + return false; + if (!lua_getmetatable(state, index)) + return false; + + // now we have our metatable on the top of the stack + // retrieving its _typeid member + lua_pushstring(state, "_typeid"); + lua_gettable(state, -2); + const auto storedTypeID = static_cast(lua_touserdata(state, -1)); + const auto typeIDToCompare = &typeid(TType); + + // if wrong typeid, returning false + lua_pop(state, 2); + if (storedTypeID != typeIDToCompare) + return false; + + return true; + } + }; + + /** + * This functions reads multiple values starting at "index" and passes them to the callback + */ + template + static auto readIntoFunction(lua_State* /*state*/, tag, TCallback&& callback, int /*index*/) + -> TRetValue + { + return callback(); + } + template + static auto readIntoFunction(lua_State* state, tag retValueTag, TCallback&& callback, int index, tag, tag... othersTags) + -> typename std::enable_if::value, TRetValue>::type + { + if (index >= 0) { + Binder binder{ callback, {} }; + return readIntoFunction(state, retValueTag, binder, index + 1, othersTags...); + } + + const auto& firstElem = Reader::type>::read(state, index); + if (!firstElem) + throw WrongTypeException(lua_typename(state, lua_type(state, index)), typeid(TFirstType)); + + Binder binder{ callback, *firstElem }; + return readIntoFunction(state, retValueTag, binder, index + 1, othersTags...); + } + template + static auto readIntoFunction(lua_State* state, tag retValueTag, TCallback&& callback, int index, tag, tag... othersTags) + -> typename std::enable_if::value, TRetValue>::type + { + if (index >= 0) + throw std::logic_error("Wrong number of parameters"); + + const auto& firstElem = Reader::type>::read(state, index); + if (!firstElem) + throw WrongTypeException(lua_typename(state, lua_type(state, index)), typeid(TFirstType)); + + Binder binder{ callback, *firstElem }; + return readIntoFunction(state, retValueTag, binder, index + 1, othersTags...); + } + + + /**************************************************/ + /* UTILITIES */ + /**************************************************/ + // structure that will ensure that a certain value is stored somewhere in the registry + struct ValueInRegistry { + // this constructor will clone and hold the value at the specified index (or by default at the top of the stack) in the registry + ValueInRegistry(lua_State* lua_, int index=-1) : lua{lua_} + { + lua_pushlightuserdata(lua, this); + lua_pushvalue(lua, -1 + index); + lua_settable(lua, LUA_REGISTRYINDEX); + } + + // removing the function from the registry + ~ValueInRegistry() + { + lua_pushlightuserdata(lua, this); + lua_pushnil(lua); + lua_settable(lua, LUA_REGISTRYINDEX); + } + + // loads the value and puts it at the top of the stack + PushedObject pop() + { + lua_pushlightuserdata(lua, this); + lua_gettable(lua, LUA_REGISTRYINDEX); + return PushedObject{lua, 1}; + } + + ValueInRegistry(const ValueInRegistry&) = delete; + ValueInRegistry& operator=(const ValueInRegistry&) = delete; + + private: + lua_State* lua; + }; + + // binds the first parameter of a function object + template + struct Binder { + TFunctionObject function; + TFirstParamType param; + + template + auto operator()(TParams&&... params) + -> decltype(function(param, std::forward(params)...)) + { + return function(param, std::forward(params)...); + } + }; + + // turns a type into a tuple + // void is turned into std::tuple<> + // existing tuples are untouched + template + struct Tupleizer; + + // this structure takes a pointer to a member function type and returns the base function type + template + struct RemoveMemberPointerFunction { typedef void type; }; // required because of a compiler bug + + // this structure takes any object and detects its function type + template + struct FunctionTypeDetector { typedef typename RemoveMemberPointerFunction::type::operator())>::type type; }; + + // this structure takes a function arguments list and has the "min" and the "max" static const member variables, whose value equal to the min and max number of parameters for the function + // the only case where "min != max" is with boost::optional at the end of the list + template + struct FunctionArgumentsCounter {}; + + // true is the template parameter is a boost::optional + template + struct IsOptional : public std::false_type {}; +}; + +/// @deprecated +static LuaContext::EmptyArray_t ATTR_UNUSED + LuaEmptyArray {}; +/// @deprecated +static LuaContext::Metatable_t ATTR_UNUSED + LuaMetatable {}; + +/**************************************************/ +/* PARTIAL IMPLEMENTATIONS */ +/**************************************************/ +template<> +inline auto LuaContext::readTopAndPop(lua_State* /*state*/, PushedObject /*obj*/) + -> void +{ +} + +// this structure takes a template parameter T +// if T is a tuple, it returns T ; if T is not a tuple, it returns std::tuple +// we have to use this structure because std::tuple> triggers a bug in both MSVC++ and GCC +template +struct LuaContext::Tupleizer { typedef std::tuple type; }; +template +struct LuaContext::Tupleizer> { typedef std::tuple type; }; +template<> +struct LuaContext::Tupleizer { typedef std::tuple<> type; }; + +// this structure takes any object and detects its function type +template +struct LuaContext::FunctionTypeDetector { typedef TRetValue type(TParameters...); }; +template +struct LuaContext::FunctionTypeDetector { typedef typename FunctionTypeDetector::type type; }; + +// this structure takes a pointer to a member function type and returns the base function type +template +struct LuaContext::RemoveMemberPointerFunction { typedef TRetValue type(TParameters...); }; +template +struct LuaContext::RemoveMemberPointerFunction { typedef TRetValue type(TParameters...); }; +template +struct LuaContext::RemoveMemberPointerFunction { typedef TRetValue type(TParameters...); }; +template +struct LuaContext::RemoveMemberPointerFunction { typedef TRetValue type(TParameters...); }; + +// implementation of PusherTotalMinSize +template +struct LuaContext::PusherTotalMinSize { static const int size = Pusher::type>::minSize + PusherTotalMinSize::size; }; +template<> +struct LuaContext::PusherTotalMinSize<> { static const int size = 0; }; + +// implementation of PusherTotalMaxSize +template +struct LuaContext::PusherTotalMaxSize { static const int size = Pusher::type>::maxSize + PusherTotalMaxSize::size; }; +template<> +struct LuaContext::PusherTotalMaxSize<> { static const int size = 0; }; + +// implementation of PusherMinSize +template +struct LuaContext::PusherMinSize +{ + static const int size = Pusher::type>::minSize < Pusher::type>::minSize + ? + PusherMinSize::type, TTypes...>::size + : + PusherMinSize::type, TTypes...>::size; +}; + +template +struct LuaContext::PusherMinSize { static const int size = Pusher::type>::minSize; }; + +// implementation of PusherMaxSize +template +struct LuaContext::PusherMaxSize { static const int size = Pusher::type>::maxSize > PusherTotalMaxSize::size ? Pusher::type>::maxSize : PusherMaxSize::size; }; +template<> +struct LuaContext::PusherMaxSize<> { static const int size = 0; }; + +// implementation of FunctionArgumentsCounter +template +struct LuaContext::FunctionArgumentsCounter { + typedef FunctionArgumentsCounter + SubType; + static const int min = (IsOptional::value && SubType::min == 0) ? 0 : 1 + SubType::min; + static const int max = 1 + SubType::max; +}; +template<> +struct LuaContext::FunctionArgumentsCounter<> { + static const int min = 0; + static const int max = 0; +}; + +// implementation of IsOptional +template +struct LuaContext::IsOptional> : public std::true_type {}; + +// implementation of LuaFunctionCaller +template +class LuaContext::LuaFunctionCaller { static_assert(std::is_function::value, "Template parameter of LuaFunctionCaller must be a function type"); }; +template +class LuaContext::LuaFunctionCaller +{ +public: + TRetValue operator()(TParams&&... params) const + { + auto obj = valueHolder->pop(); + return call(state, std::move(obj), std::forward(params)...); + } + +private: + std::shared_ptr valueHolder; + lua_State* state; + +private: + friend LuaContext; + explicit LuaFunctionCaller(lua_State* state_, int index) : + valueHolder(std::make_shared(state_, index)), + state(state_) + {} +}; + + +/**************************************************/ +/* PUSH FUNCTIONS */ +/**************************************************/ +// specializations of the Pusher structure + +// opaque Lua references +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const LuaContext::LuaObject& value) noexcept { + if (value.objectInRegistry.get()) { + PushedObject obj = value.objectInRegistry->pop(); + return obj; + } else { + lua_pushnil(state); + return PushedObject{state, 1}; + } + } +}; + +// boolean +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, bool value) noexcept { + lua_pushboolean(state, value); + return PushedObject{state, 1}; + } +}; + +// string +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const std::string& value) noexcept { + lua_pushlstring(state, value.c_str(), value.length()); + return PushedObject{state, 1}; + } +}; + +// const char* +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const char* value) noexcept { + lua_pushstring(state, value); + return PushedObject{state, 1}; + } +}; + +// const char[N] +template +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const char* value) noexcept { + lua_pushstring(state, value); + return PushedObject{state, 1}; + } +}; + +// floating numbers +template +struct LuaContext::Pusher::value>::type> { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, T value) noexcept { + lua_pushnumber(state, value); + return PushedObject{state, 1}; + } +}; + +// integers +template +struct LuaContext::Pusher::value>::type> { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, T value) noexcept { + lua_pushinteger(state, value); + return PushedObject{state, 1}; + } +}; + +// nil +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, std::nullptr_t) noexcept { + lua_pushnil(state); + return PushedObject{state, 1}; + } +}; + +// empty arrays +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, EmptyArray_t) noexcept { + lua_newtable(state); + return PushedObject{state, 1}; + } +}; + +// std::type_info* is a lightuserdata +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const std::type_info* ptr) noexcept { + lua_pushlightuserdata(state, const_cast(ptr)); + return PushedObject{state, 1}; + } +}; + +// thread +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const LuaContext::ThreadID& value) noexcept { + lua_pushthread(value.state); + return PushedObject{state, 1}; + } +}; + +// maps +template +struct LuaContext::Pusher> { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const std::map& value) noexcept { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Can't push multiple elements for a table key"); + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Can't push multiple elements for a table value"); + + auto obj = Pusher::push(state, EmptyArray); + + for (auto i = value.begin(), e = value.end(); i != e; ++i) + setTable(state, obj, i->first, i->second); + + return obj; + } +}; + +// unordered_maps +template +struct LuaContext::Pusher> { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const std::unordered_map& value) noexcept { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Can't push multiple elements for a table key"); + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Can't push multiple elements for a table value"); + + auto obj = Pusher::push(state, EmptyArray); + + for (auto i = value.begin(), e = value.end(); i != e; ++i) + setTable(state, obj, i->first, i->second); + + return obj; + } +}; + +// vectors of pairs +template +struct LuaContext::Pusher>> { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const std::vector>& value) noexcept { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Can't push multiple elements for a table key"); + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Can't push multiple elements for a table value"); + + auto obj = Pusher::push(state, EmptyArray); + + for (auto i = value.begin(), e = value.end(); i != e; ++i) + setTable(state, obj, i->first, i->second); + + return obj; + } +}; + +// vectors +template +struct LuaContext::Pusher> { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, const std::vector& value) noexcept { + static_assert(Pusher::type>::minSize == 1 && Pusher::type>::maxSize == 1, "Can't push multiple elements for a table value"); + + auto obj = Pusher::push(state, EmptyArray); + + for (unsigned int i = 0; i < value.size(); ++i) + setTable(state, obj, i + 1, value[i]); + + return obj; + } +}; + +// unique_ptr +template +struct LuaContext::Pusher> { + static const int minSize = Pusher>::minSize; + static const int maxSize = Pusher>::maxSize; + + static PushedObject push(lua_State* state, std::unique_ptr value) noexcept { + return Pusher>::push(state, std::move(value)); + } +}; + +// enum +template +struct LuaContext::Pusher::value>::type> { + #if !defined(__clang__) || __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ > 3) + typedef typename std::underlying_type::type + RealType; + #else + // implementation when std::underlying_type is not supported + typedef unsigned long + RealType; + #endif + + static const int minSize = Pusher::minSize; + static const int maxSize = Pusher::maxSize; + + static PushedObject push(lua_State* state, TEnum value) noexcept { + return Pusher::push(state, static_cast(value)); + } +}; + +// any function +// this specialization is not directly called, but is called by other specializations +template +struct LuaContext::Pusher +{ + static const int minSize = 1; + static const int maxSize = 1; + + // counts the number of arguments + typedef FunctionArgumentsCounter + LocalFunctionArgumentsCounter; + + // this is the version of "push" for non-trivially destructible function objects + template + static auto push(lua_State* state, TFunctionObject fn) noexcept + -> typename std::enable_if::value, PushedObject>::type + { + // TODO: is_move_constructible not supported by some compilers + //static_assert(std::is_move_constructible::value, "The function object must be move-constructible"); + + // when the lua script calls the thing we will push on the stack, we want "fn" to be executed + // if we used lua's cfunctions system, we could not detect when the function is no longer in use, which could cause problems + // so we use userdata instead + + // this function is called when the lua script tries to call our custom data type + // we transfer execution to the "callback" function below + const auto callCallback = [](lua_State* lua) -> int { + assert(lua_gettop(lua) >= 1); + assert(lua_isuserdata(lua, 1)); + auto function = static_cast(lua_touserdata(lua, 1)); + assert(function); + + return callback(lua, function, lua_gettop(lua) - 1).release(); + }; + + // this one is called when lua's garbage collector no longer needs our custom data type + // we call the function object's destructor + const auto garbageCallback = [](lua_State* lua) -> int { + assert(lua_gettop(lua) == 1); + auto function = static_cast(lua_touserdata(lua, 1)); + assert(function); + function->~TFunctionObject(); + return 0; + }; + + // creating the object + // lua_newuserdata allocates memory in the internals of the lua library and returns it so we can fill it + // and that's what we do with placement-new + const auto functionLocation = static_cast(lua_newuserdata(state, sizeof(TFunctionObject))); + new (functionLocation) TFunctionObject(std::move(fn)); + + // creating the metatable (over the object on the stack) + // lua_settable pops the key and value we just pushed, so stack management is easy + // all that remains on the stack after these function calls is the metatable + lua_newtable(state); + lua_pushstring(state, "__call"); + lua_pushcfunction(state, callCallback); + lua_settable(state, -3); + + lua_pushstring(state, "__gc"); + lua_pushcfunction(state, garbageCallback); + lua_settable(state, -3); + + // at this point, the stack contains the object at offset -2 and the metatable at offset -1 + // lua_setmetatable will bind the two together and pop the metatable + // our custom function remains on the stack (and that's what we want) + lua_setmetatable(state, -2); + + return PushedObject{state, 1}; + } + + // this is the version of "push" for trivially destructible objects + template + static auto push(lua_State* state, TFunctionObject fn) noexcept + -> typename std::enable_if::value, PushedObject>::type + { + // TODO: is_move_constructible not supported by some compilers + //static_assert(std::is_move_constructible::value, "The function object must be move-constructible"); + + // when the lua script calls the thing we will push on the stack, we want "fn" to be executed + // since "fn" doesn't need to be destroyed, we simply push it on the stack + + // this is the cfunction that is the callback + const auto function = [](lua_State* state_) -> int + { + // the function object is an upvalue + const auto toCall = static_cast(lua_touserdata(state_, lua_upvalueindex(1))); + return callback(state_, toCall, lua_gettop(state_)).release(); + }; + + // we copy the function object onto the stack + const auto functionObjectLocation = static_cast(lua_newuserdata(state, sizeof(TFunctionObject))); + new (functionObjectLocation) TFunctionObject(std::move(fn)); + + // pushing the function with the function object as upvalue + lua_pushcclosure(state, function, 1); + return PushedObject{state, 1}; + } + + // this is the version of "push" for pointer to functions + static auto push(lua_State* state, TReturnType (*fn)(TParameters...)) noexcept + -> PushedObject + { + // when the lua script calls the thing we will push on the stack, we want "fn" to be executed + // since "fn" doesn't need to be destroyed, we simply push it on the stack + + // this is the cfunction that is the callback + const auto function = [](lua_State* state_) -> int + { + // the function object is an upvalue + const auto toCall = reinterpret_cast(lua_touserdata(state_, lua_upvalueindex(1))); + return callback(state_, toCall, lua_gettop(state_)).release(); + }; + + // we copy the function object onto the stack + lua_pushlightuserdata(state, reinterpret_cast(fn)); + + // pushing the function with the function object as upvalue + lua_pushcclosure(state, function, 1); + return PushedObject{state, 1}; + } + + // this is the version of "push" for references to functions + static auto push(lua_State* state, TReturnType (&fn)(TParameters...)) noexcept + -> PushedObject + { + return push(state, &fn); + } + +private: + // callback that calls the function object + // this function is used by the callbacks and handles loading arguments from the stack and pushing the return value back + template + static auto callback(lua_State* state, TFunctionObject* toCall, int argumentsCount) + -> PushedObject + { + // checking if number of parameters is correct + if (argumentsCount < LocalFunctionArgumentsCounter::min) { + // if not, using lua_error to return an error + luaL_where(state, 1); + lua_pushstring(state, "This function requires at least "); + lua_pushnumber(state, LocalFunctionArgumentsCounter::min); + lua_pushstring(state, " parameter(s)"); + lua_concat(state, 4); + luaError(state); + + } else if (argumentsCount > LocalFunctionArgumentsCounter::max) { + // if not, using lua_error to return an error + luaL_where(state, 1); + lua_pushstring(state, "This function requires at most "); + lua_pushnumber(state, LocalFunctionArgumentsCounter::max); + lua_pushstring(state, " parameter(s)"); + lua_concat(state, 4); + luaError(state); + } + + // calling the function + try { + return callback2(state, *toCall, argumentsCount); + + } catch (const WrongTypeException& ex) { + // wrong parameter type, using lua_error to return an error + luaL_where(state, 1); + lua_pushstring(state, "Unable to convert parameter from "); + lua_pushstring(state, ex.luaType.c_str()); + lua_pushstring(state, " to "); + lua_pushstring(state, ex.destination.name()); + lua_concat(state, 4); + luaError(state); + + } catch (...) { + Pusher::push(state, std::current_exception()).release(); + luaError(state); + } + } + + template + static auto callback2(lua_State* state, TFunctionObject&& toCall, int argumentsCount) + -> typename std::enable_if::value && !std::is_void::value, PushedObject>::type + { + // pushing the result on the stack and returning number of pushed elements + typedef Pusher::type> + P; + return P::push(state, readIntoFunction(state, tag{}, toCall, -argumentsCount, tag{}...)); + } + + template + static auto callback2(lua_State* state, TFunctionObject&& toCall, int argumentsCount) + -> typename std::enable_if::value && !std::is_void::value, PushedObject>::type + { + readIntoFunction(state, tag{}, toCall, -argumentsCount, tag{}...); + return PushedObject{state, 0}; + } +}; + +// C function pointers +template +struct LuaContext::Pusher +{ + // using the function-pushing implementation + typedef Pusher + SubPusher; + static const int minSize = SubPusher::minSize; + static const int maxSize = SubPusher::maxSize; + + template + static PushedObject push(lua_State* state, TType value) noexcept { + return SubPusher::push(state, value); + } +}; + +// C function references +template +struct LuaContext::Pusher +{ + // using the function-pushing implementation + typedef Pusher + SubPusher; + static const int minSize = SubPusher::minSize; + static const int maxSize = SubPusher::maxSize; + + template + static PushedObject push(lua_State* state, TType value) noexcept { + return SubPusher::push(state, value); + } +}; + +// std::function +template +struct LuaContext::Pusher> +{ + // using the function-pushing implementation + typedef Pusher + SubPusher; + static const int minSize = SubPusher::minSize; + static const int maxSize = SubPusher::maxSize; + + static PushedObject push(lua_State* state, const std::function& value) noexcept { + return SubPusher::push(state, value); + } +}; + +// boost::variant +template +struct LuaContext::Pusher> +{ + static const int minSize = PusherMinSize::size; + static const int maxSize = PusherMaxSize::size; + + static PushedObject push(lua_State* state, const boost::variant& value) noexcept { + PushedObject obj{state, 0}; + VariantWriter writer{state, obj}; + value.apply_visitor(writer); + return obj; + } + +private: + struct VariantWriter : public boost::static_visitor<> { + template + void operator()(TType value) noexcept + { + obj = Pusher::type>::push(state, std::move(value)); + } + + VariantWriter(lua_State* state_, PushedObject& obj_) : state(state_), obj(obj_) {} + lua_State* state; + PushedObject& obj; + }; +}; + +// boost::optional +template +struct LuaContext::Pusher> { + typedef Pusher::type> + UnderlyingPusher; + + static const int minSize = UnderlyingPusher::minSize < 1 ? UnderlyingPusher::minSize : 1; + static const int maxSize = UnderlyingPusher::maxSize > 1 ? UnderlyingPusher::maxSize : 1; + + static PushedObject push(lua_State* state, const boost::optional& value) noexcept { + if (value) { + return UnderlyingPusher::push(state, value.get()); + } else { + lua_pushnil(state); + return PushedObject{state, 1}; + } + } +}; + +// tuple +template +struct LuaContext::Pusher> { + // TODO: NOT EXCEPTION SAFE /!\ // + static const int minSize = PusherTotalMinSize::size; + static const int maxSize = PusherTotalMaxSize::size; + + static PushedObject push(lua_State* state, const std::tuple& value) noexcept { + return PushedObject{state, push2(state, value, std::integral_constant{})}; + } + + static PushedObject push(lua_State* state, std::tuple&& value) noexcept { + return PushedObject{state, push2(state, std::move(value), std::integral_constant{})}; + } + +private: + template + static int push2(lua_State* state, const std::tuple& value, std::integral_constant) noexcept { + typedef typename std::tuple_element>::type ElemType; + + return Pusher::type>::push(state, std::get(value)).release() + + push2(state, value, std::integral_constant{}); + } + + template + static int push2(lua_State* state, std::tuple&& value, std::integral_constant) noexcept { + typedef typename std::tuple_element>::type ElemType; + + return Pusher::type>::push(state, std::move(std::get(value))).release() + + push2(state, std::move(value), std::integral_constant{}); + } + + static int push2(lua_State* /*state*/, const std::tuple&, std::integral_constant) noexcept { + return 0; + } + + static int push2(lua_State* /*state*/, std::tuple&&, std::integral_constant) noexcept { + return 0; + } +}; + +/**************************************************/ +/* READ FUNCTIONS */ +/**************************************************/ +// specializations of the Reader structures + +// opaque Lua references +template<> +struct LuaContext::Reader +{ + static auto read(lua_State* state, int index) + -> boost::optional + { + LuaContext::LuaObject obj(state, index); + return obj; + } +}; + +// reading null +template<> +struct LuaContext::Reader +{ + static auto read(lua_State* state, int index) + -> boost::optional + { + if (!lua_isnil(state, index)) + return boost::none; + return nullptr; + } +}; + +// integrals +template +struct LuaContext::Reader< + TType, + typename std::enable_if::value>::type + > +{ + static auto read(lua_State* state, int index) + -> boost::optional + { +# if LUA_VERSION_NUM >= 502 + + int success; + auto value = lua_tointegerx(state, index, &success); + if (success == 0) + return boost::none; + return static_cast(value); + +# else + + if (!lua_isnumber(state, index)) + return boost::none; + return static_cast(lua_tointeger(state, index)); + +# endif + } +}; + +// floating points +template +struct LuaContext::Reader< + TType, + typename std::enable_if::value>::type + > +{ + static auto read(lua_State* state, int index) + -> boost::optional + { +# if LUA_VERSION_NUM >= 502 + + int success; + auto value = lua_tonumberx(state, index, &success); + if (success == 0) + return boost::none; + return static_cast(value); + +# else + + if (!lua_isnumber(state, index)) + return boost::none; + return static_cast(lua_tonumber(state, index)); + +# endif + } +}; + +// boolean +template<> +struct LuaContext::Reader +{ + static auto read(lua_State* state, int index) + -> boost::optional + { + if (!lua_isboolean(state, index)) + return boost::none; + return lua_toboolean(state, index) != 0; + } +}; + +// string +// lua_tostring returns a temporary pointer, but that's not a problem since we copy +// the data into a std::string +template<> +struct LuaContext::Reader +{ + static auto read(lua_State* state, int index) + -> boost::optional + { + size_t len; + const auto val = lua_tolstring(state, index, &len); + if (val == 0) + return boost::none; + return std::string(val, len); + } +}; + +// enums +template +struct LuaContext::Reader< + TType, + typename std::enable_if::value>::type + > +{ + static auto read(lua_State* state, int index) + -> boost::optional + { + if (!lua_isnumber(state, index) || fmod(lua_tonumber(state, index), 1.) != 0) + return boost::none; + return static_cast(lua_tointeger(state, index)); + } +}; + +// LuaFunctionCaller +template +struct LuaContext::Reader> +{ + typedef LuaFunctionCaller + ReturnType; + + static auto read(lua_State* state, int index) + -> boost::optional + { + if (lua_isfunction(state, index) == 0 && lua_isuserdata(state, index) == 0) + return boost::none; + return ReturnType(state, index); + } +}; + +// function +template +struct LuaContext::Reader> +{ + static auto read(lua_State* state, int index) + -> boost::optional> + { + if (auto val = Reader>::read(state, index)) + { + std::function f{*val}; + return boost::optional>{std::move(f)}; + } + + return boost::none; + } +}; + +// vector of pairs +template +struct LuaContext::Reader>> +{ + static auto read(lua_State* state, int index) + -> boost::optional>> + { + if (!lua_istable(state, index)) + return boost::none; + + std::vector> result; + + // we traverse the table at the top of the stack + lua_pushnil(state); // first key + while (lua_next(state, (index > 0) ? index : (index - 1)) != 0) { + // now a key and its value are pushed on the stack + try { + auto val1 = Reader::read(state, -2); + auto val2 = Reader::read(state, -1); + + if (!val1.is_initialized() || !val2.is_initialized()) { + lua_pop(state, 2); // we remove the value and the key + return {}; + } + + result.push_back({ val1.get(), val2.get() }); + lua_pop(state, 1); // we remove the value but keep the key for the next iteration + + } catch(...) { + lua_pop(state, 2); // we remove the value and the key + return {}; + } + } + + return { std::move(result) }; + } +}; + +// map +template +struct LuaContext::Reader> +{ + static auto read(lua_State* state, int index) + -> boost::optional> + { + if (!lua_istable(state, index)) + return boost::none; + + std::map result; + + // we traverse the table at the top of the stack + lua_pushnil(state); // first key + while (lua_next(state, (index > 0) ? index : (index - 1)) != 0) { + // now a key and its value are pushed on the stack + try { + auto key = Reader::read(state, -2); + auto value = Reader::read(state, -1); + + if (!key.is_initialized() || !value.is_initialized()) { + lua_pop(state, 2); // we remove the value and the key + return {}; + } + + result.insert({ key.get(), value.get() }); + lua_pop(state, 1); // we remove the value but keep the key for the next iteration + + } catch(...) { + lua_pop(state, 2); // we remove the value and the key + return {}; + } + } + + return { std::move(result) }; + } +}; + +// unordered_map +template +struct LuaContext::Reader> +{ + static auto read(lua_State* state, int index) + -> boost::optional> + { + if (!lua_istable(state, index)) + return boost::none; + + std::unordered_map result; + + // we traverse the table at the top of the stack + lua_pushnil(state); // first key + while (lua_next(state, (index > 0) ? index : (index - 1)) != 0) { + // now a key and its value are pushed on the stack + try { + auto key = Reader::read(state, -2); + auto value = Reader::read(state, -1); + + if (!key.is_initialized() || !value.is_initialized()) { + lua_pop(state, 2); // we remove the value and the key + return {}; + } + + result.insert({ key.get(), value.get() }); + lua_pop(state, 1); // we remove the value but keep the key for the next iteration + + } catch(...) { + lua_pop(state, 2); // we remove the value and the key + return {}; + } + } + + return { std::move(result) }; + } +}; + +// optional +// IMPORTANT: optional means "either nil or the value of the right type" +// * if the value is nil, then an optional containing an empty optional is returned +// * if the value is of the right type, then an optional containing an optional containing the value is returned +// * if the value is of the wrong type, then an empty optional is returned +template +struct LuaContext::Reader> +{ + static auto read(lua_State* state, int index) + -> boost::optional> + { + if (lua_isnil(state, index)) + return boost::optional{boost::none}; + if (auto&& other = Reader::read(state, index)) + return std::move(other); + return boost::none; + } +}; + +// variant +template +struct LuaContext::Reader> +{ + typedef boost::variant + ReturnType; + +private: + // class doing operations for a range of types from TIterBegin to TIterEnd + template + struct VariantReader + { + using SubReader = Reader::type>::type>; + + static auto read(lua_State* state, int index) + -> boost::optional + { + // note: using SubReader::read triggers a compilation error when used with a reference + if (const auto val = SubReader::read(state, index)) + return boost::variant{*val}; + return VariantReader::type, TIterEnd>::read(state, index); + } + }; + + // specialization of class above being called when list of remaining types is empty + template + struct VariantReader::type::value == 0>::type> + { + static auto read(lua_State* /*state*/, int /*index*/) + -> boost::optional + { + return boost::none; + } + }; + + // this is the main type + typedef VariantReader::type, typename boost::mpl::end::type> + MainVariantReader; + +public: + static auto read(lua_State* state, int index) + -> boost::optional + { + return MainVariantReader::read(state, index); + } +}; + +// reading a tuple +// tuple have an additional argument for their functions, that is the maximum size to read +// if maxSize is smaller than the tuple size, then the remaining parameters will be left to default value +template<> +struct LuaContext::Reader> +{ + static auto read(lua_State* /*state*/, int /*index*/, int /*maxSize*/ = 0) + -> boost::optional> + { + return std::tuple<>{}; + } +}; + +template +struct LuaContext::Reader, + typename std::enable_if::value>::type // TODO: replace by std::is_default_constructible when it works on every compiler + > +{ + // this is the "TFirst is NOT default constructible" version + + typedef std::tuple + ReturnType; + + static auto read(lua_State* state, int index, int maxSize = std::tuple_size::value) + -> boost::optional + { + if (maxSize <= 0) + return boost::none; + + auto firstVal = Reader::read(state, index); + auto othersVal = Reader>::read(state, index + 1, maxSize - 1); + + if (!firstVal || !othersVal) + return boost::none; + + return std::tuple_cat(std::tuple(*firstVal), std::move(*othersVal)); + } +}; + +template +struct LuaContext::Reader, + typename std::enable_if::value>::type // TODO: replace by std::is_default_constructible when it works on every compiler + > +{ + // this is the "TFirst is default-constructible" version + + typedef std::tuple + ReturnType; + + static auto read(lua_State* state, int index, int maxSize = std::tuple_size::value) + -> boost::optional + { + auto othersVal = Reader>::read(state, index + 1, maxSize - 1); + if (!othersVal) + return boost::none; + + if (maxSize <= 0) + return std::tuple_cat(std::tuple(), std::move(*othersVal)); + + auto firstVal = Reader::read(state, index); + if (!firstVal) + return boost::none; + + return std::tuple_cat(std::tuple(*firstVal), std::move(*othersVal)); + } +}; + +#endif diff --git a/ext/yahttp/LICENSE b/ext/yahttp/LICENSE new file mode 100644 index 0000000..08f6f64 --- /dev/null +++ b/ext/yahttp/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Aki Tuomi + +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. diff --git a/ext/yahttp/Makefile.am b/ext/yahttp/Makefile.am new file mode 100644 index 0000000..aaaeee0 --- /dev/null +++ b/ext/yahttp/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = yahttp + +EXTRA_DIST = LICENSE README.md diff --git a/ext/yahttp/Makefile.in b/ext/yahttp/Makefile.in new file mode 100644 index 0000000..3e1df0f --- /dev/null +++ b/ext/yahttp/Makefile.in @@ -0,0 +1,695 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 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@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 = ext/yahttp +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/m4/boost.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)/m4/pdns_check_clock_gettime.m4 \ + $(top_srcdir)/m4/pdns_check_curl.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ + $(top_srcdir)/m4/pdns_check_libdecaf.m4 \ + $(top_srcdir)/m4/pdns_check_libsodium.m4 \ + $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ + $(top_srcdir)/m4/pdns_check_network_libs.m4 \ + $(top_srcdir)/m4/pdns_check_os.m4 \ + $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ + $(top_srcdir)/m4/pdns_check_ragel.m4 \ + $(top_srcdir)/m4/pdns_check_virtualenv.m4 \ + $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ + $(top_srcdir)/m4/pdns_enable_botan.m4 \ + $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ + $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ + $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ + $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ + $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ + $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ + $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ + $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ + $(top_srcdir)/m4/pdns_stack_protector.m4 \ + $(top_srcdir)/m4/pdns_with_lua.m4 \ + $(top_srcdir)/m4/pdns_with_luajit.m4 \ + $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ + $(top_srcdir)/m4/pdns_with_protobuf.m4 \ + $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +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" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ +BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ +BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_LDPATH = @BOOST_LDPATH@ +BOOST_ROOT = @BOOST_ROOT@ +BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ +BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ +BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ +BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ +BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ +BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ +BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ +BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ +BOTAN_CFLAGS = @BOTAN_CFLAGS@ +BOTAN_LIBS = @BOTAN_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CURL = @CURL@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DYNLINKFLAGS = @DYNLINKFLAGS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ +LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBDECAF_LIBS = @LIBDECAF_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NET_SNMP_CFLAGS = @NET_SNMP_CFLAGS@ +NET_SNMP_LIBS = @NET_SNMP_LIBS@ +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@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ +PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@ +PROTOBUF_LIBS = @PROTOBUF_LIBS@ +PROTOC = @PROTOC@ +RAGEL = @RAGEL@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RT_LIBS = @RT_LIBS@ +SANITIZER_FLAGS = @SANITIZER_FLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ +THREADFLAGS = @THREADFLAGS@ +VERSION = @VERSION@ +VIRTUALENV = @VIRTUALENV@ +WARN_CFLAGS = @WARN_CFLAGS@ +YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ +YAHTTP_LIBS = @YAHTTP_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +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@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pdns_configure_args = @pdns_configure_args@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +socketdir = @socketdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemd = @systemd@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = yahttp +EXTRA_DIST = LICENSE README.md +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(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) --foreign ext/yahttp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign ext/yahttp/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: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(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 + +# 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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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 +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +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 Makefile +distclean-am: clean-am distclean-generic 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 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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic 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-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-am 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/ext/yahttp/README.md b/ext/yahttp/README.md new file mode 100644 index 0000000..7cd9e35 --- /dev/null +++ b/ext/yahttp/README.md @@ -0,0 +1,69 @@ +Yet Another HTTP Library +======================== + +YaHTTP aims to be a pure http request/response parser that has no IO ties. It is intended to be used on small-footprint applications and other utilities that want to use HTTP over something else than network IO. + +[![Build Status](https://travis-ci.org/cmouse/yahttp.svg?branch=master)](https://travis-ci.org/cmouse/yahttp) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/2161/badge.svg)](https://scan.coverity.com/projects/2161) +[![Coverage Status](https://coveralls.io/repos/cmouse/yahttp/badge.svg?branch=master%0A)](https://coveralls.io/r/cmouse/yahttp?branch=master%0A) + +WARNINGS +-------- +If you are upgrading from version before May 02, 2014 - *PLEASE BE SURE TO CHECK THAT EVERYTHING WORKS AS EXPECTED*. There has been complete overhaul of the library and many things have changed. + +NOTES +----- +Do not use resp = req, or resp(req) to build the response object, despite it being supported. This will cause request headers to get duplicated. Also, you *must* set response#version to request#version if you intend to support older than HTTP/1.1 clients. Set response#status to at least 200, it won't be done for you. No Server or Product token is sent either, you can add those if you want. + +If you do not want to send chunked responses, set content-length header. Setting this header will always disable chunked responses. This will also happen if you downgrade your responses to version 10 or 9. + +Integration guide +----------------- + +Here are some instructions on how to integrate YaHTTP into your project. + +With automake and libtool +------------------------- + +If you don't need router or any of the C++11 features, you can just create empty yahttp-config.h, or symlink it to your project's config.h for the yahttp.hpp to include. Then just put this stuff into it's own folder and create Makefile.am with following contents (you can change the compilation flags): + +``` +noinst_LTLIBRARIES=libyahttp.la +libyahttp_la_CXXFLAGS=$(RELRO_CFLAGS) $(PIE_CFLAGS) -D__STRICT_ANSI__ +libyahttp_la_SOURCES=cookie.hpp exception.hpp reqresp.cpp reqresp.hpp router.cpp router.hpp url.hpp utility.hpp yahttp.hpp +``` + +You can define RELRO and PIE to match your project. + +To compile your project use -Lpath/to/yahttp -lyahttp + +If you need router, additionally check for boost or C++11 and replace yahttp-config.h to config.h in yahttp.hpp or add relevant options to your compiler CXXFLAGS. See below for the flags. + +Without automake +---------------- + +Create simple Makefile with contents for C++11: + +``` +OBJECTS=reqresp.o router.o +CXX=gcc +CXXFLAGS=-W -Wall -DHAVE_CXX11 -std=c++11 +``` + +Or create simple Makefile with contents for boost: + +``` +OBJECTS=reqresp.o router.o +CXX=gcc +CXXFLAGS=-W -Wall -DHAVE_BOOST +``` + +Or if you don't need either one, just: + +``` +OBJECTS=reqresp.o +CXX=gcc +CXXFLAGS=-W -Wall +``` + +YaHTTP include files can be placed where the rest of your includes are. Then just add your own code there and it should work just fine. diff --git a/ext/yahttp/yahttp/Makefile.am b/ext/yahttp/yahttp/Makefile.am new file mode 100644 index 0000000..3ed41e5 --- /dev/null +++ b/ext/yahttp/yahttp/Makefile.am @@ -0,0 +1,13 @@ +noinst_LTLIBRARIES = libyahttp.la + +libyahttp_la_SOURCES = \ + cookie.hpp \ + exception.hpp \ + reqresp.cpp \ + reqresp.hpp \ + router.cpp \ + router.hpp \ + url.hpp \ + utility.hpp \ + yahttp-config.h \ + yahttp.hpp diff --git a/ext/yahttp/yahttp/Makefile.in b/ext/yahttp/yahttp/Makefile.in new file mode 100644 index 0000000..bae464d --- /dev/null +++ b/ext/yahttp/yahttp/Makefile.in @@ -0,0 +1,695 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 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@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 = ext/yahttp/yahttp +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/build-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/m4/boost.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)/m4/pdns_check_clock_gettime.m4 \ + $(top_srcdir)/m4/pdns_check_curl.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ + $(top_srcdir)/m4/pdns_check_libdecaf.m4 \ + $(top_srcdir)/m4/pdns_check_libsodium.m4 \ + $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ + $(top_srcdir)/m4/pdns_check_network_libs.m4 \ + $(top_srcdir)/m4/pdns_check_os.m4 \ + $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ + $(top_srcdir)/m4/pdns_check_ragel.m4 \ + $(top_srcdir)/m4/pdns_check_virtualenv.m4 \ + $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ + $(top_srcdir)/m4/pdns_enable_botan.m4 \ + $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ + $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ + $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ + $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ + $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ + $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ + $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ + $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ + $(top_srcdir)/m4/pdns_stack_protector.m4 \ + $(top_srcdir)/m4/pdns_with_lua.m4 \ + $(top_srcdir)/m4/pdns_with_luajit.m4 \ + $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ + $(top_srcdir)/m4/pdns_with_protobuf.m4 \ + $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libyahttp_la_LIBADD = +am_libyahttp_la_OBJECTS = reqresp.lo router.lo +libyahttp_la_OBJECTS = $(am_libyahttp_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libyahttp_la_SOURCES) +DIST_SOURCES = $(libyahttp_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ +BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ +BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_LDPATH = @BOOST_LDPATH@ +BOOST_ROOT = @BOOST_ROOT@ +BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ +BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ +BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ +BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ +BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ +BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ +BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ +BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ +BOTAN_CFLAGS = @BOTAN_CFLAGS@ +BOTAN_LIBS = @BOTAN_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CURL = @CURL@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DYNLINKFLAGS = @DYNLINKFLAGS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ +LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBDECAF_LIBS = @LIBDECAF_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NET_SNMP_CFLAGS = @NET_SNMP_CFLAGS@ +NET_SNMP_LIBS = @NET_SNMP_LIBS@ +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@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ +PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@ +PROTOBUF_LIBS = @PROTOBUF_LIBS@ +PROTOC = @PROTOC@ +RAGEL = @RAGEL@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RT_LIBS = @RT_LIBS@ +SANITIZER_FLAGS = @SANITIZER_FLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ +THREADFLAGS = @THREADFLAGS@ +VERSION = @VERSION@ +VIRTUALENV = @VIRTUALENV@ +WARN_CFLAGS = @WARN_CFLAGS@ +YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ +YAHTTP_LIBS = @YAHTTP_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +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@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pdns_configure_args = @pdns_configure_args@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +socketdir = @socketdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemd = @systemd@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libyahttp.la +libyahttp_la_SOURCES = \ + cookie.hpp \ + exception.hpp \ + reqresp.cpp \ + reqresp.hpp \ + router.cpp \ + router.hpp \ + url.hpp \ + utility.hpp \ + yahttp-config.h \ + yahttp.hpp + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(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) --foreign ext/yahttp/yahttp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign ext/yahttp/yahttp/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: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libyahttp.la: $(libyahttp_la_OBJECTS) $(libyahttp_la_DEPENDENCIES) $(EXTRA_libyahttp_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libyahttp_la_OBJECTS) $(libyahttp_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reqresp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/router.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +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 $(LTLIBRARIES) +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +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-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +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 -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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + 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-man install-pdf install-pdf-am \ + install-ps install-ps-am 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 tags-am 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/ext/yahttp/yahttp/cookie.hpp b/ext/yahttp/yahttp/cookie.hpp new file mode 100644 index 0000000..c597c7c --- /dev/null +++ b/ext/yahttp/yahttp/cookie.hpp @@ -0,0 +1,143 @@ +namespace YaHTTP { + /*! Implements a single cookie */ + class Cookie { + public: + Cookie() { + secure = false; + httponly = false; + name = value = ""; + expires = DateTime(); + }; //!< Set the cookie to empty value + + Cookie(const Cookie &rhs) { + name = rhs.name; + value = rhs.value; + domain = rhs.domain; + path = rhs.path; + secure = rhs.secure; + httponly = rhs.httponly; + expires = rhs.expires; + }; //0) + oss << "; domain=" << domain; + if (path.size()>0) + oss << "; path=" << path; + if (secure) + oss << "; secure"; + if (httponly) + oss << "; httpOnly"; + return oss.str(); + }; //!< Stringify the cookie + }; + + /*! Implements a Cookie jar for storing multiple cookies */ + class CookieJar { + public: + std::map cookies; //cookies = rhs.cookies; + } //cookies.clear(); + } + + void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value) { + size_t pos; + pos = keyvalue.find("="); + if (pos == std::string::npos) throw "Not a Key-Value pair (cookie)"; + key = std::string(keyvalue.begin(), keyvalue.begin()+pos); + value = std::string(keyvalue.begin()+pos+1, keyvalue.end()); + } // lcookies; + Cookie c; + pos = 0; + while(pos < cookiestr.size()) { + if ((npos = cookiestr.find("; ", pos)) == std::string::npos) + npos = cookiestr.size(); + keyValuePair(cookiestr.substr(pos, npos-pos), c.name, c.value); + c.name = YaHTTP::Utility::decodeURL(c.name); + c.value = YaHTTP::Utility::decodeURL(c.value); + lcookies.push_back(c); + pos = npos+2; + } + for(std::list::iterator i = lcookies.begin(); i != lcookies.end(); i++) { + this->cookies[i->name] = *i; + } + } + + void parseSetCookieHeader(const std::string &cookiestr) { + Cookie c; + size_t pos,npos; + std::string k, v; + + if ((pos = cookiestr.find("; ", 0)) == std::string::npos) + pos = cookiestr.size(); + keyValuePair(cookiestr.substr(0, pos), c.name, c.value); + c.name = YaHTTP::Utility::decodeURL(c.name); + c.value = YaHTTP::Utility::decodeURL(c.value); + if (pos < cookiestr.size()) pos+=2; + + while(pos < cookiestr.size()) { + if ((npos = cookiestr.find("; ", pos)) == std::string::npos) + npos = cookiestr.size(); + std::string s = cookiestr.substr(pos, npos-pos); + if (s.find("=") != std::string::npos) + keyValuePair(s, k, v); + else + k = s; + if (k == "expires") { + DateTime dt; + dt.parseCookie(v); + c.expires = dt; + } else if (k == "domain") { + c.domain = v; + } else if (k == "path") { + c.path = v; + } else if (k == "httpOnly") { + c.httponly = true; + } else if (k == "secure") { + c.secure = true; + } else { + // ignore crap + break; + } + pos = npos+2; + } + + this->cookies[c.name] = c; + }; // + +namespace YaHTTP { + /*! Generic error class */ + class Error: public std::exception { + public: + Error() {}; + Error(const std::string& reason_): reason(reason_) {}; + virtual ~Error() throw() {}; + + virtual const char* what() const throw() + { + return reason.c_str(); + } + const std::string reason; // + bool AsyncLoader::feed(const std::string& somedata) { + buffer.append(somedata); + while(state < 2) { + int cr=0; + pos = buffer.find_first_of("\n"); + // need to find CRLF in buffer + if (pos == std::string::npos) return false; + if (pos>0 && buffer[pos-1]=='\r') + cr=1; + std::string line(buffer.begin(), buffer.begin()+pos-cr); // exclude CRLF + buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer including CRLF + + if (state == 0) { // startup line + if (target->kind == YAHTTP_TYPE_REQUEST) { + std::string ver; + std::string tmpurl; + std::istringstream iss(line); + iss >> target->method >> tmpurl >> ver; + if (ver.size() == 0) + target->version = 9; + else if (ver.find("HTTP/0.9") == 0) + target->version = 9; + else if (ver.find("HTTP/1.0") == 0) + target->version = 10; + else if (ver.find("HTTP/1.1") == 0) + target->version = 11; + else + throw ParseError("HTTP version not supported"); + // uppercase the target method + std::transform(target->method.begin(), target->method.end(), target->method.begin(), ::toupper); + target->url.parse(tmpurl); + target->getvars = Utility::parseUrlParameters(target->url.parameters); + state = 1; + } else if(target->kind == YAHTTP_TYPE_RESPONSE) { + std::string ver; + std::istringstream iss(line); + std::string::size_type pos1; + iss >> ver >> target->status; + std::getline(iss, target->statusText); + pos1=0; + while(pos1 < target->statusText.size() && YaHTTP::isspace(target->statusText.at(pos1))) pos1++; + target->statusText = target->statusText.substr(pos1); + if ((pos1 = target->statusText.find("\r")) != std::string::npos) { + target->statusText = target->statusText.substr(0, pos1-1); + } + if (ver.size() == 0) { + target->version = 9; + } else if (ver.find("HTTP/0.9") == 0) + target->version = 9; + else if (ver.find("HTTP/1.0") == 0) + target->version = 10; + else if (ver.find("HTTP/1.1") == 0) + target->version = 11; + else + throw ParseError("HTTP version not supported"); + state = 1; + } + } else if (state == 1) { + std::string key,value; + size_t pos1; + if (line.empty()) { + chunked = (target->headers.find("transfer-encoding") != target->headers.end() && target->headers["transfer-encoding"] == "chunked"); + state = 2; + break; + } + // split headers + if ((pos1 = line.find(": ")) == std::string::npos) + throw ParseError("Malformed header line"); + key = line.substr(0, pos1); + value = line.substr(pos1+2); + for(std::string::iterator it=key.begin(); it != key.end(); it++) + if (YaHTTP::isspace(*it)) + throw ParseError("Header key contains whitespace which is not allowed by RFC"); + + Utility::trim(value); + std::transform(key.begin(), key.end(), key.begin(), ::tolower); + // is it already defined + + if (key == "set-cookie" && target->kind == YAHTTP_TYPE_RESPONSE) { + target->jar.parseSetCookieHeader(value); + } else if (key == "cookie" && target->kind == YAHTTP_TYPE_REQUEST) { + target->jar.parseCookieHeader(value); + } else { + if (key == "host" && target->kind == YAHTTP_TYPE_REQUEST) { + // maybe it contains port? + if ((pos1 = value.find(":")) == std::string::npos) { + target->url.host = value; + } else { + target->url.host = value.substr(0, pos1); + target->url.port = ::atoi(value.substr(pos1).c_str()); + } + } + if (target->headers.find(key) != target->headers.end()) { + target->headers[key] = target->headers[key] + ";" + value; + } else { + target->headers[key] = value; + } + } + } + } + + minbody = 0; + // check for expected body size + if (target->kind == YAHTTP_TYPE_REQUEST) maxbody = target->max_request_size; + else if (target->kind == YAHTTP_TYPE_RESPONSE) maxbody = target->max_response_size; + else maxbody = 0; + + if (!chunked) { + if (target->headers.find("content-length") != target->headers.end()) { + std::istringstream maxbodyS(target->headers["content-length"]); + maxbodyS >> minbody; + maxbody = minbody; + } + if (minbody < 1) return true; // guess there isn't anything left. + if (target->kind == YAHTTP_TYPE_REQUEST && static_cast(minbody) > target->max_request_size) throw ParseError("Max request body size exceeded"); + else if (target->kind == YAHTTP_TYPE_RESPONSE && static_cast(minbody) > target->max_response_size) throw ParseError("Max response body size exceeded"); + } + + if (maxbody == 0) hasBody = false; + else hasBody = true; + + if (buffer.size() == 0) return ready(); + + while(buffer.size() > 0) { + if (chunked) { + if (chunk_size == 0) { + char buf[100]; + // read chunk length + if ((pos = buffer.find('\n')) == std::string::npos) return false; + if (pos > 99) + throw ParseError("Impossible chunk_size"); + buffer.copy(buf, pos); + buf[pos]=0; // just in case... + buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer + sscanf(buf, "%x", &chunk_size); + if (chunk_size == 0) { state = 3; break; } // last chunk + } else { + int crlf=1; + if (buffer.size() < static_cast(chunk_size+1)) return false; // expect newline + if (buffer.at(chunk_size) == '\r') { + if (buffer.size() < static_cast(chunk_size+2) || buffer.at(chunk_size+1) != '\n') return false; // expect newline after carriage return + crlf=2; + } else if (buffer.at(chunk_size) != '\n') return false; + std::string tmp = buffer.substr(0, chunk_size); + buffer.erase(buffer.begin(), buffer.begin()+chunk_size+crlf); + bodybuf << tmp; + chunk_size = 0; + if (buffer.size() == 0) break; // just in case + } + } else { + if (bodybuf.str().length() + buffer.length() > maxbody) + bodybuf << buffer.substr(0, maxbody - bodybuf.str().length()); + else + bodybuf << buffer; + buffer = ""; + } + } + + if (chunk_size!=0) return false; // need more data + + return ready(); + }; + + void HTTPBase::write(std::ostream& os) const { + if (kind == YAHTTP_TYPE_REQUEST) { + std::ostringstream getparmbuf; + std::string getparms; + // prepare URL + for(strstr_map_t::const_iterator i = getvars.begin(); i != getvars.end(); i++) { + getparmbuf << Utility::encodeURL(i->first, false) << "=" << Utility::encodeURL(i->second, false) << "&"; + } + if (getparmbuf.str().length() > 0) { + std::string buf = getparmbuf.str(); + getparms = "?" + std::string(buf.begin(), buf.end() - 1); + } + else + getparms = ""; + os << method << " " << url.path << getparms << " HTTP/" << versionStr(this->version); + } else if (kind == YAHTTP_TYPE_RESPONSE) { + os << "HTTP/" << versionStr(this->version) << " " << status << " "; + if (statusText.empty()) + os << Utility::status2text(status); + else + os << statusText; + } + os << "\r\n"; + + bool cookieSent = false; + bool sendChunked = false; + + if (this->version > 10) { // 1.1 or better + if (headers.find("content-length") == headers.end() && !this->is_multipart) { + // must use chunked on response + sendChunked = (kind == YAHTTP_TYPE_RESPONSE); + if ((headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second != "chunked")) { + throw YaHTTP::Error("Transfer-encoding must be chunked, or Content-Length defined"); + } + if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) { + sendChunked = true; + os << "Transfer-Encoding: chunked\r\n"; + } + } else { + sendChunked = false; + } + } + + // write headers + strstr_map_t::const_iterator iter = headers.begin(); + while(iter != headers.end()) { + if (iter->first == "host" && (kind != YAHTTP_TYPE_REQUEST || version < 10)) { iter++; continue; } + if (iter->first == "transfer-encoding" && sendChunked) { iter++; continue; } + std::string header = Utility::camelizeHeader(iter->first); + if (header == "Cookie" || header == "Set-Cookie") cookieSent = true; + os << Utility::camelizeHeader(iter->first) << ": " << iter->second << "\r\n"; + iter++; + } + if (version > 9 && !cookieSent && jar.cookies.size() > 0) { // write cookies + if (kind == YAHTTP_TYPE_REQUEST) { + bool first = true; + os << "Cookie: "; + for(strcookie_map_t::const_iterator i = jar.cookies.begin(); i != jar.cookies.end(); i++) { + if (first) + first = false; + else + os << "; "; + os << Utility::encodeURL(i->second.name) << "=" << Utility::encodeURL(i->second.value); + } + } else if (kind == YAHTTP_TYPE_REQUEST) { + for(strcookie_map_t::const_iterator i = jar.cookies.begin(); i != jar.cookies.end(); i++) { + os << "Set-Cookie: "; + os << i->second.str() << "\r\n"; + } + } + } + os << "\r\n"; +#ifdef HAVE_CPP_FUNC_PTR + this->renderer(this, os, sendChunked); +#else + SendbodyRenderer r; + r(this, os, chunked) +#endif + }; + + std::ostream& operator<<(std::ostream& os, const Response &resp) { + resp.write(os); + return os; + }; + + std::istream& operator>>(std::istream& is, Response &resp) { + YaHTTP::AsyncResponseLoader arl; + arl.initialize(&resp); + while(is.good()) { + char buf[1024]; + is.read(buf, 1024); + if (is.gcount()>0) { // did we actually read anything + is.clear(); + if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed + } + } + // throw unless ready + if (arl.ready() == false) + throw ParseError("Was not able to extract a valid Response from stream"); + arl.finalize(); + return is; + }; + + std::ostream& operator<<(std::ostream& os, const Request &req) { + req.write(os); + return os; + }; + + std::istream& operator>>(std::istream& is, Request &req) { + YaHTTP::AsyncRequestLoader arl; + arl.initialize(&req); + while(is.good()) { + char buf[1024]; + is.read(buf, 1024); + if (is.gcount() > 0) { // did we actually read anything + is.clear(); + if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed + } + } + if (arl.ready() == false) + throw ParseError("Was not able to extract a valid Request from stream"); + arl.finalize(); + return is; + }; +}; diff --git a/ext/yahttp/yahttp/reqresp.hpp b/ext/yahttp/yahttp/reqresp.hpp new file mode 100644 index 0000000..d9e7a19 --- /dev/null +++ b/ext/yahttp/yahttp/reqresp.hpp @@ -0,0 +1,351 @@ +#ifdef HAVE_CXX11 +#include +#define HAVE_CPP_FUNC_PTR +namespace funcptr = std; +#else +#ifdef HAVE_BOOST +#include +namespace funcptr = boost; +#define HAVE_CPP_FUNC_PTR +#endif +#endif + +#include +#include + +#ifndef WIN32 +#include +#include +#endif + +#include + +#ifndef YAHTTP_MAX_REQUEST_SIZE +#define YAHTTP_MAX_REQUEST_SIZE 2097152 +#endif + +#ifndef YAHTTP_MAX_RESPONSE_SIZE +#define YAHTTP_MAX_RESPONSE_SIZE 2097152 +#endif + +#define YAHTTP_TYPE_REQUEST 1 +#define YAHTTP_TYPE_RESPONSE 2 + +namespace YaHTTP { + typedef std::map strcookie_map_t; //body.length();i+=1024) { + cl = std::min(static_cast(1024), doc->body.length()-i); // for less than 1k blocks + os << std::hex << cl << std::dec << "\r\n"; + os << doc->body.substr(i, cl) << "\r\n"; + } + os << 0 << "\r\n\r\n"; // last chunk + } else { + os << doc->body; + } + return doc->body.length(); + }; //path = path_; + }; + + size_t operator()(const HTTPBase *doc __attribute__((unused)), std::ostream& os, bool chunked) const { + char buf[4096]; + size_t n,k; +#ifdef HAVE_CXX11 + std::ifstream ifs(path, std::ifstream::binary); +#else + std::ifstream ifs(path.c_str(), std::ifstream::binary); +#endif + n = 0; + + while(ifs.good()) { + ifs.read(buf, sizeof buf); + n += (k = ifs.gcount()); + if (k > 0) { + if (chunked) os << std::hex << k << std::dec << "\r\n"; + os.write(buf, k); + if (chunked) os << "\r\n"; + } + } + if (chunked) os << 0 << "\r\n\r\n"; + return n; + }; //url = rhs.url; this->kind = rhs.kind; + this->status = rhs.status; this->statusText = rhs.statusText; + this->method = rhs.method; this->headers = rhs.headers; + this->jar = rhs.jar; this->postvars = rhs.postvars; + this->parameters = rhs.parameters; this->getvars = rhs.getvars; + this->body = rhs.body; this->max_request_size = rhs.max_request_size; + this->max_response_size = rhs.max_response_size; this->version = rhs.version; +#ifdef HAVE_CPP_FUNC_PTR + this->renderer = rhs.renderer; +#endif + this->is_multipart = rhs.is_multipart; + }; + HTTPBase& operator=(const HTTPBase& rhs) { + this->url = rhs.url; this->kind = rhs.kind; + this->status = rhs.status; this->statusText = rhs.statusText; + this->method = rhs.method; this->headers = rhs.headers; + this->jar = rhs.jar; this->postvars = rhs.postvars; + this->parameters = rhs.parameters; this->getvars = rhs.getvars; + this->body = rhs.body; this->max_request_size = rhs.max_request_size; + this->max_response_size = rhs.max_response_size; this->version = rhs.version; +#ifdef HAVE_CPP_FUNC_PTR + this->renderer = rhs.renderer; +#endif + this->is_multipart = rhs.is_multipart; + return *this; + }; +public: + URL url; // renderer; //kind = YAHTTP_TYPE_RESPONSE; + }; + Response& operator=(const HTTPBase& rhs) { + HTTPBase::operator=(rhs); + this->kind = YAHTTP_TYPE_RESPONSE; + return *this; + }; + void initialize() { + HTTPBase::initialize(); + this->kind = YAHTTP_TYPE_RESPONSE; + } + void initialize(const HTTPBase& rhs) { + HTTPBase::initialize(); + this->kind = YAHTTP_TYPE_RESPONSE; + // copy SOME attributes + this->url = rhs.url; + this->method = rhs.method; + this->jar = rhs.jar; + this->version = rhs.version; + } + friend std::ostream& operator<<(std::ostream& os, const Response &resp); + friend std::istream& operator>>(std::istream& is, Response &resp); + }; + + /* Request class, represents a HTTP Request document */ + class Request: public HTTPBase { + public: + Request() { initialize(); }; + Request(const HTTPBase& rhs): HTTPBase(rhs) { + this->kind = YAHTTP_TYPE_REQUEST; + }; + Request& operator=(const HTTPBase& rhs) { + HTTPBase::operator=(rhs); + this->kind = YAHTTP_TYPE_REQUEST; + return *this; + }; + void initialize() { + HTTPBase::initialize(); + this->kind = YAHTTP_TYPE_REQUEST; + } + void initialize(const HTTPBase& rhs) { + HTTPBase::initialize(); + this->kind = YAHTTP_TYPE_REQUEST; + // copy SOME attributes + this->url = rhs.url; + this->method = rhs.method; + this->jar = rhs.jar; + this->version = rhs.version; + } + void setup(const std::string& method_, const std::string& url_) { + this->url.parse(url_); + this->headers["host"] = this->url.host; + this->method = method_; + std::transform(this->method.begin(), this->method.end(), this->method.begin(), ::toupper); + this->headers["user-agent"] = "YaHTTP v1.0"; + }; //first, false) << "=" << Utility::encodeURL(i->second, false) << "&"; + } + // remove last bit + if (postbuf.str().length()>0) + body = postbuf.str().substr(0, postbuf.str().length()-1); + else + body = ""; + headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8"; + } else if (format == multipart) { + headers["content-type"] = "multipart/form-data; boundary=YaHTTP-12ca543"; + this->is_multipart = true; + for(strstr_map_t::const_iterator i = POST().begin(); i != POST().end(); i++) { + postbuf << "--YaHTTP-12ca543\r\nContent-Disposition: form-data; name=\"" << Utility::encodeURL(i->first, false) << "\"; charset=UTF-8\r\nContent-Length: " << i->second.size() << "\r\n\r\n" + << Utility::encodeURL(i->second, false) << "\r\n"; + } + postbuf << "--"; + body = postbuf.str(); + } + + postbuf.str(""); + postbuf << body.length(); + // set method and change headers + method = "POST"; + if (!this->is_multipart) + headers["content-length"] = postbuf.str(); + }; //>(std::istream& is, Request &resp); + }; + + /*! Asynchronous HTTP document loader */ + template + class AsyncLoader { + public: + T* target; //target = target_; + hasBody = false; + buffer = ""; + this->target->initialize(); + }; // 1 && + (!hasBody || + (bodybuf.str().size() <= maxbody && + bodybuf.str().size() >= minbody) + ) + ); + }; //headers.find("content-type"); + if (cpos != target->headers.end() && Utility::iequals(cpos->second, "application/x-www-form-urlencoded", 32)) { + target->postvars = Utility::parseUrlParameters(bodybuf.str()); + } + target->body = bodybuf.str(); + } + bodybuf.str(""); + this->target = NULL; + }; // { + }; + + /*! Asynchronous HTTP request loader */ + class AsyncRequestLoader: public AsyncLoader { + }; + +}; diff --git a/ext/yahttp/yahttp/router.cpp b/ext/yahttp/yahttp/router.cpp new file mode 100644 index 0000000..a92be62 --- /dev/null +++ b/ext/yahttp/yahttp/router.cpp @@ -0,0 +1,161 @@ +/* @file + * @brief Concrete implementation of Router + */ +#include "yahttp.hpp" +#include "router.hpp" + +namespace YaHTTP { + typedef funcptr::tuple TDelim; + + // router is defined here. + YaHTTP::Router Router::router; + + void Router::map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name) { + std::string method2 = method; + bool isopen=false; + // add into vector + for(std::string::const_iterator i = url.begin(); i != url.end(); i++) { + if (*i == '<' && isopen) throw Error("Invalid URL mask, cannot have < after <"); + if (*i == '<') isopen = true; + if (*i == '>' && !isopen) throw Error("Invalid URL mask, cannot have > without < first"); + if (*i == '>') isopen = false; + } + std::transform(method2.begin(), method2.end(), method2.begin(), ::toupper); + routes.push_back(funcptr::make_tuple(method2, url, handler, name)); + }; + + bool Router::route(Request *req, THandlerFunction& handler) { + std::map params; + int pos1,pos2; + bool matched = false; + std::string rname; + + // iterate routes + for(TRouteList::iterator i = routes.begin(); !matched && i != routes.end(); i++) { + int k1,k2,k3; + std::string pname; + std::string method, url; + funcptr::tie(method, url, handler, rname) = *i; + + if (method.empty() == false && req->method != method) continue; // no match on method + // see if we can't match the url + params.clear(); + // simple matcher func + for(k1=0, k2=0; k1 < static_cast(url.size()) && k2 < static_cast(req->url.path.size()); ) { + if (url[k1] == '<') { + pos1 = k2; + k3 = k1+1; + // start of parameter + while(k1 < static_cast(url.size()) && url[k1] != '>') k1++; + pname = std::string(url.begin()+k3, url.begin()+k1); + // then we also look it on the url + if (pname[0]=='*') { + pname = pname.substr(1); + // this matches whatever comes after it, basically end of string + pos2 = req->url.path.size(); + matched = true; + if (pname != "") + params[pname] = funcptr::tie(pos1,pos2); + k1 = url.size(); + k2 = req->url.path.size(); + break; + } else { + // match until url[k1] + while(k2 < static_cast(req->url.path.size()) && req->url.path[k2] != url[k1+1]) k2++; + pos2 = k2; + params[pname] = funcptr::tie(pos1,pos2); + } + k2--; + } + else if (url[k1] != req->url.path[k2]) { + break; + } + + k1++; k2++; + } + + // ensure. + if (url[k1] != req->url.path[k2]) + matched = false; + else + matched = true; + } + + if (!matched) { return false; } // no route + req->parameters.clear(); + + for(std::map::iterator i = params.begin(); i != params.end(); i++) { + int p1,p2; + funcptr::tie(p1,p2) = i->second; + std::string value(req->url.path.begin() + p1, req->url.path.begin() + p2); + value = Utility::decodeURL(value); + req->parameters[i->first] = value; + } + + req->routeName = rname; + + return true; + }; + + void Router::printRoutes(std::ostream &os) { + for(TRouteList::iterator i = routes.begin(); i != routes.end(); i++) { +#ifdef HAVE_CXX11 + std::streamsize ss = os.width(); + std::ios::fmtflags ff = os.setf(std::ios::left); + os.width(10); + os << std::get<0>(*i); + os.width(50); + os << std::get<1>(*i); + os.width(ss); + os.setf(ff); + os << " " << std::get<3>(*i); + os << std::endl; +#else + os << i->get<0>() << " " << i->get<1>() << " " << i->get<3>() << std::endl; +#endif + } + }; + + std::pair Router::urlFor(const std::string &name, const strstr_map_t& arguments) { + std::ostringstream path; + std::string mask,method,result; + int k1,k2,k3; + + bool found = false; + for(TRouteList::iterator i = routes.begin(); !found && i != routes.end(); i++) { +#ifdef HAVE_CXX11 + if (std::get<3>(*i) == name) { mask = std::get<1>(*i); method = std::get<0>(*i); found = true; } +#else + if (i->get<3>() == name) { mask = i->get<1>(); method = i->get<0>(); found = true; } +#endif + } + + if (!found) + throw Error("Route not found"); + + for(k1=0,k3=0;k1(mask.size());k1++) { + if (mask[k1] == '<') { + std::string pname; + strstr_map_t::const_iterator pptr; + k2=k1; + while(k1(mask.size()) && mask[k1]!='>') k1++; + path << mask.substr(k3,k2-k3); + if (mask[k2+1] == '*') + pname = std::string(mask.begin() + k2 + 2, mask.begin() + k1); + else + pname = std::string(mask.begin() + k2 + 1, mask.begin() + k1); + if ((pptr = arguments.find(pname)) != arguments.end()) + path << Utility::encodeURL(pptr->second); + k3 = k1+1; + } + else if (mask[k1] == '*') { + // ready + k3++; + continue; + } + } + path << mask.substr(k3); + result = path.str(); + return std::make_pair(method, result); + } +}; diff --git a/ext/yahttp/yahttp/router.hpp b/ext/yahttp/yahttp/router.hpp new file mode 100644 index 0000000..145123b --- /dev/null +++ b/ext/yahttp/yahttp/router.hpp @@ -0,0 +1,75 @@ +#ifndef _YAHTTP_ROUTER_HPP +#define _YAHTTP_ROUTER_HPP 1 +/* @file + * @brief Defines router class and support structures + */ +#ifdef HAVE_CXX11 +#include +#include +#define HAVE_CPP_FUNC_PTR +#define IGNORE std::ignore +namespace funcptr = std; +#else +#ifdef HAVE_BOOST +#include +#include +#define IGNORE boost::tuples::ignore +namespace funcptr = boost; +#define HAVE_CPP_FUNC_PTR +#else +#warning "You need to configure with boost or have C++11 capable compiler for router" +#endif +#endif + +#ifdef HAVE_CPP_FUNC_PTR +#include +#include + +namespace YaHTTP { + typedef funcptr::function THandlerFunction; //!< Handler function pointer + typedef funcptr::tuple TRoute; //!< Route tuple (method, urlmask, handler, name) + typedef std::vector TRouteList; //!< List of routes in order of evaluation + + /*! Implements simple router. + +This class implements a router for masked urls. The URL mask syntax is as of follows + +/<masked>/url<number>/<hi>.<format> + +You can use <*param> to denote that everything will be matched and consumed into the parameter, including slash (/). Use <*> to denote that URL +is consumed but not stored. Note that only path is matched, scheme, host and url parameters are ignored. + */ + class Router { + private: + Router() {}; + static Router router; // urlFor(const std::string &name, const strstr_map_t& arguments); //url.path + static void PrintRoutes(std::ostream &os) { router.printRoutes(os); }; // URLFor(const std::string &name, const strstr_map_t& arguments) { return router.urlFor(name,arguments); }; // +#include + +#include "utility.hpp" + +#ifndef YAHTTP_MAX_URL_LENGTH +#define YAHTTP_MAX_URL_LENGTH 2048 +#endif + +namespace YaHTTP { + /*! URL parser and container */ + class URL { + private: + bool parseSchema(const std::string& url, size_t &pos) { + size_t pos1; + if (pos >= url.size()) return false; // no data + if ( (pos1 = url.find_first_of(":",pos)) == std::string::npos ) return false; // schema is mandatory + protocol = url.substr(pos, pos1-pos); + if (protocol == "http") port = 80; + if (protocol == "https") port = 443; + pos = pos1+1; // after : + if (url.compare(pos, 2, "//") == 0) { + pathless = false; // if this is true we put rest into parameters + pos += 2; + } + return true; + }; //= url.size()) return true; // no data + if ( (pos1 = url.find_first_of("/", pos)) == std::string::npos ) { + host = url.substr(pos); + path = "/"; + pos = url.size(); + } else { + host = url.substr(pos, pos1-pos); + pos = pos1; + } + if ( (pos1 = host.find_first_of(":")) != std::string::npos ) { + std::istringstream tmp(host.substr(pos1+1)); + tmp >> port; + host = host.substr(0, pos1); + } + return true; + }; //= url.size()) return true; // no data + + if ( (pos1 = url.find_first_of("@",pos)) == std::string::npos ) return true; // no userinfo + pos2 = url.find_first_of(":",pos); + + if (pos2 != std::string::npos) { // comes with password + username = url.substr(pos, pos2 - pos); + password = url.substr(pos2+1, pos1 - pos2 - 1); + password = Utility::decodeURL(password); + } else { + username = url.substr(pos, pos1 - pos); + } + pos = pos1+1; + username = Utility::decodeURL(username); + return true; + }; //= url.size()) return true; // no data + if (url[pos] != '/') return false; // not an url + if ( (pos1 = url.find_first_of("?", pos)) == std::string::npos ) { + path = url.substr(pos); + pos = url.size(); + } else { + path = url.substr(pos, pos1-pos); + pos = pos1; + } + return true; + }; //= url.size()) return true; // no data + if (url[pos] == '#') return true; // anchor starts here + if (url[pos] != '?') return false; // not a parameter + if ( (pos1 = url.find_first_of("#", pos)) == std::string::npos ) { + parameters = url.substr(pos+1);; + pos = url.size(); + } else { + parameters = url.substr(pos+1, pos1-pos-1); + pos = pos1; + } + if (parameters.size()>0 && *(parameters.end()-1) == '&') parameters.resize(parameters.size()-1); + return true; + }; //= url.size()) return true; // no data + if (url[pos] != '#') return false; // not anchor + anchor = url.substr(pos+1); + return true; + }; // 0) + oss << ":" << port; + + oss << path; + if (parameters.empty() == false) { + if (!pathless) + oss << "?"; + oss << parameters; + } + if (anchor.empty() == false) + oss << "#" << anchor; + return oss.str(); + }; // YAHTTP_MAX_URL_LENGTH) return false; + size_t pos = 0; + if (*(url.begin()) != '/') { // full url? + if (parseSchema(url, pos) == false) return false; + if (pathless) { + parameters = url.substr(pos); + return true; + } + if (parseUserPass(url, pos) == false) return false; + if (parseHost(url, pos) == false) return false; + } + if (parsePath(url, pos) == false) return false; + if (parseParameters(url, pos) == false) return false; + return parseAnchor(url, pos); + }; // strstr_map_t; //utc_offset = ((t2-t)/10)*10; // removes any possible differences. +#endif + }; //utc_offset = 0; +#endif + }; //tm_year + 1900; + month = tm->tm_mon + 1; + day = tm->tm_mday; + hours = tm->tm_hour; + minutes = tm->tm_min; + seconds = tm->tm_sec; + wday = tm->tm_wday; +#ifdef HAVE_TM_GMTOFF + utc_offset = tm->tm_gmtoff; +#endif + isSet = true; + }; // 6) throw std::range_error("Invalid date"); + if (month < 1 || month > 12) throw std::range_error("Invalid date"); + if (year < 0) throw std::range_error("Invalid date"); + if (hours < 0 || hours > 23 || + minutes < 0 || minutes > 59 || + seconds < 0 || seconds > 60) throw std::range_error("Invalid date"); + }; //=0) oss << "+"; + else oss << "-"; + int tmp_off = ( utc_offset < 0 ? utc_offset*-1 : utc_offset ); + oss << std::setfill('0') << std::setw(2) << (tmp_off/3600); + oss << std::setfill('0') << std::setw(2) << (tmp_off%3600)/60; + + return oss.str(); + }; //utc_offset = 0; + } else { + std::cout << cookie_date << std::endl; + throw YaHTTP::ParseError("Unparseable date (did not match pattern cookie)"); + } + }; // result.length()) return result; // end of result + code = result.substr(pos1+1, 2); + a = std::tolower(code[0]); b = std::tolower(code[1]); + + if ((( '0' > a || a > '9') && ('a' > a || a > 'f')) || + (( '0' > b || b > '9') && ('a' > b || b > 'f'))) { + pos2 = pos1+3; + continue; + } + + if ('0' <= a && a <= '9') a = a - '0'; + if ('a' <= a && a <= 'f') a = a - 'a' + 0x0a; + if ('0' <= b && b <= '9') b = b - '0'; + if ('a' <= b && b <= 'f') b = b - 'a' + 0x0a; + + c = (a<<4)+b; + result = result.replace(pos1,3,1,c); + pos2=pos1; + } + return result; + }; //(*iter)); + result = result.replace(pos, 1, "%", 1).insert(pos+1, repl, 2); + iter = result.begin() + pos + 2; + } + } + return result; + }; //(&component[0]); + std::size_t s = component.size() * sizeof((*component.begin())); + std::vector vec(p, p+s); + + std::ostringstream result; + std::string skip = "+-.,&;_#%[]?/@(){}="; + for(std::vector::iterator iter = vec.begin(); iter != vec.end(); iter++) { + if (!YaHTTP::isalnum((char)*iter) && (!asUrl || skip.find((char)*iter) == std::string::npos)) { + // bit more complex replace + result << "%" << std::hex << std::setw(2) << std::setfill('0') << static_cast(*iter); + } else result << (char)*iter; + } + return result.str(); + }; // nextpos) { + delim = nextpos; + } + std::string key; + std::string value; + if (delim == std::string::npos) { + key = parameters.substr(pos); + } else { + key = parameters.substr(pos, delim-pos); + if (nextpos == std::string::npos) { + value = parameters.substr(delim+1); + } else { + value = parameters.substr(delim+1, nextpos-delim-1); + } + } + if (key.empty()) { + // no parameters at all + break; + } + key = decodeURL(key); + value = decodeURL(value); + parameter_map[key] = value; + if (nextpos == std::string::npos) { + // no more parameters left + break; + } + + pos = nextpos+1; + } + return parameter_map; + }; // Content-Type + }; +}; +#endif diff --git a/ext/yahttp/yahttp/yahttp-config.h b/ext/yahttp/yahttp/yahttp-config.h new file mode 100644 index 0000000..1ac2545 --- /dev/null +++ b/ext/yahttp/yahttp/yahttp-config.h @@ -0,0 +1 @@ +#include "config.h" diff --git a/ext/yahttp/yahttp/yahttp.hpp b/ext/yahttp/yahttp/yahttp.hpp new file mode 100644 index 0000000..d60be7a --- /dev/null +++ b/ext/yahttp/yahttp/yahttp.hpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "yahttp-config.h" +#include "exception.hpp" +#include "url.hpp" +#include "utility.hpp" +#include "url.hpp" +#include "cookie.hpp" +#include "reqresp.hpp" + +/*! \mainpage Yet Another HTTP Library Documentation +\section sec_quick_start Quick start example + +@code +#include + +int main(void) { + std::ifstream ifs("request.txt"); + YaHTTP::Request req; + ifs >> req; + + std::cout << req.method " " << req.url.path << std::endl; + return 0; +} +@endcode +\author Aki Tuomi +*/ diff --git a/filterpo.cc b/filterpo.cc new file mode 100644 index 0000000..c73b202 --- /dev/null +++ b/filterpo.cc @@ -0,0 +1,418 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ + +#include +#include + +#include "filterpo.hh" +#include "namespaces.hh" +#include "dnsrecords.hh" + +DNSFilterEngine::DNSFilterEngine() +{ +} + +bool DNSFilterEngine::Zone::findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const +{ + return findNamedPolicy(d_qpolName, qname, pol); +} + +bool DNSFilterEngine::Zone::findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const +{ + return findNamedPolicy(d_propolName, qname, pol); +} + +bool DNSFilterEngine::Zone::findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const +{ + if (const auto fnd = d_propolNSAddr.lookup(addr)) { + pol = fnd->second; + return true; + } + return false; +} + +bool DNSFilterEngine::Zone::findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const +{ + if (const auto fnd = d_postpolAddr.lookup(addr)) { + pol = fnd->second; + return true; + } + return false; +} + +bool DNSFilterEngine::Zone::findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const +{ + if (const auto fnd = d_qpolAddr.lookup(addr)) { + pol = fnd->second; + return true; + } + return false; +} + +bool DNSFilterEngine::Zone::findNamedPolicy(const std::unordered_map& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol) const +{ + /* for www.powerdns.com, we need to check: + www.powerdns.com. + *.powerdns.com. + *.com. + *. + */ + + std::unordered_map::const_iterator iter; + iter = polmap.find(qname); + + if(iter != polmap.end()) { + pol=iter->second; + return true; + } + + DNSName s(qname); + while(s.chopOff()){ + iter = polmap.find(g_wildcarddnsname+s); + if(iter != polmap.end()) { + pol=iter->second; + return true; + } + } + return false; +} + +DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const DNSName& qname, const std::unordered_map& discardedPolicies) const +{ + // cout<<"Got question for nameserver name "<getName(); + if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) { + continue; + } + + if(z->findNSPolicy(qname, pol)) { + // cerr<<"Had a hit on the nameserver ("<& discardedPolicies) const +{ + Policy pol; + // cout<<"Got question for nameserver IP "<getName(); + if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) { + continue; + } + + if(z->findNSIPPolicy(address, pol)) { + // cerr<<"Had a hit on the nameserver ("<& discardedPolicies) const +{ + // cout<<"Got question for "<getName(); + if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) { + continue; + } + + if(z->findQNamePolicy(qname, pol)) { + // cerr<<"Had a hit on the name of the query"<findClientPolicy(ca, pol)) { + // cerr<<"Had a hit on the IP address ("<& records, const std::unordered_map& discardedPolicies) const +{ + Policy pol; + ComboAddress ca; + for(const auto& r : records) { + if(r.d_place != DNSResourceRecord::ANSWER) + continue; + if(r.d_type == QType::A) { + if (auto rec = getRR(r)) { + ca = rec->getCA(); + } + } + else if(r.d_type == QType::AAAA) { + if (auto rec = getRR(r)) { + ca = rec->getCA(); + } + } + else + continue; + + for(const auto& z : d_zones) { + const auto zoneName = z->getName(); + if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) { + continue; + } + + if(z->findResponsePolicy(ca, pol)) { + return pol; + } + } + } + return pol; +} + +void DNSFilterEngine::assureZones(size_t zone) +{ + if(d_zones.size() <= zone) + d_zones.resize(zone+1); +} + +void DNSFilterEngine::Zone::addClientTrigger(const Netmask& nm, Policy pol) +{ + pol.d_name = d_name; + pol.d_type = PolicyType::ClientIP; + d_qpolAddr.insert(nm).second=pol; +} + +void DNSFilterEngine::Zone::addResponseTrigger(const Netmask& nm, Policy pol) +{ + pol.d_name = d_name; + pol.d_type = PolicyType::ResponseIP; + d_postpolAddr.insert(nm).second=pol; +} + +void DNSFilterEngine::Zone::addQNameTrigger(const DNSName& n, Policy pol) +{ + pol.d_name = d_name; + pol.d_type = PolicyType::QName; + d_qpolName[n]=pol; +} + +void DNSFilterEngine::Zone::addNSTrigger(const DNSName& n, Policy pol) +{ + pol.d_name = d_name; + pol.d_type = PolicyType::NSDName; + d_propolName[n]=pol; +} + +void DNSFilterEngine::Zone::addNSIPTrigger(const Netmask& nm, Policy pol) +{ + pol.d_name = d_name; + pol.d_type = PolicyType::NSIP; + d_propolNSAddr.insert(nm).second = pol; +} + +bool DNSFilterEngine::Zone::rmClientTrigger(const Netmask& nm, Policy pol) +{ + d_qpolAddr.erase(nm); + return true; +} + +bool DNSFilterEngine::Zone::rmResponseTrigger(const Netmask& nm, Policy pol) +{ + d_postpolAddr.erase(nm); + return true; +} + +bool DNSFilterEngine::Zone::rmQNameTrigger(const DNSName& n, Policy pol) +{ + d_qpolName.erase(n); // XXX verify we had identical policy? + return true; +} + +bool DNSFilterEngine::Zone::rmNSTrigger(const DNSName& n, Policy pol) +{ + d_propolName.erase(n); // XXX verify policy matched? =pol; + return true; +} + +bool DNSFilterEngine::Zone::rmNSIPTrigger(const Netmask& nm, Policy pol) +{ + d_propolNSAddr.erase(nm); + return true; +} + +DNSRecord DNSFilterEngine::Policy::getCustomRecord(const DNSName& qname) const +{ + if (d_kind != PolicyKind::Custom) { + throw std::runtime_error("Asking for a custom record from a filtering policy of a non-custom type"); + } + + DNSRecord result; + result.d_name = qname; + result.d_type = d_custom->getType(); + result.d_ttl = d_ttl; + result.d_class = QClass::IN; + result.d_place = DNSResourceRecord::ANSWER; + result.d_content = d_custom; + + if (result.d_type == QType::CNAME) { + const auto content = std::dynamic_pointer_cast(d_custom); + if (content) { + DNSName target = content->getTarget(); + if (target.isWildcard()) { + target.chopOff(); + result.d_content = std::make_shared(qname + target); + } + } + } + + return result; +} + +std::string DNSFilterEngine::Policy::getKindToString() const +{ + static const DNSName drop("rpz-drop."), truncate("rpz-tcp-only."), noaction("rpz-passthru."); + static const DNSName rpzClientIP("rpz-client-ip"), rpzIP("rpz-ip"), + rpzNSDname("rpz-nsdname"), rpzNSIP("rpz-nsip."); + static const std::string rpzPrefix("rpz-"); + + switch(d_kind) { + case DNSFilterEngine::PolicyKind::NoAction: + return noaction.toString(); + case DNSFilterEngine::PolicyKind::Drop: + return drop.toString(); + case DNSFilterEngine::PolicyKind::NXDOMAIN: + return g_rootdnsname.toString(); + case PolicyKind::NODATA: + return g_wildcarddnsname.toString(); + case DNSFilterEngine::PolicyKind::Truncate: + return truncate.toString(); + default: + throw std::runtime_error("Unexpected DNSFilterEngine::Policy kind"); + } +} + +DNSRecord DNSFilterEngine::Policy::getRecord(const DNSName& qname) const +{ + DNSRecord dr; + + if (d_kind == PolicyKind::Custom) { + dr = getCustomRecord(qname); + } + else { + dr.d_name = qname; + dr.d_ttl = static_cast(d_ttl); + dr.d_type = QType::CNAME; + dr.d_class = QClass::IN; + dr.d_content = DNSRecordContent::mastermake(QType::CNAME, QClass::IN, getKindToString()); + } + + return dr; +} + +void DNSFilterEngine::Zone::dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const +{ + DNSRecord dr = pol.getRecord(name); + fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str()); +} + +DNSName DNSFilterEngine::Zone::maskToRPZ(const Netmask& nm) +{ + int bits = nm.getBits(); + DNSName res(std::to_string(bits)); + const auto addr = nm.getNetwork(); + + if (addr.isIPv4()) { + const uint8_t* bytes = reinterpret_cast(&addr.sin4.sin_addr.s_addr); + res += DNSName(std::to_string(bytes[3]) + "." + std::to_string(bytes[2]) + "." + std::to_string(bytes[1]) + "." + std::to_string(bytes[0])); + } + else { + DNSName temp; + const auto str = addr.toString(); + const auto len = str.size(); + std::string::size_type begin = 0; + + while (begin < len) { + std::string::size_type end = str.find(":", begin); + std::string sub; + if (end != string::npos) { + sub = str.substr(begin, end - begin); + } + else { + sub = str.substr(begin); + } + + if (sub.empty()) { + temp = DNSName("zz") + temp; + } + else { + temp = DNSName(sub) + temp; + } + + if (end == string::npos) { + break; + } + begin = end + 1; + } + res += temp; + } + + return res; +} + + +void DNSFilterEngine::Zone::dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol) const +{ + DNSName full = maskToRPZ(nm); + full += name; + + DNSRecord dr = pol.getRecord(full); + fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str()); +} + +void DNSFilterEngine::Zone::dump(FILE* fp) const +{ + /* fake the SOA record */ + auto soa = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800"); + fprintf(fp, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str()); + + for (const auto& pair : d_qpolName) { + dumpNamedPolicy(fp, pair.first + d_domain, pair.second); + } + + for (const auto& pair : d_propolName) { + dumpNamedPolicy(fp, pair.first + DNSName("rpz-nsdname.") + d_domain, pair.second); + } + + for (const auto pair : d_qpolAddr) { + dumpAddrPolicy(fp, pair->first, DNSName("rpz-client-ip.") + d_domain, pair->second); + } + + for (const auto pair : d_propolNSAddr) { + dumpAddrPolicy(fp, pair->first, DNSName("rpz-nsip.") + d_domain, pair->second); + } + + for (const auto pair : d_postpolAddr) { + dumpAddrPolicy(fp, pair->first, DNSName("rpz-ip.") + d_domain, pair->second); + } +} diff --git a/filterpo.hh b/filterpo.hh new file mode 100644 index 0000000..ba43829 --- /dev/null +++ b/filterpo.hh @@ -0,0 +1,228 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include "iputils.hh" +#include "dns.hh" +#include "dnsname.hh" +#include "dnsparser.hh" +#include +#include + +/* This class implements a filtering policy that is able to fully implement RPZ, but is not bound to it. + In other words, it is generic enough to support RPZ, but could get its data from other places. + + + We know the following actions: + + No action - just pass it on + Drop - drop a query, no response + NXDOMAIN - fake up an NXDOMAIN for the query + NODATA - just return no data for this qtype + Truncate - set TC bit + Modified - "we fake an answer for you" + + These actions can be caused by the following triggers: + + qname - the query name + client-ip - the IP address of the requestor + response-ip - an IP address in the response + ns-name - the name of a server used in the delegation + ns-ip - the IP address of a server used in the delegation + + This means we get several hook points: + 1) when the query comes in: qname & client-ip + 2) during processing: ns-name & ns-ip + 3) after processing: response-ip + + Triggers meanwhile can apply to: + Verbatim domain names + Wildcard versions (*.domain.com does NOT match domain.com) + Netmasks (IPv4 and IPv6) + Finally, triggers are grouped in different zones. The "first" zone that has a match + is consulted. Then within that zone, rules again have precedences. +*/ + + +class DNSFilterEngine +{ +public: + enum class PolicyKind { NoAction, Drop, NXDOMAIN, NODATA, Truncate, Custom}; + enum class PolicyType { None, QName, ClientIP, ResponseIP, NSDName, NSIP }; + + struct Policy + { + Policy(): d_custom(nullptr), d_name(nullptr), d_kind(PolicyKind::NoAction), d_type(PolicyType::None), d_ttl(0) + { + } + bool operator==(const Policy& rhs) const + { + return d_kind == rhs.d_kind; // XXX check d_custom too! + } + std::string getKindToString() const; + DNSRecord getCustomRecord(const DNSName& qname) const; + DNSRecord getRecord(const DNSName& qname) const; + + std::shared_ptr d_custom; + std::shared_ptr d_name; + PolicyKind d_kind; + PolicyType d_type; + int32_t d_ttl; + }; + + class Zone { + public: + void clear() + { + d_qpolAddr.clear(); + d_postpolAddr.clear(); + d_propolName.clear(); + d_propolNSAddr.clear(); + d_qpolName.clear(); + } + void reserve(size_t entriesCount) + { + d_qpolName.reserve(entriesCount); + } + void setName(const std::string& name) + { + d_name = std::make_shared(name); + } + void setDomain(const DNSName& domain) + { + d_domain = domain; + } + void setSerial(uint32_t serial) + { + d_serial = serial; + } + void setRefresh(uint32_t refresh) + { + d_refresh = refresh; + } + const std::shared_ptr getName() const + { + return d_name; + } + + DNSName getDomain() const + { + return d_domain; + } + + uint32_t getRefresh() const + { + return d_refresh; + } + + size_t size() const + { + return d_qpolAddr.size() + d_postpolAddr.size() + d_propolName.size() + d_propolNSAddr.size() + d_qpolName.size(); + + } + + void dump(FILE * fp) const; + + void addClientTrigger(const Netmask& nm, Policy pol); + void addQNameTrigger(const DNSName& nm, Policy pol); + void addNSTrigger(const DNSName& dn, Policy pol); + void addNSIPTrigger(const Netmask& nm, Policy pol); + void addResponseTrigger(const Netmask& nm, Policy pol); + + bool rmClientTrigger(const Netmask& nm, Policy pol); + bool rmQNameTrigger(const DNSName& nm, Policy pol); + bool rmNSTrigger(const DNSName& dn, Policy pol); + bool rmNSIPTrigger(const Netmask& nm, Policy pol); + bool rmResponseTrigger(const Netmask& nm, Policy pol); + + bool findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const; + bool findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const; + bool findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const; + bool findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const; + bool findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const; + + private: + static DNSName maskToRPZ(const Netmask& nm); + bool findNamedPolicy(const std::unordered_map& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol) const; + void dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const; + void dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol) const; + + std::unordered_map d_qpolName; // QNAME trigger (RPZ) + NetmaskTree d_qpolAddr; // Source address + std::unordered_map d_propolName; // NSDNAME (RPZ) + NetmaskTree d_propolNSAddr; // NSIP (RPZ) + NetmaskTree d_postpolAddr; // IP trigger (RPZ) + DNSName d_domain; + std::shared_ptr d_name; + uint32_t d_serial{0}; + uint32_t d_refresh{0}; + }; + + DNSFilterEngine(); + void clear() + { + for(auto& z : d_zones) { + z->clear(); + } + } + const std::shared_ptr getZone(size_t zoneIdx) const + { + std::shared_ptr result{nullptr}; + if (zoneIdx < d_zones.size()) { + result = d_zones[zoneIdx]; + } + return result; + } + const std::shared_ptr getZone(const std::string& name) const + { + for (const auto zone : d_zones) { + const auto& zName = zone->getName(); + if (zName && *zName == name) { + return zone; + } + } + return nullptr; + } + size_t addZone(std::shared_ptr newZone) + { + d_zones.push_back(newZone); + return (d_zones.size() - 1); + } + void setZone(size_t zoneIdx, std::shared_ptr newZone) + { + if (newZone) { + assureZones(zoneIdx); + d_zones[zoneIdx] = newZone; + } + } + + Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map& discardedPolicies) const; + Policy getProcessingPolicy(const DNSName& qname, const std::unordered_map& discardedPolicies) const; + Policy getProcessingPolicy(const ComboAddress& address, const std::unordered_map& discardedPolicies) const; + Policy getPostPolicy(const vector& records, const std::unordered_map& discardedPolicies) const; + + size_t size() const { + return d_zones.size(); + } +private: + void assureZones(size_t zone); + vector> d_zones; +}; diff --git a/gettime.cc b/gettime.cc new file mode 100644 index 0000000..b6d95a4 --- /dev/null +++ b/gettime.cc @@ -0,0 +1,52 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "gettime.hh" +#include "config.h" + +#ifdef HAVE_CLOCK_GETTIME +#include + +#ifndef CLOCK_MONOTONIC_RAW +#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC +#endif + +int gettime(struct timespec *tp, bool needRealTime) +{ + return clock_gettime(needRealTime ? CLOCK_REALTIME : CLOCK_MONOTONIC, tp); +} + +#else +#include + +int gettime(struct timespec *tp, bool needRealTime) +{ + struct timeval tv; + + int ret = gettimeofday(&tv, NULL); + if(ret < 0) return ret; + + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; + return ret; +} + +#endif diff --git a/gettime.hh b/gettime.hh new file mode 100644 index 0000000..29c0fca --- /dev/null +++ b/gettime.hh @@ -0,0 +1,24 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +extern int gettime(struct timespec *tp, bool needRealTime=false); diff --git a/gss_context.cc b/gss_context.cc new file mode 100644 index 0000000..55c54be --- /dev/null +++ b/gss_context.cc @@ -0,0 +1,495 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include "namespaces.hh" +#include "dns.hh" +#include "dnsparser.hh" +#include "dnspacket.hh" +#include "dnsrecords.hh" +#include "logger.hh" +#include "lock.hh" +#include "arguments.hh" + +#include +#include +#include "gss_context.hh" + +#ifndef ENABLE_GSS_TSIG + +bool GssContext::supported() { return false; } +GssContext::GssContext() { d_error = GSS_CONTEXT_UNSUPPORTED; d_type = GSS_CONTEXT_NONE; } +GssContext::GssContext(const DNSName& label) { d_error = GSS_CONTEXT_UNSUPPORTED; d_type = GSS_CONTEXT_NONE; } +void GssContext::setLocalPrincipal(const std::string& name) {} +bool GssContext::getLocalPrincipal(std::string& name) { return false; } +void GssContext::setPeerPrincipal(const std::string& name) {} +bool GssContext::getPeerPrincipal(std::string& name) { return false; } +void GssContext::generateLabel(const std::string& suffix) {} +void GssContext::setLabel(const DNSName& label) {} +bool GssContext::init(const std::string &input, std::string& output) { return false; } +bool GssContext::accept(const std::string &input, std::string& output) { return false; } +bool GssContext::destroy() { return false; } +bool GssContext::expired() { return false; } +bool GssContext::valid() { return false; } +bool GssContext::sign(const std::string &input, std::string& output) { return false; } +bool GssContext::verify(const std::string &input, const std::string &signature) { return false; } +GssContextError GssContext::getError() { return GSS_CONTEXT_UNSUPPORTED; } + +#else + +class GssCredential : boost::noncopyable { +public: + GssCredential(const std::string& name, const gss_cred_usage_t usage) { + gss_buffer_desc buffer; + d_name = GSS_C_NO_NAME; + d_nameS = name; + d_cred = GSS_C_NO_CREDENTIAL; + + d_usage = usage; + d_valid = false; + + if (name.empty() == false) { + buffer.length = name.size(); + buffer.value = (void*)name.c_str(); + d_maj = gss_import_name(&d_min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name); + if (d_maj != GSS_S_COMPLETE) { + d_valid = false; + return; + } + } + + renew(); + }; + + ~GssCredential() { + OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); + if (d_cred != GSS_C_NO_CREDENTIAL) + tmp_maj = gss_release_cred(&tmp_min, &d_cred); + if (d_name != GSS_C_NO_NAME) + tmp_maj = gss_release_name(&tmp_min, &d_name); + }; + + bool expired() const { + if (d_expires == -1) return false; + return time((time_t*)NULL)>d_expires; + } + + bool renew() { + OM_uint32 time_rec, tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); + d_maj = gss_acquire_cred(&d_min, d_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, d_usage, &d_cred, NULL, &time_rec); + + if (d_maj != GSS_S_COMPLETE) { + d_valid = false; + tmp_maj = gss_release_name(&tmp_min, &d_name); + d_name = GSS_C_NO_NAME; + return false; + } + + d_valid = true; + + if (time_rec > GSS_C_INDEFINITE) { + d_expires = time((time_t*)NULL)+time_rec; + } else { + d_expires = -1; + } + + return true; + } + + bool valid() { + return d_valid && !expired(); + } + + OM_uint32 d_maj,d_min; + + bool d_valid; + int64_t d_expires; + std::string d_nameS; + gss_name_t d_name; + gss_cred_id_t d_cred; + gss_cred_usage_t d_usage; +}; + +std::map > s_gss_accept_creds; +std::map > s_gss_init_creds; + +class GssSecContext : boost::noncopyable { +public: + GssSecContext(boost::shared_ptr cred) { + if (cred->valid() == false) throw PDNSException("Invalid credential " + cred->d_nameS); + d_cred = cred; + d_state = GssStateInitial; + d_ctx = GSS_C_NO_CONTEXT; + d_expires = 0; + d_maj = d_min = 0; + d_peer_name = GSS_C_NO_NAME; + d_type = GSS_CONTEXT_NONE; + } + + ~GssSecContext() { + OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); + if (d_ctx != GSS_C_NO_CONTEXT) { + tmp_maj = gss_delete_sec_context(&tmp_min, &d_ctx, GSS_C_NO_BUFFER); + } + if (d_peer_name != GSS_C_NO_NAME) { + tmp_maj = gss_release_name(&tmp_min, &(d_peer_name)); + } + } + + GssContextType d_type; + gss_ctx_id_t d_ctx; + gss_name_t d_peer_name; + int64_t d_expires; + boost::shared_ptr d_cred; + OM_uint32 d_maj,d_min; + + enum { + GssStateInitial, + GssStateNegotiate, + GssStateComplete, + GssStateError + } d_state; + +}; + +std::map > s_gss_sec_context; + +bool GssContext::supported() { return true; } + +void GssContext::initialize() { + d_peerPrincipal = ""; + d_localPrincipal = ""; + d_error = GSS_CONTEXT_NO_ERROR; + d_type = GSS_CONTEXT_NONE; +} + +GssContext::GssContext() { + initialize(); + generateLabel("pdns.tsig."); +} + +GssContext::GssContext(const DNSName& label) { + initialize(); + setLabel(label); +} + +void GssContext::generateLabel(const std::string& suffix) { + std::ostringstream oss; + oss << std::hex << time((time_t*)NULL) << "." << suffix; + setLabel(DNSName(oss.str())); +} + +void GssContext::setLabel(const DNSName& label) { + d_label = label; + if (s_gss_sec_context.find(d_label) != s_gss_sec_context.end()) { + d_ctx = s_gss_sec_context[d_label]; + d_type = d_ctx->d_type; + } +} + +bool GssContext::expired() { + return (!d_ctx || (d_ctx->d_expires > -1 && d_ctx->d_expires < time((time_t*)NULL))); +} + +bool GssContext::valid() { + return (d_ctx && !expired() && d_ctx->d_state == GssSecContext::GssStateComplete); +} + +bool GssContext::init(const std::string &input, std::string& output) { + OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); + OM_uint32 maj,min; + gss_buffer_desc recv_tok, send_tok, buffer; + OM_uint32 flags; + OM_uint32 expires; + + boost::shared_ptr cred; + if (d_label.empty()) { + d_error = GSS_CONTEXT_INVALID; + return false; + } + + d_type = GSS_CONTEXT_INIT; + + if (s_gss_init_creds.find(d_localPrincipal) != s_gss_init_creds.end()) { + cred = s_gss_init_creds[d_localPrincipal]; + } else { + s_gss_init_creds[d_localPrincipal] = boost::make_shared(d_localPrincipal, GSS_C_INITIATE); + cred = s_gss_init_creds[d_localPrincipal]; + } + + // see if we can find a context in non-completed state + if (d_ctx) { + if (d_ctx->d_state != GssSecContext::GssStateNegotiate) { + d_error = GSS_CONTEXT_INVALID; + return false; + } + } else { + // make context + s_gss_sec_context[d_label] = boost::make_shared(cred); + s_gss_sec_context[d_label]->d_type = d_type; + d_ctx = s_gss_sec_context[d_label]; + d_ctx->d_state = GssSecContext::GssStateNegotiate; + } + + recv_tok.length = input.size(); + recv_tok.value = (void*)input.c_str(); + + if (d_peerPrincipal.empty() == false) { + buffer.value = (void*)d_peerPrincipal.c_str(); + buffer.length = d_peerPrincipal.size(); + maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &(d_ctx->d_peer_name)); + if (maj != GSS_S_COMPLETE) { + processError("gss_import_name", maj, min); + return false; + } + } + + maj = gss_init_sec_context(&min, cred->d_cred, &(d_ctx->d_ctx), d_ctx->d_peer_name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &recv_tok, NULL, &send_tok, &flags, &expires); + + if (send_tok.length>0) { + output.assign((const char*)send_tok.value, send_tok.length); + tmp_maj = gss_release_buffer(&tmp_min, &send_tok); + } + + if (maj == GSS_S_COMPLETE) { + if (expires > GSS_C_INDEFINITE) { + d_ctx->d_expires = time((time_t*)NULL) + expires; + } else { + d_ctx->d_expires = -1; + } + d_ctx->d_state = GssSecContext::GssStateComplete; + return true; + } else if (maj != GSS_S_CONTINUE_NEEDED) { + processError("gss_init_sec_context", maj,min); + } + + return (maj == GSS_S_CONTINUE_NEEDED); +} + +bool GssContext::accept(const std::string &input, std::string& output) { + OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); + OM_uint32 maj,min; + gss_buffer_desc recv_tok, send_tok; + OM_uint32 flags; + OM_uint32 expires; + + boost::shared_ptr cred; + if (d_label.empty()) { + d_error = GSS_CONTEXT_INVALID; + return false; + } + + d_type = GSS_CONTEXT_ACCEPT; + + if (s_gss_accept_creds.find(d_localPrincipal) != s_gss_accept_creds.end()) { + cred = s_gss_accept_creds[d_localPrincipal]; + } else { + s_gss_accept_creds[d_localPrincipal] = boost::make_shared(d_localPrincipal, GSS_C_ACCEPT); + cred = s_gss_accept_creds[d_localPrincipal]; + } + + // see if we can find a context in non-completed state + if (d_ctx) { + if (d_ctx->d_state != GssSecContext::GssStateNegotiate) { + d_error = GSS_CONTEXT_INVALID; + return false; + } + } else { + // make context + s_gss_sec_context[d_label] = boost::make_shared(cred); + s_gss_sec_context[d_label]->d_type = d_type; + d_ctx = s_gss_sec_context[d_label]; + d_ctx->d_state = GssSecContext::GssStateNegotiate; + } + + recv_tok.length = input.size(); + recv_tok.value = (void*)input.c_str(); + + maj = gss_accept_sec_context(&min, &(d_ctx->d_ctx), cred->d_cred, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &(d_ctx->d_peer_name), NULL, &send_tok, &flags, &expires, NULL); + + if (send_tok.length>0) { + output.assign((const char*)send_tok.value, send_tok.length); + tmp_maj = gss_release_buffer(&tmp_min, &send_tok); + } + + if (maj == GSS_S_COMPLETE) { + if (expires > GSS_C_INDEFINITE) { + d_ctx->d_expires = time((time_t*)NULL) + expires; + } else { + d_ctx->d_expires = -1; + } + d_ctx->d_state = GssSecContext::GssStateComplete; + return true; + } else if (maj != GSS_S_CONTINUE_NEEDED) { + processError("gss_accept_sec_context", maj,min); + } + return (maj == GSS_S_CONTINUE_NEEDED); +}; + +bool GssContext::sign(const std::string& input, std::string& output) { + OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); + OM_uint32 maj,min; + + gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + + recv_tok.length = input.size(); + recv_tok.value = (void*)input.c_str(); + + maj = gss_get_mic(&min, d_ctx->d_ctx, GSS_C_QOP_DEFAULT, &recv_tok, &send_tok); + + if (send_tok.length>0) { + output.assign((const char*)send_tok.value, send_tok.length); + tmp_maj = gss_release_buffer(&tmp_min, &send_tok); + } + + if (maj != GSS_S_COMPLETE) { + processError("gss_get_mic", maj,min); + } + + return (maj == GSS_S_COMPLETE); +} + +bool GssContext::verify(const std::string& input, const std::string& signature) { + OM_uint32 maj,min; + + gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc sign_tok = GSS_C_EMPTY_BUFFER; + + recv_tok.length = input.size(); + recv_tok.value = (void*)input.c_str(); + sign_tok.length = signature.size(); + sign_tok.value = (void*)signature.c_str(); + + maj = gss_verify_mic(&min, d_ctx->d_ctx, &recv_tok, &sign_tok, NULL); + + if (maj != GSS_S_COMPLETE) { + processError("gss_get_mic", maj,min); + } + + return (maj == GSS_S_COMPLETE); +} + +bool GssContext::destroy() { + return false; +} + +void GssContext::setLocalPrincipal(const std::string& name) { + d_localPrincipal = name; +} + +bool GssContext::getLocalPrincipal(std::string& name) { + name = d_localPrincipal; + return name.size()>0; +} + +void GssContext::setPeerPrincipal(const std::string& name) { + d_peerPrincipal = name; +} + +bool GssContext::getPeerPrincipal(std::string& name) { + gss_buffer_desc value; + OM_uint32 maj,min; + + if (d_ctx->d_peer_name != GSS_C_NO_NAME) { + maj = gss_display_name(&min, d_ctx->d_peer_name, &value, NULL); + if (maj == GSS_S_COMPLETE && value.length > 0) { + name.assign((const char*)value.value, value.length); + maj = gss_release_buffer(&min, &value); + return true; + } else { + return false; + } + } else { + return false; + } +} + +void GssContext::processError(const std::string& method, OM_uint32 maj, OM_uint32 min) { + OM_uint32 tmp_min; + gss_buffer_desc msg; + OM_uint32 msg_ctx; + + msg_ctx = 0; + while (1) { + ostringstream oss; + gss_display_status(&tmp_min, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); + oss << method << ": " << (char*)msg.value; + d_gss_errors.push_back(oss.str()); + if (!msg_ctx) break; + } + msg_ctx = 0; + while (1) { + ostringstream oss; + gss_display_status(&tmp_min, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); + oss << method << ": " << (char*)msg.value; + d_gss_errors.push_back(oss.str()); + if (!msg_ctx) break; + } +} + +#endif + +bool gss_add_signature(const DNSName& context, const std::string& message, std::string& mac) { + string tmp_mac; + GssContext gssctx(context); + if (!gssctx.valid()) { + L< +#include +#include +#endif + +//! Generic errors +enum GssContextError { + GSS_CONTEXT_NO_ERROR, + GSS_CONTEXT_UNSUPPORTED, + GSS_CONTEXT_NOT_FOUND, + GSS_CONTEXT_NOT_INITIALIZED, + GSS_CONTEXT_INVALID, + GSS_CONTEXT_EXPIRED, + GSS_CONTEXT_ALREADY_INITIALIZED +}; + +//! GSS context types +enum GssContextType { + GSS_CONTEXT_NONE, + GSS_CONTEXT_INIT, + GSS_CONTEXT_ACCEPT +}; + +class GssSecContext; + +/*! Class for representing GSS names, such as host/host.domain.com@REALM. +*/ +class GssName { +public: + //! Initialize to empty name + GssName() { + setName(""); + }; + + //! Initialize using specific name + GssName(const std::string& name) { + setName(name); + }; + + //! Parse name into native representation + bool setName(const std::string& name) { +#ifdef ENABLE_GSS_TSIG + gss_buffer_desc buffer; + d_name = GSS_C_NO_NAME; + + if (!name.empty()) { + buffer.length = name.size(); + buffer.value = (void*)name.c_str(); + d_maj = gss_import_name(&d_min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name); + return d_maj == GSS_S_COMPLETE; + } + + return true; +#endif + return false; + }; + + ~GssName() { +#ifdef ENABLE_GSS_TSIG + if (d_name != GSS_C_NO_NAME) + gss_release_name(&d_min, &d_name); +#endif + }; + + //! Compare two Gss Names, if no gss support is compiled in, returns false always + //! This is not necessarily same as string comparison between two non-parsed names + bool operator==(const GssName& rhs) { +#ifdef ENABLE_GSS_TSIG + OM_uint32 maj,min; + int result; + maj = gss_compare_name(&min, d_name, rhs.d_name, &result); + return (maj == GSS_S_COMPLETE && result != 0); +#endif + return false; + } + + //! Compare two Gss Names, if no gss support is compiled in, returns false always + //! This is not necessarily same as string comparison between two non-parsed names + bool match(const std::string& name) { +#ifdef ENABLE_GSS_TSIG + OM_uint32 maj,min; + int result; + gss_name_t comp; + gss_buffer_desc buffer; + buffer.length = name.size(); + buffer.value = (void*)name.c_str(); + maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &comp); + if (maj != GSS_S_COMPLETE) + throw PDNSException("Could not import " + name + ": " + std::to_string(maj) + string(",") + std::to_string(min)); + // do comparison + maj = gss_compare_name(&min, d_name, comp, &result); + gss_release_name(&min, &comp); + return (maj == GSS_S_COMPLETE && result != 0); +#else + return false; +#endif + }; + + //! Check if GSS name was parsed successfully. + bool valid() { +#ifdef ENABLE_GSS_TSIG + return d_maj == GSS_S_COMPLETE; +#else + return false; +#endif + } +private: +#ifdef ENABLE_GSS_TSIG + OM_uint32 d_maj,d_min; + gss_name_t d_name; +#endif +}; + +class GssContext { +public: + static bool supported(); // getErrorStrings() { return d_gss_errors; } // d_gss_errors; // d_ctx; // + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + 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 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This 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. + diff --git a/html/detail.css b/html/detail.css new file mode 100644 index 0000000..b0567a4 --- /dev/null +++ b/html/detail.css @@ -0,0 +1,104 @@ +.rickshaw_graph .detail { + pointer-events: none; + position: absolute; + top: 0; + z-index: 2; + background: rgba(0, 0, 0, 0.1); + bottom: 0; + width: 1px; + transition: opacity 0.25s linear; + -moz-transition: opacity 0.25s linear; + -o-transition: opacity 0.25s linear; + -webkit-transition: opacity 0.25s linear; +} +.rickshaw_graph .detail.inactive { + opacity: 0; +} +.rickshaw_graph .detail .item.active { + opacity: 1; +} +.rickshaw_graph .detail .x_label { + font-family: Arial, sans-serif; + border-radius: 3px; + padding: 6px; + opacity: 0.5; + border: 1px solid #e0e0e0; + font-size: 12px; + position: absolute; + background: white; + white-space: nowrap; + top: -20px; /* add this */ +} +.rickshaw_graph .detail .x_label.left { + left: 0; +} +.rickshaw_graph .detail .x_label.right { + right: 0; +} +.rickshaw_graph .detail .item { + position: absolute; + z-index: 2; + border-radius: 3px; + padding: 0.25em; + font-size: 12px; + font-family: Arial, sans-serif; + opacity: 0; + background: rgba(0, 0, 0, 0.4); + color: white; + border: 1px solid rgba(0, 0, 0, 0.4); + margin-left: 1em; + margin-right: 1em; + margin-top: -1em; + white-space: nowrap; +} +.rickshaw_graph .detail .item.left { + left: 0; +} +.rickshaw_graph .detail .item.right { + right: 0; +} +.rickshaw_graph .detail .item.active { + opacity: 1; + background: rgba(0, 0, 0, 0.8); +} +.rickshaw_graph .detail .item:after { + position: absolute; + display: block; + width: 0; + height: 0; + + content: ""; + + border: 5px solid transparent; +} +.rickshaw_graph .detail .item.left:after { + top: 1em; + left: -5px; + margin-top: -5px; + border-right-color: rgba(0, 0, 0, 0.8); + border-left-width: 0; +} +.rickshaw_graph .detail .item.right:after { + top: 1em; + right: -5px; + margin-top: -5px; + border-left-color: rgba(0, 0, 0, 0.8); + border-right-width: 0; +} +.rickshaw_graph .detail .dot { + width: 4px; + height: 4px; + margin-left: -2px; + margin-top: -2px; + border-radius: 5px; + position: absolute; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); + background: white; + border-width: 2px; + border-style: solid; + display: none; + background-clip: padding-box; +} +.rickshaw_graph .detail .dot.active { + display: block; +} diff --git a/html/graph.css b/html/graph.css new file mode 100644 index 0000000..1f9c976 --- /dev/null +++ b/html/graph.css @@ -0,0 +1,177 @@ +/* graph */ + +.rickshaw_graph { + position: relative; +} +.rickshaw_graph svg { + display: block; + overflow: hidden; +} + +/* ticks */ + +.rickshaw_graph .x_tick { + position: absolute; + top: 0; + bottom: 0; + width: 0px; + border-left: 1px dotted rgba(0, 0, 0, 0.2); + pointer-events: none; +} +.rickshaw_graph .x_tick .title { + position: absolute; + font-size: 12px; + font-family: Arial, sans-serif; + opacity: 0.5; + white-space: nowrap; + margin-left: 3px; + bottom: 1px; +} + +/* annotations */ + +.rickshaw_annotation_timeline { + height: 1px; + border-top: 1px solid #e0e0e0; + margin-top: 10px; + position: relative; +} +.rickshaw_annotation_timeline .annotation { + position: absolute; + height: 6px; + width: 6px; + margin-left: -2px; + top: -3px; + border-radius: 5px; + background-color: rgba(0, 0, 0, 0.25); +} +.rickshaw_graph .annotation_line { + position: absolute; + top: 0; + bottom: -6px; + width: 0px; + border-left: 2px solid rgba(0, 0, 0, 0.3); + display: none; +} +.rickshaw_graph .annotation_line.active { + display: block; +} + +.rickshaw_graph .annotation_range { + background: rgba(0, 0, 0, 0.1); + display: none; + position: absolute; + top: 0; + bottom: -6px; +} +.rickshaw_graph .annotation_range.active { + display: block; +} +.rickshaw_graph .annotation_range.active.offscreen { + display: none; +} + +.rickshaw_annotation_timeline .annotation .content { + background: white; + color: black; + opacity: 0.9; + padding: 5px 5px; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.8); + border-radius: 3px; + position: relative; + z-index: 20; + font-size: 12px; + padding: 6px 8px 8px; + top: 18px; + left: -11px; + width: 160px; + display: none; + cursor: pointer; +} +.rickshaw_annotation_timeline .annotation .content:before { + content: "\25b2"; + position: absolute; + top: -11px; + color: white; + text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8); +} +.rickshaw_annotation_timeline .annotation.active, +.rickshaw_annotation_timeline .annotation:hover { + background-color: rgba(0, 0, 0, 0.8); + cursor: none; +} +.rickshaw_annotation_timeline .annotation .content:hover { + z-index: 50; +} +.rickshaw_annotation_timeline .annotation.active .content { + display: block; +} +.rickshaw_annotation_timeline .annotation:hover .content { + display: block; + z-index: 50; +} +.rickshaw_graph .y_axis, +.rickshaw_graph .x_axis_d3 { + fill: none; +} +.rickshaw_graph .y_ticks .tick, +.rickshaw_graph .x_ticks_d3 .tick { + stroke: rgba(0, 0, 0, 0.16); + stroke-width: 2px; + shape-rendering: crisp-edges; + pointer-events: none; +} +.rickshaw_graph .y_grid .tick, +.rickshaw_graph .x_grid_d3 .tick { + z-index: -1; + stroke: rgba(0, 0, 0, 0.20); + stroke-width: 1px; + stroke-dasharray: 1 1; +} +.rickshaw_graph .y_grid .tick[data-y-value="0"] { + stroke-dasharray: 1 0; +} +.rickshaw_graph .y_grid path, +.rickshaw_graph .x_grid_d3 path { + fill: none; + stroke: none; +} +.rickshaw_graph .y_ticks path, +.rickshaw_graph .x_ticks_d3 path { + fill: none; + stroke: #808080; +} +.rickshaw_graph .y_ticks text, +.rickshaw_graph .x_ticks_d3 text { + opacity: 0.5; + font-size: 12px; + pointer-events: none; +} +.rickshaw_graph .x_tick.glow .title, +.rickshaw_graph .y_ticks.glow text { + fill: black; + color: black; + text-shadow: + -1px 1px 0 rgba(255, 255, 255, 0.1), + 1px -1px 0 rgba(255, 255, 255, 0.1), + 1px 1px 0 rgba(255, 255, 255, 0.1), + 0px 1px 0 rgba(255, 255, 255, 0.1), + 0px -1px 0 rgba(255, 255, 255, 0.1), + 1px 0px 0 rgba(255, 255, 255, 0.1), + -1px 0px 0 rgba(255, 255, 255, 0.1), + -1px -1px 0 rgba(255, 255, 255, 0.1); +} +.rickshaw_graph .x_tick.inverse .title, +.rickshaw_graph .y_ticks.inverse text { + fill: white; + color: white; + text-shadow: + -1px 1px 0 rgba(0, 0, 0, 0.8), + 1px -1px 0 rgba(0, 0, 0, 0.8), + 1px 1px 0 rgba(0, 0, 0, 0.8), + 0px 1px 0 rgba(0, 0, 0, 0.8), + 0px -1px 0 rgba(0, 0, 0, 0.8), + 1px 0px 0 rgba(0, 0, 0, 0.8), + -1px 0px 0 rgba(0, 0, 0, 0.8), + -1px -1px 0 rgba(0, 0, 0, 0.8); +} diff --git a/html/index.html b/html/index.html new file mode 100644 index 0000000..61b6b0f --- /dev/null +++ b/html/index.html @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + diff --git a/html/js/d3.js b/html/js/d3.js new file mode 100644 index 0000000..d35f274 --- /dev/null +++ b/html/js/d3.js @@ -0,0 +1,8981 @@ +d3 = function() { + var d3 = { + version: "3.3.6" + }; + if (!Date.now) Date.now = function() { + return +new Date(); + }; + var d3_arraySlice = [].slice, d3_array = function(list) { + return d3_arraySlice.call(list); + }; + var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window; + try { + d3_array(d3_documentElement.childNodes)[0].nodeType; + } catch (e) { + d3_array = function(list) { + var i = list.length, array = new Array(i); + while (i--) array[i] = list[i]; + return array; + }; + } + try { + d3_document.createElement("div").style.setProperty("opacity", 0, ""); + } catch (error) { + var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; + d3_element_prototype.setAttribute = function(name, value) { + d3_element_setAttribute.call(this, name, value + ""); + }; + d3_element_prototype.setAttributeNS = function(space, local, value) { + d3_element_setAttributeNS.call(this, space, local, value + ""); + }; + d3_style_prototype.setProperty = function(name, value, priority) { + d3_style_setProperty.call(this, name, value + "", priority); + }; + } + d3.ascending = function(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + }; + d3.descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + }; + d3.min = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && a > b) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; + } + return a; + }; + d3.max = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && b > a) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; + } + return a; + }; + d3.extent = function(array, f) { + var i = -1, n = array.length, a, b, c; + if (arguments.length === 1) { + while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined; + while (++i < n) if ((b = array[i]) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } else { + while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } + return [ a, c ]; + }; + d3.sum = function(array, f) { + var s = 0, n = array.length, a, i = -1; + if (arguments.length === 1) { + while (++i < n) if (!isNaN(a = +array[i])) s += a; + } else { + while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; + } + return s; + }; + function d3_number(x) { + return x != null && !isNaN(x); + } + d3.mean = function(array, f) { + var n = array.length, a, m = 0, i = -1, j = 0; + if (arguments.length === 1) { + while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; + } else { + while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; + } + return j ? m : undefined; + }; + d3.quantile = function(values, p) { + var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; + return e ? v + e * (values[h] - v) : v; + }; + d3.median = function(array, f) { + if (arguments.length > 1) array = array.map(f); + array = array.filter(d3_number); + return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; + }; + d3.bisector = function(f) { + return { + left: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; + } + return lo; + } + }; + }; + var d3_bisector = d3.bisector(function(d) { + return d; + }); + d3.bisectLeft = d3_bisector.left; + d3.bisect = d3.bisectRight = d3_bisector.right; + d3.shuffle = function(array) { + var m = array.length, t, i; + while (m) { + i = Math.random() * m-- | 0; + t = array[m], array[m] = array[i], array[i] = t; + } + return array; + }; + d3.permute = function(array, indexes) { + var i = indexes.length, permutes = new Array(i); + while (i--) permutes[i] = array[indexes[i]]; + return permutes; + }; + d3.pairs = function(array) { + var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n); + while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ]; + return pairs; + }; + d3.zip = function() { + if (!(n = arguments.length)) return []; + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { + zip[j] = arguments[j][i]; + } + } + return zips; + }; + function d3_zipLength(d) { + return d.length; + } + d3.transpose = function(matrix) { + return d3.zip.apply(d3, matrix); + }; + d3.keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; + }; + d3.values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; + }; + d3.entries = function(map) { + var entries = []; + for (var key in map) entries.push({ + key: key, + value: map[key] + }); + return entries; + }; + d3.merge = function(arrays) { + return Array.prototype.concat.apply([], arrays); + }; + d3.range = function(start, stop, step) { + if (arguments.length < 3) { + step = 1; + if (arguments.length < 2) { + stop = start; + start = 0; + } + } + if ((stop - start) / step === Infinity) throw new Error("infinite range"); + var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; + start *= k, stop *= k, step *= k; + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); + return range; + }; + function d3_range_integerScale(x) { + var k = 1; + while (x * k % 1) k *= 10; + return k; + } + function d3_class(ctor, properties) { + try { + for (var key in properties) { + Object.defineProperty(ctor.prototype, key, { + value: properties[key], + enumerable: false + }); + } + } catch (e) { + ctor.prototype = properties; + } + } + d3.map = function(object) { + var map = new d3_Map(); + if (object instanceof d3_Map) object.forEach(function(key, value) { + map.set(key, value); + }); else for (var key in object) map.set(key, object[key]); + return map; + }; + function d3_Map() {} + d3_class(d3_Map, { + has: function(key) { + return d3_map_prefix + key in this; + }, + get: function(key) { + return this[d3_map_prefix + key]; + }, + set: function(key, value) { + return this[d3_map_prefix + key] = value; + }, + remove: function(key) { + key = d3_map_prefix + key; + return key in this && delete this[key]; + }, + keys: function() { + var keys = []; + this.forEach(function(key) { + keys.push(key); + }); + return keys; + }, + values: function() { + var values = []; + this.forEach(function(key, value) { + values.push(value); + }); + return values; + }, + entries: function() { + var entries = []; + this.forEach(function(key, value) { + entries.push({ + key: key, + value: value + }); + }); + return entries; + }, + forEach: function(f) { + for (var key in this) { + if (key.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, key.substring(1), this[key]); + } + } + } + }); + var d3_map_prefix = "\x00", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); + d3.nest = function() { + var nest = {}, keys = [], sortKeys = [], sortValues, rollup; + function map(mapType, array, depth) { + if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; + var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { + values.push(object); + } else { + valuesByKey.set(keyValue, [ object ]); + } + } + if (mapType) { + object = mapType(); + setter = function(keyValue, values) { + object.set(keyValue, map(mapType, values, depth)); + }; + } else { + object = {}; + setter = function(keyValue, values) { + object[keyValue] = map(mapType, values, depth); + }; + } + valuesByKey.forEach(setter); + return object; + } + function entries(map, depth) { + if (depth >= keys.length) return map; + var array = [], sortKey = sortKeys[depth++]; + map.forEach(function(key, keyMap) { + array.push({ + key: key, + values: entries(keyMap, depth) + }); + }); + return sortKey ? array.sort(function(a, b) { + return sortKey(a.key, b.key); + }) : array; + } + nest.map = function(array, mapType) { + return map(mapType, array, 0); + }; + nest.entries = function(array) { + return entries(map(d3.map, array, 0), 0); + }; + nest.key = function(d) { + keys.push(d); + return nest; + }; + nest.sortKeys = function(order) { + sortKeys[keys.length - 1] = order; + return nest; + }; + nest.sortValues = function(order) { + sortValues = order; + return nest; + }; + nest.rollup = function(f) { + rollup = f; + return nest; + }; + return nest; + }; + d3.set = function(array) { + var set = new d3_Set(); + if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); + return set; + }; + function d3_Set() {} + d3_class(d3_Set, { + has: function(value) { + return d3_map_prefix + value in this; + }, + add: function(value) { + this[d3_map_prefix + value] = true; + return value; + }, + remove: function(value) { + value = d3_map_prefix + value; + return value in this && delete this[value]; + }, + values: function() { + var values = []; + this.forEach(function(value) { + values.push(value); + }); + return values; + }, + forEach: function(f) { + for (var value in this) { + if (value.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, value.substring(1)); + } + } + } + }); + d3.behavior = {}; + d3.rebind = function(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; + }; + function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return value === source ? target : value; + }; + } + function d3_vendorSymbol(object, name) { + if (name in object) return name; + name = name.charAt(0).toUpperCase() + name.substring(1); + for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { + var prefixName = d3_vendorPrefixes[i] + name; + if (prefixName in object) return prefixName; + } + } + var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; + function d3_noop() {} + d3.dispatch = function() { + var dispatch = new d3_dispatch(), i = -1, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + return dispatch; + }; + function d3_dispatch() {} + d3_dispatch.prototype.on = function(type, listener) { + var i = type.indexOf("."), name = ""; + if (i >= 0) { + name = type.substring(i + 1); + type = type.substring(0, i); + } + if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); + if (arguments.length === 2) { + if (listener == null) for (type in this) { + if (this.hasOwnProperty(type)) this[type].on(name, null); + } + return this; + } + }; + function d3_dispatch_event(dispatch) { + var listeners = [], listenerByName = new d3_Map(); + function event() { + var z = listeners, i = -1, n = z.length, l; + while (++i < n) if (l = z[i].on) l.apply(this, arguments); + return dispatch; + } + event.on = function(name, listener) { + var l = listenerByName.get(name), i; + if (arguments.length < 2) return l && l.on; + if (l) { + l.on = null; + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); + listenerByName.remove(name); + } + if (listener) listeners.push(listenerByName.set(name, { + on: listener + })); + return dispatch; + }; + return event; + } + d3.event = null; + function d3_eventPreventDefault() { + d3.event.preventDefault(); + } + function d3_eventSource() { + var e = d3.event, s; + while (s = e.sourceEvent) e = s; + return e; + } + function d3_eventDispatch(target) { + var dispatch = new d3_dispatch(), i = 0, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + dispatch.of = function(thiz, argumentz) { + return function(e1) { + try { + var e0 = e1.sourceEvent = d3.event; + e1.target = target; + d3.event = e1; + dispatch[e1.type].apply(thiz, argumentz); + } finally { + d3.event = e0; + } + }; + }; + return dispatch; + } + d3.requote = function(s) { + return s.replace(d3_requote_re, "\\$&"); + }; + var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; + var d3_subclass = {}.__proto__ ? function(object, prototype) { + object.__proto__ = prototype; + } : function(object, prototype) { + for (var property in prototype) object[property] = prototype[property]; + }; + function d3_selection(groups) { + d3_subclass(groups, d3_selectionPrototype); + return groups; + } + var d3_select = function(s, n) { + return n.querySelector(s); + }, d3_selectAll = function(s, n) { + return n.querySelectorAll(s); + }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { + return d3_selectMatcher.call(n, s); + }; + if (typeof Sizzle === "function") { + d3_select = function(s, n) { + return Sizzle(s, n)[0] || null; + }; + d3_selectAll = function(s, n) { + return Sizzle.uniqueSort(Sizzle(s, n)); + }; + d3_selectMatches = Sizzle.matchesSelector; + } + d3.selection = function() { + return d3_selectionRoot; + }; + var d3_selectionPrototype = d3.selection.prototype = []; + d3_selectionPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, group, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(subnode = selector.call(node, node.__data__, i, j)); + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selector(selector) { + return typeof selector === "function" ? selector : function() { + return d3_select(selector, this); + }; + } + d3_selectionPrototype.selectAll = function(selector) { + var subgroups = [], subgroup, node; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); + subgroup.parentNode = node; + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selectorAll(selector) { + return typeof selector === "function" ? selector : function() { + return d3_selectAll(selector, this); + }; + } + var d3_nsPrefix = { + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + d3.ns = { + prefix: d3_nsPrefix, + qualify: function(name) { + var i = name.indexOf(":"), prefix = name; + if (i >= 0) { + prefix = name.substring(0, i); + name = name.substring(i + 1); + } + return d3_nsPrefix.hasOwnProperty(prefix) ? { + space: d3_nsPrefix[prefix], + local: name + } : name; + } + }; + d3_selectionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(); + name = d3.ns.qualify(name); + return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); + } + for (value in name) this.each(d3_selection_attr(value, name[value])); + return this; + } + return this.each(d3_selection_attr(name, value)); + }; + function d3_selection_attr(name, value) { + name = d3.ns.qualify(name); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrConstant() { + this.setAttribute(name, value); + } + function attrConstantNS() { + this.setAttributeNS(name.space, name.local, value); + } + function attrFunction() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); + } + function attrFunctionNS() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); + } + return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; + } + function d3_collapse(s) { + return s.trim().replace(/\s+/g, " "); + } + d3_selectionPrototype.classed = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; + if (value = node.classList) { + while (++i < n) if (!value.contains(name[i])) return false; + } else { + value = node.getAttribute("class"); + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; + } + return true; + } + for (value in name) this.each(d3_selection_classed(value, name[value])); + return this; + } + return this.each(d3_selection_classed(name, value)); + }; + function d3_selection_classedRe(name) { + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); + } + function d3_selection_classed(name, value) { + name = name.trim().split(/\s+/).map(d3_selection_classedName); + var n = name.length; + function classedConstant() { + var i = -1; + while (++i < n) name[i](this, value); + } + function classedFunction() { + var i = -1, x = value.apply(this, arguments); + while (++i < n) name[i](this, x); + } + return typeof value === "function" ? classedFunction : classedConstant; + } + function d3_selection_classedName(name) { + var re = d3_selection_classedRe(name); + return function(node, value) { + if (c = node.classList) return value ? c.add(name) : c.remove(name); + var c = node.getAttribute("class") || ""; + if (value) { + re.lastIndex = 0; + if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); + } else { + node.setAttribute("class", d3_collapse(c.replace(re, " "))); + } + }; + } + d3_selectionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); + return this; + } + if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); + priority = ""; + } + return this.each(d3_selection_style(name, value, priority)); + }; + function d3_selection_style(name, value, priority) { + function styleNull() { + this.style.removeProperty(name); + } + function styleConstant() { + this.style.setProperty(name, value, priority); + } + function styleFunction() { + var x = value.apply(this, arguments); + if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); + } + return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; + } + d3_selectionPrototype.property = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") return this.node()[name]; + for (value in name) this.each(d3_selection_property(value, name[value])); + return this; + } + return this.each(d3_selection_property(name, value)); + }; + function d3_selection_property(name, value) { + function propertyNull() { + delete this[name]; + } + function propertyConstant() { + this[name] = value; + } + function propertyFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this[name]; else this[name] = x; + } + return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; + } + d3_selectionPrototype.text = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + } : value == null ? function() { + this.textContent = ""; + } : function() { + this.textContent = value; + }) : this.node().textContent; + }; + d3_selectionPrototype.html = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + } : value == null ? function() { + this.innerHTML = ""; + } : function() { + this.innerHTML = value; + }) : this.node().innerHTML; + }; + d3_selectionPrototype.append = function(name) { + name = d3_selection_creator(name); + return this.select(function() { + return this.appendChild(name.apply(this, arguments)); + }); + }; + function d3_selection_creator(name) { + return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { + return d3_document.createElementNS(name.space, name.local); + } : function() { + return d3_document.createElementNS(this.namespaceURI, name); + }; + } + d3_selectionPrototype.insert = function(name, before) { + name = d3_selection_creator(name); + before = d3_selection_selector(before); + return this.select(function() { + return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)); + }); + }; + d3_selectionPrototype.remove = function() { + return this.each(function() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); + }); + }; + d3_selectionPrototype.data = function(value, key) { + var i = -1, n = this.length, group, node; + if (!arguments.length) { + value = new Array(n = (group = this[0]).length); + while (++i < n) { + if (node = group[i]) { + value[i] = node.__data__; + } + } + return value; + } + function bind(group, groupData) { + var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; + if (key) { + var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; + for (i = -1; ++i < n; ) { + keyValue = key.call(node = group[i], node.__data__, i); + if (nodeByKeyValue.has(keyValue)) { + exitNodes[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + keyValues.push(keyValue); + } + for (i = -1; ++i < m; ) { + keyValue = key.call(groupData, nodeData = groupData[i], i); + if (node = nodeByKeyValue.get(keyValue)) { + updateNodes[i] = node; + node.__data__ = nodeData; + } else if (!dataByKeyValue.has(keyValue)) { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + dataByKeyValue.set(keyValue, nodeData); + nodeByKeyValue.remove(keyValue); + } + for (i = -1; ++i < n; ) { + if (nodeByKeyValue.has(keyValues[i])) { + exitNodes[i] = group[i]; + } + } + } else { + for (i = -1; ++i < n0; ) { + node = group[i]; + nodeData = groupData[i]; + if (node) { + node.__data__ = nodeData; + updateNodes[i] = node; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + } + for (;i < m; ++i) { + enterNodes[i] = d3_selection_dataNode(groupData[i]); + } + for (;i < n; ++i) { + exitNodes[i] = group[i]; + } + } + enterNodes.update = updateNodes; + enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; + enter.push(enterNodes); + update.push(updateNodes); + exit.push(exitNodes); + } + var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); + if (typeof value === "function") { + while (++i < n) { + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); + } + } else { + while (++i < n) { + bind(group = this[i], value); + } + } + update.enter = function() { + return enter; + }; + update.exit = function() { + return exit; + }; + return update; + }; + function d3_selection_dataNode(data) { + return { + __data__: data + }; + } + d3_selectionPrototype.datum = function(value) { + return arguments.length ? this.property("__data__", value) : this.property("__data__"); + }; + d3_selectionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_filter(selector) { + return function() { + return d3_selectMatches(this, selector); + }; + } + d3_selectionPrototype.order = function() { + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + return this; + }; + d3_selectionPrototype.sort = function(comparator) { + comparator = d3_selection_sortComparator.apply(this, arguments); + for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); + return this.order(); + }; + function d3_selection_sortComparator(comparator) { + if (!arguments.length) comparator = d3.ascending; + return function(a, b) { + return a && b ? comparator(a.__data__, b.__data__) : !a - !b; + }; + } + d3_selectionPrototype.each = function(callback) { + return d3_selection_each(this, function(node, i, j) { + callback.call(node, node.__data__, i, j); + }); + }; + function d3_selection_each(groups, callback) { + for (var j = 0, m = groups.length; j < m; j++) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { + if (node = group[i]) callback(node, i, j); + } + } + return groups; + } + d3_selectionPrototype.call = function(callback) { + var args = d3_array(arguments); + callback.apply(args[0] = this, args); + return this; + }; + d3_selectionPrototype.empty = function() { + return !this.node(); + }; + d3_selectionPrototype.node = function() { + for (var j = 0, m = this.length; j < m; j++) { + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + var node = group[i]; + if (node) return node; + } + } + return null; + }; + d3_selectionPrototype.size = function() { + var n = 0; + this.each(function() { + ++n; + }); + return n; + }; + function d3_selection_enter(selection) { + d3_subclass(selection, d3_selection_enterPrototype); + return selection; + } + var d3_selection_enterPrototype = []; + d3.selection.enter = d3_selection_enter; + d3.selection.enter.prototype = d3_selection_enterPrototype; + d3_selection_enterPrototype.append = d3_selectionPrototype.append; + d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; + d3_selection_enterPrototype.node = d3_selectionPrototype.node; + d3_selection_enterPrototype.call = d3_selectionPrototype.call; + d3_selection_enterPrototype.size = d3_selectionPrototype.size; + d3_selection_enterPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, upgroup, group, node; + for (var j = -1, m = this.length; ++j < m; ) { + upgroup = (group = this[j]).update; + subgroups.push(subgroup = []); + subgroup.parentNode = group.parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); + subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + d3_selection_enterPrototype.insert = function(name, before) { + if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); + return d3_selectionPrototype.insert.call(this, name, before); + }; + function d3_selection_enterInsertBefore(enter) { + var i0, j0; + return function(d, i, j) { + var group = enter[j].update, n = group.length, node; + if (j != j0) j0 = j, i0 = 0; + if (i >= i0) i0 = i + 1; + while (!(node = group[i0]) && ++i0 < n) ; + return node; + }; + } + d3_selectionPrototype.transition = function() { + var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || { + time: Date.now(), + ease: d3_ease_cubicInOut, + delay: 0, + duration: 250 + }; + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) d3_transitionNode(node, i, id, transition); + subgroup.push(node); + } + } + return d3_transition(subgroups, id); + }; + d3_selectionPrototype.interrupt = function() { + return this.each(d3_selection_interrupt); + }; + function d3_selection_interrupt() { + var lock = this.__transition__; + if (lock) ++lock.active; + } + d3.select = function(node) { + var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + d3.selectAll = function(nodes) { + var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + var d3_selectionRoot = d3.select(d3_documentElement); + d3_selectionPrototype.on = function(type, listener, capture) { + var n = arguments.length; + if (n < 3) { + if (typeof type !== "string") { + if (n < 2) listener = false; + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); + return this; + } + if (n < 2) return (n = this.node()["__on" + type]) && n._; + capture = false; + } + return this.each(d3_selection_on(type, listener, capture)); + }; + function d3_selection_on(type, listener, capture) { + var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; + if (i > 0) type = type.substring(0, i); + var filter = d3_selection_onFilters.get(type); + if (filter) type = filter, wrap = d3_selection_onFilter; + function onRemove() { + var l = this[name]; + if (l) { + this.removeEventListener(type, l, l.$); + delete this[name]; + } + } + function onAdd() { + var l = wrap(listener, d3_array(arguments)); + onRemove.call(this); + this.addEventListener(type, this[name] = l, l.$ = capture); + l._ = listener; + } + function removeAll() { + var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; + for (var name in this) { + if (match = name.match(re)) { + var l = this[name]; + this.removeEventListener(match[1], l, l.$); + delete this[name]; + } + } + } + return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; + } + var d3_selection_onFilters = d3.map({ + mouseenter: "mouseover", + mouseleave: "mouseout" + }); + d3_selection_onFilters.forEach(function(k) { + if ("on" + k in d3_document) d3_selection_onFilters.remove(k); + }); + function d3_selection_onListener(listener, argumentz) { + return function(e) { + var o = d3.event; + d3.event = e; + argumentz[0] = this.__data__; + try { + listener.apply(this, argumentz); + } finally { + d3.event = o; + } + }; + } + function d3_selection_onFilter(listener, argumentz) { + var l = d3_selection_onListener(listener, argumentz); + return function(e) { + var target = this, related = e.relatedTarget; + if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { + l.call(target, e); + } + }; + } + var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; + function d3_event_dragSuppress() { + var name = ".dragsuppress-" + ++d3_event_dragId, touchmove = "touchmove" + name, selectstart = "selectstart" + name, dragstart = "dragstart" + name, click = "click" + name, w = d3.select(d3_window).on(touchmove, d3_eventPreventDefault).on(selectstart, d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style = d3_documentElement.style, select = style[d3_event_dragSelect]; + style[d3_event_dragSelect] = "none"; + return function(suppressClick) { + w.on(name, null); + style[d3_event_dragSelect] = select; + if (suppressClick) { + function off() { + w.on(click, null); + } + w.on(click, function() { + d3_eventPreventDefault(); + off(); + }, true); + setTimeout(off, 0); + } + }; + } + d3.mouse = function(container) { + return d3_mousePoint(container, d3_eventSource()); + }; + var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; + function d3_mousePoint(container, e) { + if (e.changedTouches) e = e.changedTouches[0]; + var svg = container.ownerSVGElement || container; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { + svg = d3.select("body").append("svg").style({ + position: "absolute", + top: 0, + left: 0, + margin: 0, + padding: 0, + border: "none" + }, "important"); + var ctm = svg[0][0].getScreenCTM(); + d3_mouse_bug44083 = !(ctm.f || ctm.e); + svg.remove(); + } + if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX, + point.y = e.clientY; + point = point.matrixTransform(container.getScreenCTM().inverse()); + return [ point.x, point.y ]; + } + var rect = container.getBoundingClientRect(); + return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; + } + d3.touches = function(container, touches) { + if (arguments.length < 2) touches = d3_eventSource().touches; + return touches ? d3_array(touches).map(function(touch) { + var point = d3_mousePoint(container, touch); + point.identifier = touch.identifier; + return point; + }) : []; + }; + d3.behavior.drag = function() { + var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); + function drag() { + this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); + } + function touchid() { + return d3.event.changedTouches[0].identifier; + } + function touchposition(parent, id) { + return d3.touches(parent).filter(function(p) { + return p.identifier === id; + })[0]; + } + function dragstart(id, position, move, end) { + return function() { + var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress(); + if (origin) { + offset = origin.apply(target, arguments); + offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; + } else { + offset = [ 0, 0 ]; + } + event_({ + type: "dragstart" + }); + function moved() { + var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; + dragged |= dx | dy; + origin_ = p; + event_({ + type: "drag", + x: p[0] + offset[0], + y: p[1] + offset[1], + dx: dx, + dy: dy + }); + } + function ended() { + w.on(move + "." + drag, null).on(end + "." + drag, null); + dragRestore(dragged && d3.event.target === eventTarget); + event_({ + type: "dragend" + }); + } + }; + } + drag.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return drag; + }; + return d3.rebind(drag, event, "on"); + }; + var π = Math.PI, τ = 2 * π, halfπ = π / 2, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π; + function d3_sgn(x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; + } + function d3_acos(x) { + return x > 1 ? 0 : x < -1 ? π : Math.acos(x); + } + function d3_asin(x) { + return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x); + } + function d3_sinh(x) { + return ((x = Math.exp(x)) - 1 / x) / 2; + } + function d3_cosh(x) { + return ((x = Math.exp(x)) + 1 / x) / 2; + } + function d3_tanh(x) { + return ((x = Math.exp(2 * x)) - 1) / (x + 1); + } + function d3_haversin(x) { + return (x = Math.sin(x / 2)) * x; + } + var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4; + d3.interpolateZoom = function(p0, p1) { + var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2]; + var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / ρ; + function interpolate(t) { + var s = t * S; + if (dr) { + var coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0)); + return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ]; + } + return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * s) ]; + } + interpolate.duration = S * 1e3; + return interpolate; + }; + d3.behavior.zoom = function() { + var view = { + x: 0, + y: 0, + k: 1 + }, translate0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1; + function zoom(g) { + g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); + } + zoom.event = function(g) { + g.each(function() { + var event_ = event.of(this, arguments), view1 = view; + if (d3_transitionInheritId) { + d3.select(this).transition().each("start.zoom", function() { + view = this.__chart__ || { + x: 0, + y: 0, + k: 1 + }; + zoomstarted(event_); + }).tween("zoom:zoom", function() { + var dx = size[0], dy = size[1], cx = dx / 2, cy = dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]); + return function(t) { + var l = i(t), k = dx / l[2]; + this.__chart__ = view = { + x: cx - l[0] * k, + y: cy - l[1] * k, + k: k + }; + zoomed(event_); + }; + }).each("end.zoom", function() { + zoomended(event_); + }); + } else { + this.__chart__ = view; + zoomstarted(event_); + zoomed(event_); + zoomended(event_); + } + }); + }; + zoom.translate = function(_) { + if (!arguments.length) return [ view.x, view.y ]; + view = { + x: +_[0], + y: +_[1], + k: view.k + }; + rescale(); + return zoom; + }; + zoom.scale = function(_) { + if (!arguments.length) return view.k; + view = { + x: view.x, + y: view.y, + k: +_ + }; + rescale(); + return zoom; + }; + zoom.scaleExtent = function(_) { + if (!arguments.length) return scaleExtent; + scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ]; + return zoom; + }; + zoom.center = function(_) { + if (!arguments.length) return center; + center = _ && [ +_[0], +_[1] ]; + return zoom; + }; + zoom.size = function(_) { + if (!arguments.length) return size; + size = _ && [ +_[0], +_[1] ]; + return zoom; + }; + zoom.x = function(z) { + if (!arguments.length) return x1; + x1 = z; + x0 = z.copy(); + view = { + x: 0, + y: 0, + k: 1 + }; + return zoom; + }; + zoom.y = function(z) { + if (!arguments.length) return y1; + y1 = z; + y0 = z.copy(); + view = { + x: 0, + y: 0, + k: 1 + }; + return zoom; + }; + function location(p) { + return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ]; + } + function point(l) { + return [ l[0] * view.k + view.x, l[1] * view.k + view.y ]; + } + function scaleTo(s) { + view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); + } + function translateTo(p, l) { + l = point(l); + view.x += p[0] - l[0]; + view.y += p[1] - l[1]; + } + function rescale() { + if (x1) x1.domain(x0.range().map(function(x) { + return (x - view.x) / view.k; + }).map(x0.invert)); + if (y1) y1.domain(y0.range().map(function(y) { + return (y - view.y) / view.k; + }).map(y0.invert)); + } + function zoomstarted(event) { + event({ + type: "zoomstart" + }); + } + function zoomed(event) { + rescale(); + event({ + type: "zoom", + scale: view.k, + translate: [ view.x, view.y ] + }); + } + function zoomended(event) { + event({ + type: "zoomend" + }); + } + function mousedowned() { + var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress(); + d3_selection_interrupt.call(target); + zoomstarted(event_); + function moved() { + dragged = 1; + translateTo(d3.mouse(target), l); + zoomed(event_); + } + function ended() { + w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); + dragRestore(dragged && d3.event.target === eventTarget); + zoomended(event_); + } + } + function touchstarted() { + var target = this, event_ = event.of(target, arguments), locations0 = {}, distance0 = 0, scale0, eventId = d3.event.changedTouches[0].identifier, touchmove = "touchmove.zoom-" + eventId, touchend = "touchend.zoom-" + eventId, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress(); + d3_selection_interrupt.call(target); + started(); + zoomstarted(event_); + function relocate() { + var touches = d3.touches(target); + scale0 = view.k; + touches.forEach(function(t) { + if (t.identifier in locations0) locations0[t.identifier] = location(t); + }); + return touches; + } + function started() { + var changed = d3.event.changedTouches; + for (var i = 0, n = changed.length; i < n; ++i) { + locations0[changed[i].identifier] = null; + } + var touches = relocate(), now = Date.now(); + if (touches.length === 1) { + if (now - touchtime < 500) { + var p = touches[0], l = locations0[p.identifier]; + scaleTo(view.k * 2); + translateTo(p, l); + d3_eventPreventDefault(); + zoomed(event_); + } + touchtime = now; + } else if (touches.length > 1) { + var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; + distance0 = dx * dx + dy * dy; + } + } + function moved() { + var touches = d3.touches(target), p0, l0, p1, l1; + for (var i = 0, n = touches.length; i < n; ++i, l1 = null) { + p1 = touches[i]; + if (l1 = locations0[p1.identifier]) { + if (l0) break; + p0 = p1, l0 = l1; + } + } + if (l1) { + var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0); + p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; + l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; + scaleTo(scale1 * scale0); + } + touchtime = null; + translateTo(p0, l0); + zoomed(event_); + } + function ended() { + if (d3.event.touches.length) { + var changed = d3.event.changedTouches; + for (var i = 0, n = changed.length; i < n; ++i) { + delete locations0[changed[i].identifier]; + } + for (var identifier in locations0) { + return void relocate(); + } + } + w.on(touchmove, null).on(touchend, null); + t.on(mousedown, mousedowned).on(touchstart, touchstarted); + dragRestore(); + zoomended(event_); + } + } + function mousewheeled() { + var event_ = event.of(this, arguments); + if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this), + zoomstarted(event_); + mousewheelTimer = setTimeout(function() { + mousewheelTimer = null; + zoomended(event_); + }, 50); + d3_eventPreventDefault(); + var point = center || d3.mouse(this); + if (!translate0) translate0 = location(point); + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k); + translateTo(point, translate0); + zoomed(event_); + } + function mousewheelreset() { + translate0 = null; + } + function dblclicked() { + var event_ = event.of(this, arguments), p = d3.mouse(this), l = location(p), k = Math.log(view.k) / Math.LN2; + zoomstarted(event_); + scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); + translateTo(p, l); + zoomed(event_); + zoomended(event_); + } + return d3.rebind(zoom, event, "on"); + }; + var d3_behavior_zoomInfinity = [ 0, Infinity ]; + var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); + }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return d3.event.wheelDelta; + }, "mousewheel") : (d3_behavior_zoomDelta = function() { + return -d3.event.detail; + }, "MozMousePixelScroll"); + function d3_Color() {} + d3_Color.prototype.toString = function() { + return this.rgb() + ""; + }; + d3.hsl = function(h, s, l) { + return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); + }; + function d3_hsl(h, s, l) { + return new d3_Hsl(h, s, l); + } + function d3_Hsl(h, s, l) { + this.h = h; + this.s = s; + this.l = l; + } + var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); + d3_hslPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, this.l / k); + }; + d3_hslPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, k * this.l); + }; + d3_hslPrototype.rgb = function() { + return d3_hsl_rgb(this.h, this.s, this.l); + }; + function d3_hsl_rgb(h, s, l) { + var m1, m2; + h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; + s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; + l = l < 0 ? 0 : l > 1 ? 1 : l; + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; + m1 = 2 * l - m2; + function v(h) { + if (h > 360) h -= 360; else if (h < 0) h += 360; + if (h < 60) return m1 + (m2 - m1) * h / 60; + if (h < 180) return m2; + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; + return m1; + } + function vv(h) { + return Math.round(v(h) * 255); + } + return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); + } + d3.hcl = function(h, c, l) { + return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); + }; + function d3_hcl(h, c, l) { + return new d3_Hcl(h, c, l); + } + function d3_Hcl(h, c, l) { + this.h = h; + this.c = c; + this.l = l; + } + var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); + d3_hclPrototype.brighter = function(k) { + return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.darker = function(k) { + return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.rgb = function() { + return d3_hcl_lab(this.h, this.c, this.l).rgb(); + }; + function d3_hcl_lab(h, c, l) { + if (isNaN(h)) h = 0; + if (isNaN(c)) c = 0; + return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); + } + d3.lab = function(l, a, b) { + return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); + }; + function d3_lab(l, a, b) { + return new d3_Lab(l, a, b); + } + function d3_Lab(l, a, b) { + this.l = l; + this.a = a; + this.b = b; + } + var d3_lab_K = 18; + var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; + var d3_labPrototype = d3_Lab.prototype = new d3_Color(); + d3_labPrototype.brighter = function(k) { + return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.darker = function(k) { + return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.rgb = function() { + return d3_lab_rgb(this.l, this.a, this.b); + }; + function d3_lab_rgb(l, a, b) { + var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; + x = d3_lab_xyz(x) * d3_lab_X; + y = d3_lab_xyz(y) * d3_lab_Y; + z = d3_lab_xyz(z) * d3_lab_Z; + return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); + } + function d3_lab_hcl(l, a, b) { + return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l); + } + function d3_lab_xyz(x) { + return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; + } + function d3_xyz_lab(x) { + return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; + } + function d3_xyz_rgb(r) { + return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); + } + d3.rgb = function(r, g, b) { + return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); + }; + function d3_rgbNumber(value) { + return d3_rgb(value >> 16, value >> 8 & 255, value & 255); + } + function d3_rgbString(value) { + return d3_rgbNumber(value) + ""; + } + function d3_rgb(r, g, b) { + return new d3_Rgb(r, g, b); + } + function d3_Rgb(r, g, b) { + this.r = r; + this.g = g; + this.b = b; + } + var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); + d3_rgbPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + var r = this.r, g = this.g, b = this.b, i = 30; + if (!r && !g && !b) return d3_rgb(i, i, i); + if (r && r < i) r = i; + if (g && g < i) g = i; + if (b && b < i) b = i; + return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k))); + }; + d3_rgbPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b)); + }; + d3_rgbPrototype.hsl = function() { + return d3_rgb_hsl(this.r, this.g, this.b); + }; + d3_rgbPrototype.toString = function() { + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); + }; + function d3_rgb_hex(v) { + return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); + } + function d3_rgb_parse(format, rgb, hsl) { + var r = 0, g = 0, b = 0, m1, m2, name; + m1 = /([a-z]+)\((.*)\)/i.exec(format); + if (m1) { + m2 = m1[2].split(","); + switch (m1[1]) { + case "hsl": + { + return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); + } + + case "rgb": + { + return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); + } + } + } + if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); + if (format != null && format.charAt(0) === "#") { + if (format.length === 4) { + r = format.charAt(1); + r += r; + g = format.charAt(2); + g += g; + b = format.charAt(3); + b += b; + } else if (format.length === 7) { + r = format.substring(1, 3); + g = format.substring(3, 5); + b = format.substring(5, 7); + } + r = parseInt(r, 16); + g = parseInt(g, 16); + b = parseInt(b, 16); + } + return rgb(r, g, b); + } + function d3_rgb_hsl(r, g, b) { + var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; + if (d) { + s = l < .5 ? d / (max + min) : d / (2 - max - min); + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; + h *= 60; + } else { + h = NaN; + s = l > 0 && l < 1 ? 0 : h; + } + return d3_hsl(h, s, l); + } + function d3_rgb_lab(r, g, b) { + r = d3_rgb_xyz(r); + g = d3_rgb_xyz(g); + b = d3_rgb_xyz(b); + var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); + } + function d3_rgb_xyz(r) { + return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); + } + function d3_rgb_parseNumber(c) { + var f = parseFloat(c); + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; + } + var d3_rgb_names = d3.map({ + aliceblue: 15792383, + antiquewhite: 16444375, + aqua: 65535, + aquamarine: 8388564, + azure: 15794175, + beige: 16119260, + bisque: 16770244, + black: 0, + blanchedalmond: 16772045, + blue: 255, + blueviolet: 9055202, + brown: 10824234, + burlywood: 14596231, + cadetblue: 6266528, + chartreuse: 8388352, + chocolate: 13789470, + coral: 16744272, + cornflowerblue: 6591981, + cornsilk: 16775388, + crimson: 14423100, + cyan: 65535, + darkblue: 139, + darkcyan: 35723, + darkgoldenrod: 12092939, + darkgray: 11119017, + darkgreen: 25600, + darkgrey: 11119017, + darkkhaki: 12433259, + darkmagenta: 9109643, + darkolivegreen: 5597999, + darkorange: 16747520, + darkorchid: 10040012, + darkred: 9109504, + darksalmon: 15308410, + darkseagreen: 9419919, + darkslateblue: 4734347, + darkslategray: 3100495, + darkslategrey: 3100495, + darkturquoise: 52945, + darkviolet: 9699539, + deeppink: 16716947, + deepskyblue: 49151, + dimgray: 6908265, + dimgrey: 6908265, + dodgerblue: 2003199, + firebrick: 11674146, + floralwhite: 16775920, + forestgreen: 2263842, + fuchsia: 16711935, + gainsboro: 14474460, + ghostwhite: 16316671, + gold: 16766720, + goldenrod: 14329120, + gray: 8421504, + green: 32768, + greenyellow: 11403055, + grey: 8421504, + honeydew: 15794160, + hotpink: 16738740, + indianred: 13458524, + indigo: 4915330, + ivory: 16777200, + khaki: 15787660, + lavender: 15132410, + lavenderblush: 16773365, + lawngreen: 8190976, + lemonchiffon: 16775885, + lightblue: 11393254, + lightcoral: 15761536, + lightcyan: 14745599, + lightgoldenrodyellow: 16448210, + lightgray: 13882323, + lightgreen: 9498256, + lightgrey: 13882323, + lightpink: 16758465, + lightsalmon: 16752762, + lightseagreen: 2142890, + lightskyblue: 8900346, + lightslategray: 7833753, + lightslategrey: 7833753, + lightsteelblue: 11584734, + lightyellow: 16777184, + lime: 65280, + limegreen: 3329330, + linen: 16445670, + magenta: 16711935, + maroon: 8388608, + mediumaquamarine: 6737322, + mediumblue: 205, + mediumorchid: 12211667, + mediumpurple: 9662683, + mediumseagreen: 3978097, + mediumslateblue: 8087790, + mediumspringgreen: 64154, + mediumturquoise: 4772300, + mediumvioletred: 13047173, + midnightblue: 1644912, + mintcream: 16121850, + mistyrose: 16770273, + moccasin: 16770229, + navajowhite: 16768685, + navy: 128, + oldlace: 16643558, + olive: 8421376, + olivedrab: 7048739, + orange: 16753920, + orangered: 16729344, + orchid: 14315734, + palegoldenrod: 15657130, + palegreen: 10025880, + paleturquoise: 11529966, + palevioletred: 14381203, + papayawhip: 16773077, + peachpuff: 16767673, + peru: 13468991, + pink: 16761035, + plum: 14524637, + powderblue: 11591910, + purple: 8388736, + red: 16711680, + rosybrown: 12357519, + royalblue: 4286945, + saddlebrown: 9127187, + salmon: 16416882, + sandybrown: 16032864, + seagreen: 3050327, + seashell: 16774638, + sienna: 10506797, + silver: 12632256, + skyblue: 8900331, + slateblue: 6970061, + slategray: 7372944, + slategrey: 7372944, + snow: 16775930, + springgreen: 65407, + steelblue: 4620980, + tan: 13808780, + teal: 32896, + thistle: 14204888, + tomato: 16737095, + turquoise: 4251856, + violet: 15631086, + wheat: 16113331, + white: 16777215, + whitesmoke: 16119285, + yellow: 16776960, + yellowgreen: 10145074 + }); + d3_rgb_names.forEach(function(key, value) { + d3_rgb_names.set(key, d3_rgbNumber(value)); + }); + function d3_functor(v) { + return typeof v === "function" ? v : function() { + return v; + }; + } + d3.functor = d3_functor; + function d3_identity(d) { + return d; + } + d3.xhr = d3_xhrType(d3_identity); + function d3_xhrType(response) { + return function(url, mimeType, callback) { + if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, + mimeType = null; + return d3_xhr(url, mimeType, response, callback); + }; + } + function d3_xhr(url, mimeType, response, callback) { + var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; + if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); + "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { + request.readyState > 3 && respond(); + }; + function respond() { + var status = request.status, result; + if (!status && request.responseText || status >= 200 && status < 300 || status === 304) { + try { + result = response.call(xhr, request); + } catch (e) { + dispatch.error.call(xhr, e); + return; + } + dispatch.load.call(xhr, result); + } else { + dispatch.error.call(xhr, request); + } + } + request.onprogress = function(event) { + var o = d3.event; + d3.event = event; + try { + dispatch.progress.call(xhr, request); + } finally { + d3.event = o; + } + }; + xhr.header = function(name, value) { + name = (name + "").toLowerCase(); + if (arguments.length < 2) return headers[name]; + if (value == null) delete headers[name]; else headers[name] = value + ""; + return xhr; + }; + xhr.mimeType = function(value) { + if (!arguments.length) return mimeType; + mimeType = value == null ? null : value + ""; + return xhr; + }; + xhr.responseType = function(value) { + if (!arguments.length) return responseType; + responseType = value; + return xhr; + }; + xhr.response = function(value) { + response = value; + return xhr; + }; + [ "get", "post" ].forEach(function(method) { + xhr[method] = function() { + return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); + }; + }); + xhr.send = function(method, data, callback) { + if (arguments.length === 2 && typeof data === "function") callback = data, data = null; + request.open(method, url, true); + if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; + if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); + if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); + if (responseType != null) request.responseType = responseType; + if (callback != null) xhr.on("error", callback).on("load", function(request) { + callback(null, request); + }); + dispatch.beforesend.call(xhr, request); + request.send(data == null ? null : data); + return xhr; + }; + xhr.abort = function() { + request.abort(); + return xhr; + }; + d3.rebind(xhr, dispatch, "on"); + return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); + } + function d3_xhr_fixCallback(callback) { + return callback.length === 1 ? function(error, request) { + callback(error == null ? request : null); + } : callback; + } + d3.dsv = function(delimiter, mimeType) { + var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); + function dsv(url, row, callback) { + if (arguments.length < 3) callback = row, row = null; + var xhr = d3.xhr(url, mimeType, callback); + xhr.row = function(_) { + return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; + }; + return xhr.row(row); + } + function response(request) { + return dsv.parse(request.responseText); + } + function typedResponse(f) { + return function(request) { + return dsv.parse(request.responseText, f); + }; + } + dsv.parse = function(text, f) { + var o; + return dsv.parseRows(text, function(row, i) { + if (o) return o(row, i - 1); + var a = new Function("d", "return {" + row.map(function(name, i) { + return JSON.stringify(name) + ": d[" + i + "]"; + }).join(",") + "}"); + o = f ? function(row, i) { + return f(a(row), i); + } : a; + }); + }; + dsv.parseRows = function(text, f) { + var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; + function token() { + if (I >= N) return EOF; + if (eol) return eol = false, EOL; + var j = I; + if (text.charCodeAt(j) === 34) { + var i = j; + while (i++ < N) { + if (text.charCodeAt(i) === 34) { + if (text.charCodeAt(i + 1) !== 34) break; + ++i; + } + } + I = i + 2; + var c = text.charCodeAt(i + 1); + if (c === 13) { + eol = true; + if (text.charCodeAt(i + 2) === 10) ++I; + } else if (c === 10) { + eol = true; + } + return text.substring(j + 1, i).replace(/""/g, '"'); + } + while (I < N) { + var c = text.charCodeAt(I++), k = 1; + if (c === 10) eol = true; else if (c === 13) { + eol = true; + if (text.charCodeAt(I) === 10) ++I, ++k; + } else if (c !== delimiterCode) continue; + return text.substring(j, I - k); + } + return text.substring(j); + } + while ((t = token()) !== EOF) { + var a = []; + while (t !== EOL && t !== EOF) { + a.push(t); + t = token(); + } + if (f && !(a = f(a, n++))) continue; + rows.push(a); + } + return rows; + }; + dsv.format = function(rows) { + if (Array.isArray(rows[0])) return dsv.formatRows(rows); + var fieldSet = new d3_Set(), fields = []; + rows.forEach(function(row) { + for (var field in row) { + if (!fieldSet.has(field)) { + fields.push(fieldSet.add(field)); + } + } + }); + return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { + return fields.map(function(field) { + return formatValue(row[field]); + }).join(delimiter); + })).join("\n"); + }; + dsv.formatRows = function(rows) { + return rows.map(formatRow).join("\n"); + }; + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + function formatValue(text) { + return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; + } + return dsv; + }; + d3.csv = d3.dsv(",", "text/csv"); + d3.tsv = d3.dsv(" ", "text/tab-separated-values"); + var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { + setTimeout(callback, 17); + }; + d3.timer = function(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + var time = then + delay, timer = { + callback: callback, + time: time, + next: null + }; + if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead = timer; + d3_timer_queueTail = timer; + if (!d3_timer_interval) { + d3_timer_timeout = clearTimeout(d3_timer_timeout); + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + }; + function d3_timer_step() { + var now = d3_timer_mark(), delay = d3_timer_sweep() - now; + if (delay > 24) { + if (isFinite(delay)) { + clearTimeout(d3_timer_timeout); + d3_timer_timeout = setTimeout(d3_timer_step, delay); + } + d3_timer_interval = 0; + } else { + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + } + d3.timer.flush = function() { + d3_timer_mark(); + d3_timer_sweep(); + }; + function d3_timer_replace(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + d3_timer_active.callback = callback; + d3_timer_active.time = then + delay; + } + function d3_timer_mark() { + var now = Date.now(); + d3_timer_active = d3_timer_queueHead; + while (d3_timer_active) { + if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time); + d3_timer_active = d3_timer_active.next; + } + return now; + } + function d3_timer_sweep() { + var t0, t1 = d3_timer_queueHead, time = Infinity; + while (t1) { + if (t1.flush) { + t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next; + } else { + if (t1.time < time) time = t1.time; + t1 = (t0 = t1).next; + } + } + d3_timer_queueTail = t0; + return time; + } + var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$"; + var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); + d3.formatPrefix = function(value, precision) { + var i = 0; + if (value) { + if (value < 0) value *= -1; + if (precision) value = d3.round(value, d3_format_precision(value, precision)); + i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); + i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); + } + return d3_formatPrefixes[8 + i / 3]; + }; + function d3_formatPrefix(d, i) { + var k = Math.pow(10, Math.abs(8 - i) * 3); + return { + scale: i > 8 ? function(d) { + return d / k; + } : function(d) { + return d * k; + }, + symbol: d + }; + } + d3.round = function(x, n) { + return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); + }; + d3.format = function(specifier) { + var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; + if (precision) precision = +precision.substring(1); + if (zfill || fill === "0" && align === "=") { + zfill = fill = "0"; + align = "="; + if (comma) width -= Math.floor((width - 1) / 4); + } + switch (type) { + case "n": + comma = true; + type = "g"; + break; + + case "%": + scale = 100; + suffix = "%"; + type = "f"; + break; + + case "p": + scale = 100; + suffix = "%"; + type = "r"; + break; + + case "b": + case "o": + case "x": + case "X": + if (symbol === "#") symbol = "0" + type.toLowerCase(); + + case "c": + case "d": + integer = true; + precision = 0; + break; + + case "s": + scale = -1; + type = "r"; + break; + } + if (symbol === "#") symbol = ""; else if (symbol === "$") symbol = d3_format_currencySymbol; + if (type == "r" && !precision) type = "g"; + if (precision != null) { + if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); + } + type = d3_format_types.get(type) || d3_format_typeDefault; + var zcomma = zfill && comma; + return function(value) { + if (integer && value % 1) return ""; + var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; + if (scale < 0) { + var prefix = d3.formatPrefix(value, precision); + value = prefix.scale(value); + suffix = prefix.symbol; + } else { + value *= scale; + } + value = type(value, precision); + var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint + value.substring(i + 1); + if (!zfill && comma) before = d3_format_group(before); + var length = symbol.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; + if (zcomma) before = d3_format_group(padding + before); + negative += symbol; + value = before + after; + return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix; + }; + }; + var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; + var d3_format_types = d3.map({ + b: function(x) { + return x.toString(2); + }, + c: function(x) { + return String.fromCharCode(x); + }, + o: function(x) { + return x.toString(8); + }, + x: function(x) { + return x.toString(16); + }, + X: function(x) { + return x.toString(16).toUpperCase(); + }, + g: function(x, p) { + return x.toPrecision(p); + }, + e: function(x, p) { + return x.toExponential(p); + }, + f: function(x, p) { + return x.toFixed(p); + }, + r: function(x, p) { + return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); + } + }); + function d3_format_precision(x, p) { + return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); + } + function d3_format_typeDefault(x) { + return x + ""; + } + var d3_format_group = d3_identity; + if (d3_format_grouping) { + var d3_format_groupingLength = d3_format_grouping.length; + d3_format_group = function(value) { + var i = value.length, t = [], j = 0, g = d3_format_grouping[0]; + while (i > 0 && g > 0) { + t.push(value.substring(i -= g, i + g)); + g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; + } + return t.reverse().join(d3_format_thousandsSeparator); + }; + } + d3.geo = {}; + function d3_adder() {} + d3_adder.prototype = { + s: 0, + t: 0, + add: function(y) { + d3_adderSum(y, this.t, d3_adderTemp); + d3_adderSum(d3_adderTemp.s, this.s, this); + if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; + }, + reset: function() { + this.s = this.t = 0; + }, + valueOf: function() { + return this.s; + } + }; + var d3_adderTemp = new d3_adder(); + function d3_adderSum(a, b, o) { + var x = o.s = a + b, bv = x - a, av = x - bv; + o.t = a - av + (b - bv); + } + d3.geo.stream = function(object, listener) { + if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { + d3_geo_streamObjectType[object.type](object, listener); + } else { + d3_geo_streamGeometry(object, listener); + } + }; + function d3_geo_streamGeometry(geometry, listener) { + if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { + d3_geo_streamGeometryType[geometry.type](geometry, listener); + } + } + var d3_geo_streamObjectType = { + Feature: function(feature, listener) { + d3_geo_streamGeometry(feature.geometry, listener); + }, + FeatureCollection: function(object, listener) { + var features = object.features, i = -1, n = features.length; + while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); + } + }; + var d3_geo_streamGeometryType = { + Sphere: function(object, listener) { + listener.sphere(); + }, + Point: function(object, listener) { + object = object.coordinates; + listener.point(object[0], object[1], object[2]); + }, + MultiPoint: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]); + }, + LineString: function(object, listener) { + d3_geo_streamLine(object.coordinates, listener, 0); + }, + MultiLineString: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); + }, + Polygon: function(object, listener) { + d3_geo_streamPolygon(object.coordinates, listener); + }, + MultiPolygon: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); + }, + GeometryCollection: function(object, listener) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) d3_geo_streamGeometry(geometries[i], listener); + } + }; + function d3_geo_streamLine(coordinates, listener, closed) { + var i = -1, n = coordinates.length - closed, coordinate; + listener.lineStart(); + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]); + listener.lineEnd(); + } + function d3_geo_streamPolygon(coordinates, listener) { + var i = -1, n = coordinates.length; + listener.polygonStart(); + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); + listener.polygonEnd(); + } + d3.geo.area = function(object) { + d3_geo_areaSum = 0; + d3.geo.stream(object, d3_geo_area); + return d3_geo_areaSum; + }; + var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); + var d3_geo_area = { + sphere: function() { + d3_geo_areaSum += 4 * π; + }, + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_areaRingSum.reset(); + d3_geo_area.lineStart = d3_geo_areaRingStart; + }, + polygonEnd: function() { + var area = 2 * d3_geo_areaRingSum; + d3_geo_areaSum += area < 0 ? 4 * π + area : area; + d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; + } + }; + function d3_geo_areaRingStart() { + var λ00, φ00, λ0, cosφ0, sinφ0; + d3_geo_area.point = function(λ, φ) { + d3_geo_area.point = nextPoint; + λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), + sinφ0 = Math.sin(φ); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + φ = φ * d3_radians / 2 + π / 4; + var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); + d3_geo_areaRingSum.add(Math.atan2(v, u)); + λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; + } + d3_geo_area.lineEnd = function() { + nextPoint(λ00, φ00); + }; + } + function d3_geo_cartesian(spherical) { + var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); + return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; + } + function d3_geo_cartesianDot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + function d3_geo_cartesianCross(a, b) { + return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; + } + function d3_geo_cartesianAdd(a, b) { + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; + } + function d3_geo_cartesianScale(vector, k) { + return [ vector[0] * k, vector[1] * k, vector[2] * k ]; + } + function d3_geo_cartesianNormalize(d) { + var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + d[0] /= l; + d[1] /= l; + d[2] /= l; + } + function d3_geo_spherical(cartesian) { + return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; + } + function d3_geo_sphericalEqual(a, b) { + return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; + } + d3.geo.bounds = function() { + var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; + var bound = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + bound.point = ringPoint; + bound.lineStart = ringStart; + bound.lineEnd = ringEnd; + dλSum = 0; + d3_geo_area.polygonStart(); + }, + polygonEnd: function() { + d3_geo_area.polygonEnd(); + bound.point = point; + bound.lineStart = lineStart; + bound.lineEnd = lineEnd; + if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; + range[0] = λ0, range[1] = λ1; + } + }; + function point(λ, φ) { + ranges.push(range = [ λ0 = λ, λ1 = λ ]); + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + function linePoint(λ, φ) { + var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); + if (p0) { + var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); + d3_geo_cartesianNormalize(inflection); + inflection = d3_geo_spherical(inflection); + var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = Math.abs(dλ) > 180; + if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = inflection[1] * d3_degrees; + if (φi > φ1) φ1 = φi; + } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = -inflection[1] * d3_degrees; + if (φi < φ0) φ0 = φi; + } else { + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + if (antimeridian) { + if (λ < λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } else { + if (λ1 >= λ0) { + if (λ < λ0) λ0 = λ; + if (λ > λ1) λ1 = λ; + } else { + if (λ > λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } + } + } else { + point(λ, φ); + } + p0 = p, λ_ = λ; + } + function lineStart() { + bound.point = linePoint; + } + function lineEnd() { + range[0] = λ0, range[1] = λ1; + bound.point = point; + p0 = null; + } + function ringPoint(λ, φ) { + if (p0) { + var dλ = λ - λ_; + dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; + } else λ__ = λ, φ__ = φ; + d3_geo_area.point(λ, φ); + linePoint(λ, φ); + } + function ringStart() { + d3_geo_area.lineStart(); + } + function ringEnd() { + ringPoint(λ__, φ__); + d3_geo_area.lineEnd(); + if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180); + range[0] = λ0, range[1] = λ1; + p0 = null; + } + function angle(λ0, λ1) { + return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; + } + function compareRanges(a, b) { + return a[0] - b[0]; + } + function withinRange(x, range) { + return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; + } + return function(feature) { + φ1 = λ1 = -(λ0 = φ0 = Infinity); + ranges = []; + d3.geo.stream(feature, bound); + var n = ranges.length; + if (n) { + ranges.sort(compareRanges); + for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { + b = ranges[i]; + if (withinRange(b[0], a) || withinRange(b[1], a)) { + if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; + if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; + } else { + merged.push(a = b); + } + } + var best = -Infinity, dλ; + for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { + b = merged[i]; + if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; + } + } + ranges = range = null; + return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; + }; + }(); + d3.geo.centroid = function(object) { + d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, d3_geo_centroid); + var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; + if (m < ε2) { + x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; + if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; + m = x * x + y * y + z * z; + if (m < ε2) return [ NaN, NaN ]; + } + return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; + }; + var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; + var d3_geo_centroid = { + sphere: d3_noop, + point: d3_geo_centroidPoint, + lineStart: d3_geo_centroidLineStart, + lineEnd: d3_geo_centroidLineEnd, + polygonStart: function() { + d3_geo_centroid.lineStart = d3_geo_centroidRingStart; + }, + polygonEnd: function() { + d3_geo_centroid.lineStart = d3_geo_centroidLineStart; + } + }; + function d3_geo_centroidPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); + } + function d3_geo_centroidPointXYZ(x, y, z) { + ++d3_geo_centroidW0; + d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; + d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; + d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; + } + function d3_geo_centroidLineStart() { + var x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroid.point = nextPoint; + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_geo_centroidLineEnd() { + d3_geo_centroid.point = d3_geo_centroidPoint; + } + function d3_geo_centroidRingStart() { + var λ00, φ00, x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ00 = λ, φ00 = φ; + d3_geo_centroid.point = nextPoint; + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + d3_geo_centroid.lineEnd = function() { + nextPoint(λ00, φ00); + d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; + d3_geo_centroid.point = d3_geo_centroidPoint; + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); + d3_geo_centroidX2 += v * cx; + d3_geo_centroidY2 += v * cy; + d3_geo_centroidZ2 += v * cz; + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_true() { + return true; + } + function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) { + var subject = [], clip = []; + segments.forEach(function(segment) { + if ((n = segment.length - 1) <= 0) return; + var n, p0 = segment[0], p1 = segment[n]; + if (d3_geo_sphericalEqual(p0, p1)) { + listener.lineStart(); + for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); + listener.lineEnd(); + return; + } + var a = { + point: p0, + points: segment, + other: null, + visited: false, + entry: true, + subject: true + }, b = { + point: p0, + points: [ p0 ], + other: a, + visited: false, + entry: false, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + a = { + point: p1, + points: [ p1 ], + other: null, + visited: false, + entry: false, + subject: true + }; + b = { + point: p1, + points: [ p1 ], + other: a, + visited: false, + entry: true, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + }); + clip.sort(compare); + d3_geo_clipPolygonLinkCircular(subject); + d3_geo_clipPolygonLinkCircular(clip); + if (!subject.length) return; + for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) { + clip[i].entry = entry = !entry; + } + var start = subject[0], current, points, point; + while (1) { + current = start; + while (current.visited) if ((current = current.next) === start) return; + points = current.points; + listener.lineStart(); + do { + current.visited = current.other.visited = true; + if (current.entry) { + if (current.subject) { + for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.next.point, 1, listener); + } + current = current.next; + } else { + if (current.subject) { + points = current.prev.points; + for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.prev.point, -1, listener); + } + current = current.prev; + } + current = current.other; + points = current.points; + } while (!current.visited); + listener.lineEnd(); + } + } + function d3_geo_clipPolygonLinkCircular(array) { + if (!(n = array.length)) return; + var n, i = 0, a = array[0], b; + while (++i < n) { + a.next = b = array[i]; + b.prev = a; + a = b; + } + a.next = b = array[0]; + b.prev = a; + } + function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { + return function(rotate, listener) { + var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]); + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + clip.point = pointRing; + clip.lineStart = ringStart; + clip.lineEnd = ringEnd; + segments = []; + polygon = []; + listener.polygonStart(); + }, + polygonEnd: function() { + clip.point = point; + clip.lineStart = lineStart; + clip.lineEnd = lineEnd; + segments = d3.merge(segments); + var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon); + if (segments.length) { + d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener); + } else if (clipStartInside) { + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + } + listener.polygonEnd(); + segments = polygon = null; + }, + sphere: function() { + listener.polygonStart(); + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + listener.polygonEnd(); + } + }; + function point(λ, φ) { + var point = rotate(λ, φ); + if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ); + } + function pointLine(λ, φ) { + var point = rotate(λ, φ); + line.point(point[0], point[1]); + } + function lineStart() { + clip.point = pointLine; + line.lineStart(); + } + function lineEnd() { + clip.point = point; + line.lineEnd(); + } + var segments; + var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; + function pointRing(λ, φ) { + ring.push([ λ, φ ]); + var point = rotate(λ, φ); + ringListener.point(point[0], point[1]); + } + function ringStart() { + ringListener.lineStart(); + ring = []; + } + function ringEnd() { + pointRing(ring[0][0], ring[0][1]); + ringListener.lineEnd(); + var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; + ring.pop(); + polygon.push(ring); + ring = null; + if (!n) return; + if (clean & 1) { + segment = ringSegments[0]; + var n = segment.length - 1, i = -1, point; + listener.lineStart(); + while (++i < n) listener.point((point = segment[i])[0], point[1]); + listener.lineEnd(); + return; + } + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); + } + return clip; + }; + } + function d3_geo_clipSegmentLength1(segment) { + return segment.length > 1; + } + function d3_geo_clipBufferListener() { + var lines = [], line; + return { + lineStart: function() { + lines.push(line = []); + }, + point: function(λ, φ) { + line.push([ λ, φ ]); + }, + lineEnd: d3_noop, + buffer: function() { + var buffer = lines; + lines = []; + line = null; + return buffer; + }, + rejoin: function() { + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); + } + }; + } + function d3_geo_clipSort(a, b) { + return ((a = a.point)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.point)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]); + } + function d3_geo_pointInPolygon(point, polygon) { + var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0; + d3_geo_areaRingSum.reset(); + for (var i = 0, n = polygon.length; i < n; ++i) { + var ring = polygon[i], m = ring.length; + if (!m) continue; + var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; + while (true) { + if (j === m) j = 0; + point = ring[j]; + var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, antimeridian = Math.abs(dλ) > π, k = sinφ0 * sinφ; + d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosφ0 * cosφ + k * Math.cos(dλ))); + polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * π : dλ; + if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { + var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); + d3_geo_cartesianNormalize(arc); + var intersection = d3_geo_cartesianCross(meridianNormal, arc); + d3_geo_cartesianNormalize(intersection); + var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); + if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) { + winding += antimeridian ^ dλ >= 0 ? 1 : -1; + } + } + if (!j++) break; + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; + } + } + return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ winding & 1; + } + var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]); + function d3_geo_clipAntimeridianLine(listener) { + var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; + return { + lineStart: function() { + listener.lineStart(); + clean = 1; + }, + point: function(λ1, φ1) { + var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); + if (Math.abs(dλ - π) < ε) { + listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + listener.point(λ1, φ0); + clean = 0; + } else if (sλ0 !== sλ1 && dλ >= π) { + if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; + if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; + φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + clean = 0; + } + listener.point(λ0 = λ1, φ0 = φ1); + sλ0 = sλ1; + }, + lineEnd: function() { + listener.lineEnd(); + λ0 = φ0 = NaN; + }, + clean: function() { + return 2 - clean; + } + }; + } + function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { + var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); + return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; + } + function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { + var φ; + if (from == null) { + φ = direction * halfπ; + listener.point(-π, φ); + listener.point(0, φ); + listener.point(π, φ); + listener.point(π, 0); + listener.point(π, -φ); + listener.point(0, -φ); + listener.point(-π, -φ); + listener.point(-π, 0); + listener.point(-π, φ); + } else if (Math.abs(from[0] - to[0]) > ε) { + var s = (from[0] < to[0] ? 1 : -1) * π; + φ = direction * s / 2; + listener.point(-s, φ); + listener.point(0, φ); + listener.point(s, φ); + } else { + listener.point(to[0], to[1]); + } + } + function d3_geo_clipCircle(radius) { + var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); + return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]); + function visible(λ, φ) { + return Math.cos(λ) * Math.cos(φ) > cr; + } + function clipLine(listener) { + var point0, c0, v0, v00, clean; + return { + lineStart: function() { + v00 = v0 = false; + clean = 1; + }, + point: function(λ, φ) { + var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; + if (!point0 && (v00 = v0 = v)) listener.lineStart(); + if (v !== v0) { + point2 = intersect(point0, point1); + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { + point1[0] += ε; + point1[1] += ε; + v = visible(point1[0], point1[1]); + } + } + if (v !== v0) { + clean = 0; + if (v) { + listener.lineStart(); + point2 = intersect(point1, point0); + listener.point(point2[0], point2[1]); + } else { + point2 = intersect(point0, point1); + listener.point(point2[0], point2[1]); + listener.lineEnd(); + } + point0 = point2; + } else if (notHemisphere && point0 && smallRadius ^ v) { + var t; + if (!(c & c0) && (t = intersect(point1, point0, true))) { + clean = 0; + if (smallRadius) { + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + } else { + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + } + } + } + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { + listener.point(point1[0], point1[1]); + } + point0 = point1, v0 = v, c0 = c; + }, + lineEnd: function() { + if (v0) listener.lineEnd(); + point0 = null; + }, + clean: function() { + return clean | (v00 && v0) << 1; + } + }; + } + function intersect(a, b, two) { + var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); + var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; + if (!determinant) return !two && a; + var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); + d3_geo_cartesianAdd(A, B); + var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); + if (t2 < 0) return; + var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); + d3_geo_cartesianAdd(q, A); + q = d3_geo_spherical(q); + if (!two) return q; + var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; + var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε; + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; + if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); + d3_geo_cartesianAdd(q1, A); + return [ q, d3_geo_spherical(q1) ]; + } + } + function code(λ, φ) { + var r = smallRadius ? radius : π - radius, code = 0; + if (λ < -r) code |= 1; else if (λ > r) code |= 2; + if (φ < -r) code |= 4; else if (φ > r) code |= 8; + return code; + } + } + var d3_geo_clipExtentMAX = 1e9; + d3.geo.clipExtent = function() { + var x0, y0, x1, y1, stream, clip, clipExtent = { + stream: function(output) { + if (stream) stream.valid = false; + stream = clip(output); + stream.valid = true; + return stream; + }, + extent: function(_) { + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; + clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]); + if (stream) stream.valid = false, stream = null; + return clipExtent; + } + }; + return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]); + }; + function d3_geo_clipExtent(x0, y0, x1, y1) { + return function(listener) { + var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + listener = bufferListener; + segments = []; + polygon = []; + clean = true; + }, + polygonEnd: function() { + listener = listener_; + segments = d3.merge(segments); + var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length; + if (inside || visible) { + listener.polygonStart(); + if (inside) { + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + } + if (visible) { + d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener); + } + listener.polygonEnd(); + } + segments = polygon = ring = null; + } + }; + function insidePolygon(p) { + var wn = 0, n = polygon.length, y = p[1]; + for (var i = 0; i < n; ++i) { + for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { + b = v[j]; + if (a[1] <= y) { + if (b[1] > y && isLeft(a, b, p) > 0) ++wn; + } else { + if (b[1] <= y && isLeft(a, b, p) < 0) --wn; + } + a = b; + } + } + return wn !== 0; + } + function isLeft(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); + } + function interpolate(from, to, direction, listener) { + var a = 0, a1 = 0; + if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { + do { + listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); + } while ((a = (a + direction + 4) % 4) !== a1); + } else { + listener.point(to[0], to[1]); + } + } + function pointVisible(x, y) { + return x0 <= x && x <= x1 && y0 <= y && y <= y1; + } + function point(x, y) { + if (pointVisible(x, y)) listener.point(x, y); + } + var x__, y__, v__, x_, y_, v_, first, clean; + function lineStart() { + clip.point = linePoint; + if (polygon) polygon.push(ring = []); + first = true; + v_ = false; + x_ = y_ = NaN; + } + function lineEnd() { + if (segments) { + linePoint(x__, y__); + if (v__ && v_) bufferListener.rejoin(); + segments.push(bufferListener.buffer()); + } + clip.point = point; + if (v_) listener.lineEnd(); + } + function linePoint(x, y) { + x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x)); + y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y)); + var v = pointVisible(x, y); + if (polygon) ring.push([ x, y ]); + if (first) { + x__ = x, y__ = y, v__ = v; + first = false; + if (v) { + listener.lineStart(); + listener.point(x, y); + } + } else { + if (v && v_) listener.point(x, y); else { + var a = [ x_, y_ ], b = [ x, y ]; + if (clipLine(a, b)) { + if (!v_) { + listener.lineStart(); + listener.point(a[0], a[1]); + } + listener.point(b[0], b[1]); + if (!v) listener.lineEnd(); + clean = false; + } else if (v) { + listener.lineStart(); + listener.point(x, y); + clean = false; + } + } + } + x_ = x, y_ = y, v_ = v; + } + return clip; + }; + function corner(p, direction) { + return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; + } + function compare(a, b) { + return comparePoints(a.point, b.point); + } + function comparePoints(a, b) { + var ca = corner(a, 1), cb = corner(b, 1); + return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; + } + function clipLine(a, b) { + var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; + if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; + if (d3_geo_clipExtentT(x0 - a[0], dx, t) && d3_geo_clipExtentT(a[0] - x1, -dx, t) && d3_geo_clipExtentT(y0 - a[1], dy, t) && d3_geo_clipExtentT(a[1] - y1, -dy, t)) { + if (t[1] < 1) { + b[0] = a[0] + t[1] * dx; + b[1] = a[1] + t[1] * dy; + } + if (t[0] > 0) { + a[0] += t[0] * dx; + a[1] += t[0] * dy; + } + return true; + } + return false; + } + } + function d3_geo_clipExtentT(num, denominator, t) { + if (Math.abs(denominator) < ε) return num <= 0; + var u = num / denominator; + if (denominator > 0) { + if (u > t[1]) return false; + if (u > t[0]) t[0] = u; + } else { + if (u < t[0]) return false; + if (u < t[1]) t[1] = u; + } + return true; + } + function d3_geo_compose(a, b) { + function compose(x, y) { + return x = a(x, y), b(x[0], x[1]); + } + if (a.invert && b.invert) compose.invert = function(x, y) { + return x = b.invert(x, y), x && a.invert(x[0], x[1]); + }; + return compose; + } + function d3_geo_conic(projectAt) { + var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); + p.parallels = function(_) { + if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; + return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); + }; + return p; + } + function d3_geo_conicEqualArea(φ0, φ1) { + var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; + function forward(λ, φ) { + var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; + return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = ρ0 - y; + return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; + }; + return forward; + } + (d3.geo.conicEqualArea = function() { + return d3_geo_conic(d3_geo_conicEqualArea); + }).raw = d3_geo_conicEqualArea; + d3.geo.albers = function() { + return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); + }; + d3.geo.albersUsa = function() { + var lower48 = d3.geo.albers(); + var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); + var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); + var point, pointStream = { + point: function(x, y) { + point = [ x, y ]; + } + }, lower48Point, alaskaPoint, hawaiiPoint; + function albersUsa(coordinates) { + var x = coordinates[0], y = coordinates[1]; + point = null; + (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); + return point; + } + albersUsa.invert = function(coordinates) { + var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; + return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); + }; + albersUsa.stream = function(stream) { + var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); + return { + point: function(x, y) { + lower48Stream.point(x, y); + alaskaStream.point(x, y); + hawaiiStream.point(x, y); + }, + sphere: function() { + lower48Stream.sphere(); + alaskaStream.sphere(); + hawaiiStream.sphere(); + }, + lineStart: function() { + lower48Stream.lineStart(); + alaskaStream.lineStart(); + hawaiiStream.lineStart(); + }, + lineEnd: function() { + lower48Stream.lineEnd(); + alaskaStream.lineEnd(); + hawaiiStream.lineEnd(); + }, + polygonStart: function() { + lower48Stream.polygonStart(); + alaskaStream.polygonStart(); + hawaiiStream.polygonStart(); + }, + polygonEnd: function() { + lower48Stream.polygonEnd(); + alaskaStream.polygonEnd(); + hawaiiStream.polygonEnd(); + } + }; + }; + albersUsa.precision = function(_) { + if (!arguments.length) return lower48.precision(); + lower48.precision(_); + alaska.precision(_); + hawaii.precision(_); + return albersUsa; + }; + albersUsa.scale = function(_) { + if (!arguments.length) return lower48.scale(); + lower48.scale(_); + alaska.scale(_ * .35); + hawaii.scale(_); + return albersUsa.translate(lower48.translate()); + }; + albersUsa.translate = function(_) { + if (!arguments.length) return lower48.translate(); + var k = lower48.scale(), x = +_[0], y = +_[1]; + lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; + alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + return albersUsa; + }; + return albersUsa.scale(1070); + }; + var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_pathAreaPolygon = 0; + d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; + }, + polygonEnd: function() { + d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; + d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); + } + }; + function d3_geo_pathAreaRingStart() { + var x00, y00, x0, y0; + d3_geo_pathArea.point = function(x, y) { + d3_geo_pathArea.point = nextPoint; + x00 = x0 = x, y00 = y0 = y; + }; + function nextPoint(x, y) { + d3_geo_pathAreaPolygon += y0 * x - x0 * y; + x0 = x, y0 = y; + } + d3_geo_pathArea.lineEnd = function() { + nextPoint(x00, y00); + }; + } + var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; + var d3_geo_pathBounds = { + point: d3_geo_pathBoundsPoint, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_pathBoundsPoint(x, y) { + if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; + if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; + if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; + if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; + } + function d3_geo_pathBuffer() { + var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointCircle = d3_geo_pathBufferCircle(_); + return stream; + }, + result: function() { + if (buffer.length) { + var result = buffer.join(""); + buffer = []; + return result; + } + } + }; + function point(x, y) { + buffer.push("M", x, ",", y, pointCircle); + } + function pointLineStart(x, y) { + buffer.push("M", x, ",", y); + stream.point = pointLine; + } + function pointLine(x, y) { + buffer.push("L", x, ",", y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + buffer.push("Z"); + } + return stream; + } + function d3_geo_pathBufferCircle(radius) { + return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; + } + var d3_geo_pathCentroid = { + point: d3_geo_pathCentroidPoint, + lineStart: d3_geo_pathCentroidLineStart, + lineEnd: d3_geo_pathCentroidLineEnd, + polygonStart: function() { + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; + }, + polygonEnd: function() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; + d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; + } + }; + function d3_geo_pathCentroidPoint(x, y) { + d3_geo_centroidX0 += x; + d3_geo_centroidY0 += y; + ++d3_geo_centroidZ0; + } + function d3_geo_pathCentroidLineStart() { + var x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + } + function d3_geo_pathCentroidLineEnd() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + } + function d3_geo_pathCentroidRingStart() { + var x00, y00, x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + z = y0 * x - x0 * y; + d3_geo_centroidX2 += z * (x0 + x); + d3_geo_centroidY2 += z * (y0 + y); + d3_geo_centroidZ2 += z * 3; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + d3_geo_pathCentroid.lineEnd = function() { + nextPoint(x00, y00); + }; + } + function d3_geo_pathContext(context) { + var pointRadius = 4.5; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointRadius = _; + return stream; + }, + result: d3_noop + }; + function point(x, y) { + context.moveTo(x, y); + context.arc(x, y, pointRadius, 0, τ); + } + function pointLineStart(x, y) { + context.moveTo(x, y); + stream.point = pointLine; + } + function pointLine(x, y) { + context.lineTo(x, y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + context.closePath(); + } + return stream; + } + function d3_geo_resample(project) { + var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; + function resample(stream) { + var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; + var resample = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + stream.polygonStart(); + resample.lineStart = ringStart; + }, + polygonEnd: function() { + stream.polygonEnd(); + resample.lineStart = lineStart; + } + }; + function point(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + } + function lineStart() { + x0 = NaN; + resample.point = linePoint; + stream.lineStart(); + } + function linePoint(λ, φ) { + var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); + resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); + stream.point(x0, y0); + } + function lineEnd() { + resample.point = point; + stream.lineEnd(); + } + function ringStart() { + lineStart(); + resample.point = ringPoint; + resample.lineEnd = ringEnd; + } + function ringPoint(λ, φ) { + linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; + resample.point = linePoint; + } + function ringEnd() { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); + resample.lineEnd = lineEnd; + lineEnd(); + } + return resample; + } + function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { + var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; + if (d2 > 4 * δ2 && depth--) { + var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; + if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); + stream.point(x2, y2); + resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); + } + } + } + resample.precision = function(_) { + if (!arguments.length) return Math.sqrt(δ2); + maxDepth = (δ2 = _ * _) > 0 && 16; + return resample; + }; + return resample; + } + d3.geo.transform = function(methods) { + return { + stream: function(stream) { + var transform = new d3_geo_transform(stream); + for (var k in methods) transform[k] = methods[k]; + return transform; + } + }; + }; + function d3_geo_transform(stream) { + this.stream = stream; + } + d3_geo_transform.prototype = { + point: function(x, y) { + this.stream.point(x, y); + }, + sphere: function() { + this.stream.sphere(); + }, + lineStart: function() { + this.stream.lineStart(); + }, + lineEnd: function() { + this.stream.lineEnd(); + }, + polygonStart: function() { + this.stream.polygonStart(); + }, + polygonEnd: function() { + this.stream.polygonEnd(); + } + }; + d3.geo.path = function() { + var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; + function path(object) { + if (object) { + if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); + if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); + d3.geo.stream(object, cacheStream); + } + return contextStream.result(); + } + path.area = function(object) { + d3_geo_pathAreaSum = 0; + d3.geo.stream(object, projectStream(d3_geo_pathArea)); + return d3_geo_pathAreaSum; + }; + path.centroid = function(object) { + d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); + return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; + }; + path.bounds = function(object) { + d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); + d3.geo.stream(object, projectStream(d3_geo_pathBounds)); + return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; + }; + path.projection = function(_) { + if (!arguments.length) return projection; + projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; + return reset(); + }; + path.context = function(_) { + if (!arguments.length) return context; + contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); + if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); + return reset(); + }; + path.pointRadius = function(_) { + if (!arguments.length) return pointRadius; + pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); + return path; + }; + function reset() { + cacheStream = null; + return path; + } + return path.projection(d3.geo.albersUsa()).context(null); + }; + function d3_geo_pathProjectStream(project) { + var resample = d3_geo_resample(function(x, y) { + return project([ x * d3_degrees, y * d3_degrees ]); + }); + return function(stream) { + var transform = new d3_geo_transform(stream = resample(stream)); + transform.point = function(x, y) { + stream.point(x * d3_radians, y * d3_radians); + }; + return transform; + }; + } + d3.geo.projection = d3_geo_projection; + d3.geo.projectionMutator = d3_geo_projectionMutator; + function d3_geo_projection(project) { + return d3_geo_projectionMutator(function() { + return project; + })(); + } + function d3_geo_projectionMutator(projectAt) { + var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { + x = project(x, y); + return [ x[0] * k + δx, δy - x[1] * k ]; + }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; + function projection(point) { + point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); + return [ point[0] * k + δx, δy - point[1] * k ]; + } + function invert(point) { + point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); + return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; + } + projection.stream = function(output) { + if (stream) stream.valid = false; + stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output)))); + stream.valid = true; + return stream; + }; + projection.clipAngle = function(_) { + if (!arguments.length) return clipAngle; + preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); + return invalidate(); + }; + projection.clipExtent = function(_) { + if (!arguments.length) return clipExtent; + clipExtent = _; + postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity; + return invalidate(); + }; + projection.scale = function(_) { + if (!arguments.length) return k; + k = +_; + return reset(); + }; + projection.translate = function(_) { + if (!arguments.length) return [ x, y ]; + x = +_[0]; + y = +_[1]; + return reset(); + }; + projection.center = function(_) { + if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; + λ = _[0] % 360 * d3_radians; + φ = _[1] % 360 * d3_radians; + return reset(); + }; + projection.rotate = function(_) { + if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; + δλ = _[0] % 360 * d3_radians; + δφ = _[1] % 360 * d3_radians; + δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; + return reset(); + }; + d3.rebind(projection, projectResample, "precision"); + function reset() { + projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); + var center = project(λ, φ); + δx = x - center[0] * k; + δy = y + center[1] * k; + return invalidate(); + } + function invalidate() { + if (stream) stream.valid = false, stream = null; + return projection; + } + return function() { + project = projectAt.apply(this, arguments); + projection.invert = project.invert && invert; + return reset(); + }; + } + function d3_geo_projectionRadians(stream) { + var transform = new d3_geo_transform(stream); + transform.point = function(λ, φ) { + stream.point(λ * d3_radians, φ * d3_radians); + }; + return transform; + } + function d3_geo_equirectangular(λ, φ) { + return [ λ, φ ]; + } + (d3.geo.equirectangular = function() { + return d3_geo_projection(d3_geo_equirectangular); + }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; + d3.geo.rotation = function(rotate) { + rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); + function forward(coordinates) { + coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + } + forward.invert = function(coordinates) { + coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + }; + return forward; + }; + function d3_geo_identityRotation(λ, φ) { + return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; + } + d3_geo_identityRotation.invert = d3_geo_equirectangular; + function d3_geo_rotation(δλ, δφ, δγ) { + return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation; + } + function d3_geo_forwardRotationλ(δλ) { + return function(λ, φ) { + return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; + }; + } + function d3_geo_rotationλ(δλ) { + var rotation = d3_geo_forwardRotationλ(δλ); + rotation.invert = d3_geo_forwardRotationλ(-δλ); + return rotation; + } + function d3_geo_rotationφγ(δφ, δγ) { + var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); + function rotation(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; + return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; + } + rotation.invert = function(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; + return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; + }; + return rotation; + } + d3.geo.circle = function() { + var origin = [ 0, 0 ], angle, precision = 6, interpolate; + function circle() { + var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; + interpolate(null, null, 1, { + point: function(x, y) { + ring.push(x = rotate(x, y)); + x[0] *= d3_degrees, x[1] *= d3_degrees; + } + }); + return { + type: "Polygon", + coordinates: [ ring ] + }; + } + circle.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return circle; + }; + circle.angle = function(x) { + if (!arguments.length) return angle; + interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); + return circle; + }; + circle.precision = function(_) { + if (!arguments.length) return precision; + interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); + return circle; + }; + return circle.angle(90); + }; + function d3_geo_circleInterpolate(radius, precision) { + var cr = Math.cos(radius), sr = Math.sin(radius); + return function(from, to, direction, listener) { + var step = direction * precision; + if (from != null) { + from = d3_geo_circleAngle(cr, from); + to = d3_geo_circleAngle(cr, to); + if (direction > 0 ? from < to : from > to) from += direction * τ; + } else { + from = radius + direction * τ; + to = radius - .5 * step; + } + for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) { + listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); + } + }; + } + function d3_geo_circleAngle(cr, point) { + var a = d3_geo_cartesian(point); + a[0] -= cr; + d3_geo_cartesianNormalize(a); + var angle = d3_acos(-a[1]); + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); + } + d3.geo.distance = function(a, b) { + var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; + return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); + }; + d3.geo.graticule = function() { + var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; + function graticule() { + return { + type: "MultiLineString", + coordinates: lines() + }; + } + function lines() { + return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { + return Math.abs(x % DX) > ε; + }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { + return Math.abs(y % DY) > ε; + }).map(y)); + } + graticule.lines = function() { + return lines().map(function(coordinates) { + return { + type: "LineString", + coordinates: coordinates + }; + }); + }; + graticule.outline = function() { + return { + type: "Polygon", + coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] + }; + }; + graticule.extent = function(_) { + if (!arguments.length) return graticule.minorExtent(); + return graticule.majorExtent(_).minorExtent(_); + }; + graticule.majorExtent = function(_) { + if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; + X0 = +_[0][0], X1 = +_[1][0]; + Y0 = +_[0][1], Y1 = +_[1][1]; + if (X0 > X1) _ = X0, X0 = X1, X1 = _; + if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; + return graticule.precision(precision); + }; + graticule.minorExtent = function(_) { + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; + x0 = +_[0][0], x1 = +_[1][0]; + y0 = +_[0][1], y1 = +_[1][1]; + if (x0 > x1) _ = x0, x0 = x1, x1 = _; + if (y0 > y1) _ = y0, y0 = y1, y1 = _; + return graticule.precision(precision); + }; + graticule.step = function(_) { + if (!arguments.length) return graticule.minorStep(); + return graticule.majorStep(_).minorStep(_); + }; + graticule.majorStep = function(_) { + if (!arguments.length) return [ DX, DY ]; + DX = +_[0], DY = +_[1]; + return graticule; + }; + graticule.minorStep = function(_) { + if (!arguments.length) return [ dx, dy ]; + dx = +_[0], dy = +_[1]; + return graticule; + }; + graticule.precision = function(_) { + if (!arguments.length) return precision; + precision = +_; + x = d3_geo_graticuleX(y0, y1, 90); + y = d3_geo_graticuleY(x0, x1, precision); + X = d3_geo_graticuleX(Y0, Y1, 90); + Y = d3_geo_graticuleY(X0, X1, precision); + return graticule; + }; + return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); + }; + function d3_geo_graticuleX(y0, y1, dy) { + var y = d3.range(y0, y1 - ε, dy).concat(y1); + return function(x) { + return y.map(function(y) { + return [ x, y ]; + }); + }; + } + function d3_geo_graticuleY(x0, x1, dx) { + var x = d3.range(x0, x1 - ε, dx).concat(x1); + return function(y) { + return x.map(function(x) { + return [ x, y ]; + }); + }; + } + function d3_source(d) { + return d.source; + } + function d3_target(d) { + return d.target; + } + d3.geo.greatArc = function() { + var source = d3_source, source_, target = d3_target, target_; + function greatArc() { + return { + type: "LineString", + coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] + }; + } + greatArc.distance = function() { + return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); + }; + greatArc.source = function(_) { + if (!arguments.length) return source; + source = _, source_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.target = function(_) { + if (!arguments.length) return target; + target = _, target_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.precision = function() { + return arguments.length ? greatArc : 0; + }; + return greatArc; + }; + d3.geo.interpolate = function(source, target) { + return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); + }; + function d3_geo_interpolate(x0, y0, x1, y1) { + var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); + var interpolate = d ? function(t) { + var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; + return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; + } : function() { + return [ x0 * d3_degrees, y0 * d3_degrees ]; + }; + interpolate.distance = d; + return interpolate; + } + d3.geo.length = function(object) { + d3_geo_lengthSum = 0; + d3.geo.stream(object, d3_geo_length); + return d3_geo_lengthSum; + }; + var d3_geo_lengthSum; + var d3_geo_length = { + sphere: d3_noop, + point: d3_noop, + lineStart: d3_geo_lengthLineStart, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_lengthLineStart() { + var λ0, sinφ0, cosφ0; + d3_geo_length.point = function(λ, φ) { + λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); + d3_geo_length.point = nextPoint; + }; + d3_geo_length.lineEnd = function() { + d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; + }; + function nextPoint(λ, φ) { + var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); + d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; + } + } + function d3_geo_azimuthal(scale, angle) { + function azimuthal(λ, φ) { + var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); + return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; + } + azimuthal.invert = function(x, y) { + var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); + return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; + }; + return azimuthal; + } + var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { + return Math.sqrt(2 / (1 + cosλcosφ)); + }, function(ρ) { + return 2 * Math.asin(ρ / 2); + }); + (d3.geo.azimuthalEqualArea = function() { + return d3_geo_projection(d3_geo_azimuthalEqualArea); + }).raw = d3_geo_azimuthalEqualArea; + var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { + var c = Math.acos(cosλcosφ); + return c && c / Math.sin(c); + }, d3_identity); + (d3.geo.azimuthalEquidistant = function() { + return d3_geo_projection(d3_geo_azimuthalEquidistant); + }).raw = d3_geo_azimuthalEquidistant; + function d3_geo_conicConformal(φ0, φ1) { + var cosφ0 = Math.cos(φ0), t = function(φ) { + return Math.tan(π / 4 + φ / 2); + }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; + if (!n) return d3_geo_mercator; + function forward(λ, φ) { + var ρ = Math.abs(Math.abs(φ) - halfπ) < ε ? 0 : F / Math.pow(t(φ), n); + return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); + return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ]; + }; + return forward; + } + (d3.geo.conicConformal = function() { + return d3_geo_conic(d3_geo_conicConformal); + }).raw = d3_geo_conicConformal; + function d3_geo_conicEquidistant(φ0, φ1) { + var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; + if (Math.abs(n) < ε) return d3_geo_equirectangular; + function forward(λ, φ) { + var ρ = G - φ; + return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = G - y; + return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; + }; + return forward; + } + (d3.geo.conicEquidistant = function() { + return d3_geo_conic(d3_geo_conicEquidistant); + }).raw = d3_geo_conicEquidistant; + var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / cosλcosφ; + }, Math.atan); + (d3.geo.gnomonic = function() { + return d3_geo_projection(d3_geo_gnomonic); + }).raw = d3_geo_gnomonic; + function d3_geo_mercator(λ, φ) { + return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; + } + d3_geo_mercator.invert = function(x, y) { + return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ]; + }; + function d3_geo_mercatorProjection(project) { + var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; + m.scale = function() { + var v = scale.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.translate = function() { + var v = translate.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.clipExtent = function(_) { + var v = clipExtent.apply(m, arguments); + if (v === m) { + if (clipAuto = _ == null) { + var k = π * scale(), t = translate(); + clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); + } + } else if (clipAuto) { + v = null; + } + return v; + }; + return m.clipExtent(null); + } + (d3.geo.mercator = function() { + return d3_geo_mercatorProjection(d3_geo_mercator); + }).raw = d3_geo_mercator; + var d3_geo_orthographic = d3_geo_azimuthal(function() { + return 1; + }, Math.asin); + (d3.geo.orthographic = function() { + return d3_geo_projection(d3_geo_orthographic); + }).raw = d3_geo_orthographic; + var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / (1 + cosλcosφ); + }, function(ρ) { + return 2 * Math.atan(ρ); + }); + (d3.geo.stereographic = function() { + return d3_geo_projection(d3_geo_stereographic); + }).raw = d3_geo_stereographic; + function d3_geo_transverseMercator(λ, φ) { + var B = Math.cos(φ) * Math.sin(λ); + return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ]; + } + d3_geo_transverseMercator.invert = function(x, y) { + return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ]; + }; + (d3.geo.transverseMercator = function() { + return d3_geo_mercatorProjection(d3_geo_transverseMercator); + }).raw = d3_geo_transverseMercator; + d3.geom = {}; + d3.svg = {}; + function d3_svg_line(projection) { + var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; + function line(data) { + var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); + function segment() { + segments.push("M", interpolate(projection(points), tension)); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); + } else if (points.length) { + segment(); + points = []; + } + } + if (points.length) segment(); + return segments.length ? segments.join("") : null; + } + line.x = function(_) { + if (!arguments.length) return x; + x = _; + return line; + }; + line.y = function(_) { + if (!arguments.length) return y; + y = _; + return line; + }; + line.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return line; + }; + line.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + return line; + }; + line.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return line; + }; + return line; + } + d3.svg.line = function() { + return d3_svg_line(d3_identity); + }; + function d3_svg_lineX(d) { + return d[0]; + } + function d3_svg_lineY(d) { + return d[1]; + } + var d3_svg_lineInterpolators = d3.map({ + linear: d3_svg_lineLinear, + "linear-closed": d3_svg_lineLinearClosed, + step: d3_svg_lineStep, + "step-before": d3_svg_lineStepBefore, + "step-after": d3_svg_lineStepAfter, + basis: d3_svg_lineBasis, + "basis-open": d3_svg_lineBasisOpen, + "basis-closed": d3_svg_lineBasisClosed, + bundle: d3_svg_lineBundle, + cardinal: d3_svg_lineCardinal, + "cardinal-open": d3_svg_lineCardinalOpen, + "cardinal-closed": d3_svg_lineCardinalClosed, + monotone: d3_svg_lineMonotone + }); + d3_svg_lineInterpolators.forEach(function(key, value) { + value.key = key; + value.closed = /-closed$/.test(key); + }); + function d3_svg_lineLinear(points) { + return points.join("L"); + } + function d3_svg_lineLinearClosed(points) { + return d3_svg_lineLinear(points) + "Z"; + } + function d3_svg_lineStep(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); + if (n > 1) path.push("H", p[0]); + return path.join(""); + } + function d3_svg_lineStepBefore(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); + return path.join(""); + } + function d3_svg_lineStepAfter(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); + return path.join(""); + } + function d3_svg_lineCardinalOpen(points, tension) { + return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineCardinalClosed(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), + points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); + } + function d3_svg_lineCardinal(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineHermite(points, tangents) { + if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { + return d3_svg_lineLinear(points); + } + var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; + if (quad) { + path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; + p0 = points[1]; + pi = 2; + } + if (tangents.length > 1) { + t = tangents[1]; + p = points[pi]; + pi++; + path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + for (var i = 2; i < tangents.length; i++, pi++) { + p = points[pi]; + t = tangents[i]; + path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + } + } + if (quad) { + var lp = points[pi]; + path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; + } + return path; + } + function d3_svg_lineCardinalTangents(points, tension) { + var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; + while (++i < n) { + p0 = p1; + p1 = p2; + p2 = points[i]; + tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); + } + return tangents; + } + function d3_svg_lineBasis(points) { + if (points.length < 3) return d3_svg_lineLinear(points); + var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + points.push(points[n - 1]); + while (++i <= n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + points.pop(); + path.push("L", pi); + return path.join(""); + } + function d3_svg_lineBasisOpen(points) { + if (points.length < 4) return d3_svg_lineLinear(points); + var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; + while (++i < 3) { + pi = points[i]; + px.push(pi[0]); + py.push(pi[1]); + } + path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); + --i; + while (++i < n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBasisClosed(points) { + var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; + while (++i < 4) { + pi = points[i % n]; + px.push(pi[0]); + py.push(pi[1]); + } + path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + --i; + while (++i < m) { + pi = points[i % n]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBundle(points, tension) { + var n = points.length - 1; + if (n) { + var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; + while (++i <= n) { + p = points[i]; + t = i / n; + p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); + p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); + } + } + return d3_svg_lineBasis(points); + } + function d3_svg_lineDot4(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; + function d3_svg_lineBasisBezier(path, x, y) { + path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); + } + function d3_svg_lineSlope(p0, p1) { + return (p1[1] - p0[1]) / (p1[0] - p0[0]); + } + function d3_svg_lineFiniteDifferences(points) { + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); + while (++i < j) { + m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; + } + m[i] = d; + return m; + } + function d3_svg_lineMonotoneTangents(points) { + var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; + while (++i < j) { + d = d3_svg_lineSlope(points[i], points[i + 1]); + if (Math.abs(d) < ε) { + m[i] = m[i + 1] = 0; + } else { + a = m[i] / d; + b = m[i + 1] / d; + s = a * a + b * b; + if (s > 9) { + s = d * 3 / Math.sqrt(s); + m[i] = s * a; + m[i + 1] = s * b; + } + } + } + i = -1; + while (++i <= j) { + s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); + tangents.push([ s || 0, m[i] * s || 0 ]); + } + return tangents; + } + function d3_svg_lineMonotone(points) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); + } + d3.geom.hull = function(vertices) { + var x = d3_svg_lineX, y = d3_svg_lineY; + if (arguments.length) return hull(vertices); + function hull(data) { + if (data.length < 3) return []; + var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; + if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, + vertices = []; i < n; ++i) { + vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); + } + for (i = 1; i < n; ++i) { + if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1] && vertices[i][0] < vertices[h][0]) h = i; + } + for (i = 0; i < n; ++i) { + if (i === h) continue; + y1 = vertices[i][1] - vertices[h][1]; + x1 = vertices[i][0] - vertices[h][0]; + points.push({ + angle: Math.atan2(y1, x1), + index: i + }); + } + points.sort(function(a, b) { + return a.angle - b.angle; + }); + a = points[0].angle; + v = points[0].index; + u = 0; + for (i = 1; i < plen; ++i) { + j = points[i].index; + if (a == points[i].angle) { + x1 = vertices[v][0] - vertices[h][0]; + y1 = vertices[v][1] - vertices[h][1]; + x2 = vertices[j][0] - vertices[h][0]; + y2 = vertices[j][1] - vertices[h][1]; + if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { + points[i].index = -1; + continue; + } else { + points[u].index = -1; + } + } + a = points[i].angle; + u = i; + v = j; + } + stack.push(h); + for (i = 0, j = 0; i < 2; ++j) { + if (points[j].index > -1) { + stack.push(points[j].index); + i++; + } + } + sp = stack.length; + for (;j < plen; ++j) { + if (points[j].index < 0) continue; + while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { + --sp; + } + stack[sp++] = points[j].index; + } + var poly = []; + for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]); + return poly; + } + hull.x = function(_) { + return arguments.length ? (x = _, hull) : x; + }; + hull.y = function(_) { + return arguments.length ? (y = _, hull) : y; + }; + return hull; + }; + function d3_geom_hullCCW(i1, i2, i3, v) { + var t, a, b, c, d, e, f; + t = v[i1]; + a = t[0]; + b = t[1]; + t = v[i2]; + c = t[0]; + d = t[1]; + t = v[i3]; + e = t[0]; + f = t[1]; + return (f - b) * (c - a) - (d - b) * (e - a) > 0; + } + d3.geom.polygon = function(coordinates) { + d3_subclass(coordinates, d3_geom_polygonPrototype); + return coordinates; + }; + var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; + d3_geom_polygonPrototype.area = function() { + var i = -1, n = this.length, a, b = this[n - 1], area = 0; + while (++i < n) { + a = b; + b = this[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + return area * .5; + }; + d3_geom_polygonPrototype.centroid = function(k) { + var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; + if (!arguments.length) k = -1 / (6 * this.area()); + while (++i < n) { + a = b; + b = this[i]; + c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + return [ x * k, y * k ]; + }; + d3_geom_polygonPrototype.clip = function(subject) { + var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; + while (++i < n) { + input = subject.slice(); + subject.length = 0; + b = this[i]; + c = input[(m = input.length - closed) - 1]; + j = -1; + while (++j < m) { + d = input[j]; + if (d3_geom_polygonInside(d, a, b)) { + if (!d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + subject.push(d); + } else if (d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + c = d; + } + if (closed) subject.push(subject[0]); + a = b; + } + return subject; + }; + function d3_geom_polygonInside(p, a, b) { + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); + } + function d3_geom_polygonIntersect(c, d, a, b) { + var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); + return [ x1 + ua * x21, y1 + ua * y21 ]; + } + function d3_geom_polygonClosed(coordinates) { + var a = coordinates[0], b = coordinates[coordinates.length - 1]; + return !(a[0] - b[0] || a[1] - b[1]); + } + d3.geom.delaunay = function(vertices) { + var edges = vertices.map(function() { + return []; + }), triangles = []; + d3_geom_voronoiTessellate(vertices, function(e) { + edges[e.region.l.index].push(vertices[e.region.r.index]); + }); + edges.forEach(function(edge, i) { + var v = vertices[i], cx = v[0], cy = v[1]; + edge.forEach(function(v) { + v.angle = Math.atan2(v[0] - cx, v[1] - cy); + }); + edge.sort(function(a, b) { + return a.angle - b.angle; + }); + for (var j = 0, m = edge.length - 1; j < m; j++) { + triangles.push([ v, edge[j], edge[j + 1] ]); + } + }); + return triangles; + }; + d3.geom.voronoi = function(points) { + var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null; + if (arguments.length) return voronoi(points); + function voronoi(data) { + var points, polygons = data.map(function() { + return []; + }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var s1, s2, x1, x2, y1, y2; + if (e.a === 1 && e.b >= 0) { + s1 = e.ep.r; + s2 = e.ep.l; + } else { + s1 = e.ep.l; + s2 = e.ep.r; + } + if (e.a === 1) { + y1 = s1 ? s1.y : -Z; + x1 = e.c - e.b * y1; + y2 = s2 ? s2.y : Z; + x2 = e.c - e.b * y2; + } else { + x1 = s1 ? s1.x : -Z; + y1 = e.c - e.a * x1; + x2 = s2 ? s2.x : Z; + y2 = e.c - e.a * x2; + } + var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; + polygons[e.region.l.index].push(v1, v2); + polygons[e.region.r.index].push(v1, v2); + }); + polygons = polygons.map(function(polygon, i) { + var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) { + return Math.atan2(v[0] - cx, v[1] - cy); + }), order = d3.range(polygon.length).sort(function(a, b) { + return angle[a] - angle[b]; + }); + return order.filter(function(d, i) { + return !i || angle[d] - angle[order[i - 1]] > ε; + }).map(function(d) { + return polygon[d]; + }); + }); + polygons.forEach(function(polygon, i) { + var n = polygon.length; + if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); + if (n > 2) return; + var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; + if (Math.abs(dy) < ε) { + var y = y0 < y1 ? -Z : Z; + polygon.push([ -Z, y ], [ Z, y ]); + } else if (dx < ε) { + var x = x0 < x1 ? -Z : Z; + polygon.push([ x, -Z ], [ x, Z ]); + } else { + var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; + if (Math.abs(z) < ε) { + polygon.push([ dy < 0 ? y : -y, y ]); + } else { + if (z > 0) y *= -1; + polygon.push([ -Z, y ], [ Z, y ]); + } + } + }); + if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]); + for (i = 0; i < n; ++i) polygons[i].point = data[i]; + return polygons; + } + voronoi.x = function(_) { + return arguments.length ? (x = _, voronoi) : x; + }; + voronoi.y = function(_) { + return arguments.length ? (y = _, voronoi) : y; + }; + voronoi.clipExtent = function(_) { + if (!arguments.length) return clipPolygon && [ clipPolygon[0], clipPolygon[2] ]; + if (_ == null) clipPolygon = null; else { + var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; + clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ] ]); + } + return voronoi; + }; + voronoi.size = function(_) { + if (!arguments.length) return clipPolygon && clipPolygon[2]; + return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); + }; + voronoi.links = function(data) { + var points, graph = data.map(function() { + return []; + }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var l = e.region.l.index, r = e.region.r.index; + if (graph[l][r]) return; + graph[l][r] = graph[r][l] = true; + links.push({ + source: data[l], + target: data[r] + }); + }); + return links; + }; + voronoi.triangles = function(data) { + if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data); + var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n = data.length; + while (++i < n) { + (points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d; + } + return d3.geom.delaunay(points).map(function(triangle) { + return triangle.map(function(point) { + return point.data; + }); + }); + }; + return voronoi; + }; + var d3_geom_voronoiOpposite = { + l: "r", + r: "l" + }; + function d3_geom_voronoiTessellate(points, callback) { + var Sites = { + list: points.map(function(v, i) { + return { + index: i, + x: v[0], + y: v[1] + }; + }).sort(function(a, b) { + return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; + }), + bottomSite: null + }; + var EdgeList = { + list: [], + leftEnd: null, + rightEnd: null, + init: function() { + EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.leftEnd.r = EdgeList.rightEnd; + EdgeList.rightEnd.l = EdgeList.leftEnd; + EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); + }, + createHalfEdge: function(edge, side) { + return { + edge: edge, + side: side, + vertex: null, + l: null, + r: null + }; + }, + insert: function(lb, he) { + he.l = lb; + he.r = lb.r; + lb.r.l = he; + lb.r = he; + }, + leftBound: function(p) { + var he = EdgeList.leftEnd; + do { + he = he.r; + } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); + he = he.l; + return he; + }, + del: function(he) { + he.l.r = he.r; + he.r.l = he.l; + he.edge = null; + }, + right: function(he) { + return he.r; + }, + left: function(he) { + return he.l; + }, + leftRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; + }, + rightRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]]; + } + }; + var Geom = { + bisect: function(s1, s2) { + var newEdge = { + region: { + l: s1, + r: s2 + }, + ep: { + l: null, + r: null + } + }; + var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; + newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; + if (adx > ady) { + newEdge.a = 1; + newEdge.b = dy / dx; + newEdge.c /= dx; + } else { + newEdge.b = 1; + newEdge.a = dx / dy; + newEdge.c /= dy; + } + return newEdge; + }, + intersect: function(el1, el2) { + var e1 = el1.edge, e2 = el2.edge; + if (!e1 || !e2 || e1.region.r == e2.region.r) { + return null; + } + var d = e1.a * e2.b - e1.b * e2.a; + if (Math.abs(d) < 1e-10) { + return null; + } + var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; + if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { + el = el1; + e = e1; + } else { + el = el2; + e = e2; + } + var rightOfSite = xint >= e.region.r.x; + if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { + return null; + } + return { + x: xint, + y: yint + }; + }, + rightOf: function(he, p) { + var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; + if (rightOfSite && he.side === "l") { + return 1; + } + if (!rightOfSite && he.side === "r") { + return 0; + } + if (e.a === 1) { + var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; + if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { + above = fast = dyp >= e.b * dxp; + } else { + above = p.x + p.y * e.b > e.c; + if (e.b < 0) { + above = !above; + } + if (!above) { + fast = 1; + } + } + if (!fast) { + var dxs = topsite.x - e.region.l.x; + above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); + if (e.b < 0) { + above = !above; + } + } + } else { + var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; + above = t1 * t1 > t2 * t2 + t3 * t3; + } + return he.side === "l" ? above : !above; + }, + endPoint: function(edge, side, site) { + edge.ep[side] = site; + if (!edge.ep[d3_geom_voronoiOpposite[side]]) return; + callback(edge); + }, + distance: function(s, t) { + var dx = s.x - t.x, dy = s.y - t.y; + return Math.sqrt(dx * dx + dy * dy); + } + }; + var EventQueue = { + list: [], + insert: function(he, site, offset) { + he.vertex = site; + he.ystar = site.y + offset; + for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { + var next = list[i]; + if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { + continue; + } else { + break; + } + } + list.splice(i, 0, he); + }, + del: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} + ls.splice(i, 1); + }, + empty: function() { + return EventQueue.list.length === 0; + }, + nextEvent: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { + if (ls[i] == he) return ls[i + 1]; + } + return null; + }, + min: function() { + var elem = EventQueue.list[0]; + return { + x: elem.vertex.x, + y: elem.ystar + }; + }, + extractMin: function() { + return EventQueue.list.shift(); + } + }; + EdgeList.init(); + Sites.bottomSite = Sites.list.shift(); + var newSite = Sites.list.shift(), newIntStar; + var lbnd, rbnd, llbnd, rrbnd, bisector; + var bot, top, temp, p, v; + var e, pm; + while (true) { + if (!EventQueue.empty()) { + newIntStar = EventQueue.min(); + } + if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { + lbnd = EdgeList.leftBound(newSite); + rbnd = EdgeList.right(lbnd); + bot = EdgeList.rightRegion(lbnd); + e = Geom.bisect(bot, newSite); + bisector = EdgeList.createHalfEdge(e, "l"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(lbnd, bisector); + if (p) { + EventQueue.del(lbnd); + EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); + } + lbnd = bisector; + bisector = EdgeList.createHalfEdge(e, "r"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(bisector, rbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, newSite)); + } + newSite = Sites.list.shift(); + } else if (!EventQueue.empty()) { + lbnd = EventQueue.extractMin(); + llbnd = EdgeList.left(lbnd); + rbnd = EdgeList.right(lbnd); + rrbnd = EdgeList.right(rbnd); + bot = EdgeList.leftRegion(lbnd); + top = EdgeList.rightRegion(rbnd); + v = lbnd.vertex; + Geom.endPoint(lbnd.edge, lbnd.side, v); + Geom.endPoint(rbnd.edge, rbnd.side, v); + EdgeList.del(lbnd); + EventQueue.del(rbnd); + EdgeList.del(rbnd); + pm = "l"; + if (bot.y > top.y) { + temp = bot; + bot = top; + top = temp; + pm = "r"; + } + e = Geom.bisect(bot, top); + bisector = EdgeList.createHalfEdge(e, pm); + EdgeList.insert(llbnd, bisector); + Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v); + p = Geom.intersect(llbnd, bisector); + if (p) { + EventQueue.del(llbnd); + EventQueue.insert(llbnd, p, Geom.distance(p, bot)); + } + p = Geom.intersect(bisector, rrbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, bot)); + } + } else { + break; + } + } + for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { + callback(lbnd.edge); + } + } + d3.geom.quadtree = function(points, x1, y1, x2, y2) { + var x = d3_svg_lineX, y = d3_svg_lineY, compat; + if (compat = arguments.length) { + x = d3_geom_quadtreeCompatX; + y = d3_geom_quadtreeCompatY; + if (compat === 3) { + y2 = y1; + x2 = x1; + y1 = x1 = 0; + } + return quadtree(points); + } + function quadtree(data) { + var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; + if (x1 != null) { + x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; + } else { + x2_ = y2_ = -(x1_ = y1_ = Infinity); + xs = [], ys = []; + n = data.length; + if (compat) for (i = 0; i < n; ++i) { + d = data[i]; + if (d.x < x1_) x1_ = d.x; + if (d.y < y1_) y1_ = d.y; + if (d.x > x2_) x2_ = d.x; + if (d.y > y2_) y2_ = d.y; + xs.push(d.x); + ys.push(d.y); + } else for (i = 0; i < n; ++i) { + var x_ = +fx(d = data[i], i), y_ = +fy(d, i); + if (x_ < x1_) x1_ = x_; + if (y_ < y1_) y1_ = y_; + if (x_ > x2_) x2_ = x_; + if (y_ > y2_) y2_ = y_; + xs.push(x_); + ys.push(y_); + } + } + var dx = x2_ - x1_, dy = y2_ - y1_; + if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; + function insert(n, d, x, y, x1, y1, x2, y2) { + if (isNaN(x) || isNaN(y)) return; + if (n.leaf) { + var nx = n.x, ny = n.y; + if (nx != null) { + if (Math.abs(nx - x) + Math.abs(ny - y) < .01) { + insertChild(n, d, x, y, x1, y1, x2, y2); + } else { + var nPoint = n.point; + n.x = n.y = n.point = null; + insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } else { + n.x = x, n.y = y, n.point = d; + } + } else { + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } + function insertChild(n, d, x, y, x1, y1, x2, y2) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right; + n.leaf = false; + n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); + if (right) x1 = sx; else x2 = sx; + if (bottom) y1 = sy; else y2 = sy; + insert(n, d, x, y, x1, y1, x2, y2); + } + var root = d3_geom_quadtreeNode(); + root.add = function(d) { + insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); + }; + root.visit = function(f) { + d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); + }; + i = -1; + if (x1 == null) { + while (++i < n) { + insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); + } + --i; + } else data.forEach(root.add); + xs = ys = data = d = null; + return root; + } + quadtree.x = function(_) { + return arguments.length ? (x = _, quadtree) : x; + }; + quadtree.y = function(_) { + return arguments.length ? (y = _, quadtree) : y; + }; + quadtree.extent = function(_) { + if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], + y2 = +_[1][1]; + return quadtree; + }; + quadtree.size = function(_) { + if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; + return quadtree; + }; + return quadtree; + }; + function d3_geom_quadtreeCompatX(d) { + return d.x; + } + function d3_geom_quadtreeCompatY(d) { + return d.y; + } + function d3_geom_quadtreeNode() { + return { + leaf: true, + nodes: [], + point: null, + x: null, + y: null + }; + } + function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { + if (!f(node, x1, y1, x2, y2)) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; + if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); + if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); + if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); + if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); + } + } + d3.interpolateRgb = d3_interpolateRgb; + function d3_interpolateRgb(a, b) { + a = d3.rgb(a); + b = d3.rgb(b); + var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; + return function(t) { + return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); + }; + } + d3.interpolateObject = d3_interpolateObject; + function d3_interpolateObject(a, b) { + var i = {}, c = {}, k; + for (k in a) { + if (k in b) { + i[k] = d3_interpolate(a[k], b[k]); + } else { + c[k] = a[k]; + } + } + for (k in b) { + if (!(k in a)) { + c[k] = b[k]; + } + } + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; + } + d3.interpolateNumber = d3_interpolateNumber; + function d3_interpolateNumber(a, b) { + b -= a = +a; + return function(t) { + return a + b * t; + }; + } + d3.interpolateString = d3_interpolateString; + function d3_interpolateString(a, b) { + var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; + a = a + "", b = b + ""; + d3_interpolate_number.lastIndex = 0; + for (i = 0; m = d3_interpolate_number.exec(b); ++i) { + if (m.index) s.push(b.substring(s0, s1 = m.index)); + q.push({ + i: s.length, + x: m[0] + }); + s.push(null); + s0 = d3_interpolate_number.lastIndex; + } + if (s0 < b.length) s.push(b.substring(s0)); + for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { + o = q[i]; + if (o.x == m[0]) { + if (o.i) { + if (s[o.i + 1] == null) { + s[o.i - 1] += o.x; + s.splice(o.i, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } else { + s[o.i - 1] += o.x + s[o.i + 1]; + s.splice(o.i, 2); + for (j = i + 1; j < n; ++j) q[j].i -= 2; + } + } else { + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } + } + q.splice(i, 1); + n--; + i--; + } else { + o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); + } + } + while (i < n) { + o = q.pop(); + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + } + n--; + } + if (s.length === 1) { + return s[0] == null ? (o = q[0].x, function(t) { + return o(t) + ""; + }) : function() { + return b; + }; + } + return function(t) { + for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; + d3.interpolate = d3_interpolate; + function d3_interpolate(a, b) { + var i = d3.interpolators.length, f; + while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; + return f; + } + d3.interpolators = [ function(a, b) { + var t = typeof b; + return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t === "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject : d3_interpolateNumber)(a, b); + } ]; + d3.interpolateArray = d3_interpolateArray; + function d3_interpolateArray(a, b) { + var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; + for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); + for (;i < na; ++i) c[i] = a[i]; + for (;i < nb; ++i) c[i] = b[i]; + return function(t) { + for (i = 0; i < n0; ++i) c[i] = x[i](t); + return c; + }; + } + var d3_ease_default = function() { + return d3_identity; + }; + var d3_ease = d3.map({ + linear: d3_ease_default, + poly: d3_ease_poly, + quad: function() { + return d3_ease_quad; + }, + cubic: function() { + return d3_ease_cubic; + }, + sin: function() { + return d3_ease_sin; + }, + exp: function() { + return d3_ease_exp; + }, + circle: function() { + return d3_ease_circle; + }, + elastic: d3_ease_elastic, + back: d3_ease_back, + bounce: function() { + return d3_ease_bounce; + } + }); + var d3_ease_mode = d3.map({ + "in": d3_identity, + out: d3_ease_reverse, + "in-out": d3_ease_reflect, + "out-in": function(f) { + return d3_ease_reflect(d3_ease_reverse(f)); + } + }); + d3.ease = function(name) { + var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; + t = d3_ease.get(t) || d3_ease_default; + m = d3_ease_mode.get(m) || d3_identity; + return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); + }; + function d3_ease_clamp(f) { + return function(t) { + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); + }; + } + function d3_ease_reverse(f) { + return function(t) { + return 1 - f(1 - t); + }; + } + function d3_ease_reflect(f) { + return function(t) { + return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); + }; + } + function d3_ease_quad(t) { + return t * t; + } + function d3_ease_cubic(t) { + return t * t * t; + } + function d3_ease_cubicInOut(t) { + if (t <= 0) return 0; + if (t >= 1) return 1; + var t2 = t * t, t3 = t2 * t; + return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); + } + function d3_ease_poly(e) { + return function(t) { + return Math.pow(t, e); + }; + } + function d3_ease_sin(t) { + return 1 - Math.cos(t * halfπ); + } + function d3_ease_exp(t) { + return Math.pow(2, 10 * (t - 1)); + } + function d3_ease_circle(t) { + return 1 - Math.sqrt(1 - t * t); + } + function d3_ease_elastic(a, p) { + var s; + if (arguments.length < 2) p = .45; + if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4; + return function(t) { + return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p); + }; + } + function d3_ease_back(s) { + if (!s) s = 1.70158; + return function(t) { + return t * t * ((s + 1) * t - s); + }; + } + function d3_ease_bounce(t) { + return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; + } + d3.interpolateHcl = d3_interpolateHcl; + function d3_interpolateHcl(a, b) { + a = d3.hcl(a); + b = d3.hcl(b); + var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; + if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; + }; + } + d3.interpolateHsl = d3_interpolateHsl; + function d3_interpolateHsl(a, b) { + a = d3.hsl(a); + b = d3.hsl(b); + var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; + if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; + }; + } + d3.interpolateLab = d3_interpolateLab; + function d3_interpolateLab(a, b) { + a = d3.lab(a); + b = d3.lab(b); + var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; + return function(t) { + return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; + }; + } + d3.interpolateRound = d3_interpolateRound; + function d3_interpolateRound(a, b) { + b -= a; + return function(t) { + return Math.round(a + b * t); + }; + } + d3.transform = function(string) { + var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); + return (d3.transform = function(string) { + if (string != null) { + g.setAttribute("transform", string); + var t = g.transform.baseVal.consolidate(); + } + return new d3_transform(t ? t.matrix : d3_transformIdentity); + })(string); + }; + function d3_transform(m) { + var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; + if (r0[0] * r1[1] < r1[0] * r0[1]) { + r0[0] *= -1; + r0[1] *= -1; + kx *= -1; + kz *= -1; + } + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; + this.translate = [ m.e, m.f ]; + this.scale = [ kx, ky ]; + this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; + } + d3_transform.prototype.toString = function() { + return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; + }; + function d3_transformDot(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + function d3_transformNormalize(a) { + var k = Math.sqrt(d3_transformDot(a, a)); + if (k) { + a[0] /= k; + a[1] /= k; + } + return k; + } + function d3_transformCombine(a, b, k) { + a[0] += k * b[0]; + a[1] += k * b[1]; + return a; + } + var d3_transformIdentity = { + a: 1, + b: 0, + c: 0, + d: 1, + e: 0, + f: 0 + }; + d3.interpolateTransform = d3_interpolateTransform; + function d3_interpolateTransform(a, b) { + var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; + if (ta[0] != tb[0] || ta[1] != tb[1]) { + s.push("translate(", null, ",", null, ")"); + q.push({ + i: 1, + x: d3_interpolateNumber(ta[0], tb[0]) + }, { + i: 3, + x: d3_interpolateNumber(ta[1], tb[1]) + }); + } else if (tb[0] || tb[1]) { + s.push("translate(" + tb + ")"); + } else { + s.push(""); + } + if (ra != rb) { + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; + q.push({ + i: s.push(s.pop() + "rotate(", null, ")") - 2, + x: d3_interpolateNumber(ra, rb) + }); + } else if (rb) { + s.push(s.pop() + "rotate(" + rb + ")"); + } + if (wa != wb) { + q.push({ + i: s.push(s.pop() + "skewX(", null, ")") - 2, + x: d3_interpolateNumber(wa, wb) + }); + } else if (wb) { + s.push(s.pop() + "skewX(" + wb + ")"); + } + if (ka[0] != kb[0] || ka[1] != kb[1]) { + n = s.push(s.pop() + "scale(", null, ",", null, ")"); + q.push({ + i: n - 4, + x: d3_interpolateNumber(ka[0], kb[0]) + }, { + i: n - 2, + x: d3_interpolateNumber(ka[1], kb[1]) + }); + } else if (kb[0] != 1 || kb[1] != 1) { + s.push(s.pop() + "scale(" + kb + ")"); + } + n = q.length; + return function(t) { + var i = -1, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + function d3_uninterpolateNumber(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return (x - a) * b; + }; + } + function d3_uninterpolateClamp(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return Math.max(0, Math.min(1, (x - a) * b)); + }; + } + d3.layout = {}; + d3.layout.bundle = function() { + return function(links) { + var paths = [], i = -1, n = links.length; + while (++i < n) paths.push(d3_layout_bundlePath(links[i])); + return paths; + }; + }; + function d3_layout_bundlePath(link) { + var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; + while (start !== lca) { + start = start.parent; + points.push(start); + } + var k = points.length; + while (end !== lca) { + points.splice(k, 0, end); + end = end.parent; + } + return points; + } + function d3_layout_bundleAncestors(node) { + var ancestors = [], parent = node.parent; + while (parent != null) { + ancestors.push(node); + node = parent; + parent = parent.parent; + } + ancestors.push(node); + return ancestors; + } + function d3_layout_bundleLeastCommonAncestor(a, b) { + if (a === b) return a; + var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; + while (aNode === bNode) { + sharedNode = aNode; + aNode = aNodes.pop(); + bNode = bNodes.pop(); + } + return sharedNode; + } + d3.layout.chord = function() { + var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; + function relayout() { + var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; + chords = []; + groups = []; + k = 0, i = -1; + while (++i < n) { + x = 0, j = -1; + while (++j < n) { + x += matrix[i][j]; + } + groupSums.push(x); + subgroupIndex.push(d3.range(n)); + k += x; + } + if (sortGroups) { + groupIndex.sort(function(a, b) { + return sortGroups(groupSums[a], groupSums[b]); + }); + } + if (sortSubgroups) { + subgroupIndex.forEach(function(d, i) { + d.sort(function(a, b) { + return sortSubgroups(matrix[i][a], matrix[i][b]); + }); + }); + } + k = (τ - padding * n) / k; + x = 0, i = -1; + while (++i < n) { + x0 = x, j = -1; + while (++j < n) { + var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; + subgroups[di + "-" + dj] = { + index: di, + subindex: dj, + startAngle: a0, + endAngle: a1, + value: v + }; + } + groups[di] = { + index: di, + startAngle: x0, + endAngle: x, + value: (x - x0) / k + }; + x += padding; + } + i = -1; + while (++i < n) { + j = i - 1; + while (++j < n) { + var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; + if (source.value || target.value) { + chords.push(source.value < target.value ? { + source: target, + target: source + } : { + source: source, + target: target + }); + } + } + } + if (sortChords) resort(); + } + function resort() { + chords.sort(function(a, b) { + return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); + }); + } + chord.matrix = function(x) { + if (!arguments.length) return matrix; + n = (matrix = x) && matrix.length; + chords = groups = null; + return chord; + }; + chord.padding = function(x) { + if (!arguments.length) return padding; + padding = x; + chords = groups = null; + return chord; + }; + chord.sortGroups = function(x) { + if (!arguments.length) return sortGroups; + sortGroups = x; + chords = groups = null; + return chord; + }; + chord.sortSubgroups = function(x) { + if (!arguments.length) return sortSubgroups; + sortSubgroups = x; + chords = null; + return chord; + }; + chord.sortChords = function(x) { + if (!arguments.length) return sortChords; + sortChords = x; + if (chords) resort(); + return chord; + }; + chord.chords = function() { + if (!chords) relayout(); + return chords; + }; + chord.groups = function() { + if (!groups) relayout(); + return groups; + }; + return chord; + }; + d3.layout.force = function() { + var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; + function repulse(node) { + return function(quad, x1, _, x2) { + if (quad.point !== node) { + var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); + if ((x2 - x1) * dn < theta) { + var k = quad.charge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + return true; + } + if (quad.point && isFinite(dn)) { + var k = quad.pointCharge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + } + } + return !quad.charge; + }; + } + force.tick = function() { + if ((alpha *= .99) < .005) { + event.end({ + type: "end", + alpha: alpha = 0 + }); + return true; + } + var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; + for (i = 0; i < m; ++i) { + o = links[i]; + s = o.source; + t = o.target; + x = t.x - s.x; + y = t.y - s.y; + if (l = x * x + y * y) { + l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; + x *= l; + y *= l; + t.x -= x * (k = s.weight / (t.weight + s.weight)); + t.y -= y * k; + s.x += x * (k = 1 - k); + s.y += y * k; + } + } + if (k = alpha * gravity) { + x = size[0] / 2; + y = size[1] / 2; + i = -1; + if (k) while (++i < n) { + o = nodes[i]; + o.x += (x - o.x) * k; + o.y += (y - o.y) * k; + } + } + if (charge) { + d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); + i = -1; + while (++i < n) { + if (!(o = nodes[i]).fixed) { + q.visit(repulse(o)); + } + } + } + i = -1; + while (++i < n) { + o = nodes[i]; + if (o.fixed) { + o.x = o.px; + o.y = o.py; + } else { + o.x -= (o.px - (o.px = o.x)) * friction; + o.y -= (o.py - (o.py = o.y)) * friction; + } + } + event.tick({ + type: "tick", + alpha: alpha + }); + }; + force.nodes = function(x) { + if (!arguments.length) return nodes; + nodes = x; + return force; + }; + force.links = function(x) { + if (!arguments.length) return links; + links = x; + return force; + }; + force.size = function(x) { + if (!arguments.length) return size; + size = x; + return force; + }; + force.linkDistance = function(x) { + if (!arguments.length) return linkDistance; + linkDistance = typeof x === "function" ? x : +x; + return force; + }; + force.distance = force.linkDistance; + force.linkStrength = function(x) { + if (!arguments.length) return linkStrength; + linkStrength = typeof x === "function" ? x : +x; + return force; + }; + force.friction = function(x) { + if (!arguments.length) return friction; + friction = +x; + return force; + }; + force.charge = function(x) { + if (!arguments.length) return charge; + charge = typeof x === "function" ? x : +x; + return force; + }; + force.gravity = function(x) { + if (!arguments.length) return gravity; + gravity = +x; + return force; + }; + force.theta = function(x) { + if (!arguments.length) return theta; + theta = +x; + return force; + }; + force.alpha = function(x) { + if (!arguments.length) return alpha; + x = +x; + if (alpha) { + if (x > 0) alpha = x; else alpha = 0; + } else if (x > 0) { + event.start({ + type: "start", + alpha: alpha = x + }); + d3.timer(force.tick); + } + return force; + }; + force.start = function() { + var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; + for (i = 0; i < n; ++i) { + (o = nodes[i]).index = i; + o.weight = 0; + } + for (i = 0; i < m; ++i) { + o = links[i]; + if (typeof o.source == "number") o.source = nodes[o.source]; + if (typeof o.target == "number") o.target = nodes[o.target]; + ++o.source.weight; + ++o.target.weight; + } + for (i = 0; i < n; ++i) { + o = nodes[i]; + if (isNaN(o.x)) o.x = position("x", w); + if (isNaN(o.y)) o.y = position("y", h); + if (isNaN(o.px)) o.px = o.x; + if (isNaN(o.py)) o.py = o.y; + } + distances = []; + if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; + strengths = []; + if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; + charges = []; + if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; + function position(dimension, size) { + var neighbors = neighbor(i), j = -1, m = neighbors.length, x; + while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; + return Math.random() * size; + } + function neighbor() { + if (!neighbors) { + neighbors = []; + for (j = 0; j < n; ++j) { + neighbors[j] = []; + } + for (j = 0; j < m; ++j) { + var o = links[j]; + neighbors[o.source.index].push(o.target); + neighbors[o.target.index].push(o.source); + } + } + return neighbors[i]; + } + return force.resume(); + }; + force.resume = function() { + return force.alpha(.1); + }; + force.stop = function() { + return force.alpha(0); + }; + force.drag = function() { + if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); + if (!arguments.length) return drag; + this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); + }; + function dragmove(d) { + d.px = d3.event.x, d.py = d3.event.y; + force.resume(); + } + return d3.rebind(force, event, "on"); + }; + function d3_layout_forceDragstart(d) { + d.fixed |= 2; + } + function d3_layout_forceDragend(d) { + d.fixed &= ~6; + } + function d3_layout_forceMouseover(d) { + d.fixed |= 4; + d.px = d.x, d.py = d.y; + } + function d3_layout_forceMouseout(d) { + d.fixed &= ~4; + } + function d3_layout_forceAccumulate(quad, alpha, charges) { + var cx = 0, cy = 0; + quad.charge = 0; + if (!quad.leaf) { + var nodes = quad.nodes, n = nodes.length, i = -1, c; + while (++i < n) { + c = nodes[i]; + if (c == null) continue; + d3_layout_forceAccumulate(c, alpha, charges); + quad.charge += c.charge; + cx += c.charge * c.cx; + cy += c.charge * c.cy; + } + } + if (quad.point) { + if (!quad.leaf) { + quad.point.x += Math.random() - .5; + quad.point.y += Math.random() - .5; + } + var k = alpha * charges[quad.point.index]; + quad.charge += quad.pointCharge = k; + cx += k * quad.point.x; + cy += k * quad.point.y; + } + quad.cx = cx / quad.charge; + quad.cy = cy / quad.charge; + } + var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; + d3.layout.hierarchy = function() { + var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; + function recurse(node, depth, nodes) { + var childs = children.call(hierarchy, node, depth); + node.depth = depth; + nodes.push(node); + if (childs && (n = childs.length)) { + var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; + while (++i < n) { + d = recurse(childs[i], j, nodes); + d.parent = node; + c.push(d); + v += d.value; + } + if (sort) c.sort(sort); + if (value) node.value = v; + } else if (value) { + node.value = +value.call(hierarchy, node, depth) || 0; + } + return node; + } + function revalue(node, depth) { + var children = node.children, v = 0; + if (children && (n = children.length)) { + var i = -1, n, j = depth + 1; + while (++i < n) v += revalue(children[i], j); + } else if (value) { + v = +value.call(hierarchy, node, depth) || 0; + } + if (value) node.value = v; + return v; + } + function hierarchy(d) { + var nodes = []; + recurse(d, 0, nodes); + return nodes; + } + hierarchy.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return hierarchy; + }; + hierarchy.children = function(x) { + if (!arguments.length) return children; + children = x; + return hierarchy; + }; + hierarchy.value = function(x) { + if (!arguments.length) return value; + value = x; + return hierarchy; + }; + hierarchy.revalue = function(root) { + revalue(root, 0); + return root; + }; + return hierarchy; + }; + function d3_layout_hierarchyRebind(object, hierarchy) { + d3.rebind(object, hierarchy, "sort", "children", "value"); + object.nodes = object; + object.links = d3_layout_hierarchyLinks; + return object; + } + function d3_layout_hierarchyChildren(d) { + return d.children; + } + function d3_layout_hierarchyValue(d) { + return d.value; + } + function d3_layout_hierarchySort(a, b) { + return b.value - a.value; + } + function d3_layout_hierarchyLinks(nodes) { + return d3.merge(nodes.map(function(parent) { + return (parent.children || []).map(function(child) { + return { + source: parent, + target: child + }; + }); + })); + } + d3.layout.partition = function() { + var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; + function position(node, x, dx, dy) { + var children = node.children; + node.x = x; + node.y = node.depth * dy; + node.dx = dx; + node.dy = dy; + if (children && (n = children.length)) { + var i = -1, n, c, d; + dx = node.value ? dx / node.value : 0; + while (++i < n) { + position(c = children[i], x, d = c.value * dx, dy); + x += d; + } + } + } + function depth(node) { + var children = node.children, d = 0; + if (children && (n = children.length)) { + var i = -1, n; + while (++i < n) d = Math.max(d, depth(children[i])); + } + return 1 + d; + } + function partition(d, i) { + var nodes = hierarchy.call(this, d, i); + position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); + return nodes; + } + partition.size = function(x) { + if (!arguments.length) return size; + size = x; + return partition; + }; + return d3_layout_hierarchyRebind(partition, hierarchy); + }; + d3.layout.pie = function() { + var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ; + function pie(data) { + var values = data.map(function(d, i) { + return +value.call(pie, d, i); + }); + var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); + var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values); + var index = d3.range(data.length); + if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { + return values[j] - values[i]; + } : function(i, j) { + return sort(data[i], data[j]); + }); + var arcs = []; + index.forEach(function(i) { + var d; + arcs[i] = { + data: data[i], + value: d = values[i], + startAngle: a, + endAngle: a += d * k + }; + }); + return arcs; + } + pie.value = function(x) { + if (!arguments.length) return value; + value = x; + return pie; + }; + pie.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return pie; + }; + pie.startAngle = function(x) { + if (!arguments.length) return startAngle; + startAngle = x; + return pie; + }; + pie.endAngle = function(x) { + if (!arguments.length) return endAngle; + endAngle = x; + return pie; + }; + return pie; + }; + var d3_layout_pieSortByValue = {}; + d3.layout.stack = function() { + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; + function stack(data, index) { + var series = data.map(function(d, i) { + return values.call(stack, d, i); + }); + var points = series.map(function(d) { + return d.map(function(v, i) { + return [ x.call(stack, v, i), y.call(stack, v, i) ]; + }); + }); + var orders = order.call(stack, points, index); + series = d3.permute(series, orders); + points = d3.permute(points, orders); + var offsets = offset.call(stack, points, index); + var n = series.length, m = series[0].length, i, j, o; + for (j = 0; j < m; ++j) { + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); + for (i = 1; i < n; ++i) { + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); + } + } + return data; + } + stack.values = function(x) { + if (!arguments.length) return values; + values = x; + return stack; + }; + stack.order = function(x) { + if (!arguments.length) return order; + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; + return stack; + }; + stack.offset = function(x) { + if (!arguments.length) return offset; + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; + return stack; + }; + stack.x = function(z) { + if (!arguments.length) return x; + x = z; + return stack; + }; + stack.y = function(z) { + if (!arguments.length) return y; + y = z; + return stack; + }; + stack.out = function(z) { + if (!arguments.length) return out; + out = z; + return stack; + }; + return stack; + }; + function d3_layout_stackX(d) { + return d.x; + } + function d3_layout_stackY(d) { + return d.y; + } + function d3_layout_stackOut(d, y0, y) { + d.y0 = y0; + d.y = y; + } + var d3_layout_stackOrders = d3.map({ + "inside-out": function(data) { + var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { + return max[a] - max[b]; + }), top = 0, bottom = 0, tops = [], bottoms = []; + for (i = 0; i < n; ++i) { + j = index[i]; + if (top < bottom) { + top += sums[j]; + tops.push(j); + } else { + bottom += sums[j]; + bottoms.push(j); + } + } + return bottoms.reverse().concat(tops); + }, + reverse: function(data) { + return d3.range(data.length).reverse(); + }, + "default": d3_layout_stackOrderDefault + }); + var d3_layout_stackOffsets = d3.map({ + silhouette: function(data) { + var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o > max) max = o; + sums.push(o); + } + for (j = 0; j < m; ++j) { + y0[j] = (max - sums[j]) / 2; + } + return y0; + }, + wiggle: function(data) { + var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; + y0[0] = o = o0 = 0; + for (j = 1; j < m; ++j) { + for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; + for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { + for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { + s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; + } + s2 += s3 * data[i][j][1]; + } + y0[j] = o -= s1 ? s2 / s1 * dx : 0; + if (o < o0) o0 = o; + } + for (j = 0; j < m; ++j) y0[j] -= o0; + return y0; + }, + expand: function(data) { + var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; + } + for (j = 0; j < m; ++j) y0[j] = 0; + return y0; + }, + zero: d3_layout_stackOffsetZero + }); + function d3_layout_stackOrderDefault(data) { + return d3.range(data.length); + } + function d3_layout_stackOffsetZero(data) { + var j = -1, m = data[0].length, y0 = []; + while (++j < m) y0[j] = 0; + return y0; + } + function d3_layout_stackMaxIndex(array) { + var i = 1, j = 0, v = array[0][1], k, n = array.length; + for (;i < n; ++i) { + if ((k = array[i][1]) > v) { + j = i; + v = k; + } + } + return j; + } + function d3_layout_stackReduceSum(d) { + return d.reduce(d3_layout_stackSum, 0); + } + function d3_layout_stackSum(p, d) { + return p + d[1]; + } + d3.layout.histogram = function() { + var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; + function histogram(data, i) { + var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; + while (++i < m) { + bin = bins[i] = []; + bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); + bin.y = 0; + } + if (m > 0) { + i = -1; + while (++i < n) { + x = values[i]; + if (x >= range[0] && x <= range[1]) { + bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; + bin.y += k; + bin.push(data[i]); + } + } + } + return bins; + } + histogram.value = function(x) { + if (!arguments.length) return valuer; + valuer = x; + return histogram; + }; + histogram.range = function(x) { + if (!arguments.length) return ranger; + ranger = d3_functor(x); + return histogram; + }; + histogram.bins = function(x) { + if (!arguments.length) return binner; + binner = typeof x === "number" ? function(range) { + return d3_layout_histogramBinFixed(range, x); + } : d3_functor(x); + return histogram; + }; + histogram.frequency = function(x) { + if (!arguments.length) return frequency; + frequency = !!x; + return histogram; + }; + return histogram; + }; + function d3_layout_histogramBinSturges(range, values) { + return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); + } + function d3_layout_histogramBinFixed(range, n) { + var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; + while (++x <= n) f[x] = m * x + b; + return f; + } + function d3_layout_histogramRange(values) { + return [ d3.min(values), d3.max(values) ]; + } + d3.layout.tree = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function tree(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0]; + function firstWalk(node, previousSibling) { + var children = node.children, layout = node._tree; + if (children && (n = children.length)) { + var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; + while (++i < n) { + child = children[i]; + firstWalk(child, previousChild); + ancestor = apportion(child, previousChild, ancestor); + previousChild = child; + } + d3_layout_treeShift(node); + var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + layout.mod = layout.prelim - midpoint; + } else { + layout.prelim = midpoint; + } + } else { + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + } + } + } + function secondWalk(node, x) { + node.x = node._tree.prelim + x; + var children = node.children; + if (children && (n = children.length)) { + var i = -1, n; + x += node._tree.mod; + while (++i < n) { + secondWalk(children[i], x); + } + } + } + function apportion(node, previousSibling, ancestor) { + if (previousSibling) { + var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; + while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { + vom = d3_layout_treeLeft(vom); + vop = d3_layout_treeRight(vop); + vop._tree.ancestor = node; + shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); + if (shift > 0) { + d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); + sip += shift; + sop += shift; + } + sim += vim._tree.mod; + sip += vip._tree.mod; + som += vom._tree.mod; + sop += vop._tree.mod; + } + if (vim && !d3_layout_treeRight(vop)) { + vop._tree.thread = vim; + vop._tree.mod += sim - sop; + } + if (vip && !d3_layout_treeLeft(vom)) { + vom._tree.thread = vip; + vom._tree.mod += sip - som; + ancestor = node; + } + } + return ancestor; + } + d3_layout_treeVisitAfter(root, function(node, previousSibling) { + node._tree = { + ancestor: node, + prelim: 0, + mod: 0, + change: 0, + shift: 0, + number: previousSibling ? previousSibling._tree.number + 1 : 0 + }; + }); + firstWalk(root); + secondWalk(root, -root._tree.prelim); + var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x *= size[0]; + node.y = node.depth * size[1]; + delete node._tree; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = node.depth / y1 * size[1]; + delete node._tree; + }); + return nodes; + } + tree.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return tree; + }; + tree.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return tree; + }; + tree.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return tree; + }; + return d3_layout_hierarchyRebind(tree, hierarchy); + }; + function d3_layout_treeSeparation(a, b) { + return a.parent == b.parent ? 1 : 2; + } + function d3_layout_treeLeft(node) { + var children = node.children; + return children && children.length ? children[0] : node._tree.thread; + } + function d3_layout_treeRight(node) { + var children = node.children, n; + return children && (n = children.length) ? children[n - 1] : node._tree.thread; + } + function d3_layout_treeSearch(node, compare) { + var children = node.children; + if (children && (n = children.length)) { + var child, n, i = -1; + while (++i < n) { + if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { + node = child; + } + } + } + return node; + } + function d3_layout_treeRightmost(a, b) { + return a.x - b.x; + } + function d3_layout_treeLeftmost(a, b) { + return b.x - a.x; + } + function d3_layout_treeDeepest(a, b) { + return a.depth - b.depth; + } + function d3_layout_treeVisitAfter(node, callback) { + function visit(node, previousSibling) { + var children = node.children; + if (children && (n = children.length)) { + var child, previousChild = null, i = -1, n; + while (++i < n) { + child = children[i]; + visit(child, previousChild); + previousChild = child; + } + } + callback(node, previousSibling); + } + visit(node, null); + } + function d3_layout_treeShift(node) { + var shift = 0, change = 0, children = node.children, i = children.length, child; + while (--i >= 0) { + child = children[i]._tree; + child.prelim += shift; + child.mod += shift; + shift += child.shift + (change += child.change); + } + } + function d3_layout_treeMove(ancestor, node, shift) { + ancestor = ancestor._tree; + node = node._tree; + var change = shift / (node.number - ancestor.number); + ancestor.change += change; + node.change -= change; + node.shift += shift; + node.prelim += shift; + node.mod += shift; + } + function d3_layout_treeAncestor(vim, node, ancestor) { + return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; + } + d3.layout.pack = function() { + var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; + function pack(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { + return radius; + }; + root.x = root.y = 0; + d3_layout_treeVisitAfter(root, function(d) { + d.r = +r(d.value); + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + if (padding) { + var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; + d3_layout_treeVisitAfter(root, function(d) { + d.r += dr; + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + d3_layout_treeVisitAfter(root, function(d) { + d.r -= dr; + }); + } + d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); + return nodes; + } + pack.size = function(_) { + if (!arguments.length) return size; + size = _; + return pack; + }; + pack.radius = function(_) { + if (!arguments.length) return radius; + radius = _ == null || typeof _ === "function" ? _ : +_; + return pack; + }; + pack.padding = function(_) { + if (!arguments.length) return padding; + padding = +_; + return pack; + }; + return d3_layout_hierarchyRebind(pack, hierarchy); + }; + function d3_layout_packSort(a, b) { + return a.value - b.value; + } + function d3_layout_packInsert(a, b) { + var c = a._pack_next; + a._pack_next = b; + b._pack_prev = a; + b._pack_next = c; + c._pack_prev = b; + } + function d3_layout_packSplice(a, b) { + a._pack_next = b; + b._pack_prev = a; + } + function d3_layout_packIntersects(a, b) { + var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; + return .999 * dr * dr > dx * dx + dy * dy; + } + function d3_layout_packSiblings(node) { + if (!(nodes = node.children) || !(n = nodes.length)) return; + var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; + function bound(node) { + xMin = Math.min(node.x - node.r, xMin); + xMax = Math.max(node.x + node.r, xMax); + yMin = Math.min(node.y - node.r, yMin); + yMax = Math.max(node.y + node.r, yMax); + } + nodes.forEach(d3_layout_packLink); + a = nodes[0]; + a.x = -a.r; + a.y = 0; + bound(a); + if (n > 1) { + b = nodes[1]; + b.x = b.r; + b.y = 0; + bound(b); + if (n > 2) { + c = nodes[2]; + d3_layout_packPlace(a, b, c); + bound(c); + d3_layout_packInsert(a, c); + a._pack_prev = c; + d3_layout_packInsert(c, b); + b = a._pack_next; + for (i = 3; i < n; i++) { + d3_layout_packPlace(a, b, c = nodes[i]); + var isect = 0, s1 = 1, s2 = 1; + for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { + if (d3_layout_packIntersects(j, c)) { + isect = 1; + break; + } + } + if (isect == 1) { + for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { + if (d3_layout_packIntersects(k, c)) { + break; + } + } + } + if (isect) { + if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); + i--; + } else { + d3_layout_packInsert(a, c); + b = c; + bound(c); + } + } + } + } + var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; + for (i = 0; i < n; i++) { + c = nodes[i]; + c.x -= cx; + c.y -= cy; + cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); + } + node.r = cr; + nodes.forEach(d3_layout_packUnlink); + } + function d3_layout_packLink(node) { + node._pack_next = node._pack_prev = node; + } + function d3_layout_packUnlink(node) { + delete node._pack_next; + delete node._pack_prev; + } + function d3_layout_packTransform(node, x, y, k) { + var children = node.children; + node.x = x += k * node.x; + node.y = y += k * node.y; + node.r *= k; + if (children) { + var i = -1, n = children.length; + while (++i < n) d3_layout_packTransform(children[i], x, y, k); + } + } + function d3_layout_packPlace(a, b, c) { + var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; + if (db && (dx || dy)) { + var da = b.r + c.r, dc = dx * dx + dy * dy; + da *= da; + db *= db; + var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); + c.x = a.x + x * dx + y * dy; + c.y = a.y + x * dy - y * dx; + } else { + c.x = a.x + db; + c.y = a.y; + } + } + d3.layout.cluster = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function cluster(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; + d3_layout_treeVisitAfter(root, function(node) { + var children = node.children; + if (children && children.length) { + node.x = d3_layout_clusterX(children); + node.y = d3_layout_clusterY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x = (node.x - root.x) * size[0]; + node.y = (root.y - node.y) * size[1]; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + }); + return nodes; + } + cluster.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return cluster; + }; + cluster.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return cluster; + }; + cluster.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return cluster; + }; + return d3_layout_hierarchyRebind(cluster, hierarchy); + }; + function d3_layout_clusterY(children) { + return 1 + d3.max(children, function(child) { + return child.y; + }); + } + function d3_layout_clusterX(children) { + return children.reduce(function(x, child) { + return x + child.x; + }, 0) / children.length; + } + function d3_layout_clusterLeft(node) { + var children = node.children; + return children && children.length ? d3_layout_clusterLeft(children[0]) : node; + } + function d3_layout_clusterRight(node) { + var children = node.children, n; + return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; + } + d3.layout.treemap = function() { + var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); + function scale(children, k) { + var i = -1, n = children.length, child, area; + while (++i < n) { + area = (child = children[i]).value * (k < 0 ? 0 : k); + child.area = isNaN(area) || area <= 0 ? 0 : area; + } + } + function squarify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while ((n = remaining.length) > 0) { + row.push(child = remaining[n - 1]); + row.area += child.area; + if (mode !== "squarify" || (score = worst(row, u)) <= best) { + remaining.pop(); + best = score; + } else { + row.area -= row.pop().area; + position(row, u, rect, false); + u = Math.min(rect.dx, rect.dy); + row.length = row.area = 0; + best = Infinity; + } + } + if (row.length) { + position(row, u, rect, true); + row.length = row.area = 0; + } + children.forEach(squarify); + } + } + function stickify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), remaining = children.slice(), child, row = []; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while (child = remaining.pop()) { + row.push(child); + row.area += child.area; + if (child.z != null) { + position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); + row.length = row.area = 0; + } + } + children.forEach(stickify); + } + } + function worst(row, u) { + var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; + while (++i < n) { + if (!(r = row[i].area)) continue; + if (r < rmin) rmin = r; + if (r > rmax) rmax = r; + } + s *= s; + u *= u; + return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; + } + function position(row, u, rect, flush) { + var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; + if (u == rect.dx) { + if (flush || v > rect.dy) v = rect.dy; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dy = v; + x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); + } + o.z = true; + o.dx += rect.x + rect.dx - x; + rect.y += v; + rect.dy -= v; + } else { + if (flush || v > rect.dx) v = rect.dx; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dx = v; + y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); + } + o.z = false; + o.dy += rect.y + rect.dy - y; + rect.x += v; + rect.dx -= v; + } + } + function treemap(d) { + var nodes = stickies || hierarchy(d), root = nodes[0]; + root.x = 0; + root.y = 0; + root.dx = size[0]; + root.dy = size[1]; + if (stickies) hierarchy.revalue(root); + scale([ root ], root.dx * root.dy / root.value); + (stickies ? stickify : squarify)(root); + if (sticky) stickies = nodes; + return nodes; + } + treemap.size = function(x) { + if (!arguments.length) return size; + size = x; + return treemap; + }; + treemap.padding = function(x) { + if (!arguments.length) return padding; + function padFunction(node) { + var p = x.call(treemap, node, node.depth); + return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); + } + function padConstant(node) { + return d3_layout_treemapPad(node, x); + } + var type; + pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], + padConstant) : padConstant; + return treemap; + }; + treemap.round = function(x) { + if (!arguments.length) return round != Number; + round = x ? Math.round : Number; + return treemap; + }; + treemap.sticky = function(x) { + if (!arguments.length) return sticky; + sticky = x; + stickies = null; + return treemap; + }; + treemap.ratio = function(x) { + if (!arguments.length) return ratio; + ratio = x; + return treemap; + }; + treemap.mode = function(x) { + if (!arguments.length) return mode; + mode = x + ""; + return treemap; + }; + return d3_layout_hierarchyRebind(treemap, hierarchy); + }; + function d3_layout_treemapPadNull(node) { + return { + x: node.x, + y: node.y, + dx: node.dx, + dy: node.dy + }; + } + function d3_layout_treemapPad(node, padding) { + var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; + if (dx < 0) { + x += dx / 2; + dx = 0; + } + if (dy < 0) { + y += dy / 2; + dy = 0; + } + return { + x: x, + y: y, + dx: dx, + dy: dy + }; + } + d3.random = { + normal: function(µ, σ) { + var n = arguments.length; + if (n < 2) σ = 1; + if (n < 1) µ = 0; + return function() { + var x, y, r; + do { + x = Math.random() * 2 - 1; + y = Math.random() * 2 - 1; + r = x * x + y * y; + } while (!r || r > 1); + return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); + }; + }, + logNormal: function() { + var random = d3.random.normal.apply(d3, arguments); + return function() { + return Math.exp(random()); + }; + }, + irwinHall: function(m) { + return function() { + for (var s = 0, j = 0; j < m; j++) s += Math.random(); + return s / m; + }; + } + }; + d3.scale = {}; + function d3_scaleExtent(domain) { + var start = domain[0], stop = domain[domain.length - 1]; + return start < stop ? [ start, stop ] : [ stop, start ]; + } + function d3_scaleRange(scale) { + return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); + } + function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { + var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); + return function(x) { + return i(u(x)); + }; + } + function d3_scale_nice(domain, nice) { + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; + if (x1 < x0) { + dx = i0, i0 = i1, i1 = dx; + dx = x0, x0 = x1, x1 = dx; + } + domain[i0] = nice.floor(x0); + domain[i1] = nice.ceil(x1); + return domain; + } + function d3_scale_niceStep(step) { + return step ? { + floor: function(x) { + return Math.floor(x / step) * step; + }, + ceil: function(x) { + return Math.ceil(x / step) * step; + } + } : d3_scale_niceIdentity; + } + var d3_scale_niceIdentity = { + floor: d3_identity, + ceil: d3_identity + }; + function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { + var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; + if (domain[k] < domain[0]) { + domain = domain.slice().reverse(); + range = range.slice().reverse(); + } + while (++j <= k) { + u.push(uninterpolate(domain[j - 1], domain[j])); + i.push(interpolate(range[j - 1], range[j])); + } + return function(x) { + var j = d3.bisect(domain, x, 1, k) - 1; + return i[j](u[j](x)); + }; + } + d3.scale.linear = function() { + return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); + }; + function d3_scale_linear(domain, range, interpolate, clamp) { + var output, input; + function rescale() { + var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; + output = linear(domain, range, uninterpolate, interpolate); + input = linear(range, domain, uninterpolate, d3_interpolate); + return scale; + } + function scale(x) { + return output(x); + } + scale.invert = function(y) { + return input(y); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.map(Number); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.rangeRound = function(x) { + return scale.range(x).interpolate(d3_interpolateRound); + }; + scale.clamp = function(x) { + if (!arguments.length) return clamp; + clamp = x; + return rescale(); + }; + scale.interpolate = function(x) { + if (!arguments.length) return interpolate; + interpolate = x; + return rescale(); + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + d3_scale_linearNice(domain, m); + return rescale(); + }; + scale.copy = function() { + return d3_scale_linear(domain, range, interpolate, clamp); + }; + return rescale(); + } + function d3_scale_linearRebind(scale, linear) { + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); + } + function d3_scale_linearNice(domain, m) { + return d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); + } + function d3_scale_linearTickRange(domain, m) { + if (m == null) m = 10; + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; + if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; + extent[0] = Math.ceil(extent[0] / step) * step; + extent[1] = Math.floor(extent[1] / step) * step + step * .5; + extent[2] = step; + return extent; + } + function d3_scale_linearTicks(domain, m) { + return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); + } + function d3_scale_linearTickFormat(domain, m, format) { + var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01); + return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { + return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join(""); + }) : ",." + precision + "f"); + } + d3.scale.log = function() { + return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); + }; + function d3_scale_log(linear, base, positive, domain) { + function log(x) { + return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); + } + function pow(x) { + return positive ? Math.pow(base, x) : -Math.pow(base, -x); + } + function scale(x) { + return linear(log(x)); + } + scale.invert = function(x) { + return pow(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + positive = x[0] >= 0; + linear.domain((domain = x.map(Number)).map(log)); + return scale; + }; + scale.base = function(_) { + if (!arguments.length) return base; + base = +_; + linear.domain(domain.map(log)); + return scale; + }; + scale.nice = function() { + var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); + linear.domain(niced); + domain = niced.map(pow); + return scale; + }; + scale.ticks = function() { + var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; + if (isFinite(j - i)) { + if (positive) { + for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); + ticks.push(pow(i)); + } else { + ticks.push(pow(i)); + for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); + } + for (i = 0; ticks[i] < u; i++) {} + for (j = ticks.length; ticks[j - 1] > v; j--) {} + ticks = ticks.slice(i, j); + } + return ticks; + }; + scale.tickFormat = function(n, format) { + if (!arguments.length) return d3_scale_logFormat; + if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); + var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, + Math.floor), e; + return function(d) { + return d / pow(f(log(d) + e)) <= k ? format(d) : ""; + }; + }; + scale.copy = function() { + return d3_scale_log(linear.copy(), base, positive, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { + floor: function(x) { + return -Math.ceil(-x); + }, + ceil: function(x) { + return -Math.floor(-x); + } + }; + d3.scale.pow = function() { + return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); + }; + function d3_scale_pow(linear, exponent, domain) { + var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); + function scale(x) { + return linear(powp(x)); + } + scale.invert = function(x) { + return powb(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + linear.domain((domain = x.map(Number)).map(powp)); + return scale; + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + return scale.domain(d3_scale_linearNice(domain, m)); + }; + scale.exponent = function(x) { + if (!arguments.length) return exponent; + powp = d3_scale_powPow(exponent = x); + powb = d3_scale_powPow(1 / exponent); + linear.domain(domain.map(powp)); + return scale; + }; + scale.copy = function() { + return d3_scale_pow(linear.copy(), exponent, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_scale_powPow(e) { + return function(x) { + return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); + }; + } + d3.scale.sqrt = function() { + return d3.scale.pow().exponent(.5); + }; + d3.scale.ordinal = function() { + return d3_scale_ordinal([], { + t: "range", + a: [ [] ] + }); + }; + function d3_scale_ordinal(domain, ranger) { + var index, range, rangeBand; + function scale(x) { + return range[((index.get(x) || ranger.t === "range" && index.set(x, domain.push(x))) - 1) % range.length]; + } + function steps(start, step) { + return d3.range(domain.length).map(function(i) { + return start + step * i; + }); + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = []; + index = new d3_Map(); + var i = -1, n = x.length, xi; + while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); + return scale[ranger.t].apply(scale, ranger.a); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + rangeBand = 0; + ranger = { + t: "range", + a: arguments + }; + return scale; + }; + scale.rangePoints = function(x, padding) { + if (arguments.length < 2) padding = 0; + var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); + range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); + rangeBand = 0; + ranger = { + t: "rangePoints", + a: arguments + }; + return scale; + }; + scale.rangeBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); + range = steps(start + step * outerPadding, step); + if (reverse) range.reverse(); + rangeBand = step * (1 - padding); + ranger = { + t: "rangeBands", + a: arguments + }; + return scale; + }; + scale.rangeRoundBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; + range = steps(start + Math.round(error / 2), step); + if (reverse) range.reverse(); + rangeBand = Math.round(step * (1 - padding)); + ranger = { + t: "rangeRoundBands", + a: arguments + }; + return scale; + }; + scale.rangeBand = function() { + return rangeBand; + }; + scale.rangeExtent = function() { + return d3_scaleExtent(ranger.a[0]); + }; + scale.copy = function() { + return d3_scale_ordinal(domain, ranger); + }; + return scale.domain(domain); + } + d3.scale.category10 = function() { + return d3.scale.ordinal().range(d3_category10); + }; + d3.scale.category20 = function() { + return d3.scale.ordinal().range(d3_category20); + }; + d3.scale.category20b = function() { + return d3.scale.ordinal().range(d3_category20b); + }; + d3.scale.category20c = function() { + return d3.scale.ordinal().range(d3_category20c); + }; + var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); + var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); + var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); + var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); + d3.scale.quantile = function() { + return d3_scale_quantile([], []); + }; + function d3_scale_quantile(domain, range) { + var thresholds; + function rescale() { + var k = 0, q = range.length; + thresholds = []; + while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); + return scale; + } + function scale(x) { + if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.filter(function(d) { + return !isNaN(d); + }).sort(d3.ascending); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.quantiles = function() { + return thresholds; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; + }; + scale.copy = function() { + return d3_scale_quantile(domain, range); + }; + return rescale(); + } + d3.scale.quantize = function() { + return d3_scale_quantize(0, 1, [ 0, 1 ]); + }; + function d3_scale_quantize(x0, x1, range) { + var kx, i; + function scale(x) { + return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; + } + function rescale() { + kx = range.length / (x1 - x0); + i = range.length - 1; + return scale; + } + scale.domain = function(x) { + if (!arguments.length) return [ x0, x1 ]; + x0 = +x[0]; + x1 = +x[x.length - 1]; + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + y = y < 0 ? NaN : y / kx + x0; + return [ y, y + 1 / kx ]; + }; + scale.copy = function() { + return d3_scale_quantize(x0, x1, range); + }; + return rescale(); + } + d3.scale.threshold = function() { + return d3_scale_threshold([ .5 ], [ 0, 1 ]); + }; + function d3_scale_threshold(domain, range) { + function scale(x) { + if (x <= x) return range[d3.bisect(domain, x)]; + } + scale.domain = function(_) { + if (!arguments.length) return domain; + domain = _; + return scale; + }; + scale.range = function(_) { + if (!arguments.length) return range; + range = _; + return scale; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return [ domain[y - 1], domain[y] ]; + }; + scale.copy = function() { + return d3_scale_threshold(domain, range); + }; + return scale; + } + d3.scale.identity = function() { + return d3_scale_identity([ 0, 1 ]); + }; + function d3_scale_identity(domain) { + function identity(x) { + return +x; + } + identity.invert = identity; + identity.domain = identity.range = function(x) { + if (!arguments.length) return domain; + domain = x.map(identity); + return identity; + }; + identity.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + identity.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + identity.copy = function() { + return d3_scale_identity(domain); + }; + return identity; + } + d3.svg.arc = function() { + var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function arc() { + var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, + a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); + return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; + } + arc.innerRadius = function(v) { + if (!arguments.length) return innerRadius; + innerRadius = d3_functor(v); + return arc; + }; + arc.outerRadius = function(v) { + if (!arguments.length) return outerRadius; + outerRadius = d3_functor(v); + return arc; + }; + arc.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return arc; + }; + arc.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return arc; + }; + arc.centroid = function() { + var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; + return [ Math.cos(a) * r, Math.sin(a) * r ]; + }; + return arc; + }; + var d3_svg_arcOffset = -halfπ, d3_svg_arcMax = τ - ε; + function d3_svg_arcInnerRadius(d) { + return d.innerRadius; + } + function d3_svg_arcOuterRadius(d) { + return d.outerRadius; + } + function d3_svg_arcStartAngle(d) { + return d.startAngle; + } + function d3_svg_arcEndAngle(d) { + return d.endAngle; + } + d3.svg.line.radial = function() { + var line = d3_svg_line(d3_svg_lineRadial); + line.radius = line.x, delete line.x; + line.angle = line.y, delete line.y; + return line; + }; + function d3_svg_lineRadial(points) { + var point, i = -1, n = points.length, r, a; + while (++i < n) { + point = points[i]; + r = point[0]; + a = point[1] + d3_svg_arcOffset; + point[0] = r * Math.cos(a); + point[1] = r * Math.sin(a); + } + return points; + } + function d3_svg_area(projection) { + var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; + function area(data) { + var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { + return x; + } : d3_functor(x1), fy1 = y0 === y1 ? function() { + return y; + } : d3_functor(y1), x, y; + function segment() { + segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); + points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); + } else if (points0.length) { + segment(); + points0 = []; + points1 = []; + } + } + if (points0.length) segment(); + return segments.length ? segments.join("") : null; + } + area.x = function(_) { + if (!arguments.length) return x1; + x0 = x1 = _; + return area; + }; + area.x0 = function(_) { + if (!arguments.length) return x0; + x0 = _; + return area; + }; + area.x1 = function(_) { + if (!arguments.length) return x1; + x1 = _; + return area; + }; + area.y = function(_) { + if (!arguments.length) return y1; + y0 = y1 = _; + return area; + }; + area.y0 = function(_) { + if (!arguments.length) return y0; + y0 = _; + return area; + }; + area.y1 = function(_) { + if (!arguments.length) return y1; + y1 = _; + return area; + }; + area.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return area; + }; + area.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + interpolateReverse = interpolate.reverse || interpolate; + L = interpolate.closed ? "M" : "L"; + return area; + }; + area.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return area; + }; + return area; + } + d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; + d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; + d3.svg.area = function() { + return d3_svg_area(d3_identity); + }; + d3.svg.area.radial = function() { + var area = d3_svg_area(d3_svg_lineRadial); + area.radius = area.x, delete area.x; + area.innerRadius = area.x0, delete area.x0; + area.outerRadius = area.x1, delete area.x1; + area.angle = area.y, delete area.y; + area.startAngle = area.y0, delete area.y0; + area.endAngle = area.y1, delete area.y1; + return area; + }; + d3.svg.chord = function() { + var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function chord(d, i) { + var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); + return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; + } + function subgroup(self, f, d, i) { + var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; + return { + r: r, + a0: a0, + a1: a1, + p0: [ r * Math.cos(a0), r * Math.sin(a0) ], + p1: [ r * Math.cos(a1), r * Math.sin(a1) ] + }; + } + function equals(a, b) { + return a.a0 == b.a0 && a.a1 == b.a1; + } + function arc(r, p, a) { + return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; + } + function curve(r0, p0, r1, p1) { + return "Q 0,0 " + p1; + } + chord.radius = function(v) { + if (!arguments.length) return radius; + radius = d3_functor(v); + return chord; + }; + chord.source = function(v) { + if (!arguments.length) return source; + source = d3_functor(v); + return chord; + }; + chord.target = function(v) { + if (!arguments.length) return target; + target = d3_functor(v); + return chord; + }; + chord.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return chord; + }; + chord.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return chord; + }; + return chord; + }; + function d3_svg_chordRadius(d) { + return d.radius; + } + d3.svg.diagonal = function() { + var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; + function diagonal(d, i) { + var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { + x: p0.x, + y: m + }, { + x: p3.x, + y: m + }, p3 ]; + p = p.map(projection); + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; + } + diagonal.source = function(x) { + if (!arguments.length) return source; + source = d3_functor(x); + return diagonal; + }; + diagonal.target = function(x) { + if (!arguments.length) return target; + target = d3_functor(x); + return diagonal; + }; + diagonal.projection = function(x) { + if (!arguments.length) return projection; + projection = x; + return diagonal; + }; + return diagonal; + }; + function d3_svg_diagonalProjection(d) { + return [ d.x, d.y ]; + } + d3.svg.diagonal.radial = function() { + var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; + diagonal.projection = function(x) { + return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; + }; + return diagonal; + }; + function d3_svg_diagonalRadialProjection(projection) { + return function() { + var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; + return [ r * Math.cos(a), r * Math.sin(a) ]; + }; + } + d3.svg.symbol = function() { + var type = d3_svg_symbolType, size = d3_svg_symbolSize; + function symbol(d, i) { + return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); + } + symbol.type = function(x) { + if (!arguments.length) return type; + type = d3_functor(x); + return symbol; + }; + symbol.size = function(x) { + if (!arguments.length) return size; + size = d3_functor(x); + return symbol; + }; + return symbol; + }; + function d3_svg_symbolSize() { + return 64; + } + function d3_svg_symbolType() { + return "circle"; + } + function d3_svg_symbolCircle(size) { + var r = Math.sqrt(size / π); + return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; + } + var d3_svg_symbols = d3.map({ + circle: d3_svg_symbolCircle, + cross: function(size) { + var r = Math.sqrt(size / 5) / 2; + return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; + }, + diamond: function(size) { + var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; + return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; + }, + square: function(size) { + var r = Math.sqrt(size) / 2; + return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; + }, + "triangle-down": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; + }, + "triangle-up": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; + } + }); + d3.svg.symbolTypes = d3_svg_symbols.keys(); + var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); + function d3_transition(groups, id) { + d3_subclass(groups, d3_transitionPrototype); + groups.id = id; + return groups; + } + var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; + d3_transitionPrototype.call = d3_selectionPrototype.call; + d3_transitionPrototype.empty = d3_selectionPrototype.empty; + d3_transitionPrototype.node = d3_selectionPrototype.node; + d3_transitionPrototype.size = d3_selectionPrototype.size; + d3.transition = function(selection) { + return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); + }; + d3.transition.prototype = d3_transitionPrototype; + d3_transitionPrototype.select = function(selector) { + var id = this.id, subgroups = [], subgroup, subnode, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + d3_transitionNode(subnode, i, id, node.__transition__[id]); + subgroup.push(subnode); + } else { + subgroup.push(null); + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.selectAll = function(selector) { + var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + transition = node.__transition__[id]; + subnodes = selector.call(node, node.__data__, i, j); + subgroups.push(subgroup = []); + for (var k = -1, o = subnodes.length; ++k < o; ) { + if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition); + subgroup.push(subnode); + } + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_transition(subgroups, this.id); + }; + d3_transitionPrototype.tween = function(name, tween) { + var id = this.id; + if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); + return d3_selection_each(this, tween == null ? function(node) { + node.__transition__[id].tween.remove(name); + } : function(node) { + node.__transition__[id].tween.set(name, tween); + }); + }; + function d3_transition_tween(groups, name, value, tween) { + var id = groups.id; + return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); + } : (value = tween(value), function(node) { + node.__transition__[id].tween.set(name, value); + })); + } + d3_transitionPrototype.attr = function(nameNS, value) { + if (arguments.length < 2) { + for (value in nameNS) this.attr(value, nameNS[value]); + return this; + } + var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrTween(b) { + return b == null ? attrNull : (b += "", function() { + var a = this.getAttribute(name), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttribute(name, i(t)); + }); + }); + } + function attrTweenNS(b) { + return b == null ? attrNullNS : (b += "", function() { + var a = this.getAttributeNS(name.space, name.local), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttributeNS(name.space, name.local, i(t)); + }); + }); + } + return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.attrTween = function(nameNS, tween) { + var name = d3.ns.qualify(nameNS); + function attrTween(d, i) { + var f = tween.call(this, d, i, this.getAttribute(name)); + return f && function(t) { + this.setAttribute(name, f(t)); + }; + } + function attrTweenNS(d, i) { + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); + return f && function(t) { + this.setAttributeNS(name.space, name.local, f(t)); + }; + } + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.style(priority, name[priority], value); + return this; + } + priority = ""; + } + function styleNull() { + this.style.removeProperty(name); + } + function styleString(b) { + return b == null ? styleNull : (b += "", function() { + var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; + return a !== b && (i = d3_interpolate(a, b), function(t) { + this.style.setProperty(name, i(t), priority); + }); + }); + } + return d3_transition_tween(this, "style." + name, value, styleString); + }; + d3_transitionPrototype.styleTween = function(name, tween, priority) { + if (arguments.length < 3) priority = ""; + function styleTween(d, i) { + var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); + return f && function(t) { + this.style.setProperty(name, f(t), priority); + }; + } + return this.tween("style." + name, styleTween); + }; + d3_transitionPrototype.text = function(value) { + return d3_transition_tween(this, "text", value, d3_transition_text); + }; + function d3_transition_text(b) { + if (b == null) b = ""; + return function() { + this.textContent = b; + }; + } + d3_transitionPrototype.remove = function() { + return this.each("end.transition", function() { + var p; + if (this.__transition__.count < 2 && (p = this.parentNode)) p.removeChild(this); + }); + }; + d3_transitionPrototype.ease = function(value) { + var id = this.id; + if (arguments.length < 1) return this.node().__transition__[id].ease; + if (typeof value !== "function") value = d3.ease.apply(d3, arguments); + return d3_selection_each(this, function(node) { + node.__transition__[id].ease = value; + }); + }; + d3_transitionPrototype.delay = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].delay = +value.call(node, node.__data__, i, j); + } : (value = +value, function(node) { + node.__transition__[id].delay = value; + })); + }; + d3_transitionPrototype.duration = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j)); + } : (value = Math.max(1, value), function(node) { + node.__transition__[id].duration = value; + })); + }; + d3_transitionPrototype.each = function(type, listener) { + var id = this.id; + if (arguments.length < 2) { + var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; + d3_transitionInheritId = id; + d3_selection_each(this, function(node, i, j) { + d3_transitionInherit = node.__transition__[id]; + type.call(node, node.__data__, i, j); + }); + d3_transitionInherit = inherit; + d3_transitionInheritId = inheritId; + } else { + d3_selection_each(this, function(node) { + var transition = node.__transition__[id]; + (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener); + }); + } + return this; + }; + d3_transitionPrototype.transition = function() { + var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if (node = group[i]) { + transition = Object.create(node.__transition__[id0]); + transition.delay += transition.duration; + d3_transitionNode(node, i, id1, transition); + } + subgroup.push(node); + } + } + return d3_transition(subgroups, id1); + }; + function d3_transitionNode(node, i, id, inherit) { + var lock = node.__transition__ || (node.__transition__ = { + active: 0, + count: 0 + }), transition = lock[id]; + if (!transition) { + var time = inherit.time; + transition = lock[id] = { + tween: new d3_Map(), + time: time, + ease: inherit.ease, + delay: inherit.delay, + duration: inherit.duration + }; + ++lock.count; + d3.timer(function(elapsed) { + var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = []; + if (delay <= elapsed) return start(elapsed - delay); + d3_timer_replace(start, delay, time); + function start(elapsed) { + if (lock.active > id) return stop(); + lock.active = id; + transition.event && transition.event.start.call(node, d, i); + transition.tween.forEach(function(key, value) { + if (value = value.call(node, d, i)) { + tweened.push(value); + } + }); + if (tick(elapsed || 1)) return 1; + d3_timer_replace(tick, delay, time); + } + function tick(elapsed) { + if (lock.active !== id) return stop(); + var t = elapsed / duration, e = ease(t), n = tweened.length; + while (n > 0) { + tweened[--n].call(node, e); + } + if (t >= 1) { + transition.event && transition.event.end.call(node, d, i); + return stop(); + } + } + function stop() { + if (--lock.count) delete lock[id]; else delete node.__transition__; + return 1; + } + }, 0, time); + } + } + d3.svg.axis = function() { + var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_; + function axis(g) { + g.each(function() { + var g = d3.select(this); + var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy(); + var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; + var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), + d3.transition(path)); + tickEnter.append("line"); + tickEnter.append("text"); + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); + switch (orient) { + case "bottom": + { + tickTransform = d3_svg_axisX; + lineEnter.attr("y2", innerTickSize); + textEnter.attr("y", Math.max(innerTickSize, 0) + tickPadding); + lineUpdate.attr("x2", 0).attr("y2", innerTickSize); + textUpdate.attr("x", 0).attr("y", Math.max(innerTickSize, 0) + tickPadding); + text.attr("dy", ".71em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize); + break; + } + + case "top": + { + tickTransform = d3_svg_axisX; + lineEnter.attr("y2", -innerTickSize); + textEnter.attr("y", -(Math.max(innerTickSize, 0) + tickPadding)); + lineUpdate.attr("x2", 0).attr("y2", -innerTickSize); + textUpdate.attr("x", 0).attr("y", -(Math.max(innerTickSize, 0) + tickPadding)); + text.attr("dy", "0em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize); + break; + } + + case "left": + { + tickTransform = d3_svg_axisY; + lineEnter.attr("x2", -innerTickSize); + textEnter.attr("x", -(Math.max(innerTickSize, 0) + tickPadding)); + lineUpdate.attr("x2", -innerTickSize).attr("y2", 0); + textUpdate.attr("x", -(Math.max(innerTickSize, 0) + tickPadding)).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "end"); + pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize); + break; + } + + case "right": + { + tickTransform = d3_svg_axisY; + lineEnter.attr("x2", innerTickSize); + textEnter.attr("x", Math.max(innerTickSize, 0) + tickPadding); + lineUpdate.attr("x2", innerTickSize).attr("y2", 0); + textUpdate.attr("x", Math.max(innerTickSize, 0) + tickPadding).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "start"); + pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize); + break; + } + } + if (scale1.rangeBand) { + var dx = scale1.rangeBand() / 2, x = function(d) { + return scale1(d) + dx; + }; + tickEnter.call(tickTransform, x); + tickUpdate.call(tickTransform, x); + } else { + tickEnter.call(tickTransform, scale0); + tickUpdate.call(tickTransform, scale1); + tickExit.call(tickTransform, scale1); + } + }); + } + axis.scale = function(x) { + if (!arguments.length) return scale; + scale = x; + return axis; + }; + axis.orient = function(x) { + if (!arguments.length) return orient; + orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; + return axis; + }; + axis.ticks = function() { + if (!arguments.length) return tickArguments_; + tickArguments_ = arguments; + return axis; + }; + axis.tickValues = function(x) { + if (!arguments.length) return tickValues; + tickValues = x; + return axis; + }; + axis.tickFormat = function(x) { + if (!arguments.length) return tickFormat_; + tickFormat_ = x; + return axis; + }; + axis.tickSize = function(x) { + var n = arguments.length; + if (!n) return innerTickSize; + innerTickSize = +x; + outerTickSize = +arguments[n - 1]; + return axis; + }; + axis.innerTickSize = function(x) { + if (!arguments.length) return innerTickSize; + innerTickSize = +x; + return axis; + }; + axis.outerTickSize = function(x) { + if (!arguments.length) return outerTickSize; + outerTickSize = +x; + return axis; + }; + axis.tickPadding = function(x) { + if (!arguments.length) return tickPadding; + tickPadding = +x; + return axis; + }; + axis.tickSubdivide = function() { + return arguments.length && axis; + }; + return axis; + }; + var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { + top: 1, + right: 1, + bottom: 1, + left: 1 + }; + function d3_svg_axisX(selection, x) { + selection.attr("transform", function(d) { + return "translate(" + x(d) + ",0)"; + }); + } + function d3_svg_axisY(selection, y) { + selection.attr("transform", function(d) { + return "translate(0," + y(d) + ")"; + }); + } + d3.svg.brush = function() { + var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0]; + function brush(g) { + g.each(function() { + var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); + var background = g.selectAll(".background").data([ 0 ]); + background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); + g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move"); + var resize = g.selectAll(".resize").data(resizes, d3_identity); + resize.exit().remove(); + resize.enter().append("g").attr("class", function(d) { + return "resize " + d; + }).style("cursor", function(d) { + return d3_svg_brushCursor[d]; + }).append("rect").attr("x", function(d) { + return /[ew]$/.test(d) ? -3 : null; + }).attr("y", function(d) { + return /^[ns]/.test(d) ? -3 : null; + }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); + resize.style("display", brush.empty() ? "none" : null); + var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range; + if (x) { + range = d3_scaleRange(x); + backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]); + redrawX(gUpdate); + } + if (y) { + range = d3_scaleRange(y); + backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]); + redrawY(gUpdate); + } + redraw(gUpdate); + }); + } + brush.event = function(g) { + g.each(function() { + var event_ = event.of(this, arguments), extent1 = { + x: xExtent, + y: yExtent, + i: xExtentDomain, + j: yExtentDomain + }, extent0 = this.__chart__ || extent1; + this.__chart__ = extent1; + if (d3_transitionInheritId) { + d3.select(this).transition().each("start.brush", function() { + xExtentDomain = extent0.i; + yExtentDomain = extent0.j; + xExtent = extent0.x; + yExtent = extent0.y; + event_({ + type: "brushstart" + }); + }).tween("brush:brush", function() { + var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y); + xExtentDomain = yExtentDomain = null; + return function(t) { + xExtent = extent1.x = xi(t); + yExtent = extent1.y = yi(t); + event_({ + type: "brush", + mode: "resize" + }); + }; + }).each("end.brush", function() { + xExtentDomain = extent1.i; + yExtentDomain = extent1.j; + event_({ + type: "brush", + mode: "resize" + }); + event_({ + type: "brushend" + }); + }); + } else { + event_({ + type: "brushstart" + }); + event_({ + type: "brush", + mode: "resize" + }); + event_({ + type: "brushend" + }); + } + }); + }; + function redraw(g) { + g.selectAll(".resize").attr("transform", function(d) { + return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")"; + }); + } + function redrawX(g) { + g.select(".extent").attr("x", xExtent[0]); + g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]); + } + function redrawY(g) { + g.select(".extent").attr("y", yExtent[0]); + g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]); + } + function brushstart() { + var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = d3.mouse(target), offset; + var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); + if (d3.event.changedTouches) { + w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); + } else { + w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); + } + g.interrupt().selectAll("*").interrupt(); + if (dragging) { + origin[0] = xExtent[0] - origin[0]; + origin[1] = yExtent[0] - origin[1]; + } else if (resizing) { + var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); + offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ]; + origin[0] = xExtent[ex]; + origin[1] = yExtent[ey]; + } else if (d3.event.altKey) center = origin.slice(); + g.style("pointer-events", "none").selectAll(".resize").style("display", null); + d3.select("body").style("cursor", eventTarget.style("cursor")); + event_({ + type: "brushstart" + }); + brushmove(); + function keydown() { + if (d3.event.keyCode == 32) { + if (!dragging) { + center = null; + origin[0] -= xExtent[1]; + origin[1] -= yExtent[1]; + dragging = 2; + } + d3_eventPreventDefault(); + } + } + function keyup() { + if (d3.event.keyCode == 32 && dragging == 2) { + origin[0] += xExtent[1]; + origin[1] += yExtent[1]; + dragging = 0; + d3_eventPreventDefault(); + } + } + function brushmove() { + var point = d3.mouse(target), moved = false; + if (offset) { + point[0] += offset[0]; + point[1] += offset[1]; + } + if (!dragging) { + if (d3.event.altKey) { + if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ]; + origin[0] = xExtent[+(point[0] < center[0])]; + origin[1] = yExtent[+(point[1] < center[1])]; + } else center = null; + } + if (resizingX && move1(point, x, 0)) { + redrawX(g); + moved = true; + } + if (resizingY && move1(point, y, 1)) { + redrawY(g); + moved = true; + } + if (moved) { + redraw(g); + event_({ + type: "brush", + mode: dragging ? "move" : "resize" + }); + } + } + function move1(point, scale, i) { + var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max; + if (dragging) { + r0 -= position; + r1 -= size + position; + } + min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i]; + if (dragging) { + max = (min += position) + size; + } else { + if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); + if (position < min) { + max = min; + min = position; + } else { + max = position; + } + } + if (extent[0] != min || extent[1] != max) { + if (i) yExtentDomain = null; else xExtentDomain = null; + extent[0] = min; + extent[1] = max; + return true; + } + } + function brushend() { + brushmove(); + g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); + d3.select("body").style("cursor", null); + w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); + dragRestore(); + event_({ + type: "brushend" + }); + } + } + brush.x = function(z) { + if (!arguments.length) return x; + x = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.y = function(z) { + if (!arguments.length) return y; + y = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.clamp = function(z) { + if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null; + if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z; + return brush; + }; + brush.extent = function(z) { + var x0, x1, y0, y1, t; + if (!arguments.length) { + if (x) { + if (xExtentDomain) { + x0 = xExtentDomain[0], x1 = xExtentDomain[1]; + } else { + x0 = xExtent[0], x1 = xExtent[1]; + if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + } + } + if (y) { + if (yExtentDomain) { + y0 = yExtentDomain[0], y1 = yExtentDomain[1]; + } else { + y0 = yExtent[0], y1 = yExtent[1]; + if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + } + } + return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; + } + if (x) { + x0 = z[0], x1 = z[1]; + if (y) x0 = x0[0], x1 = x1[0]; + xExtentDomain = [ x0, x1 ]; + if (x.invert) x0 = x(x0), x1 = x(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ]; + } + if (y) { + y0 = z[0], y1 = z[1]; + if (x) y0 = y0[1], y1 = y1[1]; + yExtentDomain = [ y0, y1 ]; + if (y.invert) y0 = y(y0), y1 = y(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ]; + } + return brush; + }; + brush.clear = function() { + if (!brush.empty()) { + xExtent = [ 0, 0 ], yExtent = [ 0, 0 ]; + xExtentDomain = yExtentDomain = null; + } + return brush; + }; + brush.empty = function() { + return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1]; + }; + return d3.rebind(brush, event, "on"); + }; + var d3_svg_brushCursor = { + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" + }; + var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; + var d3_time = d3.time = {}, d3_date = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; + function d3_date_utc() { + this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); + } + d3_date_utc.prototype = { + getDate: function() { + return this._.getUTCDate(); + }, + getDay: function() { + return this._.getUTCDay(); + }, + getFullYear: function() { + return this._.getUTCFullYear(); + }, + getHours: function() { + return this._.getUTCHours(); + }, + getMilliseconds: function() { + return this._.getUTCMilliseconds(); + }, + getMinutes: function() { + return this._.getUTCMinutes(); + }, + getMonth: function() { + return this._.getUTCMonth(); + }, + getSeconds: function() { + return this._.getUTCSeconds(); + }, + getTime: function() { + return this._.getTime(); + }, + getTimezoneOffset: function() { + return 0; + }, + valueOf: function() { + return this._.valueOf(); + }, + setDate: function() { + d3_time_prototype.setUTCDate.apply(this._, arguments); + }, + setDay: function() { + d3_time_prototype.setUTCDay.apply(this._, arguments); + }, + setFullYear: function() { + d3_time_prototype.setUTCFullYear.apply(this._, arguments); + }, + setHours: function() { + d3_time_prototype.setUTCHours.apply(this._, arguments); + }, + setMilliseconds: function() { + d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); + }, + setMinutes: function() { + d3_time_prototype.setUTCMinutes.apply(this._, arguments); + }, + setMonth: function() { + d3_time_prototype.setUTCMonth.apply(this._, arguments); + }, + setSeconds: function() { + d3_time_prototype.setUTCSeconds.apply(this._, arguments); + }, + setTime: function() { + d3_time_prototype.setTime.apply(this._, arguments); + } + }; + var d3_time_prototype = Date.prototype; + var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; + var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + function d3_time_interval(local, step, number) { + function round(date) { + var d0 = local(date), d1 = offset(d0, 1); + return date - d0 < d1 - date ? d0 : d1; + } + function ceil(date) { + step(date = local(new d3_date(date - 1)), 1); + return date; + } + function offset(date, k) { + step(date = new d3_date(+date), k); + return date; + } + function range(t0, t1, dt) { + var time = ceil(t0), times = []; + if (dt > 1) { + while (time < t1) { + if (!(number(time) % dt)) times.push(new Date(+time)); + step(time, 1); + } + } else { + while (time < t1) times.push(new Date(+time)), step(time, 1); + } + return times; + } + function range_utc(t0, t1, dt) { + try { + d3_date = d3_date_utc; + var utc = new d3_date_utc(); + utc._ = t0; + return range(utc, t1, dt); + } finally { + d3_date = Date; + } + } + local.floor = local; + local.round = round; + local.ceil = ceil; + local.offset = offset; + local.range = range; + var utc = local.utc = d3_time_interval_utc(local); + utc.floor = utc; + utc.round = d3_time_interval_utc(round); + utc.ceil = d3_time_interval_utc(ceil); + utc.offset = d3_time_interval_utc(offset); + utc.range = range_utc; + return local; + } + function d3_time_interval_utc(method) { + return function(date, k) { + try { + d3_date = d3_date_utc; + var utc = new d3_date_utc(); + utc._ = date; + return method(utc, k)._; + } finally { + d3_date = Date; + } + }; + } + d3_time.year = d3_time_interval(function(date) { + date = d3_time.day(date); + date.setMonth(0, 1); + return date; + }, function(date, offset) { + date.setFullYear(date.getFullYear() + offset); + }, function(date) { + return date.getFullYear(); + }); + d3_time.years = d3_time.year.range; + d3_time.years.utc = d3_time.year.utc.range; + d3_time.day = d3_time_interval(function(date) { + var day = new d3_date(2e3, 0); + day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); + return day; + }, function(date, offset) { + date.setDate(date.getDate() + offset); + }, function(date) { + return date.getDate() - 1; + }); + d3_time.days = d3_time.day.range; + d3_time.days.utc = d3_time.day.utc.range; + d3_time.dayOfYear = function(date) { + var year = d3_time.year(date); + return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); + }; + d3_time_daySymbols.forEach(function(day, i) { + day = day.toLowerCase(); + i = 7 - i; + var interval = d3_time[day] = d3_time_interval(function(date) { + (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); + return date; + }, function(date, offset) { + date.setDate(date.getDate() + Math.floor(offset) * 7); + }, function(date) { + var day = d3_time.year(date).getDay(); + return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); + }); + d3_time[day + "s"] = interval.range; + d3_time[day + "s"].utc = interval.utc.range; + d3_time[day + "OfYear"] = function(date) { + var day = d3_time.year(date).getDay(); + return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7); + }; + }); + d3_time.week = d3_time.sunday; + d3_time.weeks = d3_time.sunday.range; + d3_time.weeks.utc = d3_time.sunday.utc.range; + d3_time.weekOfYear = d3_time.sundayOfYear; + d3_time.format = d3_time_format; + function d3_time_format(template) { + var n = template.length; + function format(date) { + var string = [], i = -1, j = 0, c, p, f; + while (++i < n) { + if (template.charCodeAt(i) === 37) { + string.push(template.substring(j, i)); + if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); + if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); + string.push(c); + j = i + 1; + } + } + string.push(template.substring(j, i)); + return string.join(""); + } + format.parse = function(string) { + var d = { + y: 1900, + m: 0, + d: 1, + H: 0, + M: 0, + S: 0, + L: 0, + Z: null + }, i = d3_time_parse(d, template, string, 0); + if (i != string.length) return null; + if ("p" in d) d.H = d.H % 12 + d.p * 12; + var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)(); + if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { + date.setFullYear(d.y, 0, 1); + date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); + } else date.setFullYear(d.y, d.m, d.d); + date.setHours(d.H + Math.floor(d.Z / 100), d.M + d.Z % 100, d.S, d.L); + return localZ ? date._ : date; + }; + format.toString = function() { + return template; + }; + return format; + } + function d3_time_parse(date, template, string, j) { + var c, p, t, i = 0, n = template.length, m = string.length; + while (i < n) { + if (j >= m) return -1; + c = template.charCodeAt(i++); + if (c === 37) { + t = template.charAt(i++); + p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t]; + if (!p || (j = p(date, string, j)) < 0) return -1; + } else if (c != string.charCodeAt(j++)) { + return -1; + } + } + return j; + } + function d3_time_formatRe(names) { + return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); + } + function d3_time_formatLookup(names) { + var map = new d3_Map(), i = -1, n = names.length; + while (++i < n) map.set(names[i].toLowerCase(), i); + return map; + } + function d3_time_formatPad(value, fill, width) { + var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; + return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); + } + var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup = d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup = d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/; + var d3_time_formatPads = { + "-": "", + _: " ", + "0": "0" + }; + var d3_time_formats = { + a: function(d) { + return d3_time_dayAbbreviations[d.getDay()]; + }, + A: function(d) { + return d3_time_days[d.getDay()]; + }, + b: function(d) { + return d3_time_monthAbbreviations[d.getMonth()]; + }, + B: function(d) { + return d3_time_months[d.getMonth()]; + }, + c: d3_time_format(d3_time_formatDateTime), + d: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + e: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + H: function(d, p) { + return d3_time_formatPad(d.getHours(), p, 2); + }, + I: function(d, p) { + return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); + }, + j: function(d, p) { + return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3); + }, + L: function(d, p) { + return d3_time_formatPad(d.getMilliseconds(), p, 3); + }, + m: function(d, p) { + return d3_time_formatPad(d.getMonth() + 1, p, 2); + }, + M: function(d, p) { + return d3_time_formatPad(d.getMinutes(), p, 2); + }, + p: function(d) { + return d.getHours() >= 12 ? "PM" : "AM"; + }, + S: function(d, p) { + return d3_time_formatPad(d.getSeconds(), p, 2); + }, + U: function(d, p) { + return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2); + }, + w: function(d) { + return d.getDay(); + }, + W: function(d, p) { + return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2); + }, + x: d3_time_format(d3_time_formatDate), + X: d3_time_format(d3_time_formatTime), + y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 100, p, 2); + }, + Y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); + }, + Z: d3_time_zone, + "%": function() { + return "%"; + } + }; + var d3_time_parsers = { + a: d3_time_parseWeekdayAbbrev, + A: d3_time_parseWeekday, + b: d3_time_parseMonthAbbrev, + B: d3_time_parseMonth, + c: d3_time_parseLocaleFull, + d: d3_time_parseDay, + e: d3_time_parseDay, + H: d3_time_parseHour24, + I: d3_time_parseHour24, + j: d3_time_parseDayOfYear, + L: d3_time_parseMilliseconds, + m: d3_time_parseMonthNumber, + M: d3_time_parseMinutes, + p: d3_time_parseAmPm, + S: d3_time_parseSeconds, + U: d3_time_parseWeekNumberSunday, + w: d3_time_parseWeekdayNumber, + W: d3_time_parseWeekNumberMonday, + x: d3_time_parseLocaleDate, + X: d3_time_parseLocaleTime, + y: d3_time_parseYear, + Y: d3_time_parseFullYear, + Z: d3_time_parseZone, + "%": d3_time_parseLiteralPercent + }; + function d3_time_parseWeekdayAbbrev(date, string, i) { + d3_time_dayAbbrevRe.lastIndex = 0; + var n = d3_time_dayAbbrevRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekday(date, string, i) { + d3_time_dayRe.lastIndex = 0; + var n = d3_time_dayRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekdayNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 1)); + return n ? (date.w = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberSunday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.U = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberMonday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.W = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMonthAbbrev(date, string, i) { + d3_time_monthAbbrevRe.lastIndex = 0; + var n = d3_time_monthAbbrevRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseMonth(date, string, i) { + d3_time_monthRe.lastIndex = 0; + var n = d3_time_monthRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseLocaleFull(date, string, i) { + return d3_time_parse(date, d3_time_formats.c.toString(), string, i); + } + function d3_time_parseLocaleDate(date, string, i) { + return d3_time_parse(date, d3_time_formats.x.toString(), string, i); + } + function d3_time_parseLocaleTime(date, string, i) { + return d3_time_parse(date, d3_time_formats.X.toString(), string, i); + } + function d3_time_parseFullYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 4)); + return n ? (date.y = +n[0], i + n[0].length) : -1; + } + function d3_time_parseYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; + } + function d3_time_parseZone(date, string, i) { + return /^[+-]\d{4}$/.test(string = string.substring(i, i + 5)) ? (date.Z = +string, + i + 5) : -1; + } + function d3_time_expandYear(d) { + return d + (d > 68 ? 1900 : 2e3); + } + function d3_time_parseMonthNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.m = n[0] - 1, i + n[0].length) : -1; + } + function d3_time_parseDay(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.d = +n[0], i + n[0].length) : -1; + } + function d3_time_parseDayOfYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.j = +n[0], i + n[0].length) : -1; + } + function d3_time_parseHour24(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.H = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMinutes(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.M = +n[0], i + n[0].length) : -1; + } + function d3_time_parseSeconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.S = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMilliseconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.L = +n[0], i + n[0].length) : -1; + } + var d3_time_numberRe = /^\s*\d+/; + function d3_time_parseAmPm(date, string, i) { + var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); + return n == null ? -1 : (date.p = n, i); + } + var d3_time_amPmLookup = d3.map({ + am: 0, + pm: 1 + }); + function d3_time_zone(d) { + var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; + return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); + } + function d3_time_parseLiteralPercent(date, string, i) { + d3_time_percentRe.lastIndex = 0; + var n = d3_time_percentRe.exec(string.substring(i, i + 1)); + return n ? i + n[0].length : -1; + } + d3_time_format.utc = d3_time_formatUtc; + function d3_time_formatUtc(template) { + var local = d3_time_format(template); + function format(date) { + try { + d3_date = d3_date_utc; + var utc = new d3_date(); + utc._ = date; + return local(utc); + } finally { + d3_date = Date; + } + } + format.parse = function(string) { + try { + d3_date = d3_date_utc; + var date = local.parse(string); + return date && date._; + } finally { + d3_date = Date; + } + }; + format.toString = local.toString; + return format; + } + var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ"); + d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; + function d3_time_formatIsoNative(date) { + return date.toISOString(); + } + d3_time_formatIsoNative.parse = function(string) { + var date = new Date(string); + return isNaN(date) ? null : date; + }; + d3_time_formatIsoNative.toString = d3_time_formatIso.toString; + d3_time.second = d3_time_interval(function(date) { + return new d3_date(Math.floor(date / 1e3) * 1e3); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 1e3); + }, function(date) { + return date.getSeconds(); + }); + d3_time.seconds = d3_time.second.range; + d3_time.seconds.utc = d3_time.second.utc.range; + d3_time.minute = d3_time_interval(function(date) { + return new d3_date(Math.floor(date / 6e4) * 6e4); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 6e4); + }, function(date) { + return date.getMinutes(); + }); + d3_time.minutes = d3_time.minute.range; + d3_time.minutes.utc = d3_time.minute.utc.range; + d3_time.hour = d3_time_interval(function(date) { + var timezone = date.getTimezoneOffset() / 60; + return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 36e5); + }, function(date) { + return date.getHours(); + }); + d3_time.hours = d3_time.hour.range; + d3_time.hours.utc = d3_time.hour.utc.range; + d3_time.month = d3_time_interval(function(date) { + date = d3_time.day(date); + date.setDate(1); + return date; + }, function(date, offset) { + date.setMonth(date.getMonth() + offset); + }, function(date) { + return date.getMonth(); + }); + d3_time.months = d3_time.month.range; + d3_time.months.utc = d3_time.month.utc.range; + function d3_time_scale(linear, methods, format) { + function scale(x) { + return linear(x); + } + scale.invert = function(x) { + return d3_time_scaleDate(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(d3_time_scaleDate); + linear.domain(x); + return scale; + }; + function tickMethod(extent, count) { + var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target); + return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) { + return d / 31536e6; + }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i]; + } + scale.nice = function(interval, skip) { + var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval); + if (method) interval = method[0], skip = method[1]; + function skipped(date) { + return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length; + } + return scale.domain(d3_scale_nice(domain, skip > 1 ? { + floor: function(date) { + while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1); + return date; + }, + ceil: function(date) { + while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1); + return date; + } + } : interval)); + }; + scale.ticks = function(interval, skip) { + var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ { + range: interval + }, skip ]; + if (method) interval = method[0], skip = method[1]; + return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip); + }; + scale.tickFormat = function() { + return format; + }; + scale.copy = function() { + return d3_time_scale(linear.copy(), methods, format); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_time_scaleDate(t) { + return new Date(t); + } + function d3_time_scaleFormat(formats) { + return function(date) { + var i = formats.length - 1, f = formats[i]; + while (!f[1](date)) f = formats[--i]; + return f[0](date); + }; + } + var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; + var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [ d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5 ], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3 ], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [ d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ]; + var d3_time_scaleLocalFormats = [ [ d3_time_format("%Y"), d3_true ], [ d3_time_format("%B"), function(d) { + return d.getMonth(); + } ], [ d3_time_format("%b %d"), function(d) { + return d.getDate() != 1; + } ], [ d3_time_format("%a %d"), function(d) { + return d.getDay() && d.getDate() != 1; + } ], [ d3_time_format("%I %p"), function(d) { + return d.getHours(); + } ], [ d3_time_format("%I:%M"), function(d) { + return d.getMinutes(); + } ], [ d3_time_format(":%S"), function(d) { + return d.getSeconds(); + } ], [ d3_time_format(".%L"), function(d) { + return d.getMilliseconds(); + } ] ]; + var d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); + d3_time_scaleLocalMethods.year = d3_time.year; + d3_time.scale = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); + }; + var d3_time_scaleMilliseconds = { + range: function(start, stop, step) { + return d3.range(+start, +stop, step).map(d3_time_scaleDate); + } + }; + var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { + return [ m[0].utc, m[1] ]; + }); + var d3_time_scaleUTCFormats = [ [ d3_time_formatUtc("%Y"), d3_true ], [ d3_time_formatUtc("%B"), function(d) { + return d.getUTCMonth(); + } ], [ d3_time_formatUtc("%b %d"), function(d) { + return d.getUTCDate() != 1; + } ], [ d3_time_formatUtc("%a %d"), function(d) { + return d.getUTCDay() && d.getUTCDate() != 1; + } ], [ d3_time_formatUtc("%I %p"), function(d) { + return d.getUTCHours(); + } ], [ d3_time_formatUtc("%I:%M"), function(d) { + return d.getUTCMinutes(); + } ], [ d3_time_formatUtc(":%S"), function(d) { + return d.getUTCSeconds(); + } ], [ d3_time_formatUtc(".%L"), function(d) { + return d.getUTCMilliseconds(); + } ] ]; + var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); + d3_time_scaleUTCMethods.year = d3_time.year.utc; + d3_time.scale.utc = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); + }; + d3.text = d3_xhrType(function(request) { + return request.responseText; + }); + d3.json = function(url, callback) { + return d3_xhr(url, "application/json", d3_json, callback); + }; + function d3_json(request) { + return JSON.parse(request.responseText); + } + d3.html = function(url, callback) { + return d3_xhr(url, "text/html", d3_html, callback); + }; + function d3_html(request) { + var range = d3_document.createRange(); + range.selectNode(d3_document.body); + return range.createContextualFragment(request.responseText); + } + d3.xml = d3_xhrType(function(request) { + return request.responseXML; + }); + return d3; +}(); \ No newline at end of file diff --git a/html/js/d3.v3.js b/html/js/d3.v3.js new file mode 100644 index 0000000..77615c0 --- /dev/null +++ b/html/js/d3.v3.js @@ -0,0 +1,5 @@ +d3=function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function u(){}function i(){}function o(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function a(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=Do.length;r>e;++e){var u=Do[e]+t;if(u in n)return u}}function c(){}function l(){}function s(n){function t(){for(var t,r=e,u=-1,i=r.length;++ue;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function T(n){return Lo(n,Io),n}function q(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t0&&(n=n.substring(0,a));var s=Zo.get(n);return s&&(n=s,l=j),a?t?u:r:t?c:i}function D(n,t){return function(e){var r=mo.event;mo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{mo.event=r}}}function j(n,t){var e=D(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function L(){var n=".dragsuppress-"+ ++Xo,t="touchmove"+n,e="selectstart"+n,r="dragstart"+n,u="click"+n,i=mo.select(_o).on(t,f).on(e,f).on(r,f),o=bo.style,a=o[Vo];return o[Vo]="none",function(t){function e(){i.on(u,null)}i.on(n,null),o[Vo]=a,t&&(i.on(u,function(){f(),e()},!0),setTimeout(e,0))}}function H(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>$o&&(_o.scrollX||_o.scrollY)){e=mo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var u=e[0][0].getScreenCTM();$o=!(u.f||u.e),e.remove()}return $o?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function F(n){return n>0?1:0>n?-1:0}function P(n){return n>1?0:-1>n?Bo:Math.acos(n)}function O(n){return n>1?Jo:-1>n?-Jo:Math.asin(n)}function R(n){return((n=Math.exp(n))-1/n)/2}function Y(n){return((n=Math.exp(n))+1/n)/2}function I(n){return((n=Math.exp(2*n))-1)/(n+1)}function U(n){return(n=Math.sin(n/2))*n}function Z(){}function V(n,t,e){return new X(n,t,e)}function X(n,t,e){this.h=n,this.s=t,this.l=e}function $(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,ot(u(n+120),u(n),u(n-120))}function B(n,t,e){return new W(n,t,e)}function W(n,t,e){this.h=n,this.c=t,this.l=e}function J(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),G(e,Math.cos(n*=Qo)*t,Math.sin(n)*t)}function G(n,t,e){return new K(n,t,e)}function K(n,t,e){this.l=n,this.a=t,this.b=e}function Q(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=tt(u)*sa,r=tt(r)*fa,i=tt(i)*ha,ot(rt(3.2404542*u-1.5371385*r-.4985314*i),rt(-.969266*u+1.8760108*r+.041556*i),rt(.0556434*u-.2040259*r+1.0572252*i))}function nt(n,t,e){return n>0?B(Math.atan2(e,t)*na,Math.sqrt(t*t+e*e),n):B(0/0,0/0,n)}function tt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function et(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function rt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function ut(n){return ot(n>>16,255&n>>8,255&n)}function it(n){return ut(n)+""}function ot(n,t,e){return new at(n,t,e)}function at(n,t,e){this.r=n,this.g=t,this.b=e}function ct(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function lt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(gt(u[0]),gt(u[1]),gt(u[2]))}return(i=da.get(n))?t(i.r,i.g,i.b):(null!=n&&"#"===n.charAt(0)&&(4===n.length?(o=n.charAt(1),o+=o,a=n.charAt(2),a+=a,c=n.charAt(3),c+=c):7===n.length&&(o=n.substring(1,3),a=n.substring(3,5),c=n.substring(5,7)),o=parseInt(o,16),a=parseInt(a,16),c=parseInt(c,16)),t(o,a,c))}function st(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),V(r,u,c)}function ft(n,t,e){n=ht(n),t=ht(t),e=ht(e);var r=et((.4124564*n+.3575761*t+.1804375*e)/sa),u=et((.2126729*n+.7151522*t+.072175*e)/fa),i=et((.0193339*n+.119192*t+.9503041*e)/ha);return G(116*u-16,500*(r-u),200*(u-i))}function ht(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function gt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function pt(n){return"function"==typeof n?n:function(){return n}}function dt(n){return n}function vt(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),mt(t,e,n,r)}}function mt(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=mo.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!_o.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=mo.event;mo.event=n;try{o.progress.call(i,c)}finally{mo.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Mo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},mo.rebind(i,o,"on"),null==r?i:i.get(yt(r))}function yt(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Mt(){var n=bt(),t=_t()-n;t>24?(isFinite(t)&&(clearTimeout(Ma),Ma=setTimeout(Mt,t)),ya=0):(ya=1,ba(Mt))}function xt(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now()),xa.callback=n,xa.time=e+t}function bt(){var n=Date.now();for(xa=va;xa;)n>=xa.time&&(xa.flush=xa.callback(n-xa.time)),xa=xa.next;return n}function _t(){for(var n,t=va,e=1/0;t;)t.flush?t=n?n.next=t.next:va=t.next:(t.time8?function(n){return n/e}:function(n){return n*e},symbol:n}}function St(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Et(n){return n+""}function kt(){}function At(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function Nt(n,t){n&&Da.hasOwnProperty(n.type)&&Da[n.type](n,t)}function Tt(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++ua;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c={point:e,points:n,other:null,visited:!1,entry:!0,subject:!0},l={point:e,points:[e],other:c,visited:!1,entry:!1,subject:!1};c.other=l,i.push(c),o.push(l),c={point:r,points:[r],other:null,visited:!1,entry:!1,subject:!0},l={point:r,points:[r],other:c,visited:!1,entry:!0,subject:!1},c.other=l,i.push(c),o.push(l)}}),o.sort(t),$t(i),$t(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].entry=c=!c;for(var s,f,h,g=i[0];;){for(s=g;s.visited;)if((s=s.next)===g)return;f=s.points,u.lineStart();do{if(s.visited=s.other.visited=!0,s.entry){if(s.subject)for(var a=0;a=0;)u.point((h=f[a])[0],h[1])}else r(s.point,s.prev.point,-1,u);s=s.prev}s=s.other,f=s.points}while(!s.visited);u.lineEnd()}}}function $t(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Wt))}}var g,p,d,v=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[],i.polygonStart()},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=mo.merge(g);var n=Kt(m,p);g.length?Xt(g,Gt,n,e,i):n&&(i.lineStart(),e(null,null,1,i),i.lineEnd()),i.polygonEnd(),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Jt(),x=t(M);return y}}function Wt(n){return n.length>1}function Jt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:c,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Gt(n,t){return((n=n.point)[0]<0?n[1]-Jo-Go:Jo-n[1])-((t=t.point)[0]<0?t[1]-Jo-Go:Jo-t[1])}function Kt(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;La.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+Bo/4,p=Math.sin(g),d=Math.cos(g),v=1;;){v===s&&(v=0),n=l[v];var m=n[0],y=n[1]/2+Bo/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=Math.abs(b)>Bo,w=p*M;if(La.add(Math.atan2(w*Math.sin(b),d*x+w*Math.cos(b))),i+=_?b+(b>=0?2:-2)*Bo:b,_^h>=e^m>=e){var S=jt(Ct(f),Ct(n));Ft(S);var E=jt(u,S);Ft(E);var k=(_^b>=0?-1:1)*O(E[2]);(r>k||r===k&&(S[0]||S[1]))&&(o+=_^b>=0?1:-1)}if(!v++)break;h=m,p=M,d=x,f=n}}return(-Go>i||Go>i&&0>La)^1&o}function Qt(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?Bo:-Bo,c=Math.abs(i-e);Math.abs(c-Bo)0?Jo:-Jo),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=Bo&&(Math.abs(e-u)Go?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function te(n,t,e,r){var u;if(null==n)u=e*Jo,r.point(-Bo,u),r.point(0,u),r.point(Bo,u),r.point(Bo,0),r.point(Bo,-u),r.point(0,-u),r.point(-Bo,-u),r.point(-Bo,0),r.point(-Bo,u);else if(Math.abs(n[0]-t[0])>Go){var i=(n[0]i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],d=t(f,h),v=o?d?0:u(f,h):d?u(f+(0>f?Bo:-Bo),h):0;if(!e&&(l=c=d)&&n.lineStart(),d!==c&&(g=r(e,p),(Ot(e,g)||Ot(p,g))&&(p[0]+=Go,p[1]+=Go,d=t(p[0],p[1]))),d!==c)s=0,d?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^d){var m;v&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!d||e&&Ot(e,p)||n.point(p[0],p[1]),e=p,c=d,i=v},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=Ct(n),u=Ct(t),o=[1,0,0],a=jt(r,u),c=Dt(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=jt(o,a),p=Ht(o,f),d=Ht(a,h);Lt(p,d);var v=g,m=Dt(p,v),y=Dt(v,v),M=m*m-y*(Dt(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=Ht(v,(-m-x)/y);if(Lt(b,p),b=Pt(b),!e)return b;var _,w=n[0],S=t[0],E=n[1],k=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=Math.abs(A-Bo)A;if(!N&&E>k&&(_=E,E=k,k=_),T?N?E+k>0^b[1]<(Math.abs(b[0]-w)Bo^(w<=b[0]&&b[0]<=S)){var q=Ht(v,(-m+x)/y);return Lt(q,p),[b,Pt(q)]}}}function u(t,e){var r=o?n:Bo-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=Math.abs(i)>Go,c=Te(n,6*Qo);return Bt(t,e,c,o?[0,-n]:[-Bo,n-Bo])}function re(n,t,e,r){function u(r,u){return Math.abs(r[0]-n)0?0:3:Math.abs(r[0]-e)0?2:1:Math.abs(r[1]-t)0?1:0:u>0?3:2}function i(n,t){return o(n.point,t.point)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}function a(u,i){var o=i[0]-u[0],a=i[1]-u[1],c=[0,1];return Math.abs(o)0&&(u[0]+=c[0]*o,u[1]+=c[0]*a),!0):!1}return function(c){function l(n){for(var t=0,e=y.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=y[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&s(l,i,n)>0&&++t:i[1]<=r&&s(l,i,n)<0&&--t,l=i;return 0!==t}function s(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(e[0]-n[0])*(t[1]-n[1])}function f(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function h(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function g(n,t){h(n,t)&&c.point(n,t)}function p(){q.point=v,y&&y.push(M=[]),k=!0,E=!1,w=S=0/0}function d(){m&&(v(x,b),_&&E&&T.rejoin(),m.push(T.buffer())),q.point=g,E&&c.lineEnd()}function v(n,t){n=Math.max(-Ja,Math.min(Ja,n)),t=Math.max(-Ja,Math.min(Ja,t));var e=h(n,t);if(y&&M.push([n,t]),k)x=n,b=t,_=e,k=!1,e&&(c.lineStart(),c.point(n,t));else if(e&&E)c.point(n,t);else{var r=[w,S],u=[n,t];a(r,u)?(E||(c.lineStart(),c.point(r[0],r[1])),c.point(u[0],u[1]),e||c.lineEnd(),A=!1):e&&(c.lineStart(),c.point(n,t),A=!1)}w=n,S=t,E=e}var m,y,M,x,b,_,w,S,E,k,A,N=c,T=Jt(),q={point:g,lineStart:p,lineEnd:d,polygonStart:function(){c=T,m=[],y=[],A=!0},polygonEnd:function(){c=N,m=mo.merge(m);var t=l([n,r]),e=A&&t,u=m.length;(e||u)&&(c.polygonStart(),e&&(c.lineStart(),f(null,null,1,c),c.lineEnd()),u&&Xt(m,i,t,f,c),c.polygonEnd()),m=y=M=null}};return q}}function ue(n,t,e){if(Math.abs(t)=n;var r=n/t;if(t>0){if(r>e[1])return!1;r>e[0]&&(e[0]=r)}else{if(rn&&(Qa=n),n>tc&&(tc=n),nc>t&&(nc=t),t>ec&&(ec=t)}function se(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=fe(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=fe(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function fe(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function he(n,t){Oa+=n,Ra+=t,++Ya}function ge(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);Ia+=o*(t+n)/2,Ua+=o*(e+r)/2,Za+=o,he(t=n,e=r)}var t,e;ic.point=function(r,u){ic.point=n,he(t=r,e=u)}}function pe(){ic.point=he}function de(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);Ia+=o*(r+n)/2,Ua+=o*(u+t)/2,Za+=o,o=u*n-r*t,Va+=o*(r+n),Xa+=o*(u+t),$a+=3*o,he(r=n,u=t)}var t,e,r,u;ic.point=function(i,o){ic.point=n,he(t=r=i,e=u=o)},ic.lineEnd=function(){n(t,e)}}function ve(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,Wo)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:c};return a}function me(n){function t(t){function r(e,r){e=n(e,r),t.point(e[0],e[1])}function u(){M=0/0,S.point=o,t.lineStart()}function o(r,u){var o=Ct([r,u]),a=n(r,u);e(M,x,y,b,_,w,M=a[0],x=a[1],y=r,b=o[0],_=o[1],w=o[2],i,t),t.point(M,x)}function a(){S.point=r,t.lineEnd()}function c(){u(),S.point=l,S.lineEnd=s}function l(n,t){o(f=n,h=t),g=M,p=x,d=b,v=_,m=w,S.point=o}function s(){e(M,x,y,b,_,w,g,p,f,d,v,m,i,t),S.lineEnd=a,a()}var f,h,g,p,d,v,m,y,M,x,b,_,w,S={point:r,lineStart:u,lineEnd:a,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=u}};return S}function e(t,i,o,a,c,l,s,f,h,g,p,d,v,m){var y=s-t,M=f-i,x=y*y+M*M;if(x>4*r&&v--){var b=a+g,_=c+p,w=l+d,S=Math.sqrt(b*b+_*_+w*w),E=Math.asin(w/=S),k=Math.abs(Math.abs(w)-1)r||Math.abs((y*q+M*z)/x-.5)>.3||u>a*g+c*p+l*d)&&(e(t,i,o,a,c,l,N,T,k,b/=S,_/=S,w,v,m),m.point(N,T),e(N,T,k,b,_,w,s,f,h,g,p,d,v,m))}}var r=.5,u=Math.cos(30*Qo),i=16;return t.precision=function(n){return arguments.length?(i=(r=n*n)>0&&16,t):Math.sqrt(r)},t}function ye(n){this.stream=n}function Me(n){var t=me(function(t,e){return n([t*na,e*na])});return function(n){var e=new ye(n=t(n));return e.point=function(t,e){n.point(t*Qo,e*Qo)},e}}function xe(n){return be(function(){return n})()}function be(n){function t(n){return n=a(n[0]*Qo,n[1]*Qo),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*na,n[1]*na]}function r(){a=ie(o=Ee(m,y,M),i);var n=i(d,v);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=me(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,d=0,v=0,m=0,y=0,M=0,x=Wa,b=dt,_=null,w=null;return t.stream=function(n){return s&&(s.valid=!1),s=_e(x(o,f(b(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(x=null==n?(_=n,Wa):ee((_=+n)*Qo),u()):_},t.clipExtent=function(n){return arguments.length?(w=n,b=n?re(n[0][0],n[0][1],n[1][0],n[1][1]):dt,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(d=n[0]%360*Qo,v=n[1]%360*Qo,r()):[d*na,v*na]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Qo,y=n[1]%360*Qo,M=n.length>2?n[2]%360*Qo:0,r()):[m*na,y*na,M*na]},mo.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function _e(n){var t=new ye(n);return t.point=function(t,e){n.point(t*Qo,e*Qo)},t}function we(n,t){return[n,t]}function Se(n,t){return[n>Bo?n-Wo:-Bo>n?n+Wo:n,t]}function Ee(n,t,e){return n?t||e?ie(Ae(n),Ne(t,e)):Ae(n):t||e?Ne(t,e):Se}function ke(n){return function(t,e){return t+=n,[t>Bo?t-Wo:-Bo>t?t+Wo:t,e]}}function Ae(n){var t=ke(n);return t.invert=ke(-n),t}function Ne(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),O(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),O(s*r-a*u)]},e}function Te(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=qe(e,u),i=qe(e,i),(o>0?i>u:u>i)&&(u+=o*Wo)):(u=n+o*Wo,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=Pt([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function qe(n,t){var e=Ct(t);e[0]-=n,Ft(e);var r=P(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Go)%(2*Math.PI)}function ze(n,t,e){var r=mo.range(n,t-Go,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function Ce(n,t,e){var r=mo.range(n,t-Go,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function De(n){return n.source}function je(n){return n.target}function Le(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(U(r-t)+u*o*U(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*na,Math.atan2(o,Math.sqrt(r*r+u*u))*na]}:function(){return[n*na,t*na]};return p.distance=h,p}function He(){function n(n,u){var i=Math.sin(u*=Qo),o=Math.cos(u),a=Math.abs((n*=Qo)-t),c=Math.cos(a);oc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;ac.point=function(u,i){t=u*Qo,e=Math.sin(i*=Qo),r=Math.cos(i),ac.point=n},ac.lineEnd=function(){ac.point=ac.lineEnd=c}}function Fe(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function Pe(n,t){function e(n,t){var e=Math.abs(Math.abs(t)-Jo)1&&u.push("H",r[0]),u.join("")}function We(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function fr(n){return n.length<3?Xe(n):n[0]+nr(n,sr(n))}function hr(n,t,e,r){var u,i,o,a,c,l,s;return u=r[n],i=u[0],o=u[1],u=r[t],a=u[0],c=u[1],u=r[e],l=u[0],s=u[1],(s-o)*(a-i)-(c-o)*(l-i)>0}function gr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function pr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function dr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function vr(n,t){var e={list:n.map(function(n,t){return{index:t,x:n[0],y:n[1]}}).sort(function(n,t){return n.yt.y?1:n.xt.x?1:0}),bottomSite:null},r={list:[],leftEnd:null,rightEnd:null,init:function(){r.leftEnd=r.createHalfEdge(null,"l"),r.rightEnd=r.createHalfEdge(null,"l"),r.leftEnd.r=r.rightEnd,r.rightEnd.l=r.leftEnd,r.list.unshift(r.leftEnd,r.rightEnd)},createHalfEdge:function(n,t){return{edge:n,side:t,vertex:null,l:null,r:null}},insert:function(n,t){t.l=n,t.r=n.r,n.r.l=t,n.r=t},leftBound:function(n){var t=r.leftEnd;do t=t.r;while(t!=r.rightEnd&&u.rightOf(t,n));return t=t.l},del:function(n){n.l.r=n.r,n.r.l=n.l,n.edge=null},right:function(n){return n.r},left:function(n){return n.l},leftRegion:function(n){return null==n.edge?e.bottomSite:n.edge.region[n.side]},rightRegion:function(n){return null==n.edge?e.bottomSite:n.edge.region[yc[n.side]]}},u={bisect:function(n,t){var e={region:{l:n,r:t},ep:{l:null,r:null}},r=t.x-n.x,u=t.y-n.y,i=r>0?r:-r,o=u>0?u:-u;return e.c=n.x*r+n.y*u+.5*(r*r+u*u),i>o?(e.a=1,e.b=u/r,e.c/=r):(e.b=1,e.a=r/u,e.c/=u),e},intersect:function(n,t){var e=n.edge,r=t.edge;if(!e||!r||e.region.r==r.region.r)return null;var u=e.a*r.b-e.b*r.a;if(Math.abs(u)<1e-10)return null;var i,o,a=(e.c*r.b-r.c*e.b)/u,c=(r.c*e.a-e.c*r.a)/u,l=e.region.r,s=r.region.r;l.y=o.region.r.x;return f&&"l"===i.side||!f&&"r"===i.side?null:{x:a,y:c}},rightOf:function(n,t){var e=n.edge,r=e.region.r,u=t.x>r.x;if(u&&"l"===n.side)return 1;if(!u&&"r"===n.side)return 0;if(1===e.a){var i=t.y-r.y,o=t.x-r.x,a=0,c=0;if(!u&&e.b<0||u&&e.b>=0?c=a=i>=e.b*o:(c=t.x+t.y*e.b>e.c,e.b<0&&(c=!c),c||(a=1)),!a){var l=r.x-e.region.l.x;c=e.b*(o*o-i*i)h*h+g*g}return"l"===n.side?c:!c},endPoint:function(n,e,r){n.ep[e]=r,n.ep[yc[e]]&&t(n)},distance:function(n,t){var e=n.x-t.x,r=n.y-t.y;return Math.sqrt(e*e+r*r)}},i={list:[],insert:function(n,t,e){n.vertex=t,n.ystar=t.y+e;for(var r=0,u=i.list,o=u.length;o>r;r++){var a=u[r];if(!(n.ystar>a.ystar||n.ystar==a.ystar&&t.x>a.vertex.x))break}u.splice(r,0,n)},del:function(n){for(var t=0,e=i.list,r=e.length;r>t&&e[t]!=n;++t);e.splice(t,1)},empty:function(){return 0===i.list.length},nextEvent:function(n){for(var t=0,e=i.list,r=e.length;r>t;++t)if(e[t]==n)return e[t+1];return null},min:function(){var n=i.list[0];return{x:n.vertex.x,y:n.ystar}},extractMin:function(){return i.list.shift()}};r.init(),e.bottomSite=e.list.shift();for(var o,a,c,l,s,f,h,g,p,d,v,m,y,M=e.list.shift();;)if(i.empty()||(o=i.min()),M&&(i.empty()||M.yg.y&&(p=h,h=g,g=p,y="r"),m=u.bisect(h,g),f=r.createHalfEdge(m,y),r.insert(l,f),u.endPoint(m,yc[y],v),d=u.intersect(l,f),d&&(i.del(l),i.insert(l,d,u.distance(d,h))),d=u.intersect(f,s),d&&i.insert(f,d,u.distance(d,h))}for(a=r.right(r.leftEnd);a!=r.rightEnd;a=r.right(a))t(a.edge)}function mr(n){return n.x}function yr(n){return n.y}function Mr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function xr(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&xr(n,c[0],e,r,o,a),c[1]&&xr(n,c[1],o,r,u,a),c[2]&&xr(n,c[2],e,a,o,i),c[3]&&xr(n,c[3],o,a,u,i)}}function br(n,t){n=mo.rgb(n),t=mo.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+ct(Math.round(e+i*n))+ct(Math.round(r+o*n))+ct(Math.round(u+a*n))}}function _r(n,t){var e,r={},u={};for(e in n)e in t?r[e]=Er(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function wr(n,t){return t-=n=+n,function(e){return n+t*e}}function Sr(n,t){var e,r,u,i,o,a=0,c=0,l=[],s=[];for(n+="",t+="",Mc.lastIndex=0,r=0;e=Mc.exec(t);++r)e.index&&l.push(t.substring(a,c=e.index)),s.push({i:l.length,x:e[0]}),l.push(null),a=Mc.lastIndex;for(ar;++r)if(o=s[r],o.x==e[0]){if(o.i)if(null==l[o.i+1])for(l[o.i-1]+=o.x,l.splice(o.i,1),u=r+1;i>u;++u)s[u].i--;else for(l[o.i-1]+=o.x+l[o.i+1],l.splice(o.i,2),u=r+1;i>u;++u)s[u].i-=2;else if(null==l[o.i+1])l[o.i]=o.x;else for(l[o.i]=o.x+l[o.i+1],l.splice(o.i+1,1),u=r+1;i>u;++u)s[u].i--;s.splice(r,1),i--,r--}else o.x=wr(parseFloat(e[0]),parseFloat(o.x));for(;i>r;)o=s.pop(),null==l[o.i+1]?l[o.i]=o.x:(l[o.i]=o.x+l[o.i+1],l.splice(o.i+1,1)),i--;return 1===l.length?null==l[0]?(o=s[0].x,function(n){return o(n)+""}):function(){return t}:function(n){for(r=0;i>r;++r)l[(o=s[r]).i]=o.x(n);return l.join("")}}function Er(n,t){for(var e,r=mo.interpolators.length;--r>=0&&!(e=mo.interpolators[r](n,t)););return e}function kr(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(Er(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Ar(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function Nr(n){return function(t){return 1-n(1-t)}}function Tr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function qr(n){return n*n}function zr(n){return n*n*n}function Cr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Dr(n){return function(t){return Math.pow(t,n)}}function jr(n){return 1-Math.cos(n*Jo)}function Lr(n){return Math.pow(2,10*(n-1))}function Hr(n){return 1-Math.sqrt(1-n*n)}function Fr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Wo*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Wo/t)}}function Pr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Or(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=mo.hcl(n),t=mo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return J(e+i*n,r+o*n,u+a*n)+""}}function Yr(n,t){n=mo.hsl(n),t=mo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return $(e+i*n,r+o*n,u+a*n)+""}}function Ir(n,t){n=mo.lab(n),t=mo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return Q(e+i*n,r+o*n,u+a*n)+""}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Zr(n){var t=[n.a,n.b],e=[n.c,n.d],r=Xr(t),u=Vr(t,e),i=Xr($r(e,t,-u))||0;t[0]*e[1]180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:wr(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:wr(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:wr(g[0],p[0])},{i:e-2,x:wr(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++ie;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function vu(n){return n.reduce(mu,0)}function mu(n,t){return n+t[1]}function yu(n,t){return Mu(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function Mu(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function xu(n){return[mo.min(n),mo.max(n)]}function bu(n,t){return n.parent==t.parent?1:2}function _u(n){var t=n.children;return t&&t.length?t[0]:n._tree.thread}function wu(n){var t,e=n.children;return e&&(t=e.length)?e[t-1]:n._tree.thread}function Su(n,t){var e=n.children;if(e&&(u=e.length))for(var r,u,i=-1;++i0&&(n=r);return n}function Eu(n,t){return n.x-t.x}function ku(n,t){return t.x-n.x}function Au(n,t){return n.depth-t.depth}function Nu(n,t){function e(n,r){var u=n.children;if(u&&(o=u.length))for(var i,o,a=null,c=-1;++c=0;)t=u[i]._tree,t.prelim+=e,t.mod+=e,e+=t.shift+(r+=t.change)}function qu(n,t,e){n=n._tree,t=t._tree;var r=e/(t.number-n.number);n.change+=r,t.change-=r,t.shift+=e,t.prelim+=e,t.mod+=e}function zu(n,t,e){return n._tree.ancestor.parent==t.parent?n._tree.ancestor:e}function Cu(n,t){return n.value-t.value}function Du(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function ju(n,t){n._pack_next=t,t._pack_prev=n}function Lu(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Hu(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(Fu),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],Ru(r,u,i),t(i),Du(r,i),r._pack_prev=i,Du(i,u),u=r._pack_next,o=3;l>o;o++){Ru(r,u,i=e[o]);var p=0,d=1,v=1;for(a=u._pack_next;a!==u;a=a._pack_next,d++)if(Lu(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!Lu(c,i);c=c._pack_prev,v++);p?(v>d||d==v&&u.ro;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(Pu)}}function Fu(n){n._pack_next=n._pack_prev=n}function Pu(n){delete n._pack_next,delete n._pack_prev}function Ou(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++iu&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function $u(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Bu(n){return n.rangeExtent?n.rangeExtent():$u(n.range())}function Wu(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Ju(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Gu(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:Tc}function Ku(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]2?Ku:Wu,c=r?Jr:Wr;return o=u(n,t,c,e),a=u(t,n,c,Er),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Ur)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return ri(n,t)},i.tickFormat=function(t,e){return ui(n,t,e)},i.nice=function(t){return ti(n,t),u()},i.copy=function(){return Qu(n,t,e,r)},u()}function ni(n,t){return mo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function ti(n,t){return Ju(n,Gu(ei(n,t)[2]))}function ei(n,t){null==t&&(t=10);var e=$u(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function ri(n,t){return mo.range.apply(mo,ei(n,t))}function ui(n,t,e){var r=-Math.floor(Math.log(ei(n,t)[2])/Math.LN10+.01);return mo.format(e?e.replace(Aa,function(n,t,e,u,i,o,a,c,l,s){return[t,e,u,i,o,a,c,l||"."+(r-2*("%"===s)),s].join("")}):",."+r+"f")}function ii(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Ju(r.map(u),e?Math:zc);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=$u(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++0;h--)o.push(i(l)*h);for(l=0;o[l]c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return qc;arguments.length<2?t=qc:"function"!=typeof t&&(t=mo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return ii(n.copy(),t,e,r)},ni(o,n)}function oi(n,t,e){function r(t){return n(u(t))}var u=ai(t),i=ai(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return ri(e,n)},r.tickFormat=function(n,t){return ui(e,n,t)},r.nice=function(n){return r.domain(ti(e,n))},r.exponent=function(o){return arguments.length?(u=ai(t=o),i=ai(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return oi(n.copy(),t,e)},ni(r,n)}function ai(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ci(n,t){function e(e){return o[((i.get(e)||"range"===t.t&&i.set(e,n.push(e)))-1)%o.length]}function r(t,e){return mo.range(n.length).map(function(n){return t+e*n})}var i,o,a;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new u;for(var o,a=-1,c=r.length;++ae?[0/0,0/0]:[e>0?u[e-1]:n[0],et?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return si(n,t,e)},u()}function fi(n,t){function e(e){return e>=e?t[mo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return fi(n,t)},e}function hi(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return ri(n,t)},t.tickFormat=function(t,e){return ui(n,t,e)},t.copy=function(){return hi(n)},t}function gi(n){return n.innerRadius}function pi(n){return n.outerRadius}function di(n){return n.startAngle}function vi(n){return n.endAngle}function mi(n){for(var t,e,r,u=-1,i=n.length;++ue?l():(i.active=e,o.event&&o.event.start.call(n,s,t),o.tween.forEach(function(e,r){(r=r.call(n,s,t))&&p.push(r)}),c(r||1)?1:(xt(c,h,a),void 0))}function c(r){if(i.active!==e)return l();for(var u=r/g,a=f(u),c=p.length;c>0;)p[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,s,t),l()):void 0}function l(){return--i.count?delete i[e]:delete n.__transition__,1}var s=n.__data__,f=o.ease,h=o.delay,g=o.duration,p=[];return r>=h?u(r-h):(xt(u,h,a),void 0)},0,a)}}function Ti(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function qi(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function zi(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ci(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new Jc(e-1)),1),e}function i(n,e){return t(n=new Jc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{Jc=zi;var r=new zi;return r._=n,o(r,t,e)}finally{Jc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Di(n);return c.floor=c,c.round=Di(r),c.ceil=Di(u),c.offset=Di(i),c.range=a,n}function Di(n){return function(t,e){try{Jc=zi;var r=new zi;return r._=t,n(r,e)._}finally{Jc=Date}}}function ji(n){function t(t){for(var r,u,i,o=[],a=-1,c=0;++aa;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=ml[o in dl?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function Hi(n){return new RegExp("^(?:"+n.map(mo.requote).join("|")+")","i")}function Fi(n){for(var t=new u,e=-1,r=n.length;++en?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Oi(n,t,e){cl.lastIndex=0;var r=cl.exec(t.substring(e));return r?(n.w=ll.get(r[0].toLowerCase()),e+r[0].length):-1}function Ri(n,t,e){ol.lastIndex=0;var r=ol.exec(t.substring(e));return r?(n.w=al.get(r[0].toLowerCase()),e+r[0].length):-1}function Yi(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Ii(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e));return r?(n.U=+r[0],e+r[0].length):-1}function Ui(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function Zi(n,t,e){hl.lastIndex=0;var r=hl.exec(t.substring(e));return r?(n.m=gl.get(r[0].toLowerCase()),e+r[0].length):-1}function Vi(n,t,e){sl.lastIndex=0;var r=sl.exec(t.substring(e));return r?(n.m=fl.get(r[0].toLowerCase()),e+r[0].length):-1}function Xi(n,t,e){return Li(n,vl.c.toString(),t,e)}function $i(n,t,e){return Li(n,vl.x.toString(),t,e)}function Bi(n,t,e){return Li(n,vl.X.toString(),t,e)}function Wi(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Ji(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+2));return r?(n.y=Ki(+r[0]),e+r[0].length):-1}function Gi(n,t,e){return/^[+-]\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=+t,e+5):-1}function Ki(n){return n+(n>68?1900:2e3)}function Qi(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function no(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function to(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function eo(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ro(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function uo(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function io(n,t,e){yl.lastIndex=0;var r=yl.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function oo(n,t,e){var r=Ml.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}function ao(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(Math.abs(t)/60),u=Math.abs(t)%60;return e+Pi(r,"0",2)+Pi(u,"0",2)}function co(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function lo(n){function t(n){try{Jc=zi;var t=new Jc;return t._=n,e(t)}finally{Jc=Date}}var e=ji(n);return t.parse=function(n){try{Jc=zi;var t=e.parse(n);return t&&t._}finally{Jc=Date}},t.toString=e.toString,t}function so(n){return n.toISOString()}function fo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=mo.bisect(bl,u);return i==bl.length?[t.year,ei(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/bl[i-1]1?{floor:function(t){for(;e(t=n.floor(t));)t=ho(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=ho(+t+1);return t}}:n))},r.ticks=function(n,t){var e=$u(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],ho(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return fo(n.copy(),t,e)},ni(r,n)}function ho(n){return new Date(n)}function go(n){return function(t){for(var e=n.length-1,r=n[e];!r[1](t);)r=n[--e];return r[0](t)}}function po(n){return JSON.parse(n.responseText)}function vo(n){var t=xo.createRange();return t.selectNode(xo.body),t.createContextualFragment(n.responseText)}var mo={version:"3.3.6"};Date.now||(Date.now=function(){return+new Date});var yo=[].slice,Mo=function(n){return yo.call(n)},xo=document,bo=xo.documentElement,_o=window;try{Mo(bo.childNodes)[0].nodeType}catch(wo){Mo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{xo.createElement("div").style.setProperty("opacity",0,"")}catch(So){var Eo=_o.Element.prototype,ko=Eo.setAttribute,Ao=Eo.setAttributeNS,No=_o.CSSStyleDeclaration.prototype,To=No.setProperty;Eo.setAttribute=function(n,t){ko.call(this,n,t+"")},Eo.setAttributeNS=function(n,t,e){Ao.call(this,n,t,e+"")},No.setProperty=function(n,t,e){To.call(this,n,t+"",e)}}mo.ascending=function(n,t){return t>n?-1:n>t?1:n>=t?0:0/0},mo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},mo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=e);)e=void 0;for(;++ur&&(e=r)}else{for(;++u=e);)e=void 0;for(;++ur&&(e=r)}return e},mo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=e);)e=void 0;for(;++ue&&(e=r)}else{for(;++u=e);)e=void 0;for(;++ue&&(e=r)}return e},mo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i=e);)e=u=void 0;for(;++ir&&(e=r),r>u&&(u=r))}else{for(;++i=e);)e=void 0;for(;++ir&&(e=r),r>u&&(u=r))}return[e,u]},mo.sum=function(n,t){var e,r=0,u=n.length,i=-1;if(1===arguments.length)for(;++i1&&(t=t.map(e)),t=t.filter(n),t.length?mo.quantile(t.sort(mo.ascending),.5):void 0},mo.bisector=function(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n.call(t,t[i],i)r;){var i=r+u>>>1;er?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},mo.zip=function(){if(!(u=arguments.length))return[];for(var n=-1,e=mo.min(arguments,t),r=new Array(e);++nr)for(;(u=n+r*++a)>t;)i.push(u/o);else for(;(u=n+r*++a)=o.length)return r?r.call(i,a):e?a.sort(e):a;for(var l,s,f,h,g=-1,p=a.length,d=o[c++],v=new u;++g=o.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,i={},o=[],a=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(mo.map,e,0),0)},i.key=function(n){return o.push(n),i},i.sortKeys=function(n){return a[o.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},mo.set=function(n){var t=new i;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},r(i,{has:function(n){return zo+n in this},add:function(n){return this[zo+n]=!0,n},remove:function(n){return n=zo+n,n in this&&delete this[n]},values:function(){var n=[];return this.forEach(function(t){n.push(t)}),n},forEach:function(n){for(var t in this)t.charCodeAt(0)===Co&&n.call(this,t.substring(1))}}),mo.behavior={},mo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},mo.event=null,mo.requote=function(n){return n.replace(jo,"\\$&")};var jo=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,Lo={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ho=function(n,t){return t.querySelector(n)},Fo=function(n,t){return t.querySelectorAll(n)},Po=bo[a(bo,"matchesSelector")],Oo=function(n,t){return Po.call(n,t)};"function"==typeof Sizzle&&(Ho=function(n,t){return Sizzle(n,t)[0]||null},Fo=function(n,t){return Sizzle.uniqueSort(Sizzle(n,t))},Oo=Sizzle.matchesSelector),mo.selection=function(){return Uo};var Ro=mo.selection.prototype=[];Ro.select=function(n){var t,e,r,u,i=[];n=d(n);for(var o=-1,a=this.length;++o=0&&(e=n.substring(0,t),n=n.substring(t+1)),Yo.hasOwnProperty(e)?{space:Yo[e],local:n}:n}},Ro.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=mo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(m(t,n[t]));return this}return this.each(m(n,t))},Ro.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=n.trim().split(/^|\s+/g)).length,u=-1;if(t=e.classList){for(;++ur){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(_(e,n[e],t));return this}if(2>r)return _o.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(_(n,t,e))},Ro.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(w(t,n[t]));return this}return this.each(w(n,t))},Ro.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Ro.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Ro.append=function(n){return n=S(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Ro.insert=function(n,t){return n=S(n),t=d(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments))})},Ro.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},Ro.data=function(n,t){function e(n,e){var r,i,o,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),d=new Array(a);if(t){var v,m=new u,y=new u,M=[];for(r=-1;++rr;++r)p[r]=E(e[r]);for(;a>r;++r)d[r]=n[r]}p.update=g,p.parentNode=g.parentNode=d.parentNode=n.parentNode,c.push(p),l.push(g),s.push(d)}var r,i,o=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++oi;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a)&&t.push(r)}return p(u)},Ro.order=function(){for(var n=-1,t=this.length;++n=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},Ro.sort=function(n){n=A.apply(this,arguments);for(var t=-1,e=this.length;++tn;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},Ro.size=function(){var n=0;return this.each(function(){++n}),n};var Io=[];mo.selection.enter=T,mo.selection.enter.prototype=Io,Io.append=Ro.append,Io.empty=Ro.empty,Io.node=Ro.node,Io.call=Ro.call,Io.size=Ro.size,Io.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++ar){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(C(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(C(n,t,e))};var Zo=mo.map({mouseenter:"mouseover",mouseleave:"mouseout"});Zo.forEach(function(n){"on"+n in xo&&Zo.remove(n)});var Vo=a(bo.style,"userSelect"),Xo=0;mo.mouse=function(n){return H(n,h())};var $o=/WebKit/.test(_o.navigator.userAgent)?-1:0;mo.touches=function(n,t){return arguments.length<2&&(t=h().touches),t?Mo(t).map(function(t){var e=H(n,t);return e.identifier=t.identifier,e}):[]},mo.behavior.drag=function(){function n(){this.on("mousedown.drag",o).on("touchstart.drag",a)}function t(){return mo.event.changedTouches[0].identifier}function e(n,t){return mo.touches(n).filter(function(n){return n.identifier===t})[0]}function r(n,t,e,r){return function(){function o(){var n=t(s,g),e=n[0]-d[0],r=n[1]-d[1];v|=e|r,d=n,f({type:"drag",x:n[0]+c[0],y:n[1]+c[1],dx:e,dy:r})}function a(){m.on(e+"."+p,null).on(r+"."+p,null),y(v&&mo.event.target===h),f({type:"dragend"})}var c,l=this,s=l.parentNode,f=u.of(l,arguments),h=mo.event.target,g=n(),p=null==g?"drag":"drag-"+g,d=t(s,g),v=0,m=mo.select(_o).on(e+"."+p,o).on(r+"."+p,a),y=L();i?(c=i.apply(l,arguments),c=[c.x-d[0],c.y-d[1]]):c=[0,0],f({type:"dragstart"})}}var u=g(n,"drag","dragstart","dragend"),i=null,o=r(c,mo.mouse,"mousemove","mouseup"),a=r(t,e,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},mo.rebind(n,u,"on")};var Bo=Math.PI,Wo=2*Bo,Jo=Bo/2,Go=1e-6,Ko=Go*Go,Qo=Bo/180,na=180/Bo,ta=Math.SQRT2,ea=2,ra=4;mo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=Y(d),o=i/(ea*h)*(e*I(ta*t+d)-R(d));return[r+o*l,u+o*s,i*e/Y(ta*t+d)]}return[r+n*l,u+n*s,i*Math.exp(ta*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+ra*f)/(2*i*ea*h),p=(c*c-i*i-ra*f)/(2*c*ea*h),d=Math.log(Math.sqrt(g*g+1)-g),v=Math.log(Math.sqrt(p*p+1)-p),m=v-d,y=(m||Math.log(c/i))/ta;return e.duration=1e3*y,e},mo.behavior.zoom=function(){function n(n){n.on(A,l).on(oa+".zoom",h).on(N,p).on("dblclick.zoom",d).on(q,s)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(k[0],Math.min(k[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){b&&b.domain(x.range().map(function(n){return(n-S.x)/S.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-S.y)/S.k}).map(_.invert))}function o(n){n({type:"zoomstart"})}function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:"zoomend"})}function l(){function n(){s=1,u(mo.mouse(r),h),a(i)}function e(){f.on(N,_o===r?p:null).on(T,null),g(s&&mo.event.target===l),c(i)}var r=this,i=C.of(r,arguments),l=mo.event.target,s=0,f=mo.select(_o).on(N,n).on(T,e),h=t(mo.mouse(r)),g=L();z.call(r),o(i)}function s(){function n(){var n=mo.touches(p);return g=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){for(var t=mo.event.changedTouches,e=0,i=t.length;i>e;++e)v[t[e].identifier]=null;var o=n(),c=Date.now();if(1===o.length){if(500>c-M){var l=o[0],s=v[l.identifier];r(2*S.k),u(l,s),f(),a(d)}M=c}else if(o.length>1){var l=o[0],h=o[1],g=l[0]-h[0],p=l[1]-h[1];m=g*g+p*p}}function i(){for(var n,t,e,i,o=mo.touches(p),c=0,l=o.length;l>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*g)}M=null,u(n,t),a(d)}function h(){if(mo.event.touches.length){for(var t=mo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}_.on(x,null).on(b,null),w.on(A,l).on(q,s),E(),c(d)}var g,p=this,d=C.of(p,arguments),v={},m=0,y=mo.event.changedTouches[0].identifier,x="touchmove.zoom-"+y,b="touchend.zoom-"+y,_=mo.select(_o).on(x,i).on(b,h),w=mo.select(p).on(A,null).on(q,e),E=L();z.call(p),e(),o(d)}function h(){var n=C.of(this,arguments);y?clearTimeout(y):(z.call(this),o(n)),y=setTimeout(function(){y=null,c(n)},50),f();var e=m||mo.mouse(this);v||(v=t(e)),r(Math.pow(2,.002*ua())*S.k),u(e,v),a(n)}function p(){v=null}function d(){var n=C.of(this,arguments),e=mo.mouse(this),i=t(e),l=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,mo.event.shiftKey?Math.ceil(l)-1:Math.floor(l)+1)),u(e,i),a(n),c(n)}var v,m,y,M,x,b,_,w,S={x:0,y:0,k:1},E=[960,500],k=ia,A="mousedown.zoom",N="mousemove.zoom",T="mouseup.zoom",q="touchstart.zoom",C=g(n,"zoomstart","zoom","zoomend");return n.event=function(n){n.each(function(){var n=C.of(this,arguments),t=S;Oc?mo.select(this).transition().each("start.zoom",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween("zoom:zoom",function(){var e=E[0],r=E[1],u=e/2,i=r/2,o=mo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each("end.zoom",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(k=null==t?ia:[+t[0],+t[1]],n):k},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.x=function(t){return arguments.length?(b=t,x=t.copy(),S={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),S={x:0,y:0,k:1},n):w},mo.rebind(n,C,"on")};var ua,ia=[0,1/0],oa="onwheel"in xo?(ua=function(){return-mo.event.deltaY*(mo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in xo?(ua=function(){return mo.event.wheelDelta},"mousewheel"):(ua=function(){return-mo.event.detail},"MozMousePixelScroll");Z.prototype.toString=function(){return this.rgb()+""},mo.hsl=function(n,t,e){return 1===arguments.length?n instanceof X?V(n.h,n.s,n.l):lt(""+n,st,V):V(+n,+t,+e)};var aa=X.prototype=new Z;aa.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),V(this.h,this.s,this.l/n)},aa.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),V(this.h,this.s,n*this.l)},aa.rgb=function(){return $(this.h,this.s,this.l)},mo.hcl=function(n,t,e){return 1===arguments.length?n instanceof W?B(n.h,n.c,n.l):n instanceof K?nt(n.l,n.a,n.b):nt((n=ft((n=mo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):B(+n,+t,+e)};var ca=W.prototype=new Z;ca.brighter=function(n){return B(this.h,this.c,Math.min(100,this.l+la*(arguments.length?n:1)))},ca.darker=function(n){return B(this.h,this.c,Math.max(0,this.l-la*(arguments.length?n:1)))},ca.rgb=function(){return J(this.h,this.c,this.l).rgb()},mo.lab=function(n,t,e){return 1===arguments.length?n instanceof K?G(n.l,n.a,n.b):n instanceof W?J(n.l,n.c,n.h):ft((n=mo.rgb(n)).r,n.g,n.b):G(+n,+t,+e)};var la=18,sa=.95047,fa=1,ha=1.08883,ga=K.prototype=new Z;ga.brighter=function(n){return G(Math.min(100,this.l+la*(arguments.length?n:1)),this.a,this.b)},ga.darker=function(n){return G(Math.max(0,this.l-la*(arguments.length?n:1)),this.a,this.b)},ga.rgb=function(){return Q(this.l,this.a,this.b)},mo.rgb=function(n,t,e){return 1===arguments.length?n instanceof at?ot(n.r,n.g,n.b):lt(""+n,ot,$):ot(~~n,~~t,~~e)};var pa=at.prototype=new Z;pa.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),ot(Math.min(255,~~(t/n)),Math.min(255,~~(e/n)),Math.min(255,~~(r/n)))):ot(u,u,u)},pa.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),ot(~~(n*this.r),~~(n*this.g),~~(n*this.b))},pa.hsl=function(){return st(this.r,this.g,this.b)},pa.toString=function(){return"#"+ct(this.r)+ct(this.g)+ct(this.b)};var da=mo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});da.forEach(function(n,t){da.set(n,ut(t))}),mo.functor=pt,mo.xhr=vt(dt),mo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=mo.xhr(n,t,i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o.row(e)}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function o(t){return t.map(a).join(n)}function a(n){return c.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var c=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=c)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==l)continue;return n.substring(t,s-a)}return n.substring(t)}for(var r,u,i={},o={},a=[],c=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();(!t||(h=t(h,f++)))&&a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new i,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(a).join(n)].concat(t.map(function(t){return u.map(function(n){return a(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(o).join("\n")},e},mo.csv=mo.dsv(",","text/csv"),mo.tsv=mo.dsv(" ","text/tab-separated-values");var va,ma,ya,Ma,xa,ba=_o[a(_o,"requestAnimationFrame")]||function(n){setTimeout(n,17)};mo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={callback:n,time:u,next:null};ma?ma.next=i:va=i,ma=i,ya||(Ma=clearTimeout(Ma),ya=1,ba(Mt))},mo.timer.flush=function(){bt(),_t()};var _a=".",wa=",",Sa=[3,3],Ea="$",ka=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(wt);mo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=mo.round(n,St(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((0>=e?e+1:e-1)/3)))),ka[8+e/3]},mo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)},mo.format=function(n){var t=Aa.exec(n),e=t[1]||" ",r=t[2]||">",u=t[3]||"",i=t[4]||"",o=t[5],a=+t[6],c=t[7],l=t[8],s=t[9],f=1,h="",g=!1;switch(l&&(l=+l.substring(1)),(o||"0"===e&&"="===r)&&(o=e="0",r="=",c&&(a-=Math.floor((a-1)/4))),s){case"n":c=!0,s="g";break;case"%":f=100,h="%",s="f";break;case"p":f=100,h="%",s="r";break;case"b":case"o":case"x":case"X":"#"===i&&(i="0"+s.toLowerCase());case"c":case"d":g=!0,l=0;break;case"s":f=-1,s="r"}"#"===i?i="":"$"===i&&(i=Ea),"r"!=s||l||(s="g"),null!=l&&("g"==s?l=Math.max(1,Math.min(21,l)):("e"==s||"f"==s)&&(l=Math.max(0,Math.min(20,l)))),s=Na.get(s)||Et;var p=o&&c;return function(n){if(g&&n%1)return"";var t=0>n||0===n&&0>1/n?(n=-n,"-"):u;if(0>f){var d=mo.formatPrefix(n,l);n=d.scale(n),h=d.symbol}else n*=f;n=s(n,l);var v=n.lastIndexOf("."),m=0>v?n:n.substring(0,v),y=0>v?"":_a+n.substring(v+1);!o&&c&&(m=Ta(m));var M=i.length+m.length+y.length+(p?0:t.length),x=a>M?new Array(M=a-M+1).join(e):"";return p&&(m=Ta(x+m)),t+=i,n=m+y,("<"===r?t+n+x:">"===r?x+t+n:"^"===r?x.substring(0,M>>=1)+t+n+x.substring(M):t+(p?n:x+n))+h}};var Aa=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,Na=mo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=mo.round(n,St(n,t))).toFixed(Math.max(0,Math.min(20,St(n*(1+1e-15),t))))}}),Ta=dt;if(Sa){var qa=Sa.length;Ta=function(n){for(var t=n.length,e=[],r=0,u=Sa[0];t>0&&u>0;)e.push(n.substring(t-=u,t+u)),u=Sa[r=(r+1)%qa];return e.reverse().join(wa)}}mo.geo={},kt.prototype={s:0,t:0,add:function(n){At(n,this.t,za),At(za.s,this.s,this),this.s?this.t+=za.t:this.s=za.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var za=new kt;mo.geo.stream=function(n,t){n&&Ca.hasOwnProperty(n.type)?Ca[n.type](n,t):Nt(n,t)};var Ca={Feature:function(n,t){Nt(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++rn?4*Bo+n:n,Ha.lineStart=Ha.lineEnd=Ha.point=c}};mo.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=Ct([t*Qo,e*Qo]);if(m){var u=jt(m,r),i=[u[1],-u[0],0],o=jt(i,u);Ft(o),o=Pt(o);var c=t-p,l=c>0?1:-1,d=o[0]*na*l,v=Math.abs(c)>180;if(v^(d>l*p&&l*t>d)){var y=o[1]*na;y>g&&(g=y)}else if(d=(d+360)%360-180,v^(d>l*p&&l*t>d)){var y=-o[1]*na;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);v?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=Math.abs(r)>180?r+(r>0?360:-360):r}else d=n,v=e;Ha.point(n,e),t(n,e)}function i(){Ha.lineStart()}function o(){u(d,v),Ha.lineEnd(),Math.abs(y)>Go&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nLa?(s=-(h=180),f=-(g=90)):y>Go?g=90:-Go>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],mo.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),mo.geo.centroid=function(n){Fa=Pa=Oa=Ra=Ya=Ia=Ua=Za=Va=Xa=$a=0,mo.geo.stream(n,Ba);var t=Va,e=Xa,r=$a,u=t*t+e*e+r*r;return Ko>u&&(t=Ia,e=Ua,r=Za,Go>Pa&&(t=Oa,e=Ra,r=Ya),u=t*t+e*e+r*r,Ko>u)?[0/0,0/0]:[Math.atan2(e,t)*na,O(r/Math.sqrt(u))*na]};var Fa,Pa,Oa,Ra,Ya,Ia,Ua,Za,Va,Xa,$a,Ba={sphere:c,point:Rt,lineStart:It,lineEnd:Ut,polygonStart:function(){Ba.lineStart=Zt},polygonEnd:function(){Ba.lineStart=It}},Wa=Bt(Vt,Qt,te,[-Bo,-Bo/2]),Ja=1e9;mo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=re(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(mo.geo.conicEqualArea=function(){return oe(ae)}).raw=ae,mo.geo.albers=function(){return mo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},mo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=mo.geo.albers(),o=mo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=mo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Go,f+.12*l+Go],[s-.214*l-Go,f+.234*l-Go]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Go,f+.166*l+Go],[s-.115*l-Go,f+.234*l-Go]]).stream(c).point,n},n.scale(1070)};var Ga,Ka,Qa,nc,tc,ec,rc={point:c,lineStart:c,lineEnd:c,polygonStart:function(){Ka=0,rc.lineStart=ce},polygonEnd:function(){rc.lineStart=rc.lineEnd=rc.point=c,Ga+=Math.abs(Ka/2)}},uc={point:le,lineStart:c,lineEnd:c,polygonStart:c,polygonEnd:c},ic={point:he,lineStart:ge,lineEnd:pe,polygonStart:function(){ic.lineStart=de},polygonEnd:function(){ic.point=he,ic.lineStart=ge,ic.lineEnd=pe}};mo.geo.transform=function(n){return{stream:function(t){var e=new ye(t);for(var r in n)e[r]=n[r];return e}}},ye.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},mo.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),mo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Ga=0,mo.geo.stream(n,u(rc)),Ga},n.centroid=function(n){return Oa=Ra=Ya=Ia=Ua=Za=Va=Xa=$a=0,mo.geo.stream(n,u(ic)),$a?[Va/$a,Xa/$a]:Za?[Ia/Za,Ua/Za]:Ya?[Oa/Ya,Ra/Ya]:[0/0,0/0]},n.bounds=function(n){return tc=ec=-(Qa=nc=1/0),mo.geo.stream(n,u(uc)),[[Qa,nc],[tc,ec]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||Me(n):dt,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new se:new ve(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(mo.geo.albersUsa()).context(null)},mo.geo.projection=xe,mo.geo.projectionMutator=be,(mo.geo.equirectangular=function(){return xe(we)}).raw=we.invert=we,mo.geo.rotation=function(n){function t(t){return t=n(t[0]*Qo,t[1]*Qo),t[0]*=na,t[1]*=na,t}return n=Ee(n[0]%360*Qo,n[1]*Qo,n.length>2?n[2]*Qo:0),t.invert=function(t){return t=n.invert(t[0]*Qo,t[1]*Qo),t[0]*=na,t[1]*=na,t},t},Se.invert=we,mo.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=Ee(-n[0]*Qo,-n[1]*Qo,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=na,n[1]*=na}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=Te((t=+r)*Qo,u*Qo),n):t},n.precision=function(r){return arguments.length?(e=Te(t*Qo,(u=+r)*Qo),n):u},n.angle(90)},mo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Qo,u=n[1]*Qo,i=t[1]*Qo,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},mo.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return mo.range(Math.ceil(i/v)*v,u,v).map(h).concat(mo.range(Math.ceil(l/m)*m,c,m).map(g)).concat(mo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return Math.abs(n%v)>Go +}).map(s)).concat(mo.range(Math.ceil(a/d)*d,o,d).filter(function(n){return Math.abs(n%m)>Go}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,d=p,v=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(v=+t[0],m=+t[1],n):[v,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],d=+t[1],n):[p,d]},n.precision=function(t){return arguments.length?(y=+t,s=ze(a,o,90),f=Ce(r,e,y),h=ze(l,c,90),g=Ce(i,u,y),n):y},n.majorExtent([[-180,-90+Go],[180,90-Go]]).minorExtent([[-180,-80-Go],[180,80+Go]])},mo.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=De,u=je;return n.distance=function(){return mo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},mo.geo.interpolate=function(n,t){return Le(n[0]*Qo,n[1]*Qo,t[0]*Qo,t[1]*Qo)},mo.geo.length=function(n){return oc=0,mo.geo.stream(n,ac),oc};var oc,ac={sphere:c,point:c,lineStart:He,lineEnd:c,polygonStart:c,polygonEnd:c},cc=Fe(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(mo.geo.azimuthalEqualArea=function(){return xe(cc)}).raw=cc;var lc=Fe(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},dt);(mo.geo.azimuthalEquidistant=function(){return xe(lc)}).raw=lc,(mo.geo.conicConformal=function(){return oe(Pe)}).raw=Pe,(mo.geo.conicEquidistant=function(){return oe(Oe)}).raw=Oe;var sc=Fe(function(n){return 1/n},Math.atan);(mo.geo.gnomonic=function(){return xe(sc)}).raw=sc,Re.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Jo]},(mo.geo.mercator=function(){return Ye(Re)}).raw=Re;var fc=Fe(function(){return 1},Math.asin);(mo.geo.orthographic=function(){return xe(fc)}).raw=fc;var hc=Fe(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(mo.geo.stereographic=function(){return xe(hc)}).raw=hc,Ie.invert=function(n,t){return[Math.atan2(R(n),Math.cos(t)),O(Math.sin(t)/Y(n))]},(mo.geo.transverseMercator=function(){return Ye(Ie)}).raw=Ie,mo.geom={},mo.svg={},mo.svg.line=function(){return Ue(dt)};var gc=mo.map({linear:Xe,"linear-closed":$e,step:Be,"step-before":We,"step-after":Je,basis:er,"basis-open":rr,"basis-closed":ur,bundle:ir,cardinal:Qe,"cardinal-open":Ge,"cardinal-closed":Ke,monotone:fr});gc.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var pc=[0,2/3,1/3,0],dc=[0,1/3,2/3,0],vc=[0,1/6,2/3,1/6];mo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u,i,o,a,c,l,s,f,h,g,p,d=pt(e),v=pt(r),m=n.length,y=m-1,M=[],x=[],b=0;if(d===Ze&&r===Ve)t=n;else for(i=0,t=[];m>i;++i)t.push([+d.call(this,u=n[i],i),+v.call(this,u,i)]);for(i=1;m>i;++i)(t[i][1]i;++i)i!==b&&(c=t[i][1]-t[b][1],a=t[i][0]-t[b][0],M.push({angle:Math.atan2(c,a),index:i}));for(M.sort(function(n,t){return n.angle-t.angle}),g=M[0].angle,h=M[0].index,f=0,i=1;y>i;++i){if(o=M[i].index,g==M[i].angle){if(a=t[h][0]-t[b][0],c=t[h][1]-t[b][1],l=t[o][0]-t[b][0],s=t[o][1]-t[b][1],a*a+c*c>=l*l+s*s){M[i].index=-1;continue}M[f].index=-1}g=M[i].angle,f=i,h=o}for(x.push(b),i=0,o=0;2>i;++o)M[o].index>-1&&(x.push(M[o].index),i++);for(p=x.length;y>o;++o)if(!(M[o].index<0)){for(;!hr(x[p-2],x[p-1],M[o].index,t);)--p;x[p++]=M[o].index}var _=[];for(i=p-1;i>=0;--i)_.push(n[x[i]]);return _}var e=Ze,r=Ve;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},mo.geom.polygon=function(n){return Lo(n,mc),n};var mc=mo.geom.polygon.prototype=[];mc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++ta;a++)e.push([u,t[a],t[a+1]])}),e},mo.geom.voronoi=function(n){function t(n){var t,i,o,a=n.map(function(){return[]}),c=pt(e),l=pt(r),s=n.length,f=1e6;if(c===Ze&&l===Ve)t=n;else for(t=new Array(s),o=0;s>o;++o)t[o]=[+c.call(this,i=n[o],o),+l.call(this,i,o)];if(vr(t,function(n){var t,e,r,u,i,o;1===n.a&&n.b>=0?(t=n.ep.r,e=n.ep.l):(t=n.ep.l,e=n.ep.r),1===n.a?(i=t?t.y:-f,r=n.c-n.b*i,o=e?e.y:f,u=n.c-n.b*o):(r=t?t.x:-f,i=n.c-n.a*r,u=e?e.x:f,o=n.c-n.a*u);var c=[r,i],l=[u,o];a[n.region.l.index].push(c,l),a[n.region.r.index].push(c,l)}),a=a.map(function(n,e){var r=t[e][0],u=t[e][1],i=n.map(function(n){return Math.atan2(n[0]-r,n[1]-u)}),o=mo.range(n.length).sort(function(n,t){return i[n]-i[t]});return o.filter(function(n,t){return!t||i[n]-i[o[t-1]]>Go}).map(function(t){return n[t]})}),a.forEach(function(n,e){var r=n.length;if(!r)return n.push([-f,-f],[-f,f],[f,f],[f,-f]);if(!(r>2)){var u=t[e],i=n[0],o=n[1],a=u[0],c=u[1],l=i[0],s=i[1],h=o[0],g=o[1],p=Math.abs(h-l),d=g-s;if(Math.abs(d)c?-f:f;n.push([-f,v],[f,v])}else if(Go>p){var m=l>a?-f:f;n.push([m,-f],[m,f])}else{var v=(l-a)*(g-s)>(h-l)*(s-c)?f:-f,y=Math.abs(d)-p;Math.abs(y)d?v:-v,v]):(y>0&&(v*=-1),n.push([-f,v],[f,v]))}}}),u)for(o=0;s>o;++o)u.clip(a[o]);for(o=0;s>o;++o)a[o].point=n[o];return a}var e=Ze,r=Ve,u=null;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.clipExtent=function(n){if(!arguments.length)return u&&[u[0],u[2]];if(null==n)u=null;else{var e=+n[0][0],r=+n[0][1],i=+n[1][0],o=+n[1][1];u=mo.geom.polygon([[e,r],[e,o],[i,o],[i,r]])}return t},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):u&&u[2]},t.links=function(n){var t,u,i,o=n.map(function(){return[]}),a=[],c=pt(e),l=pt(r),s=n.length;if(c===Ze&&l===Ve)t=n;else for(t=new Array(s),i=0;s>i;++i)t[i]=[+c.call(this,u=n[i],i),+l.call(this,u,i)];return vr(t,function(t){var e=t.region.l.index,r=t.region.r.index;o[e][r]||(o[e][r]=o[r][e]=!0,a.push({source:n[e],target:n[r]}))}),a},t.triangles=function(n){if(e===Ze&&r===Ve)return mo.geom.delaunay(n);for(var t,u=new Array(c),i=pt(e),o=pt(r),a=-1,c=n.length;++a=l,h=r>=s,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=Mr()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,d,v,m,y,M=pt(a),x=pt(c);if(null!=t)d=t,v=e,m=r,y=u;else if(m=y=-(d=v=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.xm&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);d>b&&(d=b),v>_&&(v=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-d,S=y-v;w>S?y=v+w:m=d+S;var E=Mr();if(E.add=function(n){i(E,n,+M(n,++g),+x(n,g),d,v,m,y)},E.visit=function(n){xr(n,E,d,v,m,y)},g=-1,null==t){for(;++g=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=bc.get(e)||xc,r=_c.get(r)||dt,Ar(r(e.apply(null,Array.prototype.slice.call(arguments,1))))},mo.interpolateHcl=Rr,mo.interpolateHsl=Yr,mo.interpolateLab=Ir,mo.interpolateRound=Ur,mo.transform=function(n){var t=xo.createElementNS(mo.ns.prefix.svg,"g");return(mo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Zr(e?e.matrix:wc)})(n)},Zr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var wc={a:1,b:0,c:0,d:1,e:0,f:0};mo.interpolateTransform=Br,mo.layout={},mo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e(u-e)*a){var c=t.charge*a*a;return n.px-=i*c,n.py-=o*c,!0}if(t.point&&isFinite(a)){var c=t.pointCharge*a*a;n.px-=i*c,n.py-=o*c}}return!t.charge}}function t(n){n.px=mo.event.x,n.py=mo.event.y,a.resume()}var e,r,u,i,o,a={},c=mo.dispatch("start","tick","end"),l=[1,1],s=.9,f=Sc,h=Ec,g=-30,p=.1,d=.8,v=[],m=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,d,y,M,x,b=v.length,_=m.length;for(e=0;_>e;++e)a=m[e],f=a.source,h=a.target,M=h.x-f.x,x=h.y-f.y,(d=M*M+x*x)&&(d=r*i[e]*((d=Math.sqrt(d))-u[e])/d,M*=d,x*=d,h.x-=M*(y=f.weight/(h.weight+f.weight)),h.y-=x*y,f.x+=M*(y=1-y),f.y+=x*y);if((y=r*p)&&(M=l[0]/2,x=l[1]/2,e=-1,y))for(;++e0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),mo.timer(a.tick)),a):r},a.start=function(){function n(n,r){for(var u,i=t(e),o=-1,a=i.length;++or;++r)c[r]=[];for(r=0;d>r;++r){var n=m[r];c[n.source.index].push(n.target),c[n.target.index].push(n.source)}}return c[e]}var e,r,c,s,p=v.length,d=m.length,y=l[0],M=l[1];for(e=0;p>e;++e)(s=v[e]).index=e,s.weight=0;for(e=0;d>e;++e)s=m[e],"number"==typeof s.source&&(s.source=v[s.source]),"number"==typeof s.target&&(s.target=v[s.target]),++s.source.weight,++s.target.weight;for(e=0;p>e;++e)s=v[e],isNaN(s.x)&&(s.x=n("x",y)),isNaN(s.y)&&(s.y=n("y",M)),isNaN(s.px)&&(s.px=s.x),isNaN(s.py)&&(s.py=s.y);if(u=[],"function"==typeof f)for(e=0;d>e;++e)u[e]=+f.call(this,m[e],e);else for(e=0;d>e;++e)u[e]=f;if(i=[],"function"==typeof h)for(e=0;d>e;++e)i[e]=+h.call(this,m[e],e);else for(e=0;d>e;++e)i[e]=h;if(o=[],"function"==typeof g)for(e=0;p>e;++e)o[e]=+g.call(this,v[e],e);else for(e=0;p>e;++e)o[e]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=mo.behavior.drag().origin(dt).on("dragstart.force",nu).on("drag.force",t).on("dragend.force",tu)),arguments.length?(this.on("mouseover.force",eu).on("mouseout.force",ru).call(e),void 0):e},mo.rebind(a,c,"on")};var Sc=20,Ec=1;mo.layout.hierarchy=function(){function n(t,o,a){var c=u.call(e,t,o);if(t.depth=o,a.push(t),c&&(l=c.length)){for(var l,s,f=-1,h=t.children=[],g=0,p=o+1;++fg;++g)for(u.call(n,l[0][g],p=d[g],s[0][g][1]),h=1;v>h;++h)u.call(n,l[h][g],p+=s[h-1][g][1],s[h][g][1]);return a}var t=dt,e=gu,r=pu,u=hu,i=su,o=fu;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:Ac.get(t)||gu,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:Nc.get(t)||pu,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var Ac=mo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(du),i=n.map(vu),o=mo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return mo.range(n.length).reverse()},"default":gu}),Nc=mo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:pu});mo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i0)for(i=-1;++i=s[0]&&a<=s[1]&&(o=c[mo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=xu,u=yu;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=pt(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return Mu(n,t)}:pt(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},mo.layout.tree=function(){function n(n,i){function o(n,t){var r=n.children,u=n._tree;if(r&&(i=r.length)){for(var i,a,l,s=r[0],f=s,h=-1;++h0&&(qu(zu(a,n,r),n,u),l+=u,s+=u),f+=a._tree.mod,l+=i._tree.mod,h+=c._tree.mod,s+=o._tree.mod;a&&!wu(o)&&(o._tree.thread=a,o._tree.mod+=f-s),i&&!_u(c)&&(c._tree.thread=i,c._tree.mod+=l-h,r=n)}return r}var l=t.call(this,n,i),s=l[0];Nu(s,function(n,t){n._tree={ancestor:n,prelim:0,mod:0,change:0,shift:0,number:t?t._tree.number+1:0}}),o(s),a(s,-s._tree.prelim);var f=Su(s,ku),h=Su(s,Eu),g=Su(s,Au),p=f.x-e(f,h)/2,d=h.x+e(h,f)/2,v=g.depth||1;return Nu(s,u?function(n){n.x*=r[0],n.y=n.depth*r[1],delete n._tree}:function(n){n.x=(n.x-p)/(d-p)*r[0],n.y=n.depth/v*r[1],delete n._tree}),l}var t=mo.layout.hierarchy().sort(null).value(null),e=bu,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},iu(n,t)},mo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Nu(a,function(n){n.r=+s(n.value)}),Nu(a,Hu),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Nu(a,function(n){n.r+=f}),Nu(a,Hu),Nu(a,function(n){n.r-=f})}return Ou(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=mo.layout.hierarchy().sort(Cu),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},iu(n,e)},mo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Nu(c,function(n){var t=n.children;t&&t.length?(n.x=Iu(t),n.y=Yu(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Uu(c),f=Zu(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Nu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=mo.layout.hierarchy().sort(null).value(null),e=bu,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},iu(n,t)},mo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++ut?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,d="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,d))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,d,l,!1),d=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,d,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++oe&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++ie.dx)&&(s=e.dx);++ie&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=mo.random.normal.apply(mo,arguments);return function(){return Math.exp(n())}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t/n}}},mo.scale={};var Tc={floor:dt,ceil:dt};mo.scale.linear=function(){return Qu([0,1],[0,1],Er,!1)},mo.scale.log=function(){return ii(mo.scale.linear().domain([0,1]),10,!0,[1,10])};var qc=mo.format(".0e"),zc={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};mo.scale.pow=function(){return oi(mo.scale.linear(),1,[0,1])},mo.scale.sqrt=function(){return mo.scale.pow().exponent(.5)},mo.scale.ordinal=function(){return ci([],{t:"range",a:[[]]})},mo.scale.category10=function(){return mo.scale.ordinal().range(Cc)},mo.scale.category20=function(){return mo.scale.ordinal().range(Dc)},mo.scale.category20b=function(){return mo.scale.ordinal().range(jc)},mo.scale.category20c=function(){return mo.scale.ordinal().range(Lc)};var Cc=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(it),Dc=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(it),jc=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(it),Lc=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(it);mo.scale.quantile=function(){return li([],[])},mo.scale.quantize=function(){return si(0,1,[0,1])},mo.scale.threshold=function(){return fi([.5],[0,1])},mo.scale.identity=function(){return hi([0,1])},mo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+Hc,a=u.apply(this,arguments)+Hc,c=(o>a&&(c=o,o=a,a=c),a-o),l=Bo>c?"0":"1",s=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a);return c>=Fc?n?"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":n?"M"+i*s+","+i*f+"A"+i+","+i+" 0 "+l+",1 "+i*h+","+i*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+l+",0 "+n*s+","+n*f+"Z":"M"+i*s+","+i*f+"A"+i+","+i+" 0 "+l+",1 "+i*h+","+i*g+"L0,0"+"Z"}var t=gi,e=pi,r=di,u=vi;return n.innerRadius=function(e){return arguments.length?(t=pt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=pt(t),n):e},n.startAngle=function(t){return arguments.length?(r=pt(t),n):r},n.endAngle=function(t){return arguments.length?(u=pt(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+Hc;return[Math.cos(i)*n,Math.sin(i)*n]},n};var Hc=-Jo,Fc=Wo-Go;mo.svg.line.radial=function(){var n=Ue(mi);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},We.reverse=Je,Je.reverse=We,mo.svg.area=function(){return yi(dt)},mo.svg.area.radial=function(){var n=yi(mi);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},mo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+Hc,s=l.call(n,u,r)+Hc;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Bo)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=De,o=je,a=Mi,c=di,l=vi;return n.radius=function(t){return arguments.length?(a=pt(t),n):a},n.source=function(t){return arguments.length?(i=pt(t),n):i},n.target=function(t){return arguments.length?(o=pt(t),n):o},n.startAngle=function(t){return arguments.length?(c=pt(t),n):c},n.endAngle=function(t){return arguments.length?(l=pt(t),n):l},n},mo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=De,e=je,r=xi;return n.source=function(e){return arguments.length?(t=pt(e),n):t},n.target=function(t){return arguments.length?(e=pt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},mo.svg.diagonal.radial=function(){var n=mo.svg.diagonal(),t=xi,e=n.projection;return n.projection=function(n){return arguments.length?e(bi(t=n)):t},n},mo.svg.symbol=function(){function n(n,r){return(Pc.get(t.call(this,n,r))||Si)(e.call(this,n,r))}var t=wi,e=_i;return n.type=function(e){return arguments.length?(t=pt(e),n):t},n.size=function(t){return arguments.length?(e=pt(t),n):e},n};var Pc=mo.map({circle:Si,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ic)),e=t*Ic;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/Yc),e=t*Yc/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/Yc),e=t*Yc/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});mo.svg.symbolTypes=Pc.keys();var Oc,Rc,Yc=Math.sqrt(3),Ic=Math.tan(30*Qo),Uc=[],Zc=0;Uc.call=Ro.call,Uc.empty=Ro.empty,Uc.node=Ro.node,Uc.size=Ro.size,mo.transition=function(n){return arguments.length?Oc?n.transition():n:Uo.transition()},mo.transition.prototype=Uc,Uc.select=function(n){var t,e,r,u=this.id,i=[];n=d(n);for(var o=-1,a=this.length;++oi;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a)&&t.push(r)}return Ei(u,this.id)},Uc.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):N(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Uc.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n)) +})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Br:Er,a=mo.ns.qualify(n);return ki(this,"attr."+n,t,a.local?i:u)},Uc.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=mo.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Uc.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+="",function(){var r,u=_o.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=Er(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return ki(this,"style."+n,t,u)},Uc.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,_o.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Uc.text=function(n){return ki(this,"text",n,Ai)},Uc.remove=function(){return this.each("end.transition",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Uc.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=mo.ease.apply(mo,arguments)),N(this,function(e){e.__transition__[t].ease=n}))},Uc.delay=function(n){var t=this.id;return N(this,"function"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Uc.duration=function(n){var t=this.id;return N(this,"function"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Uc.each=function(n,t){var e=this.id;if(arguments.length<2){var r=Rc,u=Oc;Oc=e,N(this,function(t,r,u){Rc=t.__transition__[e],n.call(t,t.__data__,r,u)}),Rc=r,Oc=u}else N(this,function(r){var u=r.__transition__[e];(u.event||(u.event=mo.dispatch("start","end"))).on(n,t)});return this},Uc.transition=function(){for(var n,t,e,r,u=this.id,i=++Zc,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],l=0,s=t.length;s>l;l++)(e=t[l])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,Ni(e,l,i,r)),n.push(e)}return Ei(o,i)},mo.svg.axis=function(){function n(n){n.each(function(){var n,l=mo.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):dt:t,p=l.selectAll(".tick").data(h,f),d=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Go),v=mo.transition(p.exit()).style("opacity",Go).remove(),m=mo.transition(p).style("opacity",1),y=Bu(f),M=l.selectAll(".domain").data([0]),x=(M.enter().append("path").attr("class","domain"),mo.transition(M));d.append("line"),d.append("text");var b=d.select("line"),_=m.select("line"),w=p.select("text").text(g),S=d.select("text"),E=m.select("text");switch(r){case"bottom":n=Ti,b.attr("y2",u),S.attr("y",Math.max(u,0)+o),_.attr("x2",0).attr("y2",u),E.attr("x",0).attr("y",Math.max(u,0)+o),w.attr("dy",".71em").style("text-anchor","middle"),x.attr("d","M"+y[0]+","+i+"V0H"+y[1]+"V"+i);break;case"top":n=Ti,b.attr("y2",-u),S.attr("y",-(Math.max(u,0)+o)),_.attr("x2",0).attr("y2",-u),E.attr("x",0).attr("y",-(Math.max(u,0)+o)),w.attr("dy","0em").style("text-anchor","middle"),x.attr("d","M"+y[0]+","+-i+"V0H"+y[1]+"V"+-i);break;case"left":n=qi,b.attr("x2",-u),S.attr("x",-(Math.max(u,0)+o)),_.attr("x2",-u).attr("y2",0),E.attr("x",-(Math.max(u,0)+o)).attr("y",0),w.attr("dy",".32em").style("text-anchor","end"),x.attr("d","M"+-i+","+y[0]+"H0V"+y[1]+"H"+-i);break;case"right":n=qi,b.attr("x2",u),S.attr("x",Math.max(u,0)+o),_.attr("x2",u).attr("y2",0),E.attr("x",Math.max(u,0)+o).attr("y",0),w.attr("dy",".32em").style("text-anchor","start"),x.attr("d","M"+i+","+y[0]+"H0V"+y[1]+"H"+i)}if(f.rangeBand){var k=f.rangeBand()/2,A=function(n){return f(n)+k};d.call(n,A),m.call(n,A)}else d.call(n,s),m.call(n,f),v.call(n,f)})}var t,e=mo.scale.linear(),r=Vc,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Xc?t+"":Vc,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Vc="bottom",Xc={top:1,right:1,bottom:1,left:1};mo.svg.brush=function(){function n(i){i.each(function(){var i=mo.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=i.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),i.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=i.selectAll(".resize").data(v,dt);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return $c[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var s,f=mo.transition(i),h=mo.transition(o);c&&(s=Bu(c),h.attr("x",s[0]).attr("width",s[1]-s[0]),e(f)),l&&(s=Bu(l),h.attr("y",s[0]).attr("height",s[1]-s[0]),r(f)),t(f)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function r(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function u(){function u(){32==mo.event.keyCode&&(N||(M=null,q[0]-=s[1],q[1]-=h[1],N=2),f())}function g(){32==mo.event.keyCode&&2==N&&(q[0]+=s[1],q[1]+=h[1],N=0,f())}function v(){var n=mo.mouse(b),u=!1;x&&(n[0]+=x[0],n[1]+=x[1]),N||(mo.event.altKey?(M||(M=[(s[0]+s[1])/2,(h[0]+h[1])/2]),q[0]=s[+(n[0]f?(u=r,r=f):u=f),g[0]!=r||g[1]!=u?(e?o=null:i=null,g[0]=r,g[1]=u,!0):void 0}function y(){v(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),mo.select("body").style("cursor",null),z.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),T(),w({type:"brushend"})}var M,x,b=this,_=mo.select(mo.event.target),w=a.of(b,arguments),S=mo.select(b),E=_.datum(),k=!/^(n|s)$/.test(E)&&c,A=!/^(e|w)$/.test(E)&&l,N=_.classed("extent"),T=L(),q=mo.mouse(b),z=mo.select(_o).on("keydown.brush",u).on("keyup.brush",g);if(mo.event.changedTouches?z.on("touchmove.brush",v).on("touchend.brush",y):z.on("mousemove.brush",v).on("mouseup.brush",y),S.interrupt().selectAll("*").interrupt(),N)q[0]=s[0]-q[0],q[1]=h[0]-q[1];else if(E){var C=+/w$/.test(E),D=+/^n/.test(E);x=[s[1-C]-q[0],h[1-D]-q[1]],q[0]=s[C],q[1]=h[D]}else mo.event.altKey&&(M=q.slice());S.style("pointer-events","none").selectAll(".resize").style("display",null),mo.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),v()}var i,o,a=g(n,"brushstart","brush","brushend"),c=null,l=null,s=[0,0],h=[0,0],p=!0,d=!0,v=Bc[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:s,y:h,i:i,j:o},e=this.__chart__||t;this.__chart__=t,Oc?mo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,s=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=kr(s,t.x),r=kr(h,t.y);return i=o=null,function(u){s=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){i=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,v=Bc[!c<<1|!l],n):c},n.y=function(t){return arguments.length?(l=t,v=Bc[!c<<1|!l],n):l},n.clamp=function(t){return arguments.length?(c&&l?(p=!!t[0],d=!!t[1]):c?p=!!t:l&&(d=!!t),n):c&&l?[p,d]:c?p:l?d:null},n.extent=function(t){var e,r,u,a,f;return arguments.length?(c&&(e=t[0],r=t[1],l&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(f=e,e=r,r=f),(e!=s[0]||r!=s[1])&&(s=[e,r])),l&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],l.invert&&(u=l(u),a=l(a)),u>a&&(f=u,u=a,a=f),(u!=h[0]||a!=h[1])&&(h=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=s[0],r=s[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(f=e,e=r,r=f))),l&&(o?(u=o[0],a=o[1]):(u=h[0],a=h[1],l.invert&&(u=l.invert(u),a=l.invert(a)),u>a&&(f=u,u=a,a=f))),c&&l?[[e,u],[r,a]]:c?[e,r]:l&&[u,a])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],i=o=null),n},n.empty=function(){return!!c&&s[0]==s[1]||!!l&&h[0]==h[1]},mo.rebind(n,a,"on")};var $c={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Bc=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Wc=mo.time={},Jc=Date,Gc=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];zi.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){Kc.setUTCDate.apply(this._,arguments)},setDay:function(){Kc.setUTCDay.apply(this._,arguments)},setFullYear:function(){Kc.setUTCFullYear.apply(this._,arguments)},setHours:function(){Kc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){Kc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){Kc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){Kc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){Kc.setUTCSeconds.apply(this._,arguments)},setTime:function(){Kc.setTime.apply(this._,arguments)}};var Kc=Date.prototype,Qc="%a %b %e %X %Y",nl="%m/%d/%Y",tl="%H:%M:%S",el=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],rl=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],ul=["January","February","March","April","May","June","July","August","September","October","November","December"],il=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];Wc.year=Ci(function(n){return n=Wc.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),Wc.years=Wc.year.range,Wc.years.utc=Wc.year.utc.range,Wc.day=Ci(function(n){var t=new Jc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),Wc.days=Wc.day.range,Wc.days.utc=Wc.day.utc.range,Wc.dayOfYear=function(n){var t=Wc.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},Gc.forEach(function(n,t){n=n.toLowerCase(),t=7-t;var e=Wc[n]=Ci(function(n){return(n=Wc.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=Wc.year(n).getDay();return Math.floor((Wc.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});Wc[n+"s"]=e.range,Wc[n+"s"].utc=e.utc.range,Wc[n+"OfYear"]=function(n){var e=Wc.year(n).getDay();return Math.floor((Wc.dayOfYear(n)+(e+t)%7)/7)}}),Wc.week=Wc.sunday,Wc.weeks=Wc.sunday.range,Wc.weeks.utc=Wc.sunday.utc.range,Wc.weekOfYear=Wc.sundayOfYear,Wc.format=ji;var ol=Hi(el),al=Fi(el),cl=Hi(rl),ll=Fi(rl),sl=Hi(ul),fl=Fi(ul),hl=Hi(il),gl=Fi(il),pl=/^%/,dl={"-":"",_:" ",0:"0"},vl={a:function(n){return rl[n.getDay()]},A:function(n){return el[n.getDay()]},b:function(n){return il[n.getMonth()]},B:function(n){return ul[n.getMonth()]},c:ji(Qc),d:function(n,t){return Pi(n.getDate(),t,2)},e:function(n,t){return Pi(n.getDate(),t,2)},H:function(n,t){return Pi(n.getHours(),t,2)},I:function(n,t){return Pi(n.getHours()%12||12,t,2)},j:function(n,t){return Pi(1+Wc.dayOfYear(n),t,3)},L:function(n,t){return Pi(n.getMilliseconds(),t,3)},m:function(n,t){return Pi(n.getMonth()+1,t,2)},M:function(n,t){return Pi(n.getMinutes(),t,2)},p:function(n){return n.getHours()>=12?"PM":"AM"},S:function(n,t){return Pi(n.getSeconds(),t,2)},U:function(n,t){return Pi(Wc.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Pi(Wc.mondayOfYear(n),t,2)},x:ji(nl),X:ji(tl),y:function(n,t){return Pi(n.getFullYear()%100,t,2)},Y:function(n,t){return Pi(n.getFullYear()%1e4,t,4)},Z:ao,"%":function(){return"%"}},ml={a:Oi,A:Ri,b:Zi,B:Vi,c:Xi,d:no,e:no,H:eo,I:eo,j:to,L:io,m:Qi,M:ro,p:oo,S:uo,U:Ii,w:Yi,W:Ui,x:$i,X:Bi,y:Ji,Y:Wi,Z:Gi,"%":co},yl=/^\s*\d+/,Ml=mo.map({am:0,pm:1});ji.utc=lo;var xl=lo("%Y-%m-%dT%H:%M:%S.%LZ");ji.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?so:xl,so.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},so.toString=xl.toString,Wc.second=Ci(function(n){return new Jc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),Wc.seconds=Wc.second.range,Wc.seconds.utc=Wc.second.utc.range,Wc.minute=Ci(function(n){return new Jc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),Wc.minutes=Wc.minute.range,Wc.minutes.utc=Wc.minute.utc.range,Wc.hour=Ci(function(n){var t=n.getTimezoneOffset()/60;return new Jc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),Wc.hours=Wc.hour.range,Wc.hours.utc=Wc.hour.utc.range,Wc.month=Ci(function(n){return n=Wc.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),Wc.months=Wc.month.range,Wc.months.utc=Wc.month.utc.range;var bl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],_l=[[Wc.second,1],[Wc.second,5],[Wc.second,15],[Wc.second,30],[Wc.minute,1],[Wc.minute,5],[Wc.minute,15],[Wc.minute,30],[Wc.hour,1],[Wc.hour,3],[Wc.hour,6],[Wc.hour,12],[Wc.day,1],[Wc.day,2],[Wc.week,1],[Wc.month,1],[Wc.month,3],[Wc.year,1]],wl=[[ji("%Y"),Vt],[ji("%B"),function(n){return n.getMonth()}],[ji("%b %d"),function(n){return 1!=n.getDate()}],[ji("%a %d"),function(n){return n.getDay()&&1!=n.getDate()}],[ji("%I %p"),function(n){return n.getHours()}],[ji("%I:%M"),function(n){return n.getMinutes()}],[ji(":%S"),function(n){return n.getSeconds()}],[ji(".%L"),function(n){return n.getMilliseconds()}]],Sl=go(wl);_l.year=Wc.year,Wc.scale=function(){return fo(mo.scale.linear(),_l,Sl)};var El={range:function(n,t,e){return mo.range(+n,+t,e).map(ho)}},kl=_l.map(function(n){return[n[0].utc,n[1]]}),Al=[[lo("%Y"),Vt],[lo("%B"),function(n){return n.getUTCMonth()}],[lo("%b %d"),function(n){return 1!=n.getUTCDate()}],[lo("%a %d"),function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],[lo("%I %p"),function(n){return n.getUTCHours()}],[lo("%I:%M"),function(n){return n.getUTCMinutes()}],[lo(":%S"),function(n){return n.getUTCSeconds()}],[lo(".%L"),function(n){return n.getUTCMilliseconds()}]],Nl=go(Al);return kl.year=Wc.year.utc,Wc.scale.utc=function(){return fo(mo.scale.linear(),kl,Nl)},mo.text=vt(function(n){return n.responseText}),mo.json=function(n,t){return mt(n,"application/json",po,t)},mo.html=function(n,t){return mt(n,"text/html",vo,t)},mo.xml=vt(function(n){return n.responseXML}),mo}(); \ No newline at end of file diff --git a/html/js/handlebars-v4.0.11.js b/html/js/handlebars-v4.0.11.js new file mode 100644 index 0000000..991748b --- /dev/null +++ b/html/js/handlebars-v4.0.11.js @@ -0,0 +1,4840 @@ +/**! + + @license + handlebars v4.0.11 + +Copyright (C) 2011-2017 by Yehuda Katz + +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. + +*/ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["Handlebars"] = factory(); + else + root["Handlebars"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _handlebarsRuntime = __webpack_require__(2); + + var _handlebarsRuntime2 = _interopRequireDefault(_handlebarsRuntime); + + // Compiler imports + + var _handlebarsCompilerAst = __webpack_require__(35); + + var _handlebarsCompilerAst2 = _interopRequireDefault(_handlebarsCompilerAst); + + var _handlebarsCompilerBase = __webpack_require__(36); + + var _handlebarsCompilerCompiler = __webpack_require__(41); + + var _handlebarsCompilerJavascriptCompiler = __webpack_require__(42); + + var _handlebarsCompilerJavascriptCompiler2 = _interopRequireDefault(_handlebarsCompilerJavascriptCompiler); + + var _handlebarsCompilerVisitor = __webpack_require__(39); + + var _handlebarsCompilerVisitor2 = _interopRequireDefault(_handlebarsCompilerVisitor); + + var _handlebarsNoConflict = __webpack_require__(34); + + var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); + + var _create = _handlebarsRuntime2['default'].create; + function create() { + var hb = _create(); + + hb.compile = function (input, options) { + return _handlebarsCompilerCompiler.compile(input, options, hb); + }; + hb.precompile = function (input, options) { + return _handlebarsCompilerCompiler.precompile(input, options, hb); + }; + + hb.AST = _handlebarsCompilerAst2['default']; + hb.Compiler = _handlebarsCompilerCompiler.Compiler; + hb.JavaScriptCompiler = _handlebarsCompilerJavascriptCompiler2['default']; + hb.Parser = _handlebarsCompilerBase.parser; + hb.parse = _handlebarsCompilerBase.parse; + + return hb; + } + + var inst = create(); + inst.create = create; + + _handlebarsNoConflict2['default'](inst); + + inst.Visitor = _handlebarsCompilerVisitor2['default']; + + inst['default'] = inst; + + exports['default'] = inst; + module.exports = exports['default']; + +/***/ }), +/* 1 */ +/***/ (function(module, exports) { + + "use strict"; + + exports["default"] = function (obj) { + return obj && obj.__esModule ? obj : { + "default": obj + }; + }; + + exports.__esModule = true; + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _handlebarsBase = __webpack_require__(4); + + var base = _interopRequireWildcard(_handlebarsBase); + + // Each of these augment the Handlebars object. No need to setup here. + // (This is done to easily share code between commonjs and browse envs) + + var _handlebarsSafeString = __webpack_require__(21); + + var _handlebarsSafeString2 = _interopRequireDefault(_handlebarsSafeString); + + var _handlebarsException = __webpack_require__(6); + + var _handlebarsException2 = _interopRequireDefault(_handlebarsException); + + var _handlebarsUtils = __webpack_require__(5); + + var Utils = _interopRequireWildcard(_handlebarsUtils); + + var _handlebarsRuntime = __webpack_require__(22); + + var runtime = _interopRequireWildcard(_handlebarsRuntime); + + var _handlebarsNoConflict = __webpack_require__(34); + + var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); + + // For compatibility and usage outside of module systems, make the Handlebars object a namespace + function create() { + var hb = new base.HandlebarsEnvironment(); + + Utils.extend(hb, base); + hb.SafeString = _handlebarsSafeString2['default']; + hb.Exception = _handlebarsException2['default']; + hb.Utils = Utils; + hb.escapeExpression = Utils.escapeExpression; + + hb.VM = runtime; + hb.template = function (spec) { + return runtime.template(spec, hb); + }; + + return hb; + } + + var inst = create(); + inst.create = create; + + _handlebarsNoConflict2['default'](inst); + + inst['default'] = inst; + + exports['default'] = inst; + module.exports = exports['default']; + +/***/ }), +/* 3 */ +/***/ (function(module, exports) { + + "use strict"; + + exports["default"] = function (obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {}; + + if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + } + + newObj["default"] = obj; + return newObj; + } + }; + + exports.__esModule = true; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.HandlebarsEnvironment = HandlebarsEnvironment; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _helpers = __webpack_require__(10); + + var _decorators = __webpack_require__(18); + + var _logger = __webpack_require__(20); + + var _logger2 = _interopRequireDefault(_logger); + + var VERSION = '4.0.11'; + exports.VERSION = VERSION; + var COMPILER_REVISION = 7; + + exports.COMPILER_REVISION = COMPILER_REVISION; + var REVISION_CHANGES = { + 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it + 2: '== 1.0.0-rc.3', + 3: '== 1.0.0-rc.4', + 4: '== 1.x.x', + 5: '== 2.0.0-alpha.x', + 6: '>= 2.0.0-beta.1', + 7: '>= 4.0.0' + }; + + exports.REVISION_CHANGES = REVISION_CHANGES; + var objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials, decorators) { + this.helpers = helpers || {}; + this.partials = partials || {}; + this.decorators = decorators || {}; + + _helpers.registerDefaultHelpers(this); + _decorators.registerDefaultDecorators(this); + } + + HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: _logger2['default'], + log: _logger2['default'].log, + + registerHelper: function registerHelper(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple helpers'); + } + _utils.extend(this.helpers, name); + } else { + this.helpers[name] = fn; + } + }, + unregisterHelper: function unregisterHelper(name) { + delete this.helpers[name]; + }, + + registerPartial: function registerPartial(name, partial) { + if (_utils.toString.call(name) === objectType) { + _utils.extend(this.partials, name); + } else { + if (typeof partial === 'undefined') { + throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined'); + } + this.partials[name] = partial; + } + }, + unregisterPartial: function unregisterPartial(name) { + delete this.partials[name]; + }, + + registerDecorator: function registerDecorator(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple decorators'); + } + _utils.extend(this.decorators, name); + } else { + this.decorators[name] = fn; + } + }, + unregisterDecorator: function unregisterDecorator(name) { + delete this.decorators[name]; + } + }; + + var log = _logger2['default'].log; + + exports.log = log; + exports.createFrame = _utils.createFrame; + exports.logger = _logger2['default']; + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports.extend = extend; + exports.indexOf = indexOf; + exports.escapeExpression = escapeExpression; + exports.isEmpty = isEmpty; + exports.createFrame = createFrame; + exports.blockParams = blockParams; + exports.appendContextPath = appendContextPath; + var escape = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`', + '=': '=' + }; + + var badChars = /[&<>"'`=]/g, + possible = /[&<>"'`=]/; + + function escapeChar(chr) { + return escape[chr]; + } + + function extend(obj /* , ...source */) { + for (var i = 1; i < arguments.length; i++) { + for (var key in arguments[i]) { + if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { + obj[key] = arguments[i][key]; + } + } + } + + return obj; + } + + var toString = Object.prototype.toString; + + exports.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + /* eslint-disable func-style */ + var isFunction = function isFunction(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + /* istanbul ignore next */ + if (isFunction(/x/)) { + exports.isFunction = isFunction = function (value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; + } + exports.isFunction = isFunction; + + /* eslint-enable func-style */ + + /* istanbul ignore next */ + var isArray = Array.isArray || function (value) { + return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; + }; + + exports.isArray = isArray; + // Older IE versions do not directly support indexOf so we must implement our own, sadly. + + function indexOf(array, value) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + return -1; + } + + function escapeExpression(string) { + if (typeof string !== 'string') { + // don't escape SafeStrings, since they're already safe + if (string && string.toHTML) { + return string.toHTML(); + } else if (string == null) { + return ''; + } else if (!string) { + return string + ''; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = '' + string; + } + + if (!possible.test(string)) { + return string; + } + return string.replace(badChars, escapeChar); + } + + function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } + + function createFrame(object) { + var frame = extend({}, object); + frame._parent = object; + return frame; + } + + function blockParams(params, ids) { + params.path = ids; + return params; + } + + function appendContextPath(contextPath, id) { + return (contextPath ? contextPath + '.' : '') + id; + } + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$defineProperty = __webpack_require__(7)['default']; + + exports.__esModule = true; + + var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + + function Exception(message, node) { + var loc = node && node.loc, + line = undefined, + column = undefined; + if (loc) { + line = loc.start.line; + column = loc.start.column; + + message += ' - ' + line + ':' + column; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + /* istanbul ignore else */ + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Exception); + } + + try { + if (loc) { + this.lineNumber = line; + + // Work around issue under safari where we can't directly set the column value + /* istanbul ignore next */ + if (_Object$defineProperty) { + Object.defineProperty(this, 'column', { + value: column, + enumerable: true + }); + } else { + this.column = column; + } + } + } catch (nop) { + /* Ignore if the browser is very particular */ + } + } + + Exception.prototype = new Error(); + + exports['default'] = Exception; + module.exports = exports['default']; + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(8), __esModule: true }; + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(9); + module.exports = function defineProperty(it, key, desc){ + return $.setDesc(it, key, desc); + }; + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + + var $Object = Object; + module.exports = { + create: $Object.create, + getProto: $Object.getPrototypeOf, + isEnum: {}.propertyIsEnumerable, + getDesc: $Object.getOwnPropertyDescriptor, + setDesc: $Object.defineProperty, + setDescs: $Object.defineProperties, + getKeys: $Object.keys, + getNames: $Object.getOwnPropertyNames, + getSymbols: $Object.getOwnPropertySymbols, + each: [].forEach + }; + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.registerDefaultHelpers = registerDefaultHelpers; + + var _helpersBlockHelperMissing = __webpack_require__(11); + + var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing); + + var _helpersEach = __webpack_require__(12); + + var _helpersEach2 = _interopRequireDefault(_helpersEach); + + var _helpersHelperMissing = __webpack_require__(13); + + var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing); + + var _helpersIf = __webpack_require__(14); + + var _helpersIf2 = _interopRequireDefault(_helpersIf); + + var _helpersLog = __webpack_require__(15); + + var _helpersLog2 = _interopRequireDefault(_helpersLog); + + var _helpersLookup = __webpack_require__(16); + + var _helpersLookup2 = _interopRequireDefault(_helpersLookup); + + var _helpersWith = __webpack_require__(17); + + var _helpersWith2 = _interopRequireDefault(_helpersWith); + + function registerDefaultHelpers(instance) { + _helpersBlockHelperMissing2['default'](instance); + _helpersEach2['default'](instance); + _helpersHelperMissing2['default'](instance); + _helpersIf2['default'](instance); + _helpersLog2['default'](instance); + _helpersLookup2['default'](instance); + _helpersWith2['default'](instance); + } + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerHelper('blockHelperMissing', function (context, options) { + var inverse = options.inverse, + fn = options.fn; + + if (context === true) { + return fn(this); + } else if (context === false || context == null) { + return inverse(this); + } else if (_utils.isArray(context)) { + if (context.length > 0) { + if (options.ids) { + options.ids = [options.name]; + } + + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + if (options.data && options.ids) { + var data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name); + options = { data: data }; + } + + return fn(context, options); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('each', function (context, options) { + if (!options) { + throw new _exception2['default']('Must pass iterator to #each'); + } + + var fn = options.fn, + inverse = options.inverse, + i = 0, + ret = '', + data = undefined, + contextPath = undefined; + + if (options.data && options.ids) { + contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; + } + + if (_utils.isFunction(context)) { + context = context.call(this); + } + + if (options.data) { + data = _utils.createFrame(options.data); + } + + function execIteration(field, index, last) { + if (data) { + data.key = field; + data.index = index; + data.first = index === 0; + data.last = !!last; + + if (contextPath) { + data.contextPath = contextPath + field; + } + } + + ret = ret + fn(context[field], { + data: data, + blockParams: _utils.blockParams([context[field], field], [contextPath + field, null]) + }); + } + + if (context && typeof context === 'object') { + if (_utils.isArray(context)) { + for (var j = context.length; i < j; i++) { + if (i in context) { + execIteration(i, i, i === context.length - 1); + } + } + } else { + var priorKey = undefined; + + for (var key in context) { + if (context.hasOwnProperty(key)) { + // We're running the iterations one step out of sync so we can detect + // the last iteration without have to scan the object twice and create + // an itermediate keys array. + if (priorKey !== undefined) { + execIteration(priorKey, i - 1); + } + priorKey = key; + i++; + } + } + if (priorKey !== undefined) { + execIteration(priorKey, i - 1, true); + } + } + } + + if (i === 0) { + ret = inverse(this); + } + + return ret; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('helperMissing', function () /* [args, ]options */{ + if (arguments.length === 1) { + // A missing field in a {{foo}} construct. + return undefined; + } else { + // Someone is actually trying to call something, blow up. + throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"'); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerHelper('if', function (conditional, options) { + if (_utils.isFunction(conditional)) { + conditional = conditional.call(this); + } + + // Default behavior is to render the positive path if the value is truthy and not empty. + // The `includeZero` option may be set to treat the condtional as purely not empty based on the + // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. + if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) { + return options.inverse(this); + } else { + return options.fn(this); + } + }); + + instance.registerHelper('unless', function (conditional, options) { + return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, hash: options.hash }); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 15 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('log', function () /* message, options */{ + var args = [undefined], + options = arguments[arguments.length - 1]; + for (var i = 0; i < arguments.length - 1; i++) { + args.push(arguments[i]); + } + + var level = 1; + if (options.hash.level != null) { + level = options.hash.level; + } else if (options.data && options.data.level != null) { + level = options.data.level; + } + args[0] = level; + + instance.log.apply(instance, args); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 16 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('lookup', function (obj, field) { + return obj && obj[field]; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerHelper('with', function (context, options) { + if (_utils.isFunction(context)) { + context = context.call(this); + } + + var fn = options.fn; + + if (!_utils.isEmpty(context)) { + var data = options.data; + if (options.data && options.ids) { + data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]); + } + + return fn(context, { + data: data, + blockParams: _utils.blockParams([context], [data && data.contextPath]) + }); + } else { + return options.inverse(this); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.registerDefaultDecorators = registerDefaultDecorators; + + var _decoratorsInline = __webpack_require__(19); + + var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline); + + function registerDefaultDecorators(instance) { + _decoratorsInline2['default'](instance); + } + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerDecorator('inline', function (fn, props, container, options) { + var ret = fn; + if (!props.partials) { + props.partials = {}; + ret = function (context, options) { + // Create a new partials stack frame prior to exec. + var original = container.partials; + container.partials = _utils.extend({}, original, props.partials); + var ret = fn(context, options); + container.partials = original; + return ret; + }; + } + + props.partials[options.args[0]] = options.fn; + + return ret; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var logger = { + methodMap: ['debug', 'info', 'warn', 'error'], + level: 'info', + + // Maps a given level value to the `methodMap` indexes above. + lookupLevel: function lookupLevel(level) { + if (typeof level === 'string') { + var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase()); + if (levelMap >= 0) { + level = levelMap; + } else { + level = parseInt(level, 10); + } + } + + return level; + }, + + // Can be overridden in the host environment + log: function log(level) { + level = logger.lookupLevel(level); + + if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) { + var method = logger.methodMap[level]; + if (!console[method]) { + // eslint-disable-line no-console + method = 'log'; + } + + for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + message[_key - 1] = arguments[_key]; + } + + console[method].apply(console, message); // eslint-disable-line no-console + } + } + }; + + exports['default'] = logger; + module.exports = exports['default']; + +/***/ }), +/* 21 */ +/***/ (function(module, exports) { + + // Build out our basic SafeString type + 'use strict'; + + exports.__esModule = true; + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = SafeString.prototype.toHTML = function () { + return '' + this.string; + }; + + exports['default'] = SafeString; + module.exports = exports['default']; + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$seal = __webpack_require__(23)['default']; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.checkRevision = checkRevision; + exports.template = template; + exports.wrapProgram = wrapProgram; + exports.resolvePartial = resolvePartial; + exports.invokePartial = invokePartial; + exports.noop = noop; + + var _utils = __webpack_require__(5); + + var Utils = _interopRequireWildcard(_utils); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _base = __webpack_require__(4); + + function checkRevision(compilerInfo) { + var compilerRevision = compilerInfo && compilerInfo[0] || 1, + currentRevision = _base.COMPILER_REVISION; + + if (compilerRevision !== currentRevision) { + if (compilerRevision < currentRevision) { + var runtimeVersions = _base.REVISION_CHANGES[currentRevision], + compilerVersions = _base.REVISION_CHANGES[compilerRevision]; + throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); + } + } + } + + function template(templateSpec, env) { + /* istanbul ignore next */ + if (!env) { + throw new _exception2['default']('No environment passed to template'); + } + if (!templateSpec || !templateSpec.main) { + throw new _exception2['default']('Unknown template object: ' + typeof templateSpec); + } + + templateSpec.main.decorator = templateSpec.main_d; + + // Note: Using env.VM references rather than local var references throughout this section to allow + // for external users to override these as psuedo-supported APIs. + env.VM.checkRevision(templateSpec.compiler); + + function invokePartialWrapper(partial, context, options) { + if (options.hash) { + context = Utils.extend({}, context, options.hash); + if (options.ids) { + options.ids[0] = true; + } + } + + partial = env.VM.resolvePartial.call(this, partial, context, options); + var result = env.VM.invokePartial.call(this, partial, context, options); + + if (result == null && env.compile) { + options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); + result = options.partials[options.name](context, options); + } + if (result != null) { + if (options.indent) { + var lines = result.split('\n'); + for (var i = 0, l = lines.length; i < l; i++) { + if (!lines[i] && i + 1 === l) { + break; + } + + lines[i] = options.indent + lines[i]; + } + result = lines.join('\n'); + } + return result; + } else { + throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); + } + } + + // Just add water + var container = { + strict: function strict(obj, name) { + if (!(name in obj)) { + throw new _exception2['default']('"' + name + '" not defined in ' + obj); + } + return obj[name]; + }, + lookup: function lookup(depths, name) { + var len = depths.length; + for (var i = 0; i < len; i++) { + if (depths[i] && depths[i][name] != null) { + return depths[i][name]; + } + } + }, + lambda: function lambda(current, context) { + return typeof current === 'function' ? current.call(context) : current; + }, + + escapeExpression: Utils.escapeExpression, + invokePartial: invokePartialWrapper, + + fn: function fn(i) { + var ret = templateSpec[i]; + ret.decorator = templateSpec[i + '_d']; + return ret; + }, + + programs: [], + program: function program(i, data, declaredBlockParams, blockParams, depths) { + var programWrapper = this.programs[i], + fn = this.fn(i); + if (data || depths || blockParams || declaredBlockParams) { + programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); + } else if (!programWrapper) { + programWrapper = this.programs[i] = wrapProgram(this, i, fn); + } + return programWrapper; + }, + + data: function data(value, depth) { + while (value && depth--) { + value = value._parent; + } + return value; + }, + merge: function merge(param, common) { + var obj = param || common; + + if (param && common && param !== common) { + obj = Utils.extend({}, common, param); + } + + return obj; + }, + // An empty object to use as replacement for null-contexts + nullContext: _Object$seal({}), + + noop: env.VM.noop, + compilerInfo: templateSpec.compiler + }; + + function ret(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var data = options.data; + + ret._setup(options); + if (!options.partial && templateSpec.useData) { + data = initData(context, data); + } + var depths = undefined, + blockParams = templateSpec.useBlockParams ? [] : undefined; + if (templateSpec.useDepths) { + if (options.depths) { + depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; + } else { + depths = [context]; + } + } + + function main(context /*, options*/) { + return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths); + } + main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams); + return main(context, options); + } + ret.isTop = true; + + ret._setup = function (options) { + if (!options.partial) { + container.helpers = container.merge(options.helpers, env.helpers); + + if (templateSpec.usePartial) { + container.partials = container.merge(options.partials, env.partials); + } + if (templateSpec.usePartial || templateSpec.useDecorators) { + container.decorators = container.merge(options.decorators, env.decorators); + } + } else { + container.helpers = options.helpers; + container.partials = options.partials; + container.decorators = options.decorators; + } + }; + + ret._child = function (i, data, blockParams, depths) { + if (templateSpec.useBlockParams && !blockParams) { + throw new _exception2['default']('must pass block params'); + } + if (templateSpec.useDepths && !depths) { + throw new _exception2['default']('must pass parent depths'); + } + + return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); + }; + return ret; + } + + function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { + function prog(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var currentDepths = depths; + if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) { + currentDepths = [context].concat(depths); + } + + return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths); + } + + prog = executeDecorators(fn, prog, container, depths, data, blockParams); + + prog.program = i; + prog.depth = depths ? depths.length : 0; + prog.blockParams = declaredBlockParams || 0; + return prog; + } + + function resolvePartial(partial, context, options) { + if (!partial) { + if (options.name === '@partial-block') { + partial = options.data['partial-block']; + } else { + partial = options.partials[options.name]; + } + } else if (!partial.call && !options.name) { + // This is a dynamic partial that returned a string + options.name = partial; + partial = options.partials[partial]; + } + return partial; + } + + function invokePartial(partial, context, options) { + // Use the current closure context to save the partial-block if this partial + var currentPartialBlock = options.data && options.data['partial-block']; + options.partial = true; + if (options.ids) { + options.data.contextPath = options.ids[0] || options.data.contextPath; + } + + var partialBlock = undefined; + if (options.fn && options.fn !== noop) { + (function () { + options.data = _base.createFrame(options.data); + // Wrapper function to get access to currentPartialBlock from the closure + var fn = options.fn; + partialBlock = options.data['partial-block'] = function partialBlockWrapper(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + // Restore the partial-block from the closure for the execution of the block + // i.e. the part inside the block of the partial call. + options.data = _base.createFrame(options.data); + options.data['partial-block'] = currentPartialBlock; + return fn(context, options); + }; + if (fn.partials) { + options.partials = Utils.extend({}, options.partials, fn.partials); + } + })(); + } + + if (partial === undefined && partialBlock) { + partial = partialBlock; + } + + if (partial === undefined) { + throw new _exception2['default']('The partial ' + options.name + ' could not be found'); + } else if (partial instanceof Function) { + return partial(context, options); + } + } + + function noop() { + return ''; + } + + function initData(context, data) { + if (!data || !('root' in data)) { + data = data ? _base.createFrame(data) : {}; + data.root = context; + } + return data; + } + + function executeDecorators(fn, prog, container, depths, data, blockParams) { + if (fn.decorator) { + var props = {}; + prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths); + Utils.extend(prog, props); + } + return prog; + } + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(24), __esModule: true }; + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(25); + module.exports = __webpack_require__(30).Object.seal; + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + + // 19.1.2.17 Object.seal(O) + var isObject = __webpack_require__(26); + + __webpack_require__(27)('seal', function($seal){ + return function seal(it){ + return $seal && isObject(it) ? $seal(it) : it; + }; + }); + +/***/ }), +/* 26 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + return typeof it === 'object' ? it !== null : typeof it === 'function'; + }; + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + + // most Object methods by ES6 should accept primitives + var $export = __webpack_require__(28) + , core = __webpack_require__(30) + , fails = __webpack_require__(33); + module.exports = function(KEY, exec){ + var fn = (core.Object || {})[KEY] || Object[KEY] + , exp = {}; + exp[KEY] = exec(fn); + $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); + }; + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + + var global = __webpack_require__(29) + , core = __webpack_require__(30) + , ctx = __webpack_require__(31) + , PROTOTYPE = 'prototype'; + + var $export = function(type, name, source){ + var IS_FORCED = type & $export.F + , IS_GLOBAL = type & $export.G + , IS_STATIC = type & $export.S + , IS_PROTO = type & $export.P + , IS_BIND = type & $export.B + , IS_WRAP = type & $export.W + , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) + , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] + , key, own, out; + if(IS_GLOBAL)source = name; + for(key in source){ + // contains in native + own = !IS_FORCED && target && key in target; + if(own && key in exports)continue; + // export native or passed + out = own ? target[key] : source[key]; + // prevent global pollution for namespaces + exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] + // bind timers to global for call from export context + : IS_BIND && own ? ctx(out, global) + // wrap global constructors for prevent change them in library + : IS_WRAP && target[key] == out ? (function(C){ + var F = function(param){ + return this instanceof C ? new C(param) : C(param); + }; + F[PROTOTYPE] = C[PROTOTYPE]; + return F; + // make static versions for prototype methods + })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; + if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; + } + }; + // type bitmap + $export.F = 1; // forced + $export.G = 2; // global + $export.S = 4; // static + $export.P = 8; // proto + $export.B = 16; // bind + $export.W = 32; // wrap + module.exports = $export; + +/***/ }), +/* 29 */ +/***/ (function(module, exports) { + + // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); + if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef + +/***/ }), +/* 30 */ +/***/ (function(module, exports) { + + var core = module.exports = {version: '1.2.6'}; + if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + + // optional / simple context binding + var aFunction = __webpack_require__(32); + module.exports = function(fn, that, length){ + aFunction(fn); + if(that === undefined)return fn; + switch(length){ + case 1: return function(a){ + return fn.call(that, a); + }; + case 2: return function(a, b){ + return fn.call(that, a, b); + }; + case 3: return function(a, b, c){ + return fn.call(that, a, b, c); + }; + } + return function(/* ...args */){ + return fn.apply(that, arguments); + }; + }; + +/***/ }), +/* 32 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + if(typeof it != 'function')throw TypeError(it + ' is not a function!'); + return it; + }; + +/***/ }), +/* 33 */ +/***/ (function(module, exports) { + + module.exports = function(exec){ + try { + return !!exec(); + } catch(e){ + return true; + } + }; + +/***/ }), +/* 34 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/* global window */ + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (Handlebars) { + /* istanbul ignore next */ + var root = typeof global !== 'undefined' ? global : window, + $Handlebars = root.Handlebars; + /* istanbul ignore next */ + Handlebars.noConflict = function () { + if (root.Handlebars === Handlebars) { + root.Handlebars = $Handlebars; + } + return Handlebars; + }; + }; + + module.exports = exports['default']; + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 35 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + var AST = { + // Public API used to evaluate derived attributes regarding AST nodes + helpers: { + // a mustache is definitely a helper if: + // * it is an eligible helper, and + // * it has at least one parameter or hash segment + helperExpression: function helperExpression(node) { + return node.type === 'SubExpression' || (node.type === 'MustacheStatement' || node.type === 'BlockStatement') && !!(node.params && node.params.length || node.hash); + }, + + scopedId: function scopedId(path) { + return (/^\.|this\b/.test(path.original) + ); + }, + + // an ID is simple if it only has one part, and that part is not + // `..` or `this`. + simpleId: function simpleId(path) { + return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth; + } + } + }; + + // Must be exported as an object rather than the root of the module as the jison lexer + // must modify the object to operate properly. + exports['default'] = AST; + module.exports = exports['default']; + +/***/ }), +/* 36 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + exports.__esModule = true; + exports.parse = parse; + + var _parser = __webpack_require__(37); + + var _parser2 = _interopRequireDefault(_parser); + + var _whitespaceControl = __webpack_require__(38); + + var _whitespaceControl2 = _interopRequireDefault(_whitespaceControl); + + var _helpers = __webpack_require__(40); + + var Helpers = _interopRequireWildcard(_helpers); + + var _utils = __webpack_require__(5); + + exports.parser = _parser2['default']; + + var yy = {}; + _utils.extend(yy, Helpers); + + function parse(input, options) { + // Just return if an already-compiled AST was passed in. + if (input.type === 'Program') { + return input; + } + + _parser2['default'].yy = yy; + + // Altering the shared object here, but this is ok as parser is a sync operation + yy.locInfo = function (locInfo) { + return new yy.SourceLocation(options && options.srcName, locInfo); + }; + + var strip = new _whitespaceControl2['default'](options); + return strip.accept(_parser2['default'].parse(input)); + } + +/***/ }), +/* 37 */ +/***/ (function(module, exports) { + + // File ignored in coverage tests via setting in .istanbul.yml + /* Jison generated parser */ + "use strict"; + + exports.__esModule = true; + var handlebars = (function () { + var parser = { trace: function trace() {}, + yy: {}, + symbols_: { "error": 2, "root": 3, "program": 4, "EOF": 5, "program_repetition0": 6, "statement": 7, "mustache": 8, "block": 9, "rawBlock": 10, "partial": 11, "partialBlock": 12, "content": 13, "COMMENT": 14, "CONTENT": 15, "openRawBlock": 16, "rawBlock_repetition_plus0": 17, "END_RAW_BLOCK": 18, "OPEN_RAW_BLOCK": 19, "helperName": 20, "openRawBlock_repetition0": 21, "openRawBlock_option0": 22, "CLOSE_RAW_BLOCK": 23, "openBlock": 24, "block_option0": 25, "closeBlock": 26, "openInverse": 27, "block_option1": 28, "OPEN_BLOCK": 29, "openBlock_repetition0": 30, "openBlock_option0": 31, "openBlock_option1": 32, "CLOSE": 33, "OPEN_INVERSE": 34, "openInverse_repetition0": 35, "openInverse_option0": 36, "openInverse_option1": 37, "openInverseChain": 38, "OPEN_INVERSE_CHAIN": 39, "openInverseChain_repetition0": 40, "openInverseChain_option0": 41, "openInverseChain_option1": 42, "inverseAndProgram": 43, "INVERSE": 44, "inverseChain": 45, "inverseChain_option0": 46, "OPEN_ENDBLOCK": 47, "OPEN": 48, "mustache_repetition0": 49, "mustache_option0": 50, "OPEN_UNESCAPED": 51, "mustache_repetition1": 52, "mustache_option1": 53, "CLOSE_UNESCAPED": 54, "OPEN_PARTIAL": 55, "partialName": 56, "partial_repetition0": 57, "partial_option0": 58, "openPartialBlock": 59, "OPEN_PARTIAL_BLOCK": 60, "openPartialBlock_repetition0": 61, "openPartialBlock_option0": 62, "param": 63, "sexpr": 64, "OPEN_SEXPR": 65, "sexpr_repetition0": 66, "sexpr_option0": 67, "CLOSE_SEXPR": 68, "hash": 69, "hash_repetition_plus0": 70, "hashSegment": 71, "ID": 72, "EQUALS": 73, "blockParams": 74, "OPEN_BLOCK_PARAMS": 75, "blockParams_repetition_plus0": 76, "CLOSE_BLOCK_PARAMS": 77, "path": 78, "dataName": 79, "STRING": 80, "NUMBER": 81, "BOOLEAN": 82, "UNDEFINED": 83, "NULL": 84, "DATA": 85, "pathSegments": 86, "SEP": 87, "$accept": 0, "$end": 1 }, + terminals_: { 2: "error", 5: "EOF", 14: "COMMENT", 15: "CONTENT", 18: "END_RAW_BLOCK", 19: "OPEN_RAW_BLOCK", 23: "CLOSE_RAW_BLOCK", 29: "OPEN_BLOCK", 33: "CLOSE", 34: "OPEN_INVERSE", 39: "OPEN_INVERSE_CHAIN", 44: "INVERSE", 47: "OPEN_ENDBLOCK", 48: "OPEN", 51: "OPEN_UNESCAPED", 54: "CLOSE_UNESCAPED", 55: "OPEN_PARTIAL", 60: "OPEN_PARTIAL_BLOCK", 65: "OPEN_SEXPR", 68: "CLOSE_SEXPR", 72: "ID", 73: "EQUALS", 75: "OPEN_BLOCK_PARAMS", 77: "CLOSE_BLOCK_PARAMS", 80: "STRING", 81: "NUMBER", 82: "BOOLEAN", 83: "UNDEFINED", 84: "NULL", 85: "DATA", 87: "SEP" }, + productions_: [0, [3, 2], [4, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [13, 1], [10, 3], [16, 5], [9, 4], [9, 4], [24, 6], [27, 6], [38, 6], [43, 2], [45, 3], [45, 1], [26, 3], [8, 5], [8, 5], [11, 5], [12, 3], [59, 5], [63, 1], [63, 1], [64, 5], [69, 1], [71, 3], [74, 3], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [56, 1], [56, 1], [79, 2], [78, 1], [86, 3], [86, 1], [6, 0], [6, 2], [17, 1], [17, 2], [21, 0], [21, 2], [22, 0], [22, 1], [25, 0], [25, 1], [28, 0], [28, 1], [30, 0], [30, 2], [31, 0], [31, 1], [32, 0], [32, 1], [35, 0], [35, 2], [36, 0], [36, 1], [37, 0], [37, 1], [40, 0], [40, 2], [41, 0], [41, 1], [42, 0], [42, 1], [46, 0], [46, 1], [49, 0], [49, 2], [50, 0], [50, 1], [52, 0], [52, 2], [53, 0], [53, 1], [57, 0], [57, 2], [58, 0], [58, 1], [61, 0], [61, 2], [62, 0], [62, 1], [66, 0], [66, 2], [67, 0], [67, 1], [70, 1], [70, 2], [76, 1], [76, 2]], + performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$ + /**/) { + + var $0 = $$.length - 1; + switch (yystate) { + case 1: + return $$[$0 - 1]; + break; + case 2: + this.$ = yy.prepareProgram($$[$0]); + break; + case 3: + this.$ = $$[$0]; + break; + case 4: + this.$ = $$[$0]; + break; + case 5: + this.$ = $$[$0]; + break; + case 6: + this.$ = $$[$0]; + break; + case 7: + this.$ = $$[$0]; + break; + case 8: + this.$ = $$[$0]; + break; + case 9: + this.$ = { + type: 'CommentStatement', + value: yy.stripComment($$[$0]), + strip: yy.stripFlags($$[$0], $$[$0]), + loc: yy.locInfo(this._$) + }; + + break; + case 10: + this.$ = { + type: 'ContentStatement', + original: $$[$0], + value: $$[$0], + loc: yy.locInfo(this._$) + }; + + break; + case 11: + this.$ = yy.prepareRawBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); + break; + case 12: + this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1] }; + break; + case 13: + this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], false, this._$); + break; + case 14: + this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], true, this._$); + break; + case 15: + this.$ = { open: $$[$0 - 5], path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 16: + this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 17: + this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 18: + this.$ = { strip: yy.stripFlags($$[$0 - 1], $$[$0 - 1]), program: $$[$0] }; + break; + case 19: + var inverse = yy.prepareBlock($$[$0 - 2], $$[$0 - 1], $$[$0], $$[$0], false, this._$), + program = yy.prepareProgram([inverse], $$[$0 - 1].loc); + program.chained = true; + + this.$ = { strip: $$[$0 - 2].strip, program: program, chain: true }; + + break; + case 20: + this.$ = $$[$0]; + break; + case 21: + this.$ = { path: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 2], $$[$0]) }; + break; + case 22: + this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); + break; + case 23: + this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); + break; + case 24: + this.$ = { + type: 'PartialStatement', + name: $$[$0 - 3], + params: $$[$0 - 2], + hash: $$[$0 - 1], + indent: '', + strip: yy.stripFlags($$[$0 - 4], $$[$0]), + loc: yy.locInfo(this._$) + }; + + break; + case 25: + this.$ = yy.preparePartialBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); + break; + case 26: + this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 4], $$[$0]) }; + break; + case 27: + this.$ = $$[$0]; + break; + case 28: + this.$ = $$[$0]; + break; + case 29: + this.$ = { + type: 'SubExpression', + path: $$[$0 - 3], + params: $$[$0 - 2], + hash: $$[$0 - 1], + loc: yy.locInfo(this._$) + }; + + break; + case 30: + this.$ = { type: 'Hash', pairs: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 31: + this.$ = { type: 'HashPair', key: yy.id($$[$0 - 2]), value: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 32: + this.$ = yy.id($$[$0 - 1]); + break; + case 33: + this.$ = $$[$0]; + break; + case 34: + this.$ = $$[$0]; + break; + case 35: + this.$ = { type: 'StringLiteral', value: $$[$0], original: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 36: + this.$ = { type: 'NumberLiteral', value: Number($$[$0]), original: Number($$[$0]), loc: yy.locInfo(this._$) }; + break; + case 37: + this.$ = { type: 'BooleanLiteral', value: $$[$0] === 'true', original: $$[$0] === 'true', loc: yy.locInfo(this._$) }; + break; + case 38: + this.$ = { type: 'UndefinedLiteral', original: undefined, value: undefined, loc: yy.locInfo(this._$) }; + break; + case 39: + this.$ = { type: 'NullLiteral', original: null, value: null, loc: yy.locInfo(this._$) }; + break; + case 40: + this.$ = $$[$0]; + break; + case 41: + this.$ = $$[$0]; + break; + case 42: + this.$ = yy.preparePath(true, $$[$0], this._$); + break; + case 43: + this.$ = yy.preparePath(false, $$[$0], this._$); + break; + case 44: + $$[$0 - 2].push({ part: yy.id($$[$0]), original: $$[$0], separator: $$[$0 - 1] });this.$ = $$[$0 - 2]; + break; + case 45: + this.$ = [{ part: yy.id($$[$0]), original: $$[$0] }]; + break; + case 46: + this.$ = []; + break; + case 47: + $$[$0 - 1].push($$[$0]); + break; + case 48: + this.$ = [$$[$0]]; + break; + case 49: + $$[$0 - 1].push($$[$0]); + break; + case 50: + this.$ = []; + break; + case 51: + $$[$0 - 1].push($$[$0]); + break; + case 58: + this.$ = []; + break; + case 59: + $$[$0 - 1].push($$[$0]); + break; + case 64: + this.$ = []; + break; + case 65: + $$[$0 - 1].push($$[$0]); + break; + case 70: + this.$ = []; + break; + case 71: + $$[$0 - 1].push($$[$0]); + break; + case 78: + this.$ = []; + break; + case 79: + $$[$0 - 1].push($$[$0]); + break; + case 82: + this.$ = []; + break; + case 83: + $$[$0 - 1].push($$[$0]); + break; + case 86: + this.$ = []; + break; + case 87: + $$[$0 - 1].push($$[$0]); + break; + case 90: + this.$ = []; + break; + case 91: + $$[$0 - 1].push($$[$0]); + break; + case 94: + this.$ = []; + break; + case 95: + $$[$0 - 1].push($$[$0]); + break; + case 98: + this.$ = [$$[$0]]; + break; + case 99: + $$[$0 - 1].push($$[$0]); + break; + case 100: + this.$ = [$$[$0]]; + break; + case 101: + $$[$0 - 1].push($$[$0]); + break; + } + }, + table: [{ 3: 1, 4: 2, 5: [2, 46], 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 1: [3] }, { 5: [1, 4] }, { 5: [2, 2], 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, 13: 11, 14: [1, 12], 15: [1, 20], 16: 17, 19: [1, 23], 24: 15, 27: 16, 29: [1, 21], 34: [1, 22], 39: [2, 2], 44: [2, 2], 47: [2, 2], 48: [1, 13], 51: [1, 14], 55: [1, 18], 59: 19, 60: [1, 24] }, { 1: [2, 1] }, { 5: [2, 47], 14: [2, 47], 15: [2, 47], 19: [2, 47], 29: [2, 47], 34: [2, 47], 39: [2, 47], 44: [2, 47], 47: [2, 47], 48: [2, 47], 51: [2, 47], 55: [2, 47], 60: [2, 47] }, { 5: [2, 3], 14: [2, 3], 15: [2, 3], 19: [2, 3], 29: [2, 3], 34: [2, 3], 39: [2, 3], 44: [2, 3], 47: [2, 3], 48: [2, 3], 51: [2, 3], 55: [2, 3], 60: [2, 3] }, { 5: [2, 4], 14: [2, 4], 15: [2, 4], 19: [2, 4], 29: [2, 4], 34: [2, 4], 39: [2, 4], 44: [2, 4], 47: [2, 4], 48: [2, 4], 51: [2, 4], 55: [2, 4], 60: [2, 4] }, { 5: [2, 5], 14: [2, 5], 15: [2, 5], 19: [2, 5], 29: [2, 5], 34: [2, 5], 39: [2, 5], 44: [2, 5], 47: [2, 5], 48: [2, 5], 51: [2, 5], 55: [2, 5], 60: [2, 5] }, { 5: [2, 6], 14: [2, 6], 15: [2, 6], 19: [2, 6], 29: [2, 6], 34: [2, 6], 39: [2, 6], 44: [2, 6], 47: [2, 6], 48: [2, 6], 51: [2, 6], 55: [2, 6], 60: [2, 6] }, { 5: [2, 7], 14: [2, 7], 15: [2, 7], 19: [2, 7], 29: [2, 7], 34: [2, 7], 39: [2, 7], 44: [2, 7], 47: [2, 7], 48: [2, 7], 51: [2, 7], 55: [2, 7], 60: [2, 7] }, { 5: [2, 8], 14: [2, 8], 15: [2, 8], 19: [2, 8], 29: [2, 8], 34: [2, 8], 39: [2, 8], 44: [2, 8], 47: [2, 8], 48: [2, 8], 51: [2, 8], 55: [2, 8], 60: [2, 8] }, { 5: [2, 9], 14: [2, 9], 15: [2, 9], 19: [2, 9], 29: [2, 9], 34: [2, 9], 39: [2, 9], 44: [2, 9], 47: [2, 9], 48: [2, 9], 51: [2, 9], 55: [2, 9], 60: [2, 9] }, { 20: 25, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 36, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 37, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 4: 38, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 13: 40, 15: [1, 20], 17: 39 }, { 20: 42, 56: 41, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 45, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 5: [2, 10], 14: [2, 10], 15: [2, 10], 18: [2, 10], 19: [2, 10], 29: [2, 10], 34: [2, 10], 39: [2, 10], 44: [2, 10], 47: [2, 10], 48: [2, 10], 51: [2, 10], 55: [2, 10], 60: [2, 10] }, { 20: 46, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 47, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 48, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 42, 56: 49, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [2, 78], 49: 50, 65: [2, 78], 72: [2, 78], 80: [2, 78], 81: [2, 78], 82: [2, 78], 83: [2, 78], 84: [2, 78], 85: [2, 78] }, { 23: [2, 33], 33: [2, 33], 54: [2, 33], 65: [2, 33], 68: [2, 33], 72: [2, 33], 75: [2, 33], 80: [2, 33], 81: [2, 33], 82: [2, 33], 83: [2, 33], 84: [2, 33], 85: [2, 33] }, { 23: [2, 34], 33: [2, 34], 54: [2, 34], 65: [2, 34], 68: [2, 34], 72: [2, 34], 75: [2, 34], 80: [2, 34], 81: [2, 34], 82: [2, 34], 83: [2, 34], 84: [2, 34], 85: [2, 34] }, { 23: [2, 35], 33: [2, 35], 54: [2, 35], 65: [2, 35], 68: [2, 35], 72: [2, 35], 75: [2, 35], 80: [2, 35], 81: [2, 35], 82: [2, 35], 83: [2, 35], 84: [2, 35], 85: [2, 35] }, { 23: [2, 36], 33: [2, 36], 54: [2, 36], 65: [2, 36], 68: [2, 36], 72: [2, 36], 75: [2, 36], 80: [2, 36], 81: [2, 36], 82: [2, 36], 83: [2, 36], 84: [2, 36], 85: [2, 36] }, { 23: [2, 37], 33: [2, 37], 54: [2, 37], 65: [2, 37], 68: [2, 37], 72: [2, 37], 75: [2, 37], 80: [2, 37], 81: [2, 37], 82: [2, 37], 83: [2, 37], 84: [2, 37], 85: [2, 37] }, { 23: [2, 38], 33: [2, 38], 54: [2, 38], 65: [2, 38], 68: [2, 38], 72: [2, 38], 75: [2, 38], 80: [2, 38], 81: [2, 38], 82: [2, 38], 83: [2, 38], 84: [2, 38], 85: [2, 38] }, { 23: [2, 39], 33: [2, 39], 54: [2, 39], 65: [2, 39], 68: [2, 39], 72: [2, 39], 75: [2, 39], 80: [2, 39], 81: [2, 39], 82: [2, 39], 83: [2, 39], 84: [2, 39], 85: [2, 39] }, { 23: [2, 43], 33: [2, 43], 54: [2, 43], 65: [2, 43], 68: [2, 43], 72: [2, 43], 75: [2, 43], 80: [2, 43], 81: [2, 43], 82: [2, 43], 83: [2, 43], 84: [2, 43], 85: [2, 43], 87: [1, 51] }, { 72: [1, 35], 86: 52 }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 52: 53, 54: [2, 82], 65: [2, 82], 72: [2, 82], 80: [2, 82], 81: [2, 82], 82: [2, 82], 83: [2, 82], 84: [2, 82], 85: [2, 82] }, { 25: 54, 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 55, 47: [2, 54] }, { 28: 60, 43: 61, 44: [1, 59], 47: [2, 56] }, { 13: 63, 15: [1, 20], 18: [1, 62] }, { 15: [2, 48], 18: [2, 48] }, { 33: [2, 86], 57: 64, 65: [2, 86], 72: [2, 86], 80: [2, 86], 81: [2, 86], 82: [2, 86], 83: [2, 86], 84: [2, 86], 85: [2, 86] }, { 33: [2, 40], 65: [2, 40], 72: [2, 40], 80: [2, 40], 81: [2, 40], 82: [2, 40], 83: [2, 40], 84: [2, 40], 85: [2, 40] }, { 33: [2, 41], 65: [2, 41], 72: [2, 41], 80: [2, 41], 81: [2, 41], 82: [2, 41], 83: [2, 41], 84: [2, 41], 85: [2, 41] }, { 20: 65, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 66, 47: [1, 67] }, { 30: 68, 33: [2, 58], 65: [2, 58], 72: [2, 58], 75: [2, 58], 80: [2, 58], 81: [2, 58], 82: [2, 58], 83: [2, 58], 84: [2, 58], 85: [2, 58] }, { 33: [2, 64], 35: 69, 65: [2, 64], 72: [2, 64], 75: [2, 64], 80: [2, 64], 81: [2, 64], 82: [2, 64], 83: [2, 64], 84: [2, 64], 85: [2, 64] }, { 21: 70, 23: [2, 50], 65: [2, 50], 72: [2, 50], 80: [2, 50], 81: [2, 50], 82: [2, 50], 83: [2, 50], 84: [2, 50], 85: [2, 50] }, { 33: [2, 90], 61: 71, 65: [2, 90], 72: [2, 90], 80: [2, 90], 81: [2, 90], 82: [2, 90], 83: [2, 90], 84: [2, 90], 85: [2, 90] }, { 20: 75, 33: [2, 80], 50: 72, 63: 73, 64: 76, 65: [1, 44], 69: 74, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 72: [1, 80] }, { 23: [2, 42], 33: [2, 42], 54: [2, 42], 65: [2, 42], 68: [2, 42], 72: [2, 42], 75: [2, 42], 80: [2, 42], 81: [2, 42], 82: [2, 42], 83: [2, 42], 84: [2, 42], 85: [2, 42], 87: [1, 51] }, { 20: 75, 53: 81, 54: [2, 84], 63: 82, 64: 76, 65: [1, 44], 69: 83, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 84, 47: [1, 67] }, { 47: [2, 55] }, { 4: 85, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 47: [2, 20] }, { 20: 86, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 87, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 26: 88, 47: [1, 67] }, { 47: [2, 57] }, { 5: [2, 11], 14: [2, 11], 15: [2, 11], 19: [2, 11], 29: [2, 11], 34: [2, 11], 39: [2, 11], 44: [2, 11], 47: [2, 11], 48: [2, 11], 51: [2, 11], 55: [2, 11], 60: [2, 11] }, { 15: [2, 49], 18: [2, 49] }, { 20: 75, 33: [2, 88], 58: 89, 63: 90, 64: 76, 65: [1, 44], 69: 91, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 65: [2, 94], 66: 92, 68: [2, 94], 72: [2, 94], 80: [2, 94], 81: [2, 94], 82: [2, 94], 83: [2, 94], 84: [2, 94], 85: [2, 94] }, { 5: [2, 25], 14: [2, 25], 15: [2, 25], 19: [2, 25], 29: [2, 25], 34: [2, 25], 39: [2, 25], 44: [2, 25], 47: [2, 25], 48: [2, 25], 51: [2, 25], 55: [2, 25], 60: [2, 25] }, { 20: 93, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 31: 94, 33: [2, 60], 63: 95, 64: 76, 65: [1, 44], 69: 96, 70: 77, 71: 78, 72: [1, 79], 75: [2, 60], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 66], 36: 97, 63: 98, 64: 76, 65: [1, 44], 69: 99, 70: 77, 71: 78, 72: [1, 79], 75: [2, 66], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 22: 100, 23: [2, 52], 63: 101, 64: 76, 65: [1, 44], 69: 102, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 92], 62: 103, 63: 104, 64: 76, 65: [1, 44], 69: 105, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 106] }, { 33: [2, 79], 65: [2, 79], 72: [2, 79], 80: [2, 79], 81: [2, 79], 82: [2, 79], 83: [2, 79], 84: [2, 79], 85: [2, 79] }, { 33: [2, 81] }, { 23: [2, 27], 33: [2, 27], 54: [2, 27], 65: [2, 27], 68: [2, 27], 72: [2, 27], 75: [2, 27], 80: [2, 27], 81: [2, 27], 82: [2, 27], 83: [2, 27], 84: [2, 27], 85: [2, 27] }, { 23: [2, 28], 33: [2, 28], 54: [2, 28], 65: [2, 28], 68: [2, 28], 72: [2, 28], 75: [2, 28], 80: [2, 28], 81: [2, 28], 82: [2, 28], 83: [2, 28], 84: [2, 28], 85: [2, 28] }, { 23: [2, 30], 33: [2, 30], 54: [2, 30], 68: [2, 30], 71: 107, 72: [1, 108], 75: [2, 30] }, { 23: [2, 98], 33: [2, 98], 54: [2, 98], 68: [2, 98], 72: [2, 98], 75: [2, 98] }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 73: [1, 109], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 23: [2, 44], 33: [2, 44], 54: [2, 44], 65: [2, 44], 68: [2, 44], 72: [2, 44], 75: [2, 44], 80: [2, 44], 81: [2, 44], 82: [2, 44], 83: [2, 44], 84: [2, 44], 85: [2, 44], 87: [2, 44] }, { 54: [1, 110] }, { 54: [2, 83], 65: [2, 83], 72: [2, 83], 80: [2, 83], 81: [2, 83], 82: [2, 83], 83: [2, 83], 84: [2, 83], 85: [2, 83] }, { 54: [2, 85] }, { 5: [2, 13], 14: [2, 13], 15: [2, 13], 19: [2, 13], 29: [2, 13], 34: [2, 13], 39: [2, 13], 44: [2, 13], 47: [2, 13], 48: [2, 13], 51: [2, 13], 55: [2, 13], 60: [2, 13] }, { 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 112, 46: 111, 47: [2, 76] }, { 33: [2, 70], 40: 113, 65: [2, 70], 72: [2, 70], 75: [2, 70], 80: [2, 70], 81: [2, 70], 82: [2, 70], 83: [2, 70], 84: [2, 70], 85: [2, 70] }, { 47: [2, 18] }, { 5: [2, 14], 14: [2, 14], 15: [2, 14], 19: [2, 14], 29: [2, 14], 34: [2, 14], 39: [2, 14], 44: [2, 14], 47: [2, 14], 48: [2, 14], 51: [2, 14], 55: [2, 14], 60: [2, 14] }, { 33: [1, 114] }, { 33: [2, 87], 65: [2, 87], 72: [2, 87], 80: [2, 87], 81: [2, 87], 82: [2, 87], 83: [2, 87], 84: [2, 87], 85: [2, 87] }, { 33: [2, 89] }, { 20: 75, 63: 116, 64: 76, 65: [1, 44], 67: 115, 68: [2, 96], 69: 117, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 118] }, { 32: 119, 33: [2, 62], 74: 120, 75: [1, 121] }, { 33: [2, 59], 65: [2, 59], 72: [2, 59], 75: [2, 59], 80: [2, 59], 81: [2, 59], 82: [2, 59], 83: [2, 59], 84: [2, 59], 85: [2, 59] }, { 33: [2, 61], 75: [2, 61] }, { 33: [2, 68], 37: 122, 74: 123, 75: [1, 121] }, { 33: [2, 65], 65: [2, 65], 72: [2, 65], 75: [2, 65], 80: [2, 65], 81: [2, 65], 82: [2, 65], 83: [2, 65], 84: [2, 65], 85: [2, 65] }, { 33: [2, 67], 75: [2, 67] }, { 23: [1, 124] }, { 23: [2, 51], 65: [2, 51], 72: [2, 51], 80: [2, 51], 81: [2, 51], 82: [2, 51], 83: [2, 51], 84: [2, 51], 85: [2, 51] }, { 23: [2, 53] }, { 33: [1, 125] }, { 33: [2, 91], 65: [2, 91], 72: [2, 91], 80: [2, 91], 81: [2, 91], 82: [2, 91], 83: [2, 91], 84: [2, 91], 85: [2, 91] }, { 33: [2, 93] }, { 5: [2, 22], 14: [2, 22], 15: [2, 22], 19: [2, 22], 29: [2, 22], 34: [2, 22], 39: [2, 22], 44: [2, 22], 47: [2, 22], 48: [2, 22], 51: [2, 22], 55: [2, 22], 60: [2, 22] }, { 23: [2, 99], 33: [2, 99], 54: [2, 99], 68: [2, 99], 72: [2, 99], 75: [2, 99] }, { 73: [1, 109] }, { 20: 75, 63: 126, 64: 76, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 23], 14: [2, 23], 15: [2, 23], 19: [2, 23], 29: [2, 23], 34: [2, 23], 39: [2, 23], 44: [2, 23], 47: [2, 23], 48: [2, 23], 51: [2, 23], 55: [2, 23], 60: [2, 23] }, { 47: [2, 19] }, { 47: [2, 77] }, { 20: 75, 33: [2, 72], 41: 127, 63: 128, 64: 76, 65: [1, 44], 69: 129, 70: 77, 71: 78, 72: [1, 79], 75: [2, 72], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 24], 14: [2, 24], 15: [2, 24], 19: [2, 24], 29: [2, 24], 34: [2, 24], 39: [2, 24], 44: [2, 24], 47: [2, 24], 48: [2, 24], 51: [2, 24], 55: [2, 24], 60: [2, 24] }, { 68: [1, 130] }, { 65: [2, 95], 68: [2, 95], 72: [2, 95], 80: [2, 95], 81: [2, 95], 82: [2, 95], 83: [2, 95], 84: [2, 95], 85: [2, 95] }, { 68: [2, 97] }, { 5: [2, 21], 14: [2, 21], 15: [2, 21], 19: [2, 21], 29: [2, 21], 34: [2, 21], 39: [2, 21], 44: [2, 21], 47: [2, 21], 48: [2, 21], 51: [2, 21], 55: [2, 21], 60: [2, 21] }, { 33: [1, 131] }, { 33: [2, 63] }, { 72: [1, 133], 76: 132 }, { 33: [1, 134] }, { 33: [2, 69] }, { 15: [2, 12] }, { 14: [2, 26], 15: [2, 26], 19: [2, 26], 29: [2, 26], 34: [2, 26], 47: [2, 26], 48: [2, 26], 51: [2, 26], 55: [2, 26], 60: [2, 26] }, { 23: [2, 31], 33: [2, 31], 54: [2, 31], 68: [2, 31], 72: [2, 31], 75: [2, 31] }, { 33: [2, 74], 42: 135, 74: 136, 75: [1, 121] }, { 33: [2, 71], 65: [2, 71], 72: [2, 71], 75: [2, 71], 80: [2, 71], 81: [2, 71], 82: [2, 71], 83: [2, 71], 84: [2, 71], 85: [2, 71] }, { 33: [2, 73], 75: [2, 73] }, { 23: [2, 29], 33: [2, 29], 54: [2, 29], 65: [2, 29], 68: [2, 29], 72: [2, 29], 75: [2, 29], 80: [2, 29], 81: [2, 29], 82: [2, 29], 83: [2, 29], 84: [2, 29], 85: [2, 29] }, { 14: [2, 15], 15: [2, 15], 19: [2, 15], 29: [2, 15], 34: [2, 15], 39: [2, 15], 44: [2, 15], 47: [2, 15], 48: [2, 15], 51: [2, 15], 55: [2, 15], 60: [2, 15] }, { 72: [1, 138], 77: [1, 137] }, { 72: [2, 100], 77: [2, 100] }, { 14: [2, 16], 15: [2, 16], 19: [2, 16], 29: [2, 16], 34: [2, 16], 44: [2, 16], 47: [2, 16], 48: [2, 16], 51: [2, 16], 55: [2, 16], 60: [2, 16] }, { 33: [1, 139] }, { 33: [2, 75] }, { 33: [2, 32] }, { 72: [2, 101], 77: [2, 101] }, { 14: [2, 17], 15: [2, 17], 19: [2, 17], 29: [2, 17], 34: [2, 17], 39: [2, 17], 44: [2, 17], 47: [2, 17], 48: [2, 17], 51: [2, 17], 55: [2, 17], 60: [2, 17] }], + defaultActions: { 4: [2, 1], 55: [2, 55], 57: [2, 20], 61: [2, 57], 74: [2, 81], 83: [2, 85], 87: [2, 18], 91: [2, 89], 102: [2, 53], 105: [2, 93], 111: [2, 19], 112: [2, 77], 117: [2, 97], 120: [2, 63], 123: [2, 69], 124: [2, 12], 136: [2, 75], 137: [2, 32] }, + parseError: function parseError(str, hash) { + throw new Error(str); + }, + parse: function parse(input) { + var self = this, + stack = [0], + vstack = [null], + lstack = [], + table = this.table, + yytext = "", + yylineno = 0, + yyleng = 0, + recovering = 0, + TERROR = 2, + EOF = 1; + this.lexer.setInput(input); + this.lexer.yy = this.yy; + this.yy.lexer = this.lexer; + this.yy.parser = this; + if (typeof this.lexer.yylloc == "undefined") this.lexer.yylloc = {}; + var yyloc = this.lexer.yylloc; + lstack.push(yyloc); + var ranges = this.lexer.options && this.lexer.options.ranges; + if (typeof this.yy.parseError === "function") this.parseError = this.yy.parseError; + function popStack(n) { + stack.length = stack.length - 2 * n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + function lex() { + var token; + token = self.lexer.lex() || 1; + if (typeof token !== "number") { + token = self.symbols_[token] || token; + } + return token; + } + var symbol, + preErrorSymbol, + state, + action, + a, + r, + yyval = {}, + p, + len, + newState, + expected; + while (true) { + state = stack[stack.length - 1]; + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol === null || typeof symbol == "undefined") { + symbol = lex(); + } + action = table[state] && table[state][symbol]; + } + if (typeof action === "undefined" || !action.length || !action[0]) { + var errStr = ""; + if (!recovering) { + expected = []; + for (p in table[state]) if (this.terminals_[p] && p > 2) { + expected.push("'" + this.terminals_[p] + "'"); + } + if (this.lexer.showPosition) { + errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; + } else { + errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'"); + } + this.parseError(errStr, { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected }); + } + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) recovering--; + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = { first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column }; + if (ranges) { + yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; + } + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + if (typeof r !== "undefined") { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; + } + }; + /* Jison generated lexer */ + var lexer = (function () { + var lexer = { EOF: 1, + parseError: function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + setInput: function setInput(input) { + this._input = input; + this._more = this._less = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 }; + if (this.options.ranges) this.yylloc.range = [0, 0]; + this.offset = 0; + return this; + }, + input: function input() { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) this.yylloc.range[1]++; + + this._input = this._input.slice(1); + return ch; + }, + unput: function unput(ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length - 1); + this.matched = this.matched.substr(0, this.matched.length - 1); + + if (lines.length - 1) this.yylineno -= lines.length - 1; + var r = this.yylloc.range; + + this.yylloc = { first_line: this.yylloc.first_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.first_column, + last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + return this; + }, + more: function more() { + this._more = true; + return this; + }, + less: function less(n) { + this.unput(this.match.slice(n)); + }, + pastInput: function pastInput() { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, ""); + }, + upcomingInput: function upcomingInput() { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20 - next.length); + } + return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); + }, + showPosition: function showPosition() { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c + "^"; + }, + next: function next() { + if (this.done) { + return this.EOF; + } + if (!this._input) this.done = true; + + var token, match, tempMatch, index, col, lines; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i = 0; i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (!this.options.flex) break; + } + } + if (match) { + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) this.yylineno += lines.length; + this.yylloc = { first_line: this.yylloc.last_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.last_column, + last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length }; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]); + if (this.done && this._input) this.done = false; + if (token) return token;else return; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { text: "", token: null, line: this.yylineno }); + } + }, + lex: function lex() { + var r = this.next(); + if (typeof r !== 'undefined') { + return r; + } else { + return this.lex(); + } + }, + begin: function begin(condition) { + this.conditionStack.push(condition); + }, + popState: function popState() { + return this.conditionStack.pop(); + }, + _currentRules: function _currentRules() { + return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; + }, + topState: function topState() { + return this.conditionStack[this.conditionStack.length - 2]; + }, + pushState: function begin(condition) { + this.begin(condition); + } }; + lexer.options = {}; + lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START + /**/) { + + function strip(start, end) { + return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng - end); + } + + var YYSTATE = YY_START; + switch ($avoiding_name_collisions) { + case 0: + if (yy_.yytext.slice(-2) === "\\\\") { + strip(0, 1); + this.begin("mu"); + } else if (yy_.yytext.slice(-1) === "\\") { + strip(0, 1); + this.begin("emu"); + } else { + this.begin("mu"); + } + if (yy_.yytext) return 15; + + break; + case 1: + return 15; + break; + case 2: + this.popState(); + return 15; + + break; + case 3: + this.begin('raw');return 15; + break; + case 4: + this.popState(); + // Should be using `this.topState()` below, but it currently + // returns the second top instead of the first top. Opened an + // issue about it at https://github.com/zaach/jison/issues/291 + if (this.conditionStack[this.conditionStack.length - 1] === 'raw') { + return 15; + } else { + yy_.yytext = yy_.yytext.substr(5, yy_.yyleng - 9); + return 'END_RAW_BLOCK'; + } + + break; + case 5: + return 15; + break; + case 6: + this.popState(); + return 14; + + break; + case 7: + return 65; + break; + case 8: + return 68; + break; + case 9: + return 19; + break; + case 10: + this.popState(); + this.begin('raw'); + return 23; + + break; + case 11: + return 55; + break; + case 12: + return 60; + break; + case 13: + return 29; + break; + case 14: + return 47; + break; + case 15: + this.popState();return 44; + break; + case 16: + this.popState();return 44; + break; + case 17: + return 34; + break; + case 18: + return 39; + break; + case 19: + return 51; + break; + case 20: + return 48; + break; + case 21: + this.unput(yy_.yytext); + this.popState(); + this.begin('com'); + + break; + case 22: + this.popState(); + return 14; + + break; + case 23: + return 48; + break; + case 24: + return 73; + break; + case 25: + return 72; + break; + case 26: + return 72; + break; + case 27: + return 87; + break; + case 28: + // ignore whitespace + break; + case 29: + this.popState();return 54; + break; + case 30: + this.popState();return 33; + break; + case 31: + yy_.yytext = strip(1, 2).replace(/\\"/g, '"');return 80; + break; + case 32: + yy_.yytext = strip(1, 2).replace(/\\'/g, "'");return 80; + break; + case 33: + return 85; + break; + case 34: + return 82; + break; + case 35: + return 82; + break; + case 36: + return 83; + break; + case 37: + return 84; + break; + case 38: + return 81; + break; + case 39: + return 75; + break; + case 40: + return 77; + break; + case 41: + return 72; + break; + case 42: + yy_.yytext = yy_.yytext.replace(/\\([\\\]])/g, '$1');return 72; + break; + case 43: + return 'INVALID'; + break; + case 44: + return 5; + break; + } + }; + lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/, /^(?:\{\{\{\{(?=[^\/]))/, /^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/, /^(?:[^\x00]*?(?=(\{\{\{\{)))/, /^(?:[\s\S]*?--(~)?\}\})/, /^(?:\()/, /^(?:\))/, /^(?:\{\{\{\{)/, /^(?:\}\}\}\})/, /^(?:\{\{(~)?>)/, /^(?:\{\{(~)?#>)/, /^(?:\{\{(~)?#\*?)/, /^(?:\{\{(~)?\/)/, /^(?:\{\{(~)?\^\s*(~)?\}\})/, /^(?:\{\{(~)?\s*else\s*(~)?\}\})/, /^(?:\{\{(~)?\^)/, /^(?:\{\{(~)?\s*else\b)/, /^(?:\{\{(~)?\{)/, /^(?:\{\{(~)?&)/, /^(?:\{\{(~)?!--)/, /^(?:\{\{(~)?![\s\S]*?\}\})/, /^(?:\{\{(~)?\*?)/, /^(?:=)/, /^(?:\.\.)/, /^(?:\.(?=([=~}\s\/.)|])))/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}(~)?\}\})/, /^(?:(~)?\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@)/, /^(?:true(?=([~}\s)])))/, /^(?:false(?=([~}\s)])))/, /^(?:undefined(?=([~}\s)])))/, /^(?:null(?=([~}\s)])))/, /^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/, /^(?:as\s+\|)/, /^(?:\|)/, /^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/, /^(?:\[(\\\]|[^\]])*\])/, /^(?:.)/, /^(?:$)/]; + lexer.conditions = { "mu": { "rules": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "inclusive": false }, "emu": { "rules": [2], "inclusive": false }, "com": { "rules": [6], "inclusive": false }, "raw": { "rules": [3, 4, 5], "inclusive": false }, "INITIAL": { "rules": [0, 1, 44], "inclusive": true } }; + return lexer; + })(); + parser.lexer = lexer; + function Parser() { + this.yy = {}; + }Parser.prototype = parser;parser.Parser = Parser; + return new Parser(); + })();exports["default"] = handlebars; + module.exports = exports["default"]; + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _visitor = __webpack_require__(39); + + var _visitor2 = _interopRequireDefault(_visitor); + + function WhitespaceControl() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + this.options = options; + } + WhitespaceControl.prototype = new _visitor2['default'](); + + WhitespaceControl.prototype.Program = function (program) { + var doStandalone = !this.options.ignoreStandalone; + + var isRoot = !this.isRootSeen; + this.isRootSeen = true; + + var body = program.body; + for (var i = 0, l = body.length; i < l; i++) { + var current = body[i], + strip = this.accept(current); + + if (!strip) { + continue; + } + + var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot), + _isNextWhitespace = isNextWhitespace(body, i, isRoot), + openStandalone = strip.openStandalone && _isPrevWhitespace, + closeStandalone = strip.closeStandalone && _isNextWhitespace, + inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace; + + if (strip.close) { + omitRight(body, i, true); + } + if (strip.open) { + omitLeft(body, i, true); + } + + if (doStandalone && inlineStandalone) { + omitRight(body, i); + + if (omitLeft(body, i)) { + // If we are on a standalone node, save the indent info for partials + if (current.type === 'PartialStatement') { + // Pull out the whitespace from the final line + current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1]; + } + } + } + if (doStandalone && openStandalone) { + omitRight((current.program || current.inverse).body); + + // Strip out the previous content node if it's whitespace only + omitLeft(body, i); + } + if (doStandalone && closeStandalone) { + // Always strip the next node + omitRight(body, i); + + omitLeft((current.inverse || current.program).body); + } + } + + return program; + }; + + WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function (block) { + this.accept(block.program); + this.accept(block.inverse); + + // Find the inverse program that is involed with whitespace stripping. + var program = block.program || block.inverse, + inverse = block.program && block.inverse, + firstInverse = inverse, + lastInverse = inverse; + + if (inverse && inverse.chained) { + firstInverse = inverse.body[0].program; + + // Walk the inverse chain to find the last inverse that is actually in the chain. + while (lastInverse.chained) { + lastInverse = lastInverse.body[lastInverse.body.length - 1].program; + } + } + + var strip = { + open: block.openStrip.open, + close: block.closeStrip.close, + + // Determine the standalone candiacy. Basically flag our content as being possibly standalone + // so our parent can determine if we actually are standalone + openStandalone: isNextWhitespace(program.body), + closeStandalone: isPrevWhitespace((firstInverse || program).body) + }; + + if (block.openStrip.close) { + omitRight(program.body, null, true); + } + + if (inverse) { + var inverseStrip = block.inverseStrip; + + if (inverseStrip.open) { + omitLeft(program.body, null, true); + } + + if (inverseStrip.close) { + omitRight(firstInverse.body, null, true); + } + if (block.closeStrip.open) { + omitLeft(lastInverse.body, null, true); + } + + // Find standalone else statments + if (!this.options.ignoreStandalone && isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) { + omitLeft(program.body); + omitRight(firstInverse.body); + } + } else if (block.closeStrip.open) { + omitLeft(program.body, null, true); + } + + return strip; + }; + + WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function (mustache) { + return mustache.strip; + }; + + WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function (node) { + /* istanbul ignore next */ + var strip = node.strip || {}; + return { + inlineStandalone: true, + open: strip.open, + close: strip.close + }; + }; + + function isPrevWhitespace(body, i, isRoot) { + if (i === undefined) { + i = body.length; + } + + // Nodes that end with newlines are considered whitespace (but are special + // cased for strip operations) + var prev = body[i - 1], + sibling = body[i - 2]; + if (!prev) { + return isRoot; + } + + if (prev.type === 'ContentStatement') { + return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(prev.original); + } + } + function isNextWhitespace(body, i, isRoot) { + if (i === undefined) { + i = -1; + } + + var next = body[i + 1], + sibling = body[i + 2]; + if (!next) { + return isRoot; + } + + if (next.type === 'ContentStatement') { + return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(next.original); + } + } + + // Marks the node to the right of the position as omitted. + // I.e. {{foo}}' ' will mark the ' ' node as omitted. + // + // If i is undefined, then the first child will be marked as such. + // + // If mulitple is truthy then all whitespace will be stripped out until non-whitespace + // content is met. + function omitRight(body, i, multiple) { + var current = body[i == null ? 0 : i + 1]; + if (!current || current.type !== 'ContentStatement' || !multiple && current.rightStripped) { + return; + } + + var original = current.value; + current.value = current.value.replace(multiple ? /^\s+/ : /^[ \t]*\r?\n?/, ''); + current.rightStripped = current.value !== original; + } + + // Marks the node to the left of the position as omitted. + // I.e. ' '{{foo}} will mark the ' ' node as omitted. + // + // If i is undefined then the last child will be marked as such. + // + // If mulitple is truthy then all whitespace will be stripped out until non-whitespace + // content is met. + function omitLeft(body, i, multiple) { + var current = body[i == null ? body.length - 1 : i - 1]; + if (!current || current.type !== 'ContentStatement' || !multiple && current.leftStripped) { + return; + } + + // We omit the last node if it's whitespace only and not preceeded by a non-content node. + var original = current.value; + current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, ''); + current.leftStripped = current.value !== original; + return current.leftStripped; + } + + exports['default'] = WhitespaceControl; + module.exports = exports['default']; + +/***/ }), +/* 39 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + function Visitor() { + this.parents = []; + } + + Visitor.prototype = { + constructor: Visitor, + mutating: false, + + // Visits a given value. If mutating, will replace the value if necessary. + acceptKey: function acceptKey(node, name) { + var value = this.accept(node[name]); + if (this.mutating) { + // Hacky sanity check: This may have a few false positives for type for the helper + // methods but will generally do the right thing without a lot of overhead. + if (value && !Visitor.prototype[value.type]) { + throw new _exception2['default']('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type); + } + node[name] = value; + } + }, + + // Performs an accept operation with added sanity check to ensure + // required keys are not removed. + acceptRequired: function acceptRequired(node, name) { + this.acceptKey(node, name); + + if (!node[name]) { + throw new _exception2['default'](node.type + ' requires ' + name); + } + }, + + // Traverses a given array. If mutating, empty respnses will be removed + // for child elements. + acceptArray: function acceptArray(array) { + for (var i = 0, l = array.length; i < l; i++) { + this.acceptKey(array, i); + + if (!array[i]) { + array.splice(i, 1); + i--; + l--; + } + } + }, + + accept: function accept(object) { + if (!object) { + return; + } + + /* istanbul ignore next: Sanity code */ + if (!this[object.type]) { + throw new _exception2['default']('Unknown type: ' + object.type, object); + } + + if (this.current) { + this.parents.unshift(this.current); + } + this.current = object; + + var ret = this[object.type](object); + + this.current = this.parents.shift(); + + if (!this.mutating || ret) { + return ret; + } else if (ret !== false) { + return object; + } + }, + + Program: function Program(program) { + this.acceptArray(program.body); + }, + + MustacheStatement: visitSubExpression, + Decorator: visitSubExpression, + + BlockStatement: visitBlock, + DecoratorBlock: visitBlock, + + PartialStatement: visitPartial, + PartialBlockStatement: function PartialBlockStatement(partial) { + visitPartial.call(this, partial); + + this.acceptKey(partial, 'program'); + }, + + ContentStatement: function ContentStatement() /* content */{}, + CommentStatement: function CommentStatement() /* comment */{}, + + SubExpression: visitSubExpression, + + PathExpression: function PathExpression() /* path */{}, + + StringLiteral: function StringLiteral() /* string */{}, + NumberLiteral: function NumberLiteral() /* number */{}, + BooleanLiteral: function BooleanLiteral() /* bool */{}, + UndefinedLiteral: function UndefinedLiteral() /* literal */{}, + NullLiteral: function NullLiteral() /* literal */{}, + + Hash: function Hash(hash) { + this.acceptArray(hash.pairs); + }, + HashPair: function HashPair(pair) { + this.acceptRequired(pair, 'value'); + } + }; + + function visitSubExpression(mustache) { + this.acceptRequired(mustache, 'path'); + this.acceptArray(mustache.params); + this.acceptKey(mustache, 'hash'); + } + function visitBlock(block) { + visitSubExpression.call(this, block); + + this.acceptKey(block, 'program'); + this.acceptKey(block, 'inverse'); + } + function visitPartial(partial) { + this.acceptRequired(partial, 'name'); + this.acceptArray(partial.params); + this.acceptKey(partial, 'hash'); + } + + exports['default'] = Visitor; + module.exports = exports['default']; + +/***/ }), +/* 40 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.SourceLocation = SourceLocation; + exports.id = id; + exports.stripFlags = stripFlags; + exports.stripComment = stripComment; + exports.preparePath = preparePath; + exports.prepareMustache = prepareMustache; + exports.prepareRawBlock = prepareRawBlock; + exports.prepareBlock = prepareBlock; + exports.prepareProgram = prepareProgram; + exports.preparePartialBlock = preparePartialBlock; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + function validateClose(open, close) { + close = close.path ? close.path.original : close; + + if (open.path.original !== close) { + var errorNode = { loc: open.path.loc }; + + throw new _exception2['default'](open.path.original + " doesn't match " + close, errorNode); + } + } + + function SourceLocation(source, locInfo) { + this.source = source; + this.start = { + line: locInfo.first_line, + column: locInfo.first_column + }; + this.end = { + line: locInfo.last_line, + column: locInfo.last_column + }; + } + + function id(token) { + if (/^\[.*\]$/.test(token)) { + return token.substr(1, token.length - 2); + } else { + return token; + } + } + + function stripFlags(open, close) { + return { + open: open.charAt(2) === '~', + close: close.charAt(close.length - 3) === '~' + }; + } + + function stripComment(comment) { + return comment.replace(/^\{\{~?\!-?-?/, '').replace(/-?-?~?\}\}$/, ''); + } + + function preparePath(data, parts, loc) { + loc = this.locInfo(loc); + + var original = data ? '@' : '', + dig = [], + depth = 0, + depthString = ''; + + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i].part, + + // If we have [] syntax then we do not treat path references as operators, + // i.e. foo.[this] resolves to approximately context.foo['this'] + isLiteral = parts[i].original !== part; + original += (parts[i].separator || '') + part; + + if (!isLiteral && (part === '..' || part === '.' || part === 'this')) { + if (dig.length > 0) { + throw new _exception2['default']('Invalid path: ' + original, { loc: loc }); + } else if (part === '..') { + depth++; + depthString += '../'; + } + } else { + dig.push(part); + } + } + + return { + type: 'PathExpression', + data: data, + depth: depth, + parts: dig, + original: original, + loc: loc + }; + } + + function prepareMustache(path, params, hash, open, strip, locInfo) { + // Must use charAt to support IE pre-10 + var escapeFlag = open.charAt(3) || open.charAt(2), + escaped = escapeFlag !== '{' && escapeFlag !== '&'; + + var decorator = /\*/.test(open); + return { + type: decorator ? 'Decorator' : 'MustacheStatement', + path: path, + params: params, + hash: hash, + escaped: escaped, + strip: strip, + loc: this.locInfo(locInfo) + }; + } + + function prepareRawBlock(openRawBlock, contents, close, locInfo) { + validateClose(openRawBlock, close); + + locInfo = this.locInfo(locInfo); + var program = { + type: 'Program', + body: contents, + strip: {}, + loc: locInfo + }; + + return { + type: 'BlockStatement', + path: openRawBlock.path, + params: openRawBlock.params, + hash: openRawBlock.hash, + program: program, + openStrip: {}, + inverseStrip: {}, + closeStrip: {}, + loc: locInfo + }; + } + + function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) { + if (close && close.path) { + validateClose(openBlock, close); + } + + var decorator = /\*/.test(openBlock.open); + + program.blockParams = openBlock.blockParams; + + var inverse = undefined, + inverseStrip = undefined; + + if (inverseAndProgram) { + if (decorator) { + throw new _exception2['default']('Unexpected inverse block on decorator', inverseAndProgram); + } + + if (inverseAndProgram.chain) { + inverseAndProgram.program.body[0].closeStrip = close.strip; + } + + inverseStrip = inverseAndProgram.strip; + inverse = inverseAndProgram.program; + } + + if (inverted) { + inverted = inverse; + inverse = program; + program = inverted; + } + + return { + type: decorator ? 'DecoratorBlock' : 'BlockStatement', + path: openBlock.path, + params: openBlock.params, + hash: openBlock.hash, + program: program, + inverse: inverse, + openStrip: openBlock.strip, + inverseStrip: inverseStrip, + closeStrip: close && close.strip, + loc: this.locInfo(locInfo) + }; + } + + function prepareProgram(statements, loc) { + if (!loc && statements.length) { + var firstLoc = statements[0].loc, + lastLoc = statements[statements.length - 1].loc; + + /* istanbul ignore else */ + if (firstLoc && lastLoc) { + loc = { + source: firstLoc.source, + start: { + line: firstLoc.start.line, + column: firstLoc.start.column + }, + end: { + line: lastLoc.end.line, + column: lastLoc.end.column + } + }; + } + } + + return { + type: 'Program', + body: statements, + strip: {}, + loc: loc + }; + } + + function preparePartialBlock(open, program, close, locInfo) { + validateClose(open, close); + + return { + type: 'PartialBlockStatement', + name: open.path, + params: open.params, + hash: open.hash, + program: program, + openStrip: open.strip, + closeStrip: close && close.strip, + loc: this.locInfo(locInfo) + }; + } + +/***/ }), +/* 41 */ +/***/ (function(module, exports, __webpack_require__) { + + /* eslint-disable new-cap */ + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.Compiler = Compiler; + exports.precompile = precompile; + exports.compile = compile; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _utils = __webpack_require__(5); + + var _ast = __webpack_require__(35); + + var _ast2 = _interopRequireDefault(_ast); + + var slice = [].slice; + + function Compiler() {} + + // the foundHelper register will disambiguate helper lookup from finding a + // function in a context. This is necessary for mustache compatibility, which + // requires that context functions in blocks are evaluated by blockHelperMissing, + // and then proceed as if the resulting value was provided to blockHelperMissing. + + Compiler.prototype = { + compiler: Compiler, + + equals: function equals(other) { + var len = this.opcodes.length; + if (other.opcodes.length !== len) { + return false; + } + + for (var i = 0; i < len; i++) { + var opcode = this.opcodes[i], + otherOpcode = other.opcodes[i]; + if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) { + return false; + } + } + + // We know that length is the same between the two arrays because they are directly tied + // to the opcode behavior above. + len = this.children.length; + for (var i = 0; i < len; i++) { + if (!this.children[i].equals(other.children[i])) { + return false; + } + } + + return true; + }, + + guid: 0, + + compile: function compile(program, options) { + this.sourceNode = []; + this.opcodes = []; + this.children = []; + this.options = options; + this.stringParams = options.stringParams; + this.trackIds = options.trackIds; + + options.blockParams = options.blockParams || []; + + // These changes will propagate to the other compiler components + var knownHelpers = options.knownHelpers; + options.knownHelpers = { + 'helperMissing': true, + 'blockHelperMissing': true, + 'each': true, + 'if': true, + 'unless': true, + 'with': true, + 'log': true, + 'lookup': true + }; + if (knownHelpers) { + for (var _name in knownHelpers) { + /* istanbul ignore else */ + if (_name in knownHelpers) { + this.options.knownHelpers[_name] = knownHelpers[_name]; + } + } + } + + return this.accept(program); + }, + + compileProgram: function compileProgram(program) { + var childCompiler = new this.compiler(), + // eslint-disable-line new-cap + result = childCompiler.compile(program, this.options), + guid = this.guid++; + + this.usePartial = this.usePartial || result.usePartial; + + this.children[guid] = result; + this.useDepths = this.useDepths || result.useDepths; + + return guid; + }, + + accept: function accept(node) { + /* istanbul ignore next: Sanity code */ + if (!this[node.type]) { + throw new _exception2['default']('Unknown type: ' + node.type, node); + } + + this.sourceNode.unshift(node); + var ret = this[node.type](node); + this.sourceNode.shift(); + return ret; + }, + + Program: function Program(program) { + this.options.blockParams.unshift(program.blockParams); + + var body = program.body, + bodyLength = body.length; + for (var i = 0; i < bodyLength; i++) { + this.accept(body[i]); + } + + this.options.blockParams.shift(); + + this.isSimple = bodyLength === 1; + this.blockParams = program.blockParams ? program.blockParams.length : 0; + + return this; + }, + + BlockStatement: function BlockStatement(block) { + transformLiteralToPath(block); + + var program = block.program, + inverse = block.inverse; + + program = program && this.compileProgram(program); + inverse = inverse && this.compileProgram(inverse); + + var type = this.classifySexpr(block); + + if (type === 'helper') { + this.helperSexpr(block, program, inverse); + } else if (type === 'simple') { + this.simpleSexpr(block); + + // now that the simple mustache is resolved, we need to + // evaluate it by executing `blockHelperMissing` + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + this.opcode('emptyHash'); + this.opcode('blockValue', block.path.original); + } else { + this.ambiguousSexpr(block, program, inverse); + + // now that the simple mustache is resolved, we need to + // evaluate it by executing `blockHelperMissing` + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + this.opcode('emptyHash'); + this.opcode('ambiguousBlockValue'); + } + + this.opcode('append'); + }, + + DecoratorBlock: function DecoratorBlock(decorator) { + var program = decorator.program && this.compileProgram(decorator.program); + var params = this.setupFullMustacheParams(decorator, program, undefined), + path = decorator.path; + + this.useDecorators = true; + this.opcode('registerDecorator', params.length, path.original); + }, + + PartialStatement: function PartialStatement(partial) { + this.usePartial = true; + + var program = partial.program; + if (program) { + program = this.compileProgram(partial.program); + } + + var params = partial.params; + if (params.length > 1) { + throw new _exception2['default']('Unsupported number of partial arguments: ' + params.length, partial); + } else if (!params.length) { + if (this.options.explicitPartialContext) { + this.opcode('pushLiteral', 'undefined'); + } else { + params.push({ type: 'PathExpression', parts: [], depth: 0 }); + } + } + + var partialName = partial.name.original, + isDynamic = partial.name.type === 'SubExpression'; + if (isDynamic) { + this.accept(partial.name); + } + + this.setupFullMustacheParams(partial, program, undefined, true); + + var indent = partial.indent || ''; + if (this.options.preventIndent && indent) { + this.opcode('appendContent', indent); + indent = ''; + } + + this.opcode('invokePartial', isDynamic, partialName, indent); + this.opcode('append'); + }, + PartialBlockStatement: function PartialBlockStatement(partialBlock) { + this.PartialStatement(partialBlock); + }, + + MustacheStatement: function MustacheStatement(mustache) { + this.SubExpression(mustache); + + if (mustache.escaped && !this.options.noEscape) { + this.opcode('appendEscaped'); + } else { + this.opcode('append'); + } + }, + Decorator: function Decorator(decorator) { + this.DecoratorBlock(decorator); + }, + + ContentStatement: function ContentStatement(content) { + if (content.value) { + this.opcode('appendContent', content.value); + } + }, + + CommentStatement: function CommentStatement() {}, + + SubExpression: function SubExpression(sexpr) { + transformLiteralToPath(sexpr); + var type = this.classifySexpr(sexpr); + + if (type === 'simple') { + this.simpleSexpr(sexpr); + } else if (type === 'helper') { + this.helperSexpr(sexpr); + } else { + this.ambiguousSexpr(sexpr); + } + }, + ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) { + var path = sexpr.path, + name = path.parts[0], + isBlock = program != null || inverse != null; + + this.opcode('getContext', path.depth); + + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + + path.strict = true; + this.accept(path); + + this.opcode('invokeAmbiguous', name, isBlock); + }, + + simpleSexpr: function simpleSexpr(sexpr) { + var path = sexpr.path; + path.strict = true; + this.accept(path); + this.opcode('resolvePossibleLambda'); + }, + + helperSexpr: function helperSexpr(sexpr, program, inverse) { + var params = this.setupFullMustacheParams(sexpr, program, inverse), + path = sexpr.path, + name = path.parts[0]; + + if (this.options.knownHelpers[name]) { + this.opcode('invokeKnownHelper', params.length, name); + } else if (this.options.knownHelpersOnly) { + throw new _exception2['default']('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr); + } else { + path.strict = true; + path.falsy = true; + + this.accept(path); + this.opcode('invokeHelper', params.length, path.original, _ast2['default'].helpers.simpleId(path)); + } + }, + + PathExpression: function PathExpression(path) { + this.addDepth(path.depth); + this.opcode('getContext', path.depth); + + var name = path.parts[0], + scoped = _ast2['default'].helpers.scopedId(path), + blockParamId = !path.depth && !scoped && this.blockParamIndex(name); + + if (blockParamId) { + this.opcode('lookupBlockParam', blockParamId, path.parts); + } else if (!name) { + // Context reference, i.e. `{{foo .}}` or `{{foo ..}}` + this.opcode('pushContext'); + } else if (path.data) { + this.options.data = true; + this.opcode('lookupData', path.depth, path.parts, path.strict); + } else { + this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped); + } + }, + + StringLiteral: function StringLiteral(string) { + this.opcode('pushString', string.value); + }, + + NumberLiteral: function NumberLiteral(number) { + this.opcode('pushLiteral', number.value); + }, + + BooleanLiteral: function BooleanLiteral(bool) { + this.opcode('pushLiteral', bool.value); + }, + + UndefinedLiteral: function UndefinedLiteral() { + this.opcode('pushLiteral', 'undefined'); + }, + + NullLiteral: function NullLiteral() { + this.opcode('pushLiteral', 'null'); + }, + + Hash: function Hash(hash) { + var pairs = hash.pairs, + i = 0, + l = pairs.length; + + this.opcode('pushHash'); + + for (; i < l; i++) { + this.pushParam(pairs[i].value); + } + while (i--) { + this.opcode('assignToHash', pairs[i].key); + } + this.opcode('popHash'); + }, + + // HELPERS + opcode: function opcode(name) { + this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc }); + }, + + addDepth: function addDepth(depth) { + if (!depth) { + return; + } + + this.useDepths = true; + }, + + classifySexpr: function classifySexpr(sexpr) { + var isSimple = _ast2['default'].helpers.simpleId(sexpr.path); + + var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); + + // a mustache is an eligible helper if: + // * its id is simple (a single part, not `this` or `..`) + var isHelper = !isBlockParam && _ast2['default'].helpers.helperExpression(sexpr); + + // if a mustache is an eligible helper but not a definite + // helper, it is ambiguous, and will be resolved in a later + // pass or at runtime. + var isEligible = !isBlockParam && (isHelper || isSimple); + + // if ambiguous, we can possibly resolve the ambiguity now + // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc. + if (isEligible && !isHelper) { + var _name2 = sexpr.path.parts[0], + options = this.options; + + if (options.knownHelpers[_name2]) { + isHelper = true; + } else if (options.knownHelpersOnly) { + isEligible = false; + } + } + + if (isHelper) { + return 'helper'; + } else if (isEligible) { + return 'ambiguous'; + } else { + return 'simple'; + } + }, + + pushParams: function pushParams(params) { + for (var i = 0, l = params.length; i < l; i++) { + this.pushParam(params[i]); + } + }, + + pushParam: function pushParam(val) { + var value = val.value != null ? val.value : val.original || ''; + + if (this.stringParams) { + if (value.replace) { + value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.'); + } + + if (val.depth) { + this.addDepth(val.depth); + } + this.opcode('getContext', val.depth || 0); + this.opcode('pushStringParam', value, val.type); + + if (val.type === 'SubExpression') { + // SubExpressions get evaluated and passed in + // in string params mode. + this.accept(val); + } + } else { + if (this.trackIds) { + var blockParamIndex = undefined; + if (val.parts && !_ast2['default'].helpers.scopedId(val) && !val.depth) { + blockParamIndex = this.blockParamIndex(val.parts[0]); + } + if (blockParamIndex) { + var blockParamChild = val.parts.slice(1).join('.'); + this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild); + } else { + value = val.original || value; + if (value.replace) { + value = value.replace(/^this(?:\.|$)/, '').replace(/^\.\//, '').replace(/^\.$/, ''); + } + + this.opcode('pushId', val.type, value); + } + } + this.accept(val); + } + }, + + setupFullMustacheParams: function setupFullMustacheParams(sexpr, program, inverse, omitEmpty) { + var params = sexpr.params; + this.pushParams(params); + + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + + if (sexpr.hash) { + this.accept(sexpr.hash); + } else { + this.opcode('emptyHash', omitEmpty); + } + + return params; + }, + + blockParamIndex: function blockParamIndex(name) { + for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) { + var blockParams = this.options.blockParams[depth], + param = blockParams && _utils.indexOf(blockParams, name); + if (blockParams && param >= 0) { + return [depth, param]; + } + } + } + }; + + function precompile(input, options, env) { + if (input == null || typeof input !== 'string' && input.type !== 'Program') { + throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input); + } + + options = options || {}; + if (!('data' in options)) { + options.data = true; + } + if (options.compat) { + options.useDepths = true; + } + + var ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options); + return new env.JavaScriptCompiler().compile(environment, options); + } + + function compile(input, options, env) { + if (options === undefined) options = {}; + + if (input == null || typeof input !== 'string' && input.type !== 'Program') { + throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); + } + + options = _utils.extend({}, options); + if (!('data' in options)) { + options.data = true; + } + if (options.compat) { + options.useDepths = true; + } + + var compiled = undefined; + + function compileInput() { + var ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options), + templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); + return env.template(templateSpec); + } + + // Template is only compiled on first use and cached after that point. + function ret(context, execOptions) { + if (!compiled) { + compiled = compileInput(); + } + return compiled.call(this, context, execOptions); + } + ret._setup = function (setupOptions) { + if (!compiled) { + compiled = compileInput(); + } + return compiled._setup(setupOptions); + }; + ret._child = function (i, data, blockParams, depths) { + if (!compiled) { + compiled = compileInput(); + } + return compiled._child(i, data, blockParams, depths); + }; + return ret; + } + + function argEquals(a, b) { + if (a === b) { + return true; + } + + if (_utils.isArray(a) && _utils.isArray(b) && a.length === b.length) { + for (var i = 0; i < a.length; i++) { + if (!argEquals(a[i], b[i])) { + return false; + } + } + return true; + } + } + + function transformLiteralToPath(sexpr) { + if (!sexpr.path.parts) { + var literal = sexpr.path; + // Casting to string here to make false and 0 literal values play nicely with the rest + // of the system. + sexpr.path = { + type: 'PathExpression', + data: false, + depth: 0, + parts: [literal.original + ''], + original: literal.original + '', + loc: literal.loc + }; + } + } + +/***/ }), +/* 42 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _base = __webpack_require__(4); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _utils = __webpack_require__(5); + + var _codeGen = __webpack_require__(43); + + var _codeGen2 = _interopRequireDefault(_codeGen); + + function Literal(value) { + this.value = value; + } + + function JavaScriptCompiler() {} + + JavaScriptCompiler.prototype = { + // PUBLIC API: You can override these methods in a subclass to provide + // alternative compiled forms for name lookup and buffering semantics + nameLookup: function nameLookup(parent, name /* , type*/) { + if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { + return [parent, '.', name]; + } else { + return [parent, '[', JSON.stringify(name), ']']; + } + }, + depthedLookup: function depthedLookup(name) { + return [this.aliasable('container.lookup'), '(depths, "', name, '")']; + }, + + compilerInfo: function compilerInfo() { + var revision = _base.COMPILER_REVISION, + versions = _base.REVISION_CHANGES[revision]; + return [revision, versions]; + }, + + appendToBuffer: function appendToBuffer(source, location, explicit) { + // Force a source as this simplifies the merge logic. + if (!_utils.isArray(source)) { + source = [source]; + } + source = this.source.wrap(source, location); + + if (this.environment.isSimple) { + return ['return ', source, ';']; + } else if (explicit) { + // This is a case where the buffer operation occurs as a child of another + // construct, generally braces. We have to explicitly output these buffer + // operations to ensure that the emitted code goes in the correct location. + return ['buffer += ', source, ';']; + } else { + source.appendToBuffer = true; + return source; + } + }, + + initializeBuffer: function initializeBuffer() { + return this.quotedString(''); + }, + // END PUBLIC API + + compile: function compile(environment, options, context, asObject) { + this.environment = environment; + this.options = options; + this.stringParams = this.options.stringParams; + this.trackIds = this.options.trackIds; + this.precompile = !asObject; + + this.name = this.environment.name; + this.isChild = !!context; + this.context = context || { + decorators: [], + programs: [], + environments: [] + }; + + this.preamble(); + + this.stackSlot = 0; + this.stackVars = []; + this.aliases = {}; + this.registers = { list: [] }; + this.hashes = []; + this.compileStack = []; + this.inlineStack = []; + this.blockParams = []; + + this.compileChildren(environment, options); + + this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat; + this.useBlockParams = this.useBlockParams || environment.useBlockParams; + + var opcodes = environment.opcodes, + opcode = undefined, + firstLoc = undefined, + i = undefined, + l = undefined; + + for (i = 0, l = opcodes.length; i < l; i++) { + opcode = opcodes[i]; + + this.source.currentLocation = opcode.loc; + firstLoc = firstLoc || opcode.loc; + this[opcode.opcode].apply(this, opcode.args); + } + + // Flush any trailing content that might be pending. + this.source.currentLocation = firstLoc; + this.pushSource(''); + + /* istanbul ignore next */ + if (this.stackSlot || this.inlineStack.length || this.compileStack.length) { + throw new _exception2['default']('Compile completed with content left on stack'); + } + + if (!this.decorators.isEmpty()) { + this.useDecorators = true; + + this.decorators.prepend('var decorators = container.decorators;\n'); + this.decorators.push('return fn;'); + + if (asObject) { + this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]); + } else { + this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n'); + this.decorators.push('}\n'); + this.decorators = this.decorators.merge(); + } + } else { + this.decorators = undefined; + } + + var fn = this.createFunctionContext(asObject); + if (!this.isChild) { + var ret = { + compiler: this.compilerInfo(), + main: fn + }; + + if (this.decorators) { + ret.main_d = this.decorators; // eslint-disable-line camelcase + ret.useDecorators = true; + } + + var _context = this.context; + var programs = _context.programs; + var decorators = _context.decorators; + + for (i = 0, l = programs.length; i < l; i++) { + if (programs[i]) { + ret[i] = programs[i]; + if (decorators[i]) { + ret[i + '_d'] = decorators[i]; + ret.useDecorators = true; + } + } + } + + if (this.environment.usePartial) { + ret.usePartial = true; + } + if (this.options.data) { + ret.useData = true; + } + if (this.useDepths) { + ret.useDepths = true; + } + if (this.useBlockParams) { + ret.useBlockParams = true; + } + if (this.options.compat) { + ret.compat = true; + } + + if (!asObject) { + ret.compiler = JSON.stringify(ret.compiler); + + this.source.currentLocation = { start: { line: 1, column: 0 } }; + ret = this.objectLiteral(ret); + + if (options.srcName) { + ret = ret.toStringWithSourceMap({ file: options.destName }); + ret.map = ret.map && ret.map.toString(); + } else { + ret = ret.toString(); + } + } else { + ret.compilerOptions = this.options; + } + + return ret; + } else { + return fn; + } + }, + + preamble: function preamble() { + // track the last context pushed into place to allow skipping the + // getContext opcode when it would be a noop + this.lastContext = 0; + this.source = new _codeGen2['default'](this.options.srcName); + this.decorators = new _codeGen2['default'](this.options.srcName); + }, + + createFunctionContext: function createFunctionContext(asObject) { + var varDeclarations = ''; + + var locals = this.stackVars.concat(this.registers.list); + if (locals.length > 0) { + varDeclarations += ', ' + locals.join(', '); + } + + // Generate minimizer alias mappings + // + // When using true SourceNodes, this will update all references to the given alias + // as the source nodes are reused in situ. For the non-source node compilation mode, + // aliases will not be used, but this case is already being run on the client and + // we aren't concern about minimizing the template size. + var aliasCount = 0; + for (var alias in this.aliases) { + // eslint-disable-line guard-for-in + var node = this.aliases[alias]; + + if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) { + varDeclarations += ', alias' + ++aliasCount + '=' + alias; + node.children[0] = 'alias' + aliasCount; + } + } + + var params = ['container', 'depth0', 'helpers', 'partials', 'data']; + + if (this.useBlockParams || this.useDepths) { + params.push('blockParams'); + } + if (this.useDepths) { + params.push('depths'); + } + + // Perform a second pass over the output to merge content when possible + var source = this.mergeSource(varDeclarations); + + if (asObject) { + params.push(source); + + return Function.apply(this, params); + } else { + return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']); + } + }, + mergeSource: function mergeSource(varDeclarations) { + var isSimple = this.environment.isSimple, + appendOnly = !this.forceBuffer, + appendFirst = undefined, + sourceSeen = undefined, + bufferStart = undefined, + bufferEnd = undefined; + this.source.each(function (line) { + if (line.appendToBuffer) { + if (bufferStart) { + line.prepend(' + '); + } else { + bufferStart = line; + } + bufferEnd = line; + } else { + if (bufferStart) { + if (!sourceSeen) { + appendFirst = true; + } else { + bufferStart.prepend('buffer += '); + } + bufferEnd.add(';'); + bufferStart = bufferEnd = undefined; + } + + sourceSeen = true; + if (!isSimple) { + appendOnly = false; + } + } + }); + + if (appendOnly) { + if (bufferStart) { + bufferStart.prepend('return '); + bufferEnd.add(';'); + } else if (!sourceSeen) { + this.source.push('return "";'); + } + } else { + varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer()); + + if (bufferStart) { + bufferStart.prepend('return buffer + '); + bufferEnd.add(';'); + } else { + this.source.push('return buffer;'); + } + } + + if (varDeclarations) { + this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')); + } + + return this.source.merge(); + }, + + // [blockValue] + // + // On stack, before: hash, inverse, program, value + // On stack, after: return value of blockHelperMissing + // + // The purpose of this opcode is to take a block of the form + // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and + // replace it on the stack with the result of properly + // invoking blockHelperMissing. + blockValue: function blockValue(name) { + var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs(name, 0, params); + + var blockName = this.popStack(); + params.splice(1, 0, blockName); + + this.push(this.source.functionCall(blockHelperMissing, 'call', params)); + }, + + // [ambiguousBlockValue] + // + // On stack, before: hash, inverse, program, value + // Compiler value, before: lastHelper=value of last found helper, if any + // On stack, after, if no lastHelper: same as [blockValue] + // On stack, after, if lastHelper: value + ambiguousBlockValue: function ambiguousBlockValue() { + // We're being a bit cheeky and reusing the options value from the prior exec + var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs('', 0, params, true); + + this.flushInline(); + + var current = this.topStack(); + params.splice(1, 0, current); + + this.pushSource(['if (!', this.lastHelper, ') { ', current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), '}']); + }, + + // [appendContent] + // + // On stack, before: ... + // On stack, after: ... + // + // Appends the string value of `content` to the current buffer + appendContent: function appendContent(content) { + if (this.pendingContent) { + content = this.pendingContent + content; + } else { + this.pendingLocation = this.source.currentLocation; + } + + this.pendingContent = content; + }, + + // [append] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Coerces `value` to a String and appends it to the current buffer. + // + // If `value` is truthy, or 0, it is coerced into a string and appended + // Otherwise, the empty string is appended + append: function append() { + if (this.isInline()) { + this.replaceStack(function (current) { + return [' != null ? ', current, ' : ""']; + }); + + this.pushSource(this.appendToBuffer(this.popStack())); + } else { + var local = this.popStack(); + this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']); + if (this.environment.isSimple) { + this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']); + } + } + }, + + // [appendEscaped] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Escape `value` and append it to the buffer + appendEscaped: function appendEscaped() { + this.pushSource(this.appendToBuffer([this.aliasable('container.escapeExpression'), '(', this.popStack(), ')'])); + }, + + // [getContext] + // + // On stack, before: ... + // On stack, after: ... + // Compiler value, after: lastContext=depth + // + // Set the value of the `lastContext` compiler value to the depth + getContext: function getContext(depth) { + this.lastContext = depth; + }, + + // [pushContext] + // + // On stack, before: ... + // On stack, after: currentContext, ... + // + // Pushes the value of the current context onto the stack. + pushContext: function pushContext() { + this.pushStackLiteral(this.contextName(this.lastContext)); + }, + + // [lookupOnContext] + // + // On stack, before: ... + // On stack, after: currentContext[name], ... + // + // Looks up the value of `name` on the current context and pushes + // it onto the stack. + lookupOnContext: function lookupOnContext(parts, falsy, strict, scoped) { + var i = 0; + + if (!scoped && this.options.compat && !this.lastContext) { + // The depthed query is expected to handle the undefined logic for the root level that + // is implemented below, so we evaluate that directly in compat mode + this.push(this.depthedLookup(parts[i++])); + } else { + this.pushContext(); + } + + this.resolvePath('context', parts, i, falsy, strict); + }, + + // [lookupBlockParam] + // + // On stack, before: ... + // On stack, after: blockParam[name], ... + // + // Looks up the value of `parts` on the given block param and pushes + // it onto the stack. + lookupBlockParam: function lookupBlockParam(blockParamId, parts) { + this.useBlockParams = true; + + this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); + this.resolvePath('context', parts, 1); + }, + + // [lookupData] + // + // On stack, before: ... + // On stack, after: data, ... + // + // Push the data lookup operator + lookupData: function lookupData(depth, parts, strict) { + if (!depth) { + this.pushStackLiteral('data'); + } else { + this.pushStackLiteral('container.data(data, ' + depth + ')'); + } + + this.resolvePath('data', parts, 0, true, strict); + }, + + resolvePath: function resolvePath(type, parts, i, falsy, strict) { + // istanbul ignore next + + var _this = this; + + if (this.options.strict || this.options.assumeObjects) { + this.push(strictLookup(this.options.strict && strict, this, parts, type)); + return; + } + + var len = parts.length; + for (; i < len; i++) { + /* eslint-disable no-loop-func */ + this.replaceStack(function (current) { + var lookup = _this.nameLookup(current, parts[i], type); + // We want to ensure that zero and false are handled properly if the context (falsy flag) + // needs to have the special handling for these values. + if (!falsy) { + return [' != null ? ', lookup, ' : ', current]; + } else { + // Otherwise we can use generic falsy handling + return [' && ', lookup]; + } + }); + /* eslint-enable no-loop-func */ + } + }, + + // [resolvePossibleLambda] + // + // On stack, before: value, ... + // On stack, after: resolved value, ... + // + // If the `value` is a lambda, replace it on the stack by + // the return value of the lambda + resolvePossibleLambda: function resolvePossibleLambda() { + this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']); + }, + + // [pushStringParam] + // + // On stack, before: ... + // On stack, after: string, currentContext, ... + // + // This opcode is designed for use in string mode, which + // provides the string value of a parameter along with its + // depth rather than resolving it immediately. + pushStringParam: function pushStringParam(string, type) { + this.pushContext(); + this.pushString(type); + + // If it's a subexpression, the string result + // will be pushed after this opcode. + if (type !== 'SubExpression') { + if (typeof string === 'string') { + this.pushString(string); + } else { + this.pushStackLiteral(string); + } + } + }, + + emptyHash: function emptyHash(omitEmpty) { + if (this.trackIds) { + this.push('{}'); // hashIds + } + if (this.stringParams) { + this.push('{}'); // hashContexts + this.push('{}'); // hashTypes + } + this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); + }, + pushHash: function pushHash() { + if (this.hash) { + this.hashes.push(this.hash); + } + this.hash = { values: [], types: [], contexts: [], ids: [] }; + }, + popHash: function popHash() { + var hash = this.hash; + this.hash = this.hashes.pop(); + + if (this.trackIds) { + this.push(this.objectLiteral(hash.ids)); + } + if (this.stringParams) { + this.push(this.objectLiteral(hash.contexts)); + this.push(this.objectLiteral(hash.types)); + } + + this.push(this.objectLiteral(hash.values)); + }, + + // [pushString] + // + // On stack, before: ... + // On stack, after: quotedString(string), ... + // + // Push a quoted version of `string` onto the stack + pushString: function pushString(string) { + this.pushStackLiteral(this.quotedString(string)); + }, + + // [pushLiteral] + // + // On stack, before: ... + // On stack, after: value, ... + // + // Pushes a value onto the stack. This operation prevents + // the compiler from creating a temporary variable to hold + // it. + pushLiteral: function pushLiteral(value) { + this.pushStackLiteral(value); + }, + + // [pushProgram] + // + // On stack, before: ... + // On stack, after: program(guid), ... + // + // Push a program expression onto the stack. This takes + // a compile-time guid and converts it into a runtime-accessible + // expression. + pushProgram: function pushProgram(guid) { + if (guid != null) { + this.pushStackLiteral(this.programExpression(guid)); + } else { + this.pushStackLiteral(null); + } + }, + + // [registerDecorator] + // + // On stack, before: hash, program, params..., ... + // On stack, after: ... + // + // Pops off the decorator's parameters, invokes the decorator, + // and inserts the decorator into the decorators list. + registerDecorator: function registerDecorator(paramSize, name) { + var foundDecorator = this.nameLookup('decorators', name, 'decorator'), + options = this.setupHelperArgs(name, paramSize); + + this.decorators.push(['fn = ', this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]), ' || fn;']); + }, + + // [invokeHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // Pops off the helper's parameters, invokes the helper, + // and pushes the helper's return value onto the stack. + // + // If the helper is not found, `helperMissing` is called. + invokeHelper: function invokeHelper(paramSize, name, isSimple) { + var nonHelper = this.popStack(), + helper = this.setupHelper(paramSize, name), + simple = isSimple ? [helper.name, ' || '] : ''; + + var lookup = ['('].concat(simple, nonHelper); + if (!this.options.strict) { + lookup.push(' || ', this.aliasable('helpers.helperMissing')); + } + lookup.push(')'); + + this.push(this.source.functionCall(lookup, 'call', helper.callParams)); + }, + + // [invokeKnownHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // This operation is used when the helper is known to exist, + // so a `helperMissing` fallback is not required. + invokeKnownHelper: function invokeKnownHelper(paramSize, name) { + var helper = this.setupHelper(paramSize, name); + this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); + }, + + // [invokeAmbiguous] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of disambiguation + // + // This operation is used when an expression like `{{foo}}` + // is provided, but we don't know at compile-time whether it + // is a helper or a path. + // + // This operation emits more code than the other options, + // and can be avoided by passing the `knownHelpers` and + // `knownHelpersOnly` flags at compile-time. + invokeAmbiguous: function invokeAmbiguous(name, helperCall) { + this.useRegister('helper'); + + var nonHelper = this.popStack(); + + this.emptyHash(); + var helper = this.setupHelper(0, name, helperCall); + + var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); + + var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; + if (!this.options.strict) { + lookup[0] = '(helper = '; + lookup.push(' != null ? helper : ', this.aliasable('helpers.helperMissing')); + } + + this.push(['(', lookup, helper.paramsInit ? ['),(', helper.paramsInit] : [], '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), ' : helper))']); + }, + + // [invokePartial] + // + // On stack, before: context, ... + // On stack after: result of partial invocation + // + // This operation pops off a context, invokes a partial with that context, + // and pushes the result of the invocation back. + invokePartial: function invokePartial(isDynamic, name, indent) { + var params = [], + options = this.setupParams(name, 1, params); + + if (isDynamic) { + name = this.popStack(); + delete options.name; + } + + if (indent) { + options.indent = JSON.stringify(indent); + } + options.helpers = 'helpers'; + options.partials = 'partials'; + options.decorators = 'container.decorators'; + + if (!isDynamic) { + params.unshift(this.nameLookup('partials', name, 'partial')); + } else { + params.unshift(name); + } + + if (this.options.compat) { + options.depths = 'depths'; + } + options = this.objectLiteral(options); + params.push(options); + + this.push(this.source.functionCall('container.invokePartial', '', params)); + }, + + // [assignToHash] + // + // On stack, before: value, ..., hash, ... + // On stack, after: ..., hash, ... + // + // Pops a value off the stack and assigns it to the current hash + assignToHash: function assignToHash(key) { + var value = this.popStack(), + context = undefined, + type = undefined, + id = undefined; + + if (this.trackIds) { + id = this.popStack(); + } + if (this.stringParams) { + type = this.popStack(); + context = this.popStack(); + } + + var hash = this.hash; + if (context) { + hash.contexts[key] = context; + } + if (type) { + hash.types[key] = type; + } + if (id) { + hash.ids[key] = id; + } + hash.values[key] = value; + }, + + pushId: function pushId(type, name, child) { + if (type === 'BlockParam') { + this.pushStackLiteral('blockParams[' + name[0] + '].path[' + name[1] + ']' + (child ? ' + ' + JSON.stringify('.' + child) : '')); + } else if (type === 'PathExpression') { + this.pushString(name); + } else if (type === 'SubExpression') { + this.pushStackLiteral('true'); + } else { + this.pushStackLiteral('null'); + } + }, + + // HELPERS + + compiler: JavaScriptCompiler, + + compileChildren: function compileChildren(environment, options) { + var children = environment.children, + child = undefined, + compiler = undefined; + + for (var i = 0, l = children.length; i < l; i++) { + child = children[i]; + compiler = new this.compiler(); // eslint-disable-line new-cap + + var existing = this.matchExistingProgram(child); + + if (existing == null) { + this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children + var index = this.context.programs.length; + child.index = index; + child.name = 'program' + index; + this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); + this.context.decorators[index] = compiler.decorators; + this.context.environments[index] = child; + + this.useDepths = this.useDepths || compiler.useDepths; + this.useBlockParams = this.useBlockParams || compiler.useBlockParams; + child.useDepths = this.useDepths; + child.useBlockParams = this.useBlockParams; + } else { + child.index = existing.index; + child.name = 'program' + existing.index; + + this.useDepths = this.useDepths || existing.useDepths; + this.useBlockParams = this.useBlockParams || existing.useBlockParams; + } + } + }, + matchExistingProgram: function matchExistingProgram(child) { + for (var i = 0, len = this.context.environments.length; i < len; i++) { + var environment = this.context.environments[i]; + if (environment && environment.equals(child)) { + return environment; + } + } + }, + + programExpression: function programExpression(guid) { + var child = this.environment.children[guid], + programParams = [child.index, 'data', child.blockParams]; + + if (this.useBlockParams || this.useDepths) { + programParams.push('blockParams'); + } + if (this.useDepths) { + programParams.push('depths'); + } + + return 'container.program(' + programParams.join(', ') + ')'; + }, + + useRegister: function useRegister(name) { + if (!this.registers[name]) { + this.registers[name] = true; + this.registers.list.push(name); + } + }, + + push: function push(expr) { + if (!(expr instanceof Literal)) { + expr = this.source.wrap(expr); + } + + this.inlineStack.push(expr); + return expr; + }, + + pushStackLiteral: function pushStackLiteral(item) { + this.push(new Literal(item)); + }, + + pushSource: function pushSource(source) { + if (this.pendingContent) { + this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation)); + this.pendingContent = undefined; + } + + if (source) { + this.source.push(source); + } + }, + + replaceStack: function replaceStack(callback) { + var prefix = ['('], + stack = undefined, + createdStack = undefined, + usedLiteral = undefined; + + /* istanbul ignore next */ + if (!this.isInline()) { + throw new _exception2['default']('replaceStack on non-inline'); + } + + // We want to merge the inline statement into the replacement statement via ',' + var top = this.popStack(true); + + if (top instanceof Literal) { + // Literals do not need to be inlined + stack = [top.value]; + prefix = ['(', stack]; + usedLiteral = true; + } else { + // Get or create the current stack name for use by the inline + createdStack = true; + var _name = this.incrStack(); + + prefix = ['((', this.push(_name), ' = ', top, ')']; + stack = this.topStack(); + } + + var item = callback.call(this, stack); + + if (!usedLiteral) { + this.popStack(); + } + if (createdStack) { + this.stackSlot--; + } + this.push(prefix.concat(item, ')')); + }, + + incrStack: function incrStack() { + this.stackSlot++; + if (this.stackSlot > this.stackVars.length) { + this.stackVars.push('stack' + this.stackSlot); + } + return this.topStackName(); + }, + topStackName: function topStackName() { + return 'stack' + this.stackSlot; + }, + flushInline: function flushInline() { + var inlineStack = this.inlineStack; + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + /* istanbul ignore if */ + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + var stack = this.incrStack(); + this.pushSource([stack, ' = ', entry, ';']); + this.compileStack.push(stack); + } + } + }, + isInline: function isInline() { + return this.inlineStack.length; + }, + + popStack: function popStack(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); + + if (!wrapped && item instanceof Literal) { + return item.value; + } else { + if (!inline) { + /* istanbul ignore next */ + if (!this.stackSlot) { + throw new _exception2['default']('Invalid stack pop'); + } + this.stackSlot--; + } + return item; + } + }, + + topStack: function topStack() { + var stack = this.isInline() ? this.inlineStack : this.compileStack, + item = stack[stack.length - 1]; + + /* istanbul ignore if */ + if (item instanceof Literal) { + return item.value; + } else { + return item; + } + }, + + contextName: function contextName(context) { + if (this.useDepths && context) { + return 'depths[' + context + ']'; + } else { + return 'depth' + context; + } + }, + + quotedString: function quotedString(str) { + return this.source.quotedString(str); + }, + + objectLiteral: function objectLiteral(obj) { + return this.source.objectLiteral(obj); + }, + + aliasable: function aliasable(name) { + var ret = this.aliases[name]; + if (ret) { + ret.referenceCount++; + return ret; + } + + ret = this.aliases[name] = this.source.wrap(name); + ret.aliasable = true; + ret.referenceCount = 1; + + return ret; + }, + + setupHelper: function setupHelper(paramSize, name, blockHelper) { + var params = [], + paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); + var foundHelper = this.nameLookup('helpers', name, 'helper'), + callContext = this.aliasable(this.contextName(0) + ' != null ? ' + this.contextName(0) + ' : (container.nullContext || {})'); + + return { + params: params, + paramsInit: paramsInit, + name: foundHelper, + callParams: [callContext].concat(params) + }; + }, + + setupParams: function setupParams(helper, paramSize, params) { + var options = {}, + contexts = [], + types = [], + ids = [], + objectArgs = !params, + param = undefined; + + if (objectArgs) { + params = []; + } + + options.name = this.quotedString(helper); + options.hash = this.popStack(); + + if (this.trackIds) { + options.hashIds = this.popStack(); + } + if (this.stringParams) { + options.hashTypes = this.popStack(); + options.hashContexts = this.popStack(); + } + + var inverse = this.popStack(), + program = this.popStack(); + + // Avoid setting fn and inverse if neither are set. This allows + // helpers to do a check for `if (options.fn)` + if (program || inverse) { + options.fn = program || 'container.noop'; + options.inverse = inverse || 'container.noop'; + } + + // The parameters go on to the stack in order (making sure that they are evaluated in order) + // so we need to pop them off the stack in reverse order + var i = paramSize; + while (i--) { + param = this.popStack(); + params[i] = param; + + if (this.trackIds) { + ids[i] = this.popStack(); + } + if (this.stringParams) { + types[i] = this.popStack(); + contexts[i] = this.popStack(); + } + } + + if (objectArgs) { + options.args = this.source.generateArray(params); + } + + if (this.trackIds) { + options.ids = this.source.generateArray(ids); + } + if (this.stringParams) { + options.types = this.source.generateArray(types); + options.contexts = this.source.generateArray(contexts); + } + + if (this.options.data) { + options.data = 'data'; + } + if (this.useBlockParams) { + options.blockParams = 'blockParams'; + } + return options; + }, + + setupHelperArgs: function setupHelperArgs(helper, paramSize, params, useRegister) { + var options = this.setupParams(helper, paramSize, params); + options = this.objectLiteral(options); + if (useRegister) { + this.useRegister('options'); + params.push('options'); + return ['options=', options]; + } else if (params) { + params.push(options); + return ''; + } else { + return options; + } + } + }; + + (function () { + var reservedWords = ('break else new var' + ' case finally return void' + ' catch for switch while' + ' continue function this with' + ' default if throw' + ' delete in try' + ' do instanceof typeof' + ' abstract enum int short' + ' boolean export interface static' + ' byte extends long super' + ' char final native synchronized' + ' class float package throws' + ' const goto private transient' + ' debugger implements protected volatile' + ' double import public let yield await' + ' null true false').split(' '); + + var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; + + for (var i = 0, l = reservedWords.length; i < l; i++) { + compilerWords[reservedWords[i]] = true; + } + })(); + + JavaScriptCompiler.isValidJavaScriptVariableName = function (name) { + return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name); + }; + + function strictLookup(requireTerminal, compiler, parts, type) { + var stack = compiler.popStack(), + i = 0, + len = parts.length; + if (requireTerminal) { + len--; + } + + for (; i < len; i++) { + stack = compiler.nameLookup(stack, parts[i], type); + } + + if (requireTerminal) { + return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')']; + } else { + return stack; + } + } + + exports['default'] = JavaScriptCompiler; + module.exports = exports['default']; + +/***/ }), +/* 43 */ +/***/ (function(module, exports, __webpack_require__) { + + /* global define */ + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var SourceNode = undefined; + + try { + /* istanbul ignore next */ + if (false) { + // We don't support this in AMD environments. For these environments, we asusme that + // they are running on the browser and thus have no need for the source-map library. + var SourceMap = require('source-map'); + SourceNode = SourceMap.SourceNode; + } + } catch (err) {} + /* NOP */ + + /* istanbul ignore if: tested but not covered in istanbul due to dist build */ + if (!SourceNode) { + SourceNode = function (line, column, srcFile, chunks) { + this.src = ''; + if (chunks) { + this.add(chunks); + } + }; + /* istanbul ignore next */ + SourceNode.prototype = { + add: function add(chunks) { + if (_utils.isArray(chunks)) { + chunks = chunks.join(''); + } + this.src += chunks; + }, + prepend: function prepend(chunks) { + if (_utils.isArray(chunks)) { + chunks = chunks.join(''); + } + this.src = chunks + this.src; + }, + toStringWithSourceMap: function toStringWithSourceMap() { + return { code: this.toString() }; + }, + toString: function toString() { + return this.src; + } + }; + } + + function castChunk(chunk, codeGen, loc) { + if (_utils.isArray(chunk)) { + var ret = []; + + for (var i = 0, len = chunk.length; i < len; i++) { + ret.push(codeGen.wrap(chunk[i], loc)); + } + return ret; + } else if (typeof chunk === 'boolean' || typeof chunk === 'number') { + // Handle primitives that the SourceNode will throw up on + return chunk + ''; + } + return chunk; + } + + function CodeGen(srcFile) { + this.srcFile = srcFile; + this.source = []; + } + + CodeGen.prototype = { + isEmpty: function isEmpty() { + return !this.source.length; + }, + prepend: function prepend(source, loc) { + this.source.unshift(this.wrap(source, loc)); + }, + push: function push(source, loc) { + this.source.push(this.wrap(source, loc)); + }, + + merge: function merge() { + var source = this.empty(); + this.each(function (line) { + source.add([' ', line, '\n']); + }); + return source; + }, + + each: function each(iter) { + for (var i = 0, len = this.source.length; i < len; i++) { + iter(this.source[i]); + } + }, + + empty: function empty() { + var loc = this.currentLocation || { start: {} }; + return new SourceNode(loc.start.line, loc.start.column, this.srcFile); + }, + wrap: function wrap(chunk) { + var loc = arguments.length <= 1 || arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1]; + + if (chunk instanceof SourceNode) { + return chunk; + } + + chunk = castChunk(chunk, this, loc); + + return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk); + }, + + functionCall: function functionCall(fn, type, params) { + params = this.generateList(params); + return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); + }, + + quotedString: function quotedString(str) { + return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, + + objectLiteral: function objectLiteral(obj) { + var pairs = []; + + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + var value = castChunk(obj[key], this); + if (value !== 'undefined') { + pairs.push([this.quotedString(key), ':', value]); + } + } + } + + var ret = this.generateList(pairs); + ret.prepend('{'); + ret.add('}'); + return ret; + }, + + generateList: function generateList(entries) { + var ret = this.empty(); + + for (var i = 0, len = entries.length; i < len; i++) { + if (i) { + ret.add(','); + } + + ret.add(castChunk(entries[i], this)); + } + + return ret; + }, + + generateArray: function generateArray(entries) { + var ret = this.generateList(entries); + ret.prepend('['); + ret.add(']'); + + return ret; + } + }; + + exports['default'] = CodeGen; + module.exports = exports['default']; + +/***/ }) +/******/ ]) +}); +; \ No newline at end of file diff --git a/html/js/jquery-1.8.3.js b/html/js/jquery-1.8.3.js new file mode 100644 index 0000000..8c24ffc --- /dev/null +++ b/html/js/jquery-1.8.3.js @@ -0,0 +1,9472 @@ +/*! + * jQuery JavaScript Library v1.8.3 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time) + */ +(function( window, undefined ) { +var + // A central reference to the root jQuery(document) + rootjQuery, + + // The deferred used on DOM ready + readyList, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + location = window.location, + navigator = window.navigator, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // Save a reference to some core methods + core_push = Array.prototype.push, + core_slice = Array.prototype.slice, + core_indexOf = Array.prototype.indexOf, + core_toString = Object.prototype.toString, + core_hasOwn = Object.prototype.hasOwnProperty, + core_trim = String.prototype.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, + + // Used for detecting and trimming whitespace + core_rnotwhite = /\S/, + core_rspace = /\s+/, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // The ready event handler and self cleanup method + DOMContentLoaded = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + } else if ( document.readyState === "complete" ) { + // we're here because readyState === "complete" in oldIE + // which is good enough for us to call the dom ready! + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context && context.nodeType ? context.ownerDocument || context : document ); + + // scripts is true for back-compat + selector = jQuery.parseHTML( match[1], doc, true ); + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + this.attr.call( selector, context, true ); + } + + return jQuery.merge( this, selector ); + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.8.3", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ), + "slice", core_slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ core_toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // scripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, scripts ) { + var parsed; + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + scripts = context; + context = 0; + } + context = context || document; + + // Single tag + if ( (parsed = rsingleTag.exec( data )) ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); + return jQuery.merge( [], + (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); + }, + + parseJSON: function( data ) { + if ( !data || typeof data !== "string") { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && core_rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var name, + i = 0, + length = obj.length, + isObj = length === undefined || jQuery.isFunction( obj ); + + if ( args ) { + if ( isObj ) { + for ( name in obj ) { + if ( callback.apply( obj[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( obj[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in obj ) { + if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var type, + ret = results || []; + + if ( arr != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + type = jQuery.type( arr ); + + if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { + core_push.call( ret, arr ); + } else { + jQuery.merge( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, + ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready, 1 ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.split( core_rspace ), function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + return jQuery.inArray( fn, list ) > -1; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? + function() { + var returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + } : + newDefer[ action ] + ); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] = list.fire + deferred[ tuple[0] ] = list.fire; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + eventName, + i, + isSupported, + clickFn, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
a"; + + // Support tests won't run in some limited or non-browser environments + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + if ( !all || !a || !all.length ) { + return {}; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form (#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: ( document.compatMode === "CSS1Compat" ), + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", clickFn = function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent("onclick"); + div.detachEvent( "onclick", clickFn ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + input.setAttribute( "checked", "checked" ); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: true, + change: true, + focusin: true + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Run tests that need a body at doc ready + jQuery(function() { + var container, div, tds, marginDiv, + divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
t
"; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // NOTE: To any future maintainer, we've window.getComputedStyle + // because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = document.createElement("div"); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
"; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + container.style.zoom = 1; + } + + // Null elements to avoid leaks in IE + body.removeChild( container ); + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + fragment.removeChild( div ); + all = a = select = opt = input = fragment = div = null; + + return support; +})(); +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + deletedIds: [], + + // Remove at next major release (1.9/2.0) + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery.removeData( elem, type + "queue", true ); + jQuery.removeData( elem, key, true ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, fixSpecified, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea|)$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var removes, className, elem, c, cl, i, l; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + if ( (value && typeof value === "string") || value === undefined ) { + removes = ( value || "" ).split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + if ( elem.nodeType === 1 && elem.className ) { + + className = (" " + elem.className + " ").replace( rclass, " " ); + + // loop over each item in the removal list + for ( c = 0, cl = removes.length; c < cl; c++ ) { + // Remove until there is nothing to remove, + while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) { + className = className.replace( " " + removes[ c ] + " " , " " ); + } + } + elem.className = value ? jQuery.trim( className ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( core_rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 + attrFn: {}, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + + attrNames = value.split( core_rspace ); + + for ( ; i < attrNames.length; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.value = value + "" ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, + rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var t, tns, type, origType, namespaces, origCount, + j, events, special, eventType, handleObj, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, "events", true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, + type = event.type || event, + namespaces = []; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + for ( old = elem; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old === (elem.ownerDocument || document) ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related, + handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = core_slice.call( arguments ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = []; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.disabled !== true || event.type !== "click" ) { + selMatch = {}; + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) + event.metaKey = !!event.metaKey; + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === "undefined" ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "_submit_attached" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "_submit_attached", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "_change_attached", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var cachedruns, + assertGetIdNotName, + Expr, + getText, + isXML, + contains, + compile, + sortOrder, + hasDuplicate, + outermostContext, + + baseHasDuplicate = true, + strundefined = "undefined", + + expando = ( "sizcache" + Math.random() ).replace( ".", "" ), + + Token = String, + document = window.document, + docElem = document.documentElement, + dirruns = 0, + done = 0, + pop = [].pop, + push = [].push, + slice = [].slice, + // Use a stripped-down indexOf if a native one is unavailable + indexOf = [].indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + // Augment a function for special use by Sizzle + markFunction = function( fn, value ) { + fn[ expando ] = value == null || value; + return fn; + }, + + createCache = function() { + var cache = {}, + keys = []; + + return markFunction(function( key, value ) { + // Only keep the most recent entries + if ( keys.push( key ) > Expr.cacheLength ) { + delete cache[ keys.shift() ]; + } + + // Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157) + return (cache[ key + " " ] = value); + }, cache ); + }, + + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // Regex + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments not in parens/brackets, + // then attribute selectors and non-pseudos (denoted by :), + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)", + + // For matchExpr.POS and matchExpr.needsContext + pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, + + rnot = /^:not/, + rsibling = /[\x20\t\r\n\f]*[+~]/, + rendsWithNot = /:not\($/, + + rheader = /h\d/i, + rinputs = /input|select|textarea|button/i, + + rbackslash = /\\(?!\\)/g, + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "POS": new RegExp( pos, "i" ), + "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) + }, + + // Support + + // Used for testing something on an element + assert = function( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } + }, + + // Check if getElementsByTagName("*") returns only elements + assertTagNameNoComments = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }), + + // Check if getAttribute returns normalized href attributes + assertHrefNotNormalized = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }), + + // Check if attributes should be retrieved by attribute nodes + assertAttributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }), + + // Check if getElementsByClassName can be trusted + assertUsableClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }), + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + assertUsableName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
"; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = document.getElementsByName && + // buggy browsers will return fewer than the correct 2 + document.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + document.getElementsByName( expando + 0 ).length; + assertGetIdNotName = !document.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + +// If slice is not available, provide a backup +try { + slice.call( docElem.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + for ( ; (elem = this[i]); i++ ) { + results.push( elem ); + } + return results; + }; +} + +function Sizzle( selector, context, results, seed ) { + results = results || []; + context = context || document; + var match, elem, xml, m, + nodeType = context.nodeType; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( nodeType !== 1 && nodeType !== 9 ) { + return []; + } + + xml = isXML( context ); + + if ( !xml && !seed ) { + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed, xml ); +} + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + return Sizzle( expr, null, null, [ elem ] ).length > 0; +}; + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + } else { + + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } + return ret; +}; + +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +// Element contains another +contains = Sizzle.contains = docElem.contains ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); + } : + docElem.compareDocumentPosition ? + function( a, b ) { + return b && !!( a.compareDocumentPosition( b ) & 16 ); + } : + function( a, b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + return false; + }; + +Sizzle.attr = function( elem, name ) { + var val, + xml = isXML( elem ); + + if ( !xml ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( xml || assertAttributes ) { + return elem.getAttribute( name ); + } + val = elem.getAttributeNode( name ); + return val ? + typeof elem[ name ] === "boolean" ? + elem[ name ] ? name : null : + val.specified ? val.value : null : + null; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + // IE6/7 return a modified href + attrHandle: assertHrefNotNormalized ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }, + + find: { + "ID": assertGetIdNotName ? + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + } : + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }, + + "TAG": assertTagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + var elem, + tmp = [], + i = 0; + + for ( ; (elem = results[i]); i++ ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }, + + "NAME": assertUsableName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }, + + "CLASS": assertUsableClassName && function( className, context, xml ) { + if ( typeof context.getElementsByClassName !== strundefined && !xml ) { + return context.getElementsByClassName( className ); + } + } + }, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( rbackslash, "" ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 3 xn-component of xn+y argument ([+-]?\d*n|) + 4 sign of xn-component + 5 x of xn-component + 6 sign of y-component + 7 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1] === "nth" ) { + // nth-child requires argument + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); + match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); + + // other types prohibit arguments + } else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var unquoted, excess; + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + if ( match[3] ) { + match[2] = match[3]; + } else if ( (unquoted = match[4]) ) { + // Only check arguments that contain a pseudo + if ( rpseudo.test(unquoted) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + unquoted = unquoted.slice( 0, excess ); + match[0] = match[0].slice( 0, excess ); + } + match[2] = unquoted; + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + "ID": assertGetIdNotName ? + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + return elem.getAttribute("id") === id; + }; + } : + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === id; + }; + }, + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); + + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ expando ][ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem, context ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.substr( result.length - check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, argument, first, last ) { + + if ( type === "nth" ) { + return function( elem ) { + var node, diff, + parent = elem.parentNode; + + if ( first === 1 && last === 0 ) { + return true; + } + + if ( parent ) { + diff = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + diff++; + if ( elem === node ) { + break; + } + } + } + } + + // Incorporate the offset (or cast to NaN), then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + }; + } + + return function( elem ) { + var node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + var nodeType; + elem = elem.firstChild; + while ( elem ) { + if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { + return false; + } + elem = elem.nextSibling; + } + return true; + }, + + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "text": function( elem ) { + var type, attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + (type = elem.type) === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); + }, + + // Input types + "radio": createInputPseudo("radio"), + "checkbox": createInputPseudo("checkbox"), + "file": createInputPseudo("file"), + "password": createInputPseudo("password"), + "image": createInputPseudo("image"), + + "submit": createButtonPseudo("submit"), + "reset": createButtonPseudo("reset"), + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "focus": function( elem ) { + var doc = elem.ownerDocument; + return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + "active": function( elem ) { + return elem === elem.ownerDocument.activeElement; + }, + + // Positional types + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + for ( var i = 0; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + for ( var i = 1; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +function siblingCheck( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; +} + +sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? + a.compareDocumentPosition : + a.compareDocumentPosition(b) & 4 + ) ? -1 : 1; + } : + function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + +// Always assume the presence of duplicates if sort doesn't +// pass them to our comparison function (as in Google Chrome). +[0, 0].sort( sortOrder ); +baseHasDuplicate = !hasDuplicate; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 1, + j = 0; + + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ expando ][ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + + // Cast descendant combinators to space + matched.type = match[0].replace( rtrim, " " ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + matched.type = type; + matched.matches = match; + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && combinator.dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( !xml ) { + var cache, + dirkey = dirruns + " " + doneName + " ", + cachedkey = dirkey + cachedruns; + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( (cache = elem[ expando ]) === cachedkey ) { + return elem.sizset; + } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { + if ( elem.sizset ) { + return elem; + } + } else { + elem[ expando ] = cachedkey; + if ( matcher( elem, context, xml ) ) { + elem.sizset = true; + return elem; + } + elem.sizset = false; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( matcher( elem, context, xml ) ) { + return elem; + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && tokens.join("") + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Nested matchers should use non-integer dirruns + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = superMatcher.el; + } + + // Add elements passing elementMatchers directly to results + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + for ( j = 0; (matcher = elementMatchers[j]); j++ ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++superMatcher.el; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + for ( j = 0; (matcher = setMatchers[j]); j++ ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + superMatcher.el = 0; + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ expando ][ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed, xml ) { + var i, tokens, token, type, find, + match = tokenize( selector ), + j = match.length; + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !xml && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().length ); + } + + // Fetch a seed set for right-to-left matching + for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( rbackslash, "" ), + rsibling.test( tokens[0].type ) && context.parentNode || context, + xml + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && tokens.join(""); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + xml, + results, + rsibling.test( selector ) + ); + return results; +} + +if ( document.querySelectorAll ) { + (function() { + var disconnectedMatch, + oldSelect = select, + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA + // A support test would require too much code (would include document ready) + rbuggyQSA = [ ":focus" ], + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + // A support test would require too much code (would include document ready) + // just skip matchesSelector for :active + rbuggyMatches = [ ":active" ], + matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector; + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here (do not put tests after this one) + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE9 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = "

"; + if ( div.querySelectorAll("[test^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here (do not put tests after this one) + div.innerHTML = ""; + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push(":enabled", ":disabled"); + } + }); + + // rbuggyQSA always contains :focus, so no need for a length check + rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") ); + + select = function( selector, context, results, seed, xml ) { + // Only use querySelectorAll when not filtering, + // when this is not xml, + // and when no QSA bugs apply + if ( !seed && !xml && !rbuggyQSA.test( selector ) ) { + var groups, i, + old = true, + nid = expando, + newContext = context, + newSelector = context.nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + groups[i].join(""); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + + return oldSelect( selector, context, results, seed, xml ); + }; + + if ( matches ) { + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + try { + matches.call( div, "[test!='']:sizzle" ); + rbuggyMatches.push( "!=", pseudos ); + } catch ( e ) {} + }); + + // rbuggyMatches always contains :active and :focus, so no need for a length check + rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); + + Sizzle.matchesSelector = function( elem, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyMatches always contains :active, so no need for an existence check + if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, null, null, [ elem ] ).length > 0; + }; + } + })(); +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Back-compat +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, l, length, n, r, ret, + self = this; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + ret = this.pushStack( "", "find", selector ); + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + rcheckableType = /^(?:checkbox|radio)$/, + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*\s*$/g, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, +// unless wrapped in a div with non-breaking characters in front of it. +if ( !jQuery.support.htmlSerialize ) { + wrapMap._default = [ 1, "X
", "
" ]; +} + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); + } + }, + + after: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); + } + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + jQuery.cleanData( [ elem ] ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName( "*" ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + if ( !isDisconnected( this[0] ) ) { + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this), old = self.html(); + self.replaceWith( value.call( this, i, old ) ); + }); + } + + if ( typeof value !== "string" ) { + value = jQuery( value ).detach(); + } + + return this.each(function() { + var next = this.nextSibling, + parent = this.parentNode; + + jQuery( this ).remove(); + + if ( next ) { + jQuery(next).before( value ); + } else { + jQuery(parent).append( value ); + } + }); + } + + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = [].concat.apply( [], args ); + + var results, first, fragment, iNoClone, + i = 0, + value = args[0], + scripts = [], + l = this.length; + + // We can't cloneNode fragments that contain checked, in WebKit + if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { + return this.each(function() { + jQuery(this).domManip( args, table, callback ); + }); + } + + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + args[0] = value.call( this, i, table ? self.html() : undefined ); + self.domManip( args, table, callback ); + }); + } + + if ( this[0] ) { + results = jQuery.buildFragment( args, this, scripts ); + fragment = results.fragment; + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + // Fragments from the fragment cache must always be cloned and never used in place. + for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + i === iNoClone ? + fragment : + jQuery.clone( fragment, true, true ) + ); + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + + if ( scripts.length ) { + jQuery.each( scripts, function( i, elem ) { + if ( elem.src ) { + if ( jQuery.ajax ) { + jQuery.ajax({ + url: elem.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.error("no ajax"); + } + } else { + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + }); + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function cloneFixAttributes( src, dest ) { + var nodeName; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + // clearAttributes removes the attributes, which we don't want, + // but also removes the attachEvent events, which we *do* want + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } + + // mergeAttributes, in contrast, only merges back on the + // original attributes, not the events + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); + + if ( nodeName === "object" ) { + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + + // IE blanks contents when cloning scripts + } else if ( nodeName === "script" && dest.text !== src.text ) { + dest.text = src.text; + } + + // Event data gets referenced instead of copied if the expando + // gets copied too + dest.removeAttribute( jQuery.expando ); +} + +jQuery.buildFragment = function( args, context, scripts ) { + var fragment, cacheable, cachehit, + first = args[ 0 ]; + + // Set context from what may come in as undefined or a jQuery collection or a node + // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 & + // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception + context = context || document; + context = !context.nodeType && context[0] || context; + context = context.ownerDocument || context; + + // Only cache "small" (1/2 KB) HTML strings that are associated with the main document + // Cloning options loses the selected state, so don't cache them + // IE 6 doesn't like it when you put or elements in a fragment + // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache + // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 + if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && + first.charAt(0) === "<" && !rnocache.test( first ) && + (jQuery.support.checkClone || !rchecked.test( first )) && + (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { + + // Mark cacheable and look for a hit + cacheable = true; + fragment = jQuery.fragments[ first ]; + cachehit = fragment !== undefined; + } + + if ( !fragment ) { + fragment = context.createDocumentFragment(); + jQuery.clean( args, context, fragment, scripts ); + + // Update the cache, but only store false + // unless this is a second parsing of the same content + if ( cacheable ) { + jQuery.fragments[ first ] = cachehit && fragment; + } + } + + return { fragment: fragment, cacheable: cacheable }; +}; + +jQuery.fragments = {}; + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + l = insert.length, + parent = this.length === 1 && this[0].parentNode; + + if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { + insert[ original ]( this[0] ); + return this; + } else { + for ( ; i < l; i++ ) { + elems = ( i > 0 ? this.clone(true) : this ).get(); + jQuery( insert[i] )[ original ]( elems ); + ret = ret.concat( elems ); + } + + return this.pushStack( ret, name, insert.selector ); + } + }; +}); + +function getAll( elem ) { + if ( typeof elem.getElementsByTagName !== "undefined" ) { + return elem.getElementsByTagName( "*" ); + + } else if ( typeof elem.querySelectorAll !== "undefined" ) { + return elem.querySelectorAll( "*" ); + + } else { + return []; + } +} + +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var srcElements, + destElements, + i, + clone; + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + // IE copies events bound via attachEvent when using cloneNode. + // Calling detachEvent on the clone will also remove the events + // from the original. In order to get around this, we use some + // proprietary methods to clear the events. Thanks to MooTools + // guys for this hotness. + + cloneFixAttributes( elem, clone ); + + // Using Sizzle here is crazy slow, so we use getElementsByTagName instead + srcElements = getAll( elem ); + destElements = getAll( clone ); + + // Weird iteration because IE will replace the length property + // with an element if you are cloning the body and one of the + // elements on the page has a name or id of "length" + for ( i = 0; srcElements[i]; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + cloneCopyEvent( elem, clone ); + + if ( deepDataAndEvents ) { + srcElements = getAll( elem ); + destElements = getAll( clone ); + + for ( i = 0; srcElements[i]; ++i ) { + cloneCopyEvent( srcElements[i], destElements[i] ); + } + } + } + + srcElements = destElements = null; + + // Return the cloned set + return clone; + }, + + clean: function( elems, context, fragment, scripts ) { + var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, + safe = context === document && safeFragment, + ret = []; + + // Ensure that context is a document + if ( !context || typeof context.createDocumentFragment === "undefined" ) { + context = document; + } + + // Use the already-created safe fragment if context permits + for ( i = 0; (elem = elems[i]) != null; i++ ) { + if ( typeof elem === "number" ) { + elem += ""; + } + + if ( !elem ) { + continue; + } + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Ensure a safe container in which to render the html + safe = safe || createSafeFragment( context ); + div = context.createElement("div"); + safe.appendChild( div ); + + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); + + // Go to html and back, then peel off extra wrappers + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + depth = wrap[0]; + div.innerHTML = wrap[1] + elem + wrap[2]; + + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + hasBody = rtbody.test(elem); + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : + + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; + + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } + } + } + + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } + + elem = div.childNodes; + + // Take out of fragment container (we need a fresh div each time) + div.parentNode.removeChild( div ); + } + } + + if ( elem.nodeType ) { + ret.push( elem ); + } else { + jQuery.merge( ret, elem ); + } + } + + // Fix #11356: Clear elements from safeFragment + if ( div ) { + elem = div = safe = null; + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + for ( i = 0; (elem = ret[i]) != null; i++ ) { + if ( jQuery.nodeName( elem, "input" ) ) { + fixDefaultChecked( elem ); + } else if ( typeof elem.getElementsByTagName !== "undefined" ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } + } + } + + // Append elements to a provided document fragment + if ( fragment ) { + // Special handling of each script element + handleScript = function( elem ) { + // Check if we consider it executable + if ( !elem.type || rscriptType.test( elem.type ) ) { + // Detach the script and store it in the scripts array (if provided) or the fragment + // Return truthy to indicate that it has been handled + return scripts ? + scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : + fragment.appendChild( elem ); + } + }; + + for ( i = 0; (elem = ret[i]) != null; i++ ) { + // Check if we're done after handling an executable script + if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { + // Append to fragment and handle embedded scripts + fragment.appendChild( elem ); + if ( typeof elem.getElementsByTagName !== "undefined" ) { + // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration + jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); + + // Splice the scripts into ret after their former ancestor and advance our index beyond them + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); + i += jsTags.length; + } + } + } + } + + return ret; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var data, id, elem, type, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + jQuery.deletedIds.push( id ); + } + } + } + } + } +}); +// Limit scope pollution from any deprecated API +(function() { + +var matched, browser; + +// Use of jQuery.browser is frowned upon. +// More details: http://api.jquery.com/jQuery.browser +// jQuery.uaMatch maintained for back-compat +jQuery.uaMatch = function( ua ) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || + /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; +}; + +matched = jQuery.uaMatch( navigator.userAgent ); +browser = {}; + +if ( matched.browser ) { + browser[ matched.browser ] = true; + browser.version = matched.version; +} + +// Chrome is Webkit, but Webkit is also Safari. +if ( browser.chrome ) { + browser.webkit = true; +} else if ( browser.webkit ) { + browser.safari = true; +} + +jQuery.browser = browser; + +jQuery.sub = function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; +}; + +})(); +var curCSS, iframe, iframeDoc, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity=([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], + + eventsToggle = jQuery.fn.toggle; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var elem, display, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + values[ index ] = jQuery._data( elem, "olddisplay" ); + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && elem.style.display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + display = curCSS( elem, "display" ); + + if ( !values[ index ] && display !== "none" ) { + jQuery._data( elem, "olddisplay", display ); + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state, fn2 ) { + var bool = typeof state === "boolean"; + + if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { + return eventsToggle.apply( this, arguments ); + } + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, numeric, extra ) { + var val, num, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( numeric || extra !== undefined ) { + num = parseFloat( val ); + return numeric || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: To any future maintainer, we've window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + curCSS = function( elem, name ) { + var ret, width, minWidth, maxWidth, + computed = window.getComputedStyle( elem, null ), + style = elem.style; + + if ( computed ) { + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + curCSS = function( elem, name ) { + var left, rsLeft, + ret = elem.currentStyle && elem.currentStyle[ name ], + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + elem.runtimeStyle.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + elem.runtimeStyle.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + // we use jQuery.css instead of curCSS here + // because of the reliableMarginRight CSS hook! + val += jQuery.css( elem, extra + cssExpand[ i ], true ); + } + + // From this point on we use curCSS for maximum performance (relevant in animations) + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } else { + // at this point, extra isn't content, so add padding + val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + valueIsBorderBox = true, + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox + ) + ) + "px"; +} + + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + if ( elemdisplay[ nodeName ] ) { + return elemdisplay[ nodeName ]; + } + + var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), + display = elem.css("display"); + elem.remove(); + + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe + if ( display === "none" || display === "" ) { + // Use the already-created iframe if possible + iframe = document.body.appendChild( + iframe || jQuery.extend( document.createElement("iframe"), { + frameBorder: 0, + width: 0, + height: 0 + }) + ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write(""); + iframeDoc.close(); + } + + elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); + + display = curCSS( elem, "display" ); + document.body.removeChild( iframe ); + } + + // Store the correct default display + elemdisplay[ nodeName ] = display; + + return display; +} + +jQuery.each([ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + // certain elements can have dimension info if we invisibly show them + // however, it must have a current display style that would benefit from this + if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) { + return jQuery.swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + }); + } else { + return getWidthOrHeight( elem, name, extra ); + } + } + }, + + set: function( elem, value, extra ) { + return setPositiveNumber( elem, value, extra ? + augmentWidthOrHeight( + elem, + name, + extra, + jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" + ) : 0 + ); + } + }; +}); + +if ( !jQuery.support.opacity ) { + jQuery.cssHooks.opacity = { + get: function( elem, computed ) { + // IE uses filters for opacity + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : + computed ? "1" : ""; + }, + + set: function( elem, value ) { + var style = elem.style, + currentStyle = elem.currentStyle, + opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", + filter = currentStyle && currentStyle.filter || style.filter || ""; + + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + style.zoom = 1; + + // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 + if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && + style.removeAttribute ) { + + // Setting style.filter to null, "" & " " still leave "filter:" in the cssText + // if "filter:" is present at all, clearType is disabled, we want to avoid this + // style.removeAttribute is IE Only, but so apparently is this code path... + style.removeAttribute( "filter" ); + + // if there there is no filter style applied in a css rule, we are done + if ( currentStyle && !currentStyle.filter ) { + return; + } + } + + // otherwise, set new filter values + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; + } + }; +} + +// These hooks cannot be added until DOM ready because the support test +// for it is not run until after DOM ready +jQuery(function() { + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + return jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + return curCSS( elem, "marginRight" ); + } + }); + } + }; + } + + // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 + // getComputedStyle returns percent when specified for top/left/bottom/right + // rather than make the css module depend on the offset module, we just check for it here + if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { + jQuery.each( [ "top", "left" ], function( i, prop ) { + jQuery.cssHooks[ prop ] = { + get: function( elem, computed ) { + if ( computed ) { + var ret = curCSS( elem, prop ); + // if curCSS returns percentage, fallback to offset + return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; + } + } + }; + }); + } + +}); + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.hidden = function( elem ) { + return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); + }; + + jQuery.expr.filters.visible = function( elem ) { + return !jQuery.expr.filters.hidden( elem ); + }; +} + +// These hooks are used by animate to expand properties +jQuery.each({ + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i, + + // assumes a single number if not a string + parts = typeof value === "string" ? value.split(" ") : [ value ], + expanded = {}; + + for ( i = 0; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +}); +var r20 = /%20/g, + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rselectTextarea = /^(?:select|textarea)/i; + +jQuery.fn.extend({ + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map(function(){ + return this.elements ? jQuery.makeArray( this.elements ) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + ( this.checked || rselectTextarea.test( this.nodeName ) || + rinput.test( this.type ) ); + }) + .map(function( i, elem ){ + var val = jQuery( this ).val(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val, i ){ + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }).get(); + } +}); + +//Serialize an array of form elements or a set of +//key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, value ) { + // If value is a function, invoke it and return its value + value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); + s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); + }; + + // Set traditional to true for jQuery <= 1.3.2 behavior. + if ( traditional === undefined ) { + traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + }); + + } else { + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ).replace( r20, "+" ); +}; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( jQuery.isArray( obj ) ) { + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + // If array item is non-scalar (array or object), encode its + // numeric index to resolve deserialization ambiguity issues. + // Note that rack (as of 1.0.0) can't currently deserialize + // nested arrays properly, and attempting to do so may cause + // a server error. Possible fixes are to modify rack's + // deserialization algorithm or to provide an option or flag + // to force array serialization to be shallow. + buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); + } + }); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + // Serialize scalar item. + add( prefix, obj ); + } +} +var + // Document location + ajaxLocParts, + ajaxLocation, + + rhash = /#.*$/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + rquery = /\?/, + rscript = /)<[^<]*)*<\/script>/gi, + rts = /([?&])_=[^&]*/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, + + // Keep a copy of the old load method + _load = jQuery.fn.load, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = ["*/"] + ["*"]; + +// #8138, IE may throw an exception when accessing +// a field from window.location if document.domain has been set +try { + ajaxLocation = location.href; +} catch( e ) { + // Use the href attribute of an A element + // since IE will modify it given document.location + ajaxLocation = document.createElement( "a" ); + ajaxLocation.href = ""; + ajaxLocation = ajaxLocation.href; +} + +// Segment location into parts +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, list, placeBefore, + dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), + i = 0, + length = dataTypes.length; + + if ( jQuery.isFunction( func ) ) { + // For each dataType in the dataTypeExpression + for ( ; i < length; i++ ) { + dataType = dataTypes[ i ]; + // We control if we're asked to add before + // any existing element + placeBefore = /^\+/.test( dataType ); + if ( placeBefore ) { + dataType = dataType.substr( 1 ) || "*"; + } + list = structure[ dataType ] = structure[ dataType ] || []; + // then we add to the structure accordingly + list[ placeBefore ? "unshift" : "push" ]( func ); + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, + dataType /* internal */, inspected /* internal */ ) { + + dataType = dataType || options.dataTypes[ 0 ]; + inspected = inspected || {}; + + inspected[ dataType ] = true; + + var selection, + list = structure[ dataType ], + i = 0, + length = list ? list.length : 0, + executeOnly = ( structure === prefilters ); + + for ( ; i < length && ( executeOnly || !selection ); i++ ) { + selection = list[ i ]( options, originalOptions, jqXHR ); + // If we got redirected to another dataType + // we try there if executing only and not done already + if ( typeof selection === "string" ) { + if ( !executeOnly || inspected[ selection ] ) { + selection = undefined; + } else { + options.dataTypes.unshift( selection ); + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, selection, inspected ); + } + } + } + // If we're only executing or nothing was selected + // we try the catchall dataType if not done already + if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, "*", inspected ); + } + // unnecessary when only executing (prefilters) + // but it'll be ignored by the caller in that case + return selection; +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + +jQuery.fn.load = function( url, params, callback ) { + if ( typeof url !== "string" && _load ) { + return _load.apply( this, arguments ); + } + + // Don't do a request if no elements are being requested + if ( !this.length ) { + return this; + } + + var selector, type, response, + self = this, + off = url.indexOf(" "); + + if ( off >= 0 ) { + selector = url.slice( off, url.length ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( jQuery.isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // Request the remote document + jQuery.ajax({ + url: url, + + // if "type" variable is undefined, then "GET" method will be used + type: type, + dataType: "html", + data: params, + complete: function( jqXHR, status ) { + if ( callback ) { + self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); + } + } + }).done(function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + // See if a selector was specified + self.html( selector ? + + // Create a dummy div to hold the results + jQuery("
") + + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append( responseText.replace( rscript, "" ) ) + + // Locate the specified elements + .find( selector ) : + + // If not, just inject the full result + responseText ); + + }); + + return this; +}; + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ + jQuery.fn[ o ] = function( f ){ + return this.on( o, f ); + }; +}); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + // shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + return jQuery.ajax({ + type: method, + url: url, + data: data, + success: callback, + dataType: type + }); + }; +}); + +jQuery.extend({ + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); + } else { + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; + } + ajaxExtend( target, settings ); + return target; + }, + + ajaxSettings: { + url: ajaxLocation, + isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), + global: true, + type: "GET", + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + processData: true, + async: true, + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + xml: "application/xml, text/xml", + html: "text/html", + text: "text/plain", + json: "application/json, text/javascript", + "*": allTypes + }, + + contents: { + xml: /xml/, + html: /html/, + json: /json/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText" + }, + + // List of data converters + // 1) key format is "source_type destination_type" (a single space in-between) + // 2) the catchall symbol "*" can be used for source_type + converters: { + + // Convert anything to text + "* text": window.String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": jQuery.parseJSON, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true + } + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var // ifModified key + ifModifiedKey, + // Response headers + responseHeadersString, + responseHeaders, + // transport + transport, + // timeout handle + timeoutTimer, + // Cross-domain detection vars + parts, + // To know if global events are to be dispatched + fireGlobals, + // Loop variable + i, + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + // Callbacks context + callbackContext = s.context || s, + // Context for global events + // It's the callbackContext if one was provided in the options + // and if it's a DOM node or a jQuery collection + globalEventContext = callbackContext !== s && + ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? + jQuery( callbackContext ) : jQuery.event, + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + // Status-dependent callbacks + statusCode = s.statusCode || {}, + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + // The jqXHR state + state = 0, + // Default abort message + strAbort = "canceled", + // Fake xhr + jqXHR = { + + readyState: 0, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( !state ) { + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Raw string + getAllResponseHeaders: function() { + return state === 2 ? responseHeadersString : null; + }, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( state === 2 ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match === undefined ? null : match; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( !state ) { + s.mimeType = type; + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + statusText = statusText || strAbort; + if ( transport ) { + transport.abort( statusText ); + } + done( 0, statusText ); + return this; + } + }; + + // Callback for when everything is done + // It is defined here because jslint complains if it is declared + // at the end of the function (which would be more logical and readable) + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Called once + if ( state === 2 ) { + return; + } + + // State is "done" now + state = 2; + + // Clear timeout if it exists + if ( timeoutTimer ) { + clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // If successful, handle type chaining + if ( status >= 200 && status < 300 || status === 304 ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + + modified = jqXHR.getResponseHeader("Last-Modified"); + if ( modified ) { + jQuery.lastModified[ ifModifiedKey ] = modified; + } + modified = jqXHR.getResponseHeader("Etag"); + if ( modified ) { + jQuery.etag[ ifModifiedKey ] = modified; + } + } + + // If not modified + if ( status === 304 ) { + + statusText = "notmodified"; + isSuccess = true; + + // If we have data + } else { + + isSuccess = ajaxConvert( s, response ); + statusText = isSuccess.state; + success = isSuccess.data; + error = isSuccess.error; + isSuccess = !error; + } + } else { + // We extract error from statusText + // then normalize statusText and status for non-aborts + error = statusText; + if ( !statusText || status ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + // Attach deferreds + deferred.promise( jqXHR ); + jqXHR.success = jqXHR.done; + jqXHR.error = jqXHR.fail; + jqXHR.complete = completeDeferred.add; + + // Status-dependent callbacks + jqXHR.statusCode = function( map ) { + if ( map ) { + var tmp; + if ( state < 2 ) { + for ( tmp in map ) { + statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; + } + } else { + tmp = map[ jqXHR.status ]; + jqXHR.always( tmp ); + } + } + return this; + }; + + // Remove hash character (#7531: and string promotion) + // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) + // We also use the url parameter if available + s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); + + // Extract dataTypes list + s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); + + // A cross-domain request is in order when we have a protocol:host:port mismatch + if ( s.crossDomain == null ) { + parts = rurl.exec( s.url.toLowerCase() ); + s.crossDomain = !!( parts && + ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || + ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != + ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) + ); + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( state === 2 ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + fireGlobals = s.global; + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // If data is available, append data to url + if ( s.data ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Get ifModifiedKey before adding the anti-cache parameter + ifModifiedKey = s.url; + + // Add anti-cache in url if needed + if ( s.cache === false ) { + + var ts = jQuery.now(), + // try replacing _= if it is there + ret = s.url.replace( rts, "$1_=" + ts ); + + // if nothing was replaced, add timestamp to the end + s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + ifModifiedKey = ifModifiedKey || s.url; + if ( jQuery.lastModified[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); + } + if ( jQuery.etag[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); + } + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { + // Abort if not done already and return + return jqXHR.abort(); + + } + + // aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + for ( i in { success: 1, error: 1, complete: 1 } ) { + jqXHR[ i ]( s[ i ] ); + } + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = setTimeout( function(){ + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + state = 1; + transport.send( requestHeaders, done ); + } catch (e) { + // Propagate exception as error if not done + if ( state < 2 ) { + done( -1, e ); + // Simply rethrow otherwise + } else { + throw e; + } + } + } + + return jqXHR; + }, + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {} + +}); + +/* Handles responses to an ajax request: + * - sets all responseXXX fields accordingly + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes, + responseFields = s.responseFields; + + // Fill responseXXX fields + for ( type in responseFields ) { + if ( type in responses ) { + jqXHR[ responseFields[type] ] = responses[ type ]; + } + } + + // Remove auto dataType and get content-type in the process + while( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +// Chain conversions given the request and the original response +function ajaxConvert( s, response ) { + + var conv, conv2, current, tmp, + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(), + prev = dataTypes[ 0 ], + converters = {}, + i = 0; + + // Apply the dataFilter if provided + if ( s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + // Convert to each sequential dataType, tolerating list modification + for ( ; (current = dataTypes[++i]); ) { + + // There's only work to do if current dataType is non-auto + if ( current !== "*" ) { + + // Convert response if prev dataType is non-auto and differs from current + if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split(" "); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.splice( i--, 0, current ); + } + + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s["throws"] ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; + } + } + } + } + + // Update prev for next iteration + prev = current; + } + } + + return { state: "success", data: response }; +} +var oldCallbacks = [], + rquestion = /\?/, + rjsonp = /(=)\?(?=&|$)|\?\?/, + nonce = jQuery.now(); + +// Default jsonp settings +jQuery.ajaxSetup({ + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + this[ callback ] = true; + return callback; + } +}); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + data = s.data, + url = s.url, + hasCallback = s.jsonp !== false, + replaceInUrl = hasCallback && rjsonp.test( url ), + replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && + !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && + rjsonp.test( data ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + overwritten = window[ callbackName ]; + + // Insert callback into url or form data + if ( replaceInUrl ) { + s.url = url.replace( rjsonp, "$1" + callbackName ); + } else if ( replaceInData ) { + s.data = data.replace( rjsonp, "$1" + callbackName ); + } else if ( hasCallback ) { + s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters["script json"] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always(function() { + // Restore preexisting value + window[ callbackName ] = overwritten; + + // Save back as free + if ( s[ callbackName ] ) { + // make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + }); + + // Delegate to script + return "script"; + } +}); +// Install script dataType +jQuery.ajaxSetup({ + accepts: { + script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /javascript|ecmascript/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +}); + +// Handle cache's special case and global +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + s.global = false; + } +}); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function(s) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + + var script, + head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; + + return { + + send: function( _, callback ) { + + script = document.createElement( "script" ); + + script.async = "async"; + + if ( s.scriptCharset ) { + script.charset = s.scriptCharset; + } + + script.src = s.url; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function( _, isAbort ) { + + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + + // Remove the script + if ( head && script.parentNode ) { + head.removeChild( script ); + } + + // Dereference the script + script = undefined; + + // Callback if not abort + if ( !isAbort ) { + callback( 200, "success" ); + } + } + }; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709 and #4378). + head.insertBefore( script, head.firstChild ); + }, + + abort: function() { + if ( script ) { + script.onload( 0, 1 ); + } + } + }; + } +}); +var xhrCallbacks, + // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { + // Abort all pending requests + for ( var key in xhrCallbacks ) { + xhrCallbacks[ key ]( 0, 1 ); + } + } : false, + xhrId = 0; + +// Functions to create xhrs +function createStandardXHR() { + try { + return new window.XMLHttpRequest(); + } catch( e ) {} +} + +function createActiveXHR() { + try { + return new window.ActiveXObject( "Microsoft.XMLHTTP" ); + } catch( e ) {} +} + +// Create the request object +// (This is still attached to ajaxSettings for backward compatibility) +jQuery.ajaxSettings.xhr = window.ActiveXObject ? + /* Microsoft failed to properly + * implement the XMLHttpRequest in IE7 (can't request local files), + * so we use the ActiveXObject when it is available + * Additionally XMLHttpRequest can be disabled in IE7/IE8 so + * we need a fallback. + */ + function() { + return !this.isLocal && createStandardXHR() || createActiveXHR(); + } : + // For all other browsers, use the standard XMLHttpRequest object + createStandardXHR; + +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); + +// Create transport if the browser can provide an xhr +if ( jQuery.support.ajax ) { + + jQuery.ajaxTransport(function( s ) { + // Cross domain only allowed if supported through XMLHttpRequest + if ( !s.crossDomain || jQuery.support.cors ) { + + var callback; + + return { + send: function( headers, complete ) { + + // Get a new xhr + var handle, i, + xhr = s.xhr(); + + // Open the socket + // Passing null username, generates a login popup on Opera (#2865) + if ( s.username ) { + xhr.open( s.type, s.url, s.async, s.username, s.password ); + } else { + xhr.open( s.type, s.url, s.async ); + } + + // Apply custom fields if provided + if ( s.xhrFields ) { + for ( i in s.xhrFields ) { + xhr[ i ] = s.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( s.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( s.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Need an extra try/catch for cross domain requests in Firefox 3 + try { + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + } catch( _ ) {} + + // Do send the request + // This may raise an exception which is actually + // handled in jQuery.ajax (so no try/catch here) + xhr.send( ( s.hasContent && s.data ) || null ); + + // Listener + callback = function( _, isAbort ) { + + var status, + statusText, + responseHeaders, + responses, + xml; + + // Firefox throws exceptions when accessing properties + // of an xhr when a network error occurred + // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) + try { + + // Was never called and is aborted or complete + if ( callback && ( isAbort || xhr.readyState === 4 ) ) { + + // Only called once + callback = undefined; + + // Do not keep as active anymore + if ( handle ) { + xhr.onreadystatechange = jQuery.noop; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } + } + + // If it's an abort + if ( isAbort ) { + // Abort it manually if needed + if ( xhr.readyState !== 4 ) { + xhr.abort(); + } + } else { + status = xhr.status; + responseHeaders = xhr.getAllResponseHeaders(); + responses = {}; + xml = xhr.responseXML; + + // Construct response list + if ( xml && xml.documentElement /* #4958 */ ) { + responses.xml = xml; + } + + // When requesting binary data, IE6-9 will throw an exception + // on any attempt to access responseText (#11426) + try { + responses.text = xhr.responseText; + } catch( e ) { + } + + // Firefox throws an exception when accessing + // statusText for faulty cross-domain requests + try { + statusText = xhr.statusText; + } catch( e ) { + // We normalize with Webkit giving an empty statusText + statusText = ""; + } + + // Filter status for non standard behaviors + + // If the request is local and we have data: assume a success + // (success with no data won't get notified, that's the best we + // can do given current implementations) + if ( !status && s.isLocal && !s.crossDomain ) { + status = responses.text ? 200 : 404; + // IE - #1450: sometimes returns 1223 when it should be 204 + } else if ( status === 1223 ) { + status = 204; + } + } + } + } catch( firefoxAccessException ) { + if ( !isAbort ) { + complete( -1, firefoxAccessException ); + } + } + + // Call complete if needed + if ( responses ) { + complete( status, statusText, responses, responseHeaders ); + } + }; + + if ( !s.async ) { + // if we're in sync mode we fire the callback + callback(); + } else if ( xhr.readyState === 4 ) { + // (IE6 & IE7) if it's in cache and has been + // retrieved directly we need to fire the callback + setTimeout( callback, 0 ); + } else { + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; + } + xhr.onreadystatechange = callback; + } + }, + + abort: function() { + if ( callback ) { + callback(0,1); + } + } + }; + } + }); +} +var fxNow, timerId, + rfxtypes = /^(?:toggle|show|hide)$/, + rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), + rrun = /queueHooks$/, + animationPrefilters = [ defaultPrefilter ], + tweeners = { + "*": [function( prop, value ) { + var end, unit, + tween = this.createTween( prop, value ), + parts = rfxnum.exec( value ), + target = tween.cur(), + start = +target || 0, + scale = 1, + maxIterations = 20; + + if ( parts ) { + end = +parts[2]; + unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + + // We need to compute starting value + if ( unit !== "px" && start ) { + // Iteratively approximate from a nonzero starting point + // Prefer the current property, because this process will be trivial if it uses the same units + // Fallback to end or a simple constant + start = jQuery.css( tween.elem, prop, true ) || end || 1; + + do { + // If previous iteration zeroed out, double until we get *something* + // Use a string for doubling factor so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + start = start / scale; + jQuery.style( tween.elem, prop, start + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // And breaking the loop if scale is unchanged or perfect, or if we've just had enough + } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); + } + + tween.unit = unit; + tween.start = start; + // If a +=/-= token was provided, we're doing a relative animation + tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; + } + return tween; + }] + }; + +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout(function() { + fxNow = undefined; + }, 0 ); + return ( fxNow = jQuery.now() ); +} + +function createTweens( animation, props ) { + jQuery.each( props, function( prop, value ) { + var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( collection[ index ].call( animation, prop, value ) ) { + + // we're done with this property + return; + } + } + }); +} + +function Animation( elem, properties, options ) { + var result, + index = 0, + tweenerIndex = 0, + length = animationPrefilters.length, + deferred = jQuery.Deferred().always( function() { + // don't match elem in the :animated selector + delete tick.elem; + }), + tick = function() { + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ]); + + if ( percent < 1 && length ) { + return remaining; + } else { + deferred.resolveWith( elem, [ animation ] ); + return false; + } + }, + animation = deferred.promise({ + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { specialEasing: {} }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end, easing ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + // if we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // resolve when we played the last frame + // otherwise, reject + if ( gotoEnd ) { + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + }), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length ; index++ ) { + result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + return result; + } + } + + createTweens( animation, props ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + jQuery.fx.timer( + jQuery.extend( tick, { + anim: animation, + queue: animation.opts.queue, + elem: elem + }) + ); + + // attach callbacks from options + return animation.progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( jQuery.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // not quite $.extend, this wont overwrite keys already present. + // also - reusing 'index' from above because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.split(" "); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length ; index++ ) { + prop = props[ index ]; + tweeners[ prop ] = tweeners[ prop ] || []; + tweeners[ prop ].unshift( callback ); + } + }, + + prefilter: function( callback, prepend ) { + if ( prepend ) { + animationPrefilters.unshift( callback ); + } else { + animationPrefilters.push( callback ); + } + } +}); + +function defaultPrefilter( elem, props, opts ) { + var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire, + anim = this, + style = elem.style, + orig = {}, + handled = [], + hidden = elem.nodeType && isHidden( elem ); + + // handle queue: false promises + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always(function() { + // doing this makes sure that the complete handler will be called + // before this completes + anim.always(function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + }); + }); + } + + // height/width overflow pass + if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { + // Make sure that nothing sneaks out + // Record all 3 overflow attributes because IE does not + // change the overflow attribute when overflowX and + // overflowY are set to the same value + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Set display property to inline-block for height/width + // animations on inline elements that are having width/height animated + if ( jQuery.css( elem, "display" ) === "inline" && + jQuery.css( elem, "float" ) === "none" ) { + + // inline-level elements accept inline-block; + // block-level elements need to be inline with layout + if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { + style.display = "inline-block"; + + } else { + style.zoom = 1; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + if ( !jQuery.support.shrinkWrapBlocks ) { + anim.done(function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + }); + } + } + + + // show/hide pass + for ( index in props ) { + value = props[ index ]; + if ( rfxtypes.exec( value ) ) { + delete props[ index ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + continue; + } + handled.push( index ); + } + } + + length = handled.length; + if ( length ) { + dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + + // store state if its toggle - enables .stop().toggle() to "reverse" + if ( toggle ) { + dataShow.hidden = !hidden; + } + if ( hidden ) { + jQuery( elem ).show(); + } else { + anim.done(function() { + jQuery( elem ).hide(); + }); + } + anim.done(function() { + var prop; + jQuery.removeData( elem, "fxshow", true ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + }); + for ( index = 0 ; index < length ; index++ ) { + prop = handled[ index ]; + tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); + orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); + + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = tween.start; + if ( hidden ) { + tween.end = tween.start; + tween.start = prop === "width" || prop === "height" ? 1 : 0; + } + } + } + } +} + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || "swing"; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + if ( tween.elem[ tween.prop ] != null && + (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { + return tween.elem[ tween.prop ]; + } + + // passing any value as a 4th parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails + // so, simple values such as "10px" are parsed to Float. + // complex values such as "rotate(1rad)" are returned as is. + result = jQuery.css( tween.elem, tween.prop, false, "" ); + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + // use step hook for back compat - use cssHook if its there - use .style if its + // available and use plain properties where available + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Remove in 2.0 - this supports IE8's panic based approach +// to setting things on disconnected nodes + +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" || + // special check for .toggle( handler, handler, ... ) + ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +}); + +jQuery.fn.extend({ + fadeTo: function( speed, to, easing, callback ) { + + // show any hidden elements after setting opacity to 0 + return this.filter( isHidden ).css( "opacity", 0 ).show() + + // animate to the value specified + .end().animate({ opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations resolve immediately + if ( empty ) { + anim.stop( true ); + } + }; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each(function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = jQuery._data( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // start the next in the queue if the last step wasn't forced + // timers currently will call their complete callbacks, which will dequeue + // but only if they were gotoEnd + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + }); + } +}); + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + attrs = { height: type }, + i = 0; + + // if we include width, step value is 1 to do all cssExpand values, + // if we don't include width, step value is 2 to skip over Left and Right + includeWidth = includeWidth? 1 : 0; + for( ; i < 4 ; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +// Generate shortcuts for custom animations +jQuery.each({ + slideDown: genFx("show"), + slideUp: genFx("hide"), + slideToggle: genFx("toggle"), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +}); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + + // normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p*Math.PI ) / 2; + } +}; + +jQuery.timers = []; +jQuery.fx = Tween.prototype.init; +jQuery.fx.tick = function() { + var timer, + timers = jQuery.timers, + i = 0; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + // Checks the timer has not already been removed + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + if ( timer() && jQuery.timers.push( timer ) && !timerId ) { + timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); + } +}; + +jQuery.fx.interval = 13; + +jQuery.fx.stop = function() { + clearInterval( timerId ); + timerId = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + // Default speed + _default: 400 +}; + +// Back Compat <1.8 extension point +jQuery.fx.step = {}; + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.animated = function( elem ) { + return jQuery.grep(jQuery.timers, function( fn ) { + return elem === fn.elem; + }).length; + }; +} +var rroot = /^(?:body|html)$/i; + +jQuery.fn.offset = function( options ) { + if ( arguments.length ) { + return options === undefined ? + this : + this.each(function( i ) { + jQuery.offset.setOffset( this, options, i ); + }); + } + + var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, + box = { top: 0, left: 0 }, + elem = this[ 0 ], + doc = elem && elem.ownerDocument; + + if ( !doc ) { + return; + } + + if ( (body = doc.body) === elem ) { + return jQuery.offset.bodyOffset( elem ); + } + + docElem = doc.documentElement; + + // Make sure it's not a disconnected DOM node + if ( !jQuery.contains( docElem, elem ) ) { + return box; + } + + // If we don't have gBCR, just use 0,0 rather than error + // BlackBerry 5, iOS 3 (original iPhone) + if ( typeof elem.getBoundingClientRect !== "undefined" ) { + box = elem.getBoundingClientRect(); + } + win = getWindow( doc ); + clientTop = docElem.clientTop || body.clientTop || 0; + clientLeft = docElem.clientLeft || body.clientLeft || 0; + scrollTop = win.pageYOffset || docElem.scrollTop; + scrollLeft = win.pageXOffset || docElem.scrollLeft; + return { + top: box.top + scrollTop - clientTop, + left: box.left + scrollLeft - clientLeft + }; +}; + +jQuery.offset = { + + bodyOffset: function( body ) { + var top = body.offsetTop, + left = body.offsetLeft; + + if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { + top += parseFloat( jQuery.css(body, "marginTop") ) || 0; + left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; + } + + return { top: top, left: left }; + }, + + setOffset: function( elem, options, i ) { + var position = jQuery.css( elem, "position" ); + + // set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + var curElem = jQuery( elem ), + curOffset = curElem.offset(), + curCSSTop = jQuery.css( elem, "top" ), + curCSSLeft = jQuery.css( elem, "left" ), + calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, + props = {}, curPosition = {}, curTop, curLeft; + + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( jQuery.isFunction( options ) ) { + options = options.call( elem, i, curOffset ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + } else { + curElem.css( props ); + } + } +}; + + +jQuery.fn.extend({ + + position: function() { + if ( !this[0] ) { + return; + } + + var elem = this[0], + + // Get *real* offsetParent + offsetParent = this.offsetParent(), + + // Get correct offsets + offset = this.offset(), + parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; + offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; + + // Add offsetParent borders + parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; + parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + }; + }, + + offsetParent: function() { + return this.map(function() { + var offsetParent = this.offsetParent || document.body; + while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || document.body; + }); + } +}); + + +// Create scrollLeft and scrollTop methods +jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { + var top = /Y/.test( prop ); + + jQuery.fn[ method ] = function( val ) { + return jQuery.access( this, function( elem, method, val ) { + var win = getWindow( elem ); + + if ( val === undefined ) { + return win ? (prop in win) ? win[ prop ] : + win.document.documentElement[ method ] : + elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : jQuery( win ).scrollLeft(), + top ? val : jQuery( win ).scrollTop() + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length, null ); + }; +}); + +function getWindow( elem ) { + return jQuery.isWindow( elem ) ? + elem : + elem.nodeType === 9 ? + elem.defaultView || elem.parentWindow : + false; +} +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { + // margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return jQuery.access( this, function( elem, type, value ) { + var doc; + + if ( jQuery.isWindow( elem ) ) { + // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there + // isn't a whole lot we can do. See pull request at this URL for discussion: + // https://github.com/jquery/jquery/pull/764 + return elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest + // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, value, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable, null ); + }; + }); +}); +// Expose jQuery to the global object +window.jQuery = window.$ = jQuery; + +// Expose jQuery as an AMD module, but only for AMD loaders that +// understand the issues with loading multiple versions of jQuery +// in a page that all might call define(). The loader will indicate +// they have special allowances for multiple jQuery versions by +// specifying define.amd.jQuery = true. Register as a named module, +// since jQuery can be concatenated with other files that may use define, +// but not use a proper concatenation script that understands anonymous +// AMD modules. A named AMD is safest and most robust way to register. +// Lowercase jquery is used because AMD module names are derived from +// file names, and jQuery is normally delivered in a lowercase file name. +// Do this after creating the global so that if an AMD module wants to call +// noConflict to hide this version of jQuery, it will work. +if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); +} + +})( window ); diff --git a/html/js/jquery-1.8.3.min.js b/html/js/jquery-1.8.3.min.js new file mode 100644 index 0000000..83589da --- /dev/null +++ b/html/js/jquery-1.8.3.min.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/html/js/jsrender.js b/html/js/jsrender.js new file mode 100644 index 0000000..8f21545 --- /dev/null +++ b/html/js/jsrender.js @@ -0,0 +1,1283 @@ +/*! JsRender v1.0pre: http://github.com/BorisMoore/jsrender */ +/* +* Optimized version of jQuery Templates, for rendering to string. +* Does not require jQuery, or HTML DOM +* Integrates with JsViews (http://github.com/BorisMoore/jsviews) +* Copyright 2012, Boris Moore +* Released under the MIT License. +*/ +// informal pre beta commit counter: 24 + +(function(global, jQuery, undefined) { + // global is the this object, which is window when running in the usual browser environment. + "use strict"; + + if (jQuery && jQuery.views || global.jsviews) { return; } // JsRender is already loaded + + //========================== Top-level vars ========================== + + var versionNumber = "v1.0pre", + + $, jsvStoreName, rTag, rTmplString, +//TODO tmplFnsCache = {}, + delimOpenChar0 = "{", delimOpenChar1 = "{", delimCloseChar0 = "}", delimCloseChar1 = "}", linkChar = "^", + FALSE = false, TRUE = true, + + rPath = /^(?:null|true|false|\d[\d.]*|([\w$]+|\.|~([\w$]+)|#(view|([\w$]+))?)([\w$.^]*?)(?:[.[^]([\w$]+)\]?)?)$/g, + // object helper view viewProperty pathTokens leafToken + + rParams = /(\()(?=|\s*\()|(?:([([])\s*)?(?:([#~]?[\w$.^]+)?\s*((\+\+|--)|\+|-|&&|\|\||===|!==|==|!=|<=|>=|[<>%*!:?\/]|(=))\s*|([#~]?[\w$.^]+)([([])?)|(,\s*)|(\(?)\\?(?:(')|("))|(?:\s*([)\]])([([]?))|(\s+)/g, + // lftPrn lftPrn2 path operator err eq path2 prn comma lftPrn2 apos quot rtPrn prn2 space + // (left paren? followed by (path? followed by operator) or (path followed by paren?)) or comma or apos or quot or right paren or space + + rNewLine = /\r?\n/g, + rUnescapeQuotes = /\\(['"])/g, + // escape quotes and \ character + rEscapeQuotes = /([\\'"])/g, + rBuildHash = /\x08(~)?([^\x08]+)\x08/g, + rTestElseIf = /^if\s/, + rFirstElem = /<(\w+)[>\s]/, + rPrevElem = /<(\w+)[^>\/]*>[^>]*$/, + autoTmplName = 0, + viewId = 0, + escapeMapForHtml = { + "&": "&", + "<": "<", + ">": ">" + }, + attrEncodeChars = /[<"'&]/g, + htmlEncodeChars = /[\x00<>"'&]/g, + tmplAttr = "data-jsv-tmpl", + fnDeclStr = "var j=j||" + (jQuery ? "jQuery." : "js") + "views,", + slice = [].slice, + + $render = {}, + jsvStores = { + template: { + compile: compileTmpl + }, + tag: { + compile: compileTag + }, + helper: {}, + converter: {} + }, + + // jsviews object ($.views if jQuery is loaded) + $views = { + jsviews: versionNumber, + render: $render, + View: View, + settings: { + delimiters: $viewsDelimiters, + debugMode: TRUE, + tryCatch: TRUE + }, + sub: { + // subscription, e.g. JsViews integration + Error: JsViewsError, + tmplFn: tmplFn, + parse: parseParams, + extend: $extend, + error: error +//TODO invoke: $invoke + }, + _cnvt: convertVal, + _tag: renderTag, + + // TODO provide better debug experience - e.g. support $.views.onError callback + _err: function(e) { + // Place a breakpoint here to intercept template rendering errors + return $viewsSettings.debugMode ? ("Error: " + (e.message || e)) + ". " : ''; + } + }; + + function JsViewsError(message, object) { + // Error exception type for JsViews/JsRender + // Override of $.views.sub.Error is possible + if (object && object.onError) { + if (object.onError(message) === FALSE) { + return; + } + } + this.name = "JsRender Error"; + this.message = message || "JsRender error"; + } + + function $extend(target, source) { + var name; + target = target || {}; + for (name in source) { + target[name] = source[name]; + } + return target; + } + +//TODO function $invoke() { +// try { +// return arguments[1].apply(arguments[0], arguments[2]); +// } +// catch(e) { +// throw new $views.sub.Error(e, arguments[0]); +// } +// } + + (JsViewsError.prototype = new Error()).constructor = JsViewsError; + + //========================== Top-level functions ========================== + + //=================== + // jsviews.delimiters + //=================== + + function $viewsDelimiters(openChars, closeChars, link) { + // Set the tag opening and closing delimiters and 'link' character. Default is "{{", "}}" and "^" + // openChars, closeChars: opening and closing strings, each with two characters + + if (!$viewsSub.rTag || arguments.length) { + delimOpenChar0 = openChars ? openChars.charAt(0) : delimOpenChar0; // Escape the characters - since they could be regex special characters + delimOpenChar1 = openChars ? openChars.charAt(1) : delimOpenChar1; + delimCloseChar0 = closeChars ? closeChars.charAt(0) : delimCloseChar0; + delimCloseChar1 = closeChars ? closeChars.charAt(1) : delimCloseChar1; + linkChar = link || linkChar; + openChars = "\\" + delimOpenChar0 + "(\\" + linkChar + ")?\\" + delimOpenChar1; // Default is "{^{" + closeChars = "\\" + delimCloseChar0 + "\\" + delimCloseChar1; // Default is "}}" + // Build regex with new delimiters + // tag (followed by / space or }) or cvtr+colon or html or code + rTag = "(?:(?:(\\w+(?=[\\/\\s\\" + delimCloseChar0 + "]))|(?:(\\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\\*)))" + + "\\s*((?:[^\\" + delimCloseChar0 + "]|\\" + delimCloseChar0 + "(?!\\" + delimCloseChar1 + "))*?)"; + + // make rTag available to JsViews (or other components) for parsing binding expressions + $viewsSub.rTag = rTag + ")"; + + rTag = new RegExp(openChars + rTag + "(\\/)?|(?:\\/(\\w+)))" + closeChars, "g"); + + // Default: bind tag converter colon html comment code params slash closeBlock + // /{(\^)?{(?:(?:(\w+(?=[\/\s}]))|(?:(\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\*)))\s*((?:[^}]|}(?!}))*?)(\/)?|(?:\/(\w+)))}}/g + + rTmplString = new RegExp("<.*>|([^\\\\]|^)[{}]|" + openChars + ".*" + closeChars); + // rTmplString looks for html tags or { or } char not preceded by \\, or JsRender tags {{xxx}}. Each of these strings are considered NOT to be jQuery selectors + } + return [delimOpenChar0, delimOpenChar1, delimCloseChar0, delimCloseChar1, linkChar]; + } + + //========= + // View.get + //========= + + function getView(type) { + // TODO complete/test/provide samples for this + // If type is undefined, returns root view (view under top view). + var view = this, + root = !type || type === "root"; + while (root && view.parent.parent || view && view.type !== type) { + view = view.parent; + } + return view; + } + + function getIndex() { + var view = this.get("item"); + return view ? view.index : undefined; + } + + getIndex.depends = function(view) { + return [view.get("item"), "index"]; + } + //========== + // View._hlp + //========== + + function getHelper(helper) { + // Helper method called as view._hlp(key) from compiled template, for helper functions or template parameters ~foo + var wrapped, + view = this; + if (helper = (view.ctx || {})[helper] || view.getRsc("helpers", helper)) { + if (typeof helper === "function") { + wrapped = function() { + // If it is of type function, we will wrap it so it gets called with view as 'this' context. + // If the helper ~foo() was in a data-link expression, the view will have a 'temporary' linkCtx property too. + // However note that helper functions on deeper paths will not have access to view and tagCtx. + // For example, ~util.foo() will have the ~util object as 'this' pointer + return helper.apply(view, arguments); + }; + $extend(wrapped, helper); + } + } + return wrapped || helper; + } + + //============== + // jsviews._cnvt + //============== + + function convertVal(converter, view, self, tagCtx, bindingPaths, text) { + // self is template object or linkCtx object + if (converter || bindingPaths) { + var tmplConverter, + linkCtx = !self.markup && self, + tag = { + tagName: converter + ":", + tagCtx: tagCtx + }, + args = tagCtx.args = slice.call(arguments, 5); + + tagCtx.view = view; + tagCtx.bind = !!(linkCtx || bindingPaths); + + if (linkCtx) { + linkCtx.tag = tag; + tag.linkCtx = linkCtx; + tagCtx.ctx = extendCtx(tagCtx.ctx, linkCtx.view.ctx); + } + tag.ctx = tagCtx.ctx || {}; + tagCtx.props = tagCtx.props || {}; + delete tagCtx.ctx; + + if (converter && ((tmplConverter = view.getRsc("converters", converter)) || error("Unknown converter: {{"+ converter + ":"))) { + // A call to {{cnvt: ... }} or {^{cnvt: ... }} or data-link="{cnvt: ... }" + text = tmplConverter.apply(tag, args); + } + if (bindingPaths) { + // A call to {^{: ... }} or {^{cnvt: ... }} + bindingPaths = view.tmpl.bnds[bindingPaths-1]; + linkCtx.paths = bindingPaths; + // Consider being able to switch off binding if parent view is not currently bound. + view._.tag = tag; // Provide this tag on view, for markerNode on bound tags, and for getting the tagCtx and linkCtx during rendering. + // Provide this tag on view, for addMarkerNode on bound tags to add the tag to view._.bnds, associated with the tag id, + // and so when rendering subsequent {{else}}, will be associated with this tag + //TODO does this work with nested elses and with {^{foo:...}} which also adds tag to view, for markerNodes. + text = view._.onRender(text, view, TRUE); + //Example: text = '' + text + ''; + } + } + return text; + } + + //============= + // jsviews._tag + //============= + + function getResource(storeName, item) { + var res, + view = this, + store = $views[storeName]; + + res = store && store[item]; + while (!res && view) { + store = view.tmpl[storeName]; + res = store && store[item]; + view = view.parent; + } + return res; + } + + function getResource2(storeName, item, root) { + var view = this, + store = !root && $views[storeName]; + return store && store[item] + || (store = view.tmpl[storeName], store && store[item]) + || view.parent && view.parent.getRsc(storeName, item, TRUE); + } + + function renderTag(tagName, parentView, self, content, tagCtx, bind) { + // Called from within compiled template function, to render a template tag + // Returns the rendered tag + + var ret, render, ctx, elses, tag, tags, + tmpl = self.markup && self, + // self is either a template object (if rendering a tag) or a linkCtx object (if linking using a link tag) + linkCtx = !tmpl && self, + parentView_ = parentView._, + parentTmpl = tmpl || parentView.tmpl, + childTemplates = parentTmpl.templates, + tagDef = parentView.getRsc("tags", tagName) || error("Unknown tag: {{"+ tagName + "}}"), + args = tagCtx.args = arguments.length > 6 ? slice.call(arguments, 6) : [], + props = tagCtx.props = tagCtx.props || {}; + + tagCtx.view = parentView; + tagCtx.ctx = extendCtx(tagCtx.ctx, parentView.ctx); // Extend parentView.ctx + ctx = tagCtx.ctx || {}; + delete tagCtx.ctx; + + // Set the tmpl property to the content of the block tag, unless set as an override property on the tag + tmpl = props.tmpl; + content = content && parentTmpl.tmpls[content - 1]; + tmpl = tmpl || content || tagDef.template || undefined; + tmpl = "" + tmpl === tmpl // if a string + ? parentView.getRsc("templates", tmpl) || $templates(tmpl) + : tmpl; + + if (tagName === "else") { + tag = parentView._.tag; + // Switch current tagCtx of tag instance to this {{else ...}} + elses = tag._elses = tag._elses || []; + elses.push(tmpl); + tagCtx.isElse = elses.length; + render = tag.render; + } + if (tagDef.init) { + // init is the constructor for the tag/control instance + + // tags hash: tag.ctx.tags, merged with parentView.ctx.tags, + tags = ctx.tags = parentView.ctx && extendCtx(ctx.tags, parentView.ctx.tags) || {}; + + tag = tag || linkCtx.tag; + if (tag) { + // tag has already been instantiated, so keep it, but attach the current context, which may have changed + // Add tag to tags hash + tags[tagName] = tag; + } else { + // If the tag has not already been instantiated, we will create a new instance and add to the tags hash, + // so ~tags.tagName will access the tag, even within the rendering of the template content of this tag +// TODO provide error handling owned by the tag - using tag.onError +// try { + tag = tags[tagName] = new tagDef.init(tagCtx, linkCtx, ctx); +// } +// catch(e) { +// tagDef.onError(e); +// } + tag.tmpl = tmpl; + + if (linkCtx) { + tag.attr = + // Setting attr on tag so renderContent knows whether to include script node markers. + linkCtx.attr = + // Setting attr on self to ensure outputting to the correct target attribute. + linkCtx.attr || tagDef.attr || ""; + } + } + ctx.tag = tag; + } else { + // This is a simple tag declared as a function. We won't instantiate a specific tag constructor - just a standard instance object. + tag = tag || { + // tag instance object if no init constructor + render: tagDef.render, + renderContent: renderContent, + tmpl: tmpl, + tagName: tagName + }; + } + + // Provide tagCtx, linkCtx and ctx access from tag + tag.tagCtx = tagCtx; + tag.ctx = ctx; + if (linkCtx) { + linkCtx.tag = tag; + tag.linkCtx = linkCtx; + } + + tag._is = "tag"; + tag._done = tagCtx.isElse ? tag._done : FALSE; // If not an {{else}} this is a new + tmpl = tmpl || tag.tmpl; + elses = tag._elses; + +//TODO The above works for initial rendering, but when refreshing {^{foo}} need also to associate with {{else}} tags. Use compilation to bind else content templates and expressions with the primary tag template and expression. + + parentView_.tag = tag; + // Provide this tag on view, for addMarkerNode on bound tags to add the tag to view._.bnds, associated with the tag id, + // for getting the tagCtx and linkCtx during rendering, and so when rendering subsequent {{else}}, will be associated with this tag + //TODO does this work with nested elses and with {^{foo:...}} which also adds tag to view, for markerNodes. + +// while (tmpl) { + // If tagDef has a 'render' function, call it. + // If the return result is undefined, return "", or, if a template (or content) is provided, + // return the rendered template(using the current data or the first parameter as data); + if (render = render || tag.render) { + ret = render.apply(tag, args); + +// TODO ret = $invoke(tag, render, args); + } + ret = ret !== undefined + ? ret // Return result of render function unless it is undefined, in which case return rendered template + : tmpl + // render template on args[0] if defined, or otherwise on the current data item + ? tag.renderContent(tagCtx.data !== undefined ? tagCtx.data : parentView.data, undefined, parentView) + : ""; // No return value from render, and no template defined, so return :: + +// tmpl = (tag !== "else" && elses) ? (tagCtx.isElse = tagCtx.isElse || 0, elses[tagCtx.isElse++]) : undefined; +//} + + // If bind, for {^{tag ... }}, insert script marker nodes + return bind ? parentView_.onRender(ret, parentView, bind) : ret; + } + + //================= + // View constructor + //================= + + function View(context, type, parentView, data, template, key, onRender) { + // Constructor for view object in view hierarchy. (Augmented by JsViews if JsViews is loaded) + var views, parentView_, + isArray = type === "array", + self_ = { + key: 0, + useKey: isArray ? 0 : 1, + id: "" + viewId++, + onRender: onRender, + bnd: {} + }, + self = { + data: data, + tmpl: template, + views: isArray ? [] : {}, + parent: parentView, + ctx: context, + type: type, + // If the data is an array, this is an 'array view' with a views array for each child 'item view' + // If the data is not an array, this is an 'item view' with a views 'map' object for any child nested views + // ._.useKey is non zero if is not an 'array view' (owning a data array). Uuse this as next key for adding to child views map + get: getView, + getIndex: getIndex, + getRsc: getResource, + _hlp: getHelper, + _: self_ + }; + + if (parentView) { + views = parentView.views; + parentView_ = parentView._; + if (parentView_.useKey) { + // Parent is an 'item view'. Add this view to its views object + // self._key = is the key in the parent view map + views[self_.key = "_" + parentView_.useKey++] = self; + } else { + // Parent is an 'array view'. Add this view to its views array + views.splice( + // self._.key = self.index - the index in the parent view array + self_.key = self.index = + key !== undefined + ? key + : views.length, + 0, self); + } + // If no context was passed in, use parent context + // If context was passed in, it should have been merged already with parent context + self.ctx = context || parentView.ctx; + } + return self; + } + + //============= + // Registration + //============= + + function compileChildResources(parentTmpl) { + var storeName, resources, resourceName, settings, compile; + for (storeName in jsvStores) { + settings = jsvStores[storeName]; + if ((compile = settings.compile) && (resources = parentTmpl[storeName + "s"])) { + for (resourceName in resources) { + // compile child resource declarations (templates, tags, converters or helpers) + resources[resourceName] = compile(resourceName, resources[resourceName], parentTmpl, storeName, settings); + } + } + } + } + + function compileTag(name, item, parentTmpl) { + var init, tmpl; + if (typeof item === "function") { + // Simple tag declared as function. No presenter instantation. + item = { + tagName: name, + render: item, + depends: item.depends + }; + } else { + // Tag declared as object, used as the prototype for tag instantiation (control/presenter) + item.tagName = name; + if (tmpl = item.template) { + item.template = "" + tmpl === tmpl ? ($templates[tmpl] || $templates(tmpl)) : tmpl; + } + if (item.init !== FALSE) { + init = item.init = item.init || function(tagCtx) {}; + init.prototype = item; + (init.prototype = item).constructor = init; + } + } + item.renderContent = renderContent; + item.attr = "html"; + if (parentTmpl) { + item._parentTmpl = parentTmpl; + } +//TODO item.onError = function(e) { +// var error; +// if (error = this.prototype.onError) { +// error.call(this, e); +// } else { +// throw e; +// } +// } + return item; + } + + function compileTmpl(name, tmpl, parentTmpl, storeName, storeSettings, options) { + // tmpl is either a template object, a selector for a template script block, the name of a compiled template, or a template object + + //==== nested functions ==== + function tmplOrMarkupFromStr(value) { + // If value is of type string - treat as selector, or name of compiled template + // Return the template object, if already compiled, or the markup string + + if (("" + value === value) || value.nodeType > 0) { + try { + elem = value.nodeType > 0 + ? value + : !rTmplString.test(value) + // If value is a string and does not contain HTML or tag content, then test as selector + && jQuery && jQuery(value)[0]; + // If selector is valid and returns at least one element, get first element + // If invalid, jQuery will throw. We will stay with the original string. + } catch (e) { } + + if (elem) { + // Generally this is a script element. + // However we allow it to be any element, so you can for example take the content of a div, + // use it as a template, and replace it by the same content rendered against data. + // e.g. for linking the content of a div to a container, and using the initial content as template: + // $.link("#content", model, {tmpl: "#content"}); + + value = elem.getAttribute(tmplAttr); + name = name || value; + value = $templates[value]; + if (!value) { + // Not already compiled and cached, so compile and cache the name + // Create a name for compiled template if none provided + name = name || "_" + autoTmplName++; + elem.setAttribute(tmplAttr, name); + value = $templates[name] = compileTmpl(name, elem.innerHTML, parentTmpl, storeName, storeSettings, options); // Use tmpl as options + } + } + return value; + } + // If value is not a string, return undefined + } + + var tmplOrMarkup, elem; + + //==== Compile the template ==== + tmpl = tmpl || ""; + tmplOrMarkup = tmplOrMarkupFromStr(tmpl); + + // If options, then this was already compiled from a (script) element template declaration. + // If not, then if tmpl is a template object, use it for options + options = options || (tmpl.markup ? tmpl : {}); + options.tmplName = name; + if (parentTmpl) { + options._parentTmpl = parentTmpl; + } + // If tmpl is not a markup string or a selector string, then it must be a template object + // In that case, get it from the markup property of the object + if (!tmplOrMarkup && tmpl.markup && (tmplOrMarkup = tmplOrMarkupFromStr(tmpl.markup))) { + if (tmplOrMarkup.fn && (tmplOrMarkup.debug !== tmpl.debug || tmplOrMarkup.allowCode !== tmpl.allowCode)) { + // if the string references a compiled template object, but the debug or allowCode props are different, need to recompile + tmplOrMarkup = tmplOrMarkup.markup; + } + } + if (tmplOrMarkup !== undefined) { + if (name && !parentTmpl) { + $render[name] = function() { + return tmpl.render.apply(tmpl, arguments); + }; + } + if (tmplOrMarkup.fn || tmpl.fn) { + // tmpl is already compiled, so use it, or if different name is provided, clone it + if (tmplOrMarkup.fn) { + if (name && name !== tmplOrMarkup.tmplName) { + tmpl = extendCtx(options, tmplOrMarkup); + } else { + tmpl = tmplOrMarkup; + } + } + } else { + // tmplOrMarkup is a markup string, not a compiled template + // Create template object + tmpl = TmplObject(tmplOrMarkup, options); + // Compile to AST and then to compiled function + tmplFn(tmplOrMarkup, tmpl); + } + compileChildResources(options); + return tmpl; + } + } + //==== /end of function compile ==== + + function TmplObject(markup, options) { + // Template object constructor + var htmlTag, + wrapMap = $viewsSettings.wrapMap || {}, + tmpl = $extend( + { + markup: markup, + tmpls: [], + links: {}, + bnds: [], + render: renderContent + }, + options + ); + + if (!options.htmlTag) { + // Set tmpl.tag to the top-level HTML tag used in the template, if any... + htmlTag = rFirstElem.exec(markup); + tmpl.htmlTag = htmlTag ? htmlTag[1].toLowerCase() : ""; + } + htmlTag = wrapMap[tmpl.htmlTag]; + if (htmlTag && htmlTag !== wrapMap.div) { + // When using JsViews, we trim templates which are inserted into HTML contexts where text nodes are not rendered (i.e. not 'Phrasing Content'). + tmpl.markup = $.trim(tmpl.markup); + tmpl._elCnt = TRUE; // element content model (no rendered text nodes), not phrasing content model + } + + return tmpl; + } + + function registerStore(storeName, storeSettings) { + + function theStore(name, item, parentTmpl) { + // The store is also the function used to add items to the store. e.g. $.templates, or $.views.tags + + // For store of name 'thing', Call as: + // $.views.things(items[, parentTmpl]), + // or $.views.things(name, item[, parentTmpl]) + + var onStore, compile, items, itemName, childTemplates, childTemplate, thisStore, childStoreName; + + if (name && "" + name !== name && !name.nodeType && !name.markup) { + // Call to $.views.things(items[, parentTmpl]), + + // Adding items to the store + // If name is a map, then item is parentTmpl. Iterate over map and call store for key. + for (itemName in name) { + theStore(itemName, name[itemName], item); + } + return $views; + } + thisStore = parentTmpl ? parentTmpl[storeNames] = parentTmpl[storeNames] || {} : theStore; + + // Adding a single unnamed item to the store + if (item === undefined) { + item = name; + name = undefined; + } + compile = storeSettings.compile; + if (onStore = $viewsSub.onBeforeStoreItem) { + // e.g. provide an external compiler or preprocess the item. + compile = onStore(thisStore, name, item, compile) || compile; + } + if (!name) { + item = compile(undefined, item); + } else if ("" + name === name) { // name must be a string + if (item === null) { + // If item is null, delete this entry + delete thisStore[name]; + } else { + thisStore[name] = compile ? (item = compile(name, item, parentTmpl, storeName, storeSettings)) : item; + } + } + if (item) { + item._is = storeName; + } + if (onStore = $viewsSub.onStoreItem) { + // e.g. JsViews integration + onStore(thisStore, name, item, compile); + } + return item; + } + + var storeNames = storeName + "s"; + + $views[storeNames] = theStore; + jsvStores[storeName] = storeSettings; + } + + //============== + // renderContent + //============== + + function renderContent(data, context, parentView, key, isLayout, onRender) { + // Render template against data as a tree of subviews (nested rendered template instances), or as a string (top-level template). + // If the data is the parent view, treat as layout template, re-render with the same data context. + var i, l, dataItem, newView, childView, itemResult, parentContext, props, swapContent, tagCtx, isTag, outerOnRender, + self = this, + tmpl = self, + allowDataLink = self.attr === undefined || self.attr === "html", + result = ""; + + if (key === TRUE) { + swapContent = TRUE; + key = 0; + } + if (isTag = self._is === "tag") { + tagCtx = self.tagCtx; + // This is a call from renderTag + tmpl = tagCtx.isElse ? self._elses[tagCtx.isElse-1] : self.tmpl; + context = extendCtx(context, self.ctx); + props = tagCtx.props; + if ( props.link === FALSE ) { + // link=false setting on block tag + // We will override inherited value of link by the explicit setting link=false taken from props + // The child views of an unlinked view are also unlinked. So setting child back to true will not have any effect. + context = context || {}; + context.link = FALSE; + } + parentView = parentView || tagCtx.view; + } else { + tmpl = self.jquery && (self[0] || error('Unknown template: "' + self.selector + '"')) // This is a call from $(selector).render + || self; + } + if (tmpl) { + if (parentView) { + onRender = onRender || parentView._.onRender; + parentContext = parentView.ctx; + if (data === parentView) { + // Inherit the data from the parent view. + // This may be the contents of an {{if}} block + // Set isLayout = true so we don't iterate the if block if the data is an array. + data = parentView.data; + isLayout = TRUE; + } + } + + // Set additional context on views created here, (as modified context inherited from the parent, and to be inherited by child views) + // Note: If no jQuery, $extend does not support chained copies - so limit extend() to two parameters + context = extendCtx(context, parentContext); + + if (!tmpl.fn) { + tmpl = $templates[tmpl] || $templates(tmpl); + } + + if (tmpl) { + onRender = (context && context.link) !== FALSE && allowDataLink && onRender; + // If link===false, do not call onRender, so no data-linking marker nodes + outerOnRender = onRender; + if (onRender === TRUE) { + // Used by view.refresh(). Don't create a new wrapper view. + outerOnRender = undefined; + onRender = parentView._.onRender; + } + if ($.isArray(data) && !isLayout) { + // Create a view for the array, whose child views correspond to each data item. (Note: if key and parentView are passed in + // along with parent view, treat as insert -e.g. from view.addViews - so parentView is already the view item for array) + newView = swapContent ? parentView : (key !== undefined && parentView) || View(context, "array", parentView, data, tmpl, key, onRender); + for (i = 0, l = data.length; i < l; i++) { + // Create a view for each data item. + dataItem = data[i]; + childView = View(context, "item", newView, dataItem, tmpl, (key || 0) + i, onRender); + itemResult = tmpl.fn(dataItem, childView, $views); + result += newView._.onRender ? newView._.onRender(itemResult, childView) : itemResult; + } + } else { + // Create a view for singleton data object. The type of the view will be the tag name, e.g. "if" or "myTag" except for + // "item", "array" and "data" views. A "data" view is from programatic render(object) against a 'singleton'. + newView = swapContent ? parentView : View(context, self.tagName||"data", parentView, data, tmpl, key, onRender); + result += tmpl.fn(data, newView, $views); + } + return outerOnRender ? outerOnRender(result, newView) : result; + } + } + return ""; + } + + //=========================== + // Build and compile template + //=========================== + + // Generate a reusable function that will serve to render a template against data + // (Compile AST then build template function) + + function error(message) { + if ($viewsSettings.debugMode) { + throw new $views.sub.Error(message); + } + } + + function syntaxError(message) { + error("Syntax error\n" + message); + } + + function tmplFn(markup, tmpl, isLinkExpression) { + // Compile markup to AST (abtract syntax tree) then build the template function code from the AST nodes + // Used for compiling templates, and also by JsViews to build functions for data link expressions + + + //==== nested functions ==== + function pushprecedingContent(shift) { + shift -= loc; + if (shift) { + content.push(markup.substr(loc, shift).replace(rNewLine, "\\n")); + } + } + + function blockTagCheck(tagName) { + tagName && syntaxError('Unmatched or missing tag: "{{/' + tagName + '}}" in template:\n' + markup); + } + + function parseTag(all, bind, tagName, converter, colon, html, comment, codeTag, params, slash, closeBlock, index) { + + // bind tag converter colon html comment code params slash closeBlock + // /{(\^)?{(?:(?:(\w+(?=[\/\s}]))|(?:(\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\*)))\s*((?:[^}]|}(?!}))*?)(\/)?|(?:\/(\w+)))}}/g + // Build abstract syntax tree (AST): [ tagName, converter, params, content, hash, bindings, contentMarkup ] + if (html) { + colon = ":"; + converter = "html"; + } + var noError, current0, + pathBindings = [], + code = "", + hash = "", + passedCtx = "", + // Block tag if not self-closing and not {{:}} or {{>}} (special case) and not a data-link expression + block = !slash && !colon && !comment && !isLinkExpression; + + //==== nested helper function ==== + tagName = tagName || colon; + pushprecedingContent(index); + loc = index + all.length; // location marker - parsed up to here + if (codeTag) { + if (allowCode) { + content.push(["*", "\n" + params.replace(rUnescapeQuotes, "$1") + "\n"]); + } + } else if (tagName) { + if (tagName === "else") { + if (rTestElseIf.test(params)) { + syntaxError('for "{{else if expr}}" use "{{else expr}}"'); + } + current[7] = markup.substring(current[7], index); // contentMarkup for block tag + current = stack.pop(); + content = current[3]; + block = TRUE; + } + if (params) { + params = params.replace(/\s*\n\s*/g, " "); // remove newlines from the params string, to avoid compiled code errors for unterminated strings + code = parseParams(params, pathBindings) + .replace(rBuildHash, function(all, isCtx, keyValue) { + if (isCtx) { + passedCtx += keyValue + ","; + } else { + hash += keyValue + ","; + } + return ""; + }); + } + hash = hash.slice(0, -1); + code = code.slice(0, -1); + noError = hash && (hash.indexOf("noerror:true") + 1) && hash || ""; + + newNode = [ + tagName, + converter || "", + code, + block && [], + "{" + (hash ? ("props:" + (noError ? "hsh": "{" + hash + "}") + + ",") : "") + 'params:"' + params + '"' + (passedCtx ? ",ctx:{" + passedCtx.slice(0, -1) + "}" : "") + "},", + noError, + //"{" + (hash ? ("props:{" + hash + "},") : "") + 'params:"' + params + '"' + (passedCtx ? ",ctx:{" + passedCtx.slice(0, -1) + "}" : "") + "},", + bind && pathBindings || 0, + ]; + content.push(newNode); + if (block) { + stack.push(current); + current = newNode; + current[7] = loc; // Store current location of open tag, to be able to add contentMarkup when we reach closing tag + } + } else if (closeBlock) { + current0 = current[0]; + blockTagCheck(closeBlock !== current0 && current0 && current0 !== "else"); + current[7] = markup.substring(current[7], index); // contentMarkup for block tag + current = stack.pop(); + } + blockTagCheck(!current && closeBlock); + content = current[3]; + } + //==== /end of nested functions ==== + + var newNode, + allowCode = tmpl && tmpl.allowCode, + astTop = [], + loc = 0, + stack = [], + content = astTop, + current = [, , , astTop]; + + markup = markup.replace(rEscapeQuotes, "\\$1"); + +//TODO result = tmplFnsCache[markup]; // Only cache if template is not named and markup length < ..., and there are no bindings or subtemplates?? Consider standard optimization for data-link="a.b.c" +// if (result) { +// tmpl.fn = result; +// } else { + +// result = markup; + + blockTagCheck(stack[0] && stack[0][3].pop()[0]); + + // Build the AST (abstract syntax tree) under astTop + markup.replace(rTag, parseTag); + + pushprecedingContent(markup.length); + + if (loc = astTop[astTop.length-1]) { + blockTagCheck("" + loc !== loc && (+loc[7] === loc[7]) && loc[0]); + } +// result = tmplFnsCache[markup] = buildCode(astTop, tmpl); +// } + return buildCode(astTop, tmpl); + } + + function buildCode(ast, tmpl) { + // Build the template function code from the AST nodes, and set as property on the passed-in template object + // Used for compiling templates, and also by JsViews to build functions for data link expressions + var ret, i, node, hasTag, noError, hasEncoder, getsValue, hasConverter, hasViewPath, tagName, converter, params, hash, bindings, bindingPaths, nestedTmpls, nestedTmpl, allowCode, content, markup, + code = "", + tmplOptions = {}, + l = ast.length; + + if (tmpl) { + if (allowCode = tmpl.allowCode) { + tmplOptions.allowCode = TRUE; + } + if (tmpl.debug) { + tmplOptions.debug = TRUE; + } + bindings = tmpl.bnds; + nestedTmpls = tmpl.tmpls; + } + + for (i = 0; i < l; i++) { + // AST nodes: [ tagName, converter, params, content, hash, bindings, contentMarkup, link ] + node = ast[i]; + + // Add newline for each callout to t() c() etc. and each markup string + ret = ""; + if ("" + node === node) { + // a markup string to be inserted + ret = 'ret+="' + node + '";'; + } else { + // a compiled tag expression to be inserted + tagName = node[0]; + if (tagName === "*") { + // Code tag: {{* }} + ret = "" + node[1]; + } else { + converter = node[1]; + params = node[2]; + content = node[3]; + hash = node[4]; + noError = node[5]; + bindingPaths = node[6]; + markup = node[7]; + + if (content) { + // Create template object for nested template + nestedTmpl = TmplObject(markup, tmplOptions); + // Compile to AST and then to compiled function + buildCode(content, nestedTmpl); + nestedTmpls.push(nestedTmpl); + } + if (bindingPaths) { + // Add leaf binding paths to template + bindings.push(bindingPaths); + bindingPaths = bindings.length; + } + hasViewPath = hasViewPath || hash.indexOf("view") > -1; + // Add newline for each callout to t() c() etc. + + //TODO consider passing in ret to c() and t() so they can look at the previous ret, and detect whether this is a jsrender tag _within_an_HTML_element_tag_ + // and if so, don't insert marker nodes, add data-link attributes to the HTML element markup... No need for people to set link=false. + + if (noError) { + // If the tag includes noerror=true, we will do a try catch around expressions for named or unnamed parameters + // passed to the tag, and return the empty string for each expression if it throws during evaluation + // TODO perhaps support noerror=xxx and return the value of the expression xxx||'', rather than always the empty string + noError = "try{prm=" + params + ";hsh={" + noError + '};}catch(e){prm="";hsh={};}\n'; + params = "prm"; + } + + ret += noError + "ret+=" + (tagName === ":" + ? (converter === "html" && !bindingPaths + ? (hasEncoder = TRUE, "h(" + params+ ");") + : converter || bindingPaths // Call _cnvt if there is a converter, or binding: {{cnvt: ... }}, {^{: ... }} or {^{cnvt: ... }} + ? (hasConverter = TRUE, 'c("' + converter + '",view,this,' + hash + bindingPaths + "," + params + ");") + : (getsValue = TRUE, "(v=" + params + ')!=u?v:"";') + ) + : (hasTag = TRUE, 't("' + tagName + '",view,this,' + + (content ? nestedTmpls.length : '""') // For block tags, pass in the key (nestedTmpls.length) to the nested content template + + "," + hash + bindingPaths + (params ? "," : "") + params) + ");"); + } + } + code += "\n" + ret; + } + + // Include only the var references that are needed in the code + code = fnDeclStr + + (noError? "prm,hsh," : "") + + (getsValue ? "v," : "") + + (hasTag ? "t=j._tag," : "") + + (hasConverter ? "c=j._cnvt," : "") + + (hasEncoder ? "h=j.converters.html," : "") + + 'ret="";\n' + + ($viewsSettings.tryCatch ? "try{\n" : "") + + (tmplOptions.debug ? "debugger;" : "") + + code + "\nreturn ret;\n" + + ($viewsSettings.tryCatch ? "\n}catch(e){return j._err(e);}" : ""); + + try { + code = new Function("data, view, j, u", code); + } catch (e) { + syntaxError("Compiled template code:\n\n" + code, e); + } + + if (tmpl) { + tmpl.fn = code; + } + return code; + } + + function parseParams(params, bindings) { + + function parseTokens(all, lftPrn0, lftPrn, path, operator, err, eq, path2, prn, comma, lftPrn2, apos, quot, rtPrn, prn2, space) { + // rParams = /(\()(?=|\s*\()|(?:([([])\s*)?(?:([#~]?[\w$^.]+)?\s*((\+\+|--)|\+|-|&&|\|\||===|!==|==|!=|<=|>=|[<>%*!:?\/]|(=))\s*|([#~]?[\w$^.]+)([([])?)|(,\s*)|(\(?)\\?(?:(')|("))|(?:\s*([)\]])([([]?))|(\s+) + // lftPrn0-flwed by (- lftPrn path operator err eq path2 prn comma lftPrn3 apos quot rtPrn prn2 space + // (left paren? followed by (path? followed by operator) or (path followed by paren?)) or comma or apos or quot or right paren or space + operator = operator || ""; + lftPrn = lftPrn || lftPrn0 || lftPrn2; + path = path || path2; + prn = prn || prn2 || ""; + + function parsePath(all, object, helper, view, viewProperty, pathTokens, leafToken) { + // rPath = /^(?:null|true|false|\d[\d.]*|([\w$]+|~([\w$]+)|#(view|([\w$]+))?)([\w$.^]*?)(?:[.[^]([\w$]+)\]?)?)$/g, + // object helper view viewProperty pathTokens leafToken + + if (object) { + bindings.push(path); + if (object !== ".") { + var leaf, + ret = (helper + ? 'view._hlp("' + helper + '")' + : view + ? "view" + : "data") + + (leafToken + ? (viewProperty + ? "." + viewProperty + : helper + ? "" + : (view ? "" : "." + object) + ) + (pathTokens || "") + : (leafToken = helper ? "" : view ? viewProperty || "" : object, "")); + + leaf = (leafToken ? "." + leafToken : ""); + ret = ret + leaf; + ret = ret.slice(0, 9) === "view.data" + ? ret.slice(5) // convert #view.data... to data... + : ret; + return ret; + } + } + return all; + } + + if (err) { + syntaxError(params); + } else { + return (aposed + // within single-quoted string + ? (aposed = !apos, (aposed ? all : '"')) + : quoted + // within double-quoted string + ? (quoted = !quot, (quoted ? all : '"')) + : + ( + (lftPrn + ? (parenDepth++, lftPrn) + : "") + + (space + ? (parenDepth + ? "" + : named + ? (named = FALSE, "\b") + : "," + ) + : eq + // named param + // Insert backspace \b (\x08) as separator for named params, used subsequently by rBuildHash + ? (parenDepth && syntaxError(params), named = TRUE, '\b' + path + ':') + : path + // path + ? (path.split("^").join(".").replace(rPath, parsePath) + + (prn + ? (fnCall[++parenDepth] = TRUE, prn) + : operator) + ) + : operator + ? operator + : rtPrn + // function + ? ((fnCall[parenDepth--] = FALSE, rtPrn) + + (prn + ? (fnCall[++parenDepth] = TRUE, prn) + : "") + ) + : comma + ? (fnCall[parenDepth] || syntaxError(params), ",") // We don't allow top-level literal arrays or objects + : lftPrn0 + ? "" + : (aposed = apos, quoted = quot, '"') + )) + ); + } + } + var named, + fnCall = {}, + parenDepth = 0, + quoted = FALSE, // boolean for string content in double quotes + aposed = FALSE; // or in single quotes + + bindings.expr = params.replace(rUnescapeQuotes, "$1"); + return (params + " ").replace(rParams, parseTokens); + } + + //========== + // Utilities + //========== + + // HTML encoding helper + function replacerForHtml(ch) { + // Original code from Mike Samuel + return escapeMapForHtml[ch] + // Intentional assignment that caches the result of encoding ch. + || (escapeMapForHtml[ch] = "&#" + ch.charCodeAt(0) + ";"); + } + + // Merge objects, in particular contexts which inherit from parent contexts + function extendCtx(context, parentContext) { + // Return copy of parentContext, unless context is defined and is different, in which case return a new merged context + // If neither context nor parentContext are undefined, return undefined + return context && context !== parentContext + ? (parentContext + ? $extend($extend({}, parentContext), context) + : context) + : parentContext && $extend({}, parentContext); + } + + //========================== Initialize ========================== + + for (jsvStoreName in jsvStores) { + registerStore(jsvStoreName, jsvStores[jsvStoreName]); + } + + var $templates = $views.templates, + $converters = $views.converters, + $helpers = $views.helpers, + $tags = $views.tags, + $viewsSub = $views.sub, + $viewsSettings = $views.settings; + + if (jQuery) { + //////////////////////////////////////////////////////////////////////////////////////////////// + // jQuery is loaded, so make $ the jQuery object + $ = jQuery; + $.render = $render; + $.views = $views; + $.templates = $templates = $views.templates; + $.fn.render = renderContent; + + } else { + //////////////////////////////////////////////////////////////////////////////////////////////// + // jQuery is not loaded. + + $ = global.jsviews = $views; + + $.isArray = Array && Array.isArray || function(obj) { + return Object.prototype.toString.call(obj) === "[object Array]"; + }; + } + + //========================== Register tags ========================== + + $tags({ + "if": function(val) { + var self = this; + // If not done and val is truey, set done=true on tag instance and render content. Otherwise return "" + // On else will call this function again on the same tag instance. + return (self._done || arguments.length && !val) + ? "" + : (self._done = true, + // Test is satisfied, so render content on current context. Rather than return undefined + // (which will render the tmpl/content on the current context but will iterate if it is an array), + // we pass in the view. This ensures treating as a layout template - with no iteration + self.renderContent(self.tagCtx.view)); + }, +// Temporary fix for binding to {{if}} +// "if": { +// render: function(val) { +// var self = this; +// return (self._done || arguments.length && !val) ? "" : (self._done = true, self.renderContent(self.tagCtx.view)); +// } +// }, + "else": function() {}, // Does nothing but ensures {{else}} tags are recognized as valid + "for": function() { + var i, arg, undef, + self = this, + tagCtx = self.tagCtx, + result = "", + args = arguments, + done = 0, + l = args.length; + + if (!l) { + return tagCtx.done + ? "" + : (tagCtx.done = TRUE, + // Test is satisfied, so render content on current context. Rather than return undefined + // (which will render the tmpl/content on the current context but will iterate if it is an array), + // we pass in the view. This ensures treating as a layout template - with no iteration + self.renderContent(tagCtx.view)); + } + for (i = 0; i < l; i++) { + arg = args[i]; + undef = arg === undefined; + if (!undef) { + done += $.isArray(arg) ? arg.length : 1; + result += self.renderContent(arg); + } else { + return ""; + } + } + tagCtx.done = done; + return result; + }, + "*": function(value) { + return value; + } + }); + + //========================== Register global helpers ========================== + + // $helpers({ // Global helper functions + // // TODO add any useful built-in helper functions + // }); + + //========================== Register converters ========================== + + $converters({ + html: function(text) { + // HTML encoding helper: Replace < > & and ' and " by corresponding entities. + return text != undefined ? String(text).replace(htmlEncodeChars, replacerForHtml) : ""; + }, + attr: function(text) { + // Attribute encoding helper: Replace < & ' and " by corresponding entities. + return text != undefined ? String(text).replace(attrEncodeChars, replacerForHtml) : ""; + }, + url: function(text) { + // TODO - support chaining {{attr|url:....}} to protect against injection attacks from url parameters containing " or '. + // URL encoding helper. + return text != undefined ? encodeURI(String(text)) : ""; + } + }); + + //========================== Define default delimiters ========================== + $viewsDelimiters(); + +})(this, this.jQuery); diff --git a/html/js/moment.js b/html/js/moment.js new file mode 100644 index 0000000..c635ec0 --- /dev/null +++ b/html/js/moment.js @@ -0,0 +1,3043 @@ +//! moment.js +//! version : 2.9.0 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +(function (undefined) { + /************************************ + Constants + ************************************/ + + var moment, + VERSION = '2.9.0', + // the global-scope this is NOT the global object in Node.js + globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this, + oldGlobalMoment, + round = Math.round, + hasOwnProperty = Object.prototype.hasOwnProperty, + i, + + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + + // internal storage for locale config files + locales = {}, + + // extra moment internal properties (plugins register props here) + momentProperties = [], + + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module && module.exports), + + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, + + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 + parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], + ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], + ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], + ['GGGG-[W]WW', /\d{4}-W\d{2}/], + ['YYYY-DDD', /\d{4}-\d{3}/] + ], + + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], + + // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30'] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, + + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + Q : 'quarter', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, + + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, + + // format function strings + formatFunctions = {}, + + // default relative time thresholds + relativeTimeThresholds = { + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month + M: 11 // months to year + }, + + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.localeData().monthsShort(this, format); + }, + MMMM : function (format) { + return this.localeData().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.localeData().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.localeData().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.localeData().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return leftZeroFill(this.weekYear(), 4); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return leftZeroFill(this.isoWeekYear(), 4); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + x : function () { + return this.valueOf(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, + + deprecations = {}, + + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], + + updateInProgress = false; + + // Pick the first defined of two or three arguments. dfl comes from + // default. + function dfl(a, b, c) { + switch (arguments.length) { + case 2: return a != null ? a : b; + case 3: return a != null ? a : b != null ? b : c; + default: throw new Error('Implement me'); + } + } + + function hasOwnProp(a, b) { + return hasOwnProperty.call(a, b); + } + + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn('Deprecation warning: ' + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + return extend(function () { + if (firstTime) { + printMsg(msg); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; + } + } + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.localeData().ordinal(func.call(this, a), period); + }; + } + + function monthDiff(a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + return -(wholeMonthDiff + adjust); + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + + + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // thie is not supposed to happen + return hour; + } + } + + /************************************ + Constructors + ************************************/ + + function Locale() { + } + + // Moment prototype object + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); + } + copyConfig(this, config); + this._d = new Date(+config._d); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + moment.updateOffset(this); + updateInProgress = false; + } + } + + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; + + this._data = {}; + + this._locale = moment.localeData(); + + this._bubble(); + } + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } + + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; + } + + function copyConfig(to, from) { + var i, prop, val; + + if (typeof from._isAMomentObject !== 'undefined') { + to._isAMomentObject = from._isAMomentObject; + } + if (typeof from._i !== 'undefined') { + to._i = from._i; + } + if (typeof from._f !== 'undefined') { + to._f = from._f; + } + if (typeof from._l !== 'undefined') { + to._l = from._l; + } + if (typeof from._strict !== 'undefined') { + to._strict = from._strict; + } + if (typeof from._tzm !== 'undefined') { + to._tzm = from._tzm; + } + if (typeof from._isUTC !== 'undefined') { + to._isUTC = from._isUTC; + } + if (typeof from._offset !== 'undefined') { + to._offset = from._offset; + } + if (typeof from._pf !== 'undefined') { + to._pf = from._pf; + } + if (typeof from._locale !== 'undefined') { + to._locale = from._locale; + } + + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } + } + } + + return to; + } + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; + + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } + + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; + + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + + return res; + } + + function momentsDifference(base, other) { + var res; + other = makeAs(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); + tmp = val; val = period; period = tmp; + } + + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; + } + + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + updateOffset = updateOffset == null ? true : updateOffset; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); + } + if (months) { + rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + moment.updateOffset(mom, days || months); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function makeList(field) { + var count, setter; + + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } + + moment[field] = function (format, index) { + var i, getter, + method = moment._locale[field], + results = []; + + if (typeof format === 'number') { + index = format; + format = undefined; + } + + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment._locale, m, format || ''); + }; + + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } + + return value; + } + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + function weeksInYear(year, dow, doy) { + return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; + } + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 24 || + (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || + m._a[SECOND] !== 0 || + m._a[MILLISECOND] !== 0)) ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + + m._pf.overflow = overflow; + } + } + + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0 && + m._pf.bigHour === undefined; + } + } + return m._isValid; + } + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, j, next, locale, split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return null; + } + + function loadLocale(name) { + var oldLocale = null; + if (!locales[name] && hasModule) { + try { + oldLocale = moment.locale(); + require('./locale/' + name); + // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales + moment.locale(oldLocale); + } catch (e) { } + } + return locales[name]; + } + + // Return a moment from input, that is local/utc/utcOffset equivalent to + // model. + function makeAs(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (moment.isMoment(input) || isDate(input) ? + +input : +moment(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + moment.updateOffset(res, false); + return res; + } else { + return moment(input).local(); + } + } + + /************************************ + Locale + ************************************/ + + + extend(Locale.prototype, { + + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); + }, + + _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), + months : function (m) { + return this._months[m.month()]; + }, + + _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, + + monthsParse : function (monthName, format, strict) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = moment.utc([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, + + _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + + _longDateFormat : { + LTS : 'h:mm:ss A', + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY LT', + LLLL : 'dddd, MMMM D, YYYY LT' + }, + longDateFormat : function (key) { + var output = this._longDateFormat[key]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, + + + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom, now) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom, [now]) : output; + }, + + _relativeTime : { + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' + }, + + relativeTime : function (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (typeof output === 'function') ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + }, + + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, + + ordinal : function (number) { + return this._ordinal.replace('%d', number); + }, + _ordinal : '%d', + _ordinalParse : /\d{1,2}/, + + preparse : function (string) { + return string; + }, + + postformat : function (string) { + return string; + }, + + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, + + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, + + firstDayOfWeek : function () { + return this._week.dow; + }, + + firstDayOfYear : function () { + return this._week.doy; + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; + } + }); + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'Q': + return parseTokenOneDigit; + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { + return parseTokenOneDigit; + } + /* falls through */ + case 'SS': + if (strict) { + return parseTokenTwoDigits; + } + /* falls through */ + case 'SSS': + if (strict) { + return parseTokenThreeDigits; + } + /* falls through */ + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return config._locale._meridiemParse; + case 'x': + return parseTokenOffsetMs; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return parseTokenOneOrTwoDigits; + case 'Do': + return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); + return a; + } + } + + function utcOffsetFromString(string) { + string = string || ''; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? minutes : -minutes; + } + + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + + switch (token) { + // QUARTER + case 'Q': + if (input != null) { + datePartArray[MONTH] = (toInt(input) - 1) * 3; + } + break; + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + case 'Do' : + if (input != null) { + datePartArray[DATE] = toInt(parseInt( + input.match(/\d{1,2}/)[0], 10)); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } + + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = moment.parseTwoDigitYear(input); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._meridiem = input; + // config._isPm = config._locale.isPM(input); + break; + // HOUR + case 'h' : // fall through to hh + case 'hh' : + config._pf.bigHour = true; + /* falls through */ + case 'H' : // fall through to HH + case 'HH' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX OFFSET (MILLISECONDS) + case 'x': + config._d = new Date(toInt(input)); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = utcOffsetFromString(input); + break; + // WEEKDAY - human + case 'dd': + case 'ddd': + case 'dddd': + a = config._locale.weekdaysParse(input); + // if we didn't get a weekday name, mark the date as invalid + if (a != null) { + config._w = config._w || {}; + config._w['d'] = a; + } else { + config._pf.invalidWeekday = input; + } + break; + // WEEK, WEEK DAY - numeric + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gggg': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = toInt(input); + } + break; + case 'gg': + case 'GG': + config._w = config._w || {}; + config._w[token] = moment.parseTwoDigitYear(input); + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); + week = dfl(w.W, 1); + weekday = dfl(w.E, 1); + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); + week = dfl(w.w, 1); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < dow) { + ++week; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + } else { + // default to begining of week + weekday = dow; + } + } + temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); + + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } + } + + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day || normalizedInput.date, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); + } + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + if (config._f === moment.ISO_8601) { + parseISO(config); + return; + } + + config._a = []; + config._pf.empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if (config._pf.bigHour === true && config._a[HOUR] <= 12) { + config._pf.bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], + config._meridiem); + dateFromConfig(config); + checkOverflow(config); + } + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + // date from iso format + function parseISO(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); + + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be 'T' or undefined + config._f = isoDates[i][0] + (match[6] || ' '); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += 'Z'; + } + makeDateFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + // date from iso format or fallback + function makeDateFromString(config) { + parseISO(config); + if (config._isValid === false) { + delete config._isValid; + moment.createFromInputFallback(config); + } + } + + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } + + function makeDateFromInput(config) { + var input = config._i, matched; + if (input === undefined) { + config._d = new Date(); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + dateFromConfig(config); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + moment.createFromInputFallback(config); + } + } + + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } + + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } + + function parseWeekday(input, locale) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = locale.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; + } + + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime(posNegDuration, withoutSuffix, locale) { + var duration = moment.duration(posNegDuration).abs(), + seconds = round(duration.as('s')), + minutes = round(duration.as('m')), + hours = round(duration.as('h')), + days = round(duration.as('d')), + months = round(duration.as('M')), + years = round(duration.as('y')), + + args = seconds < relativeTimeThresholds.s && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < relativeTimeThresholds.m && ['mm', minutes] || + hours === 1 && ['h'] || + hours < relativeTimeThresholds.h && ['hh', hours] || + days === 1 && ['d'] || + days < relativeTimeThresholds.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || + years === 1 && ['y'] || ['yy', years]; + + args[2] = withoutSuffix; + args[3] = +posNegDuration > 0; + args[4] = locale; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; + + d = d === 0 ? 7 : d; + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f, + res; + + config._locale = config._locale || moment.localeData(config._l); + + if (input === null || (format === undefined && input === '')) { + return moment.invalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (moment.isMoment(input)) { + return new Moment(input, true); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } + + res = new Moment(config); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + moment = function (input, format, locale, strict) { + var c; + + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = locale; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); + + return makeMoment(c); + }; + + moment.suppressDeprecationWarnings = false; + + moment.createFromInputFallback = deprecate( + 'moment construction falls back to js Date. This is ' + + 'discouraged and will be removed in upcoming major ' + + 'release. Please refer to ' + + 'https://github.com/moment/moment/issues/1407 for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return moment(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + moment.min = function () { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + }; + + moment.max = function () { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + }; + + // creating with utc + moment.utc = function (input, format, locale, strict) { + var c; + + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); + + return makeMoment(c).utc(); + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso, + diffRes; + + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // constant that refers to the ISO standard + moment.ISO_8601 = function () {}; + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + moment.momentProperties = momentProperties; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // This function allows you to set a threshold for relative time strings + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; + }; + + moment.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + function (key, value) { + return moment.locale(key, value); + } + ); + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + moment.locale = function (key, values) { + var data; + if (key) { + if (typeof(values) !== 'undefined') { + data = moment.defineLocale(key, values); + } + else { + data = moment.localeData(key); + } + + if (data) { + moment.duration._locale = moment._locale = data; + } + } + + return moment._locale._abbr; + }; + + moment.defineLocale = function (name, values) { + if (values !== null) { + values.abbr = name; + if (!locales[name]) { + locales[name] = new Locale(); + } + locales[name].set(values); + + // backwards compat for now: also set the locale + moment.locale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + }; + + moment.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + function (key) { + return moment.localeData(key); + } + ); + + // returns locale data + moment.localeData = function (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return moment._locale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + }; + + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && hasOwnProp(obj, '_isAMomentObject')); + }; + + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; + + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } + + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } + + return m; + }; + + moment.parseZone = function () { + return moment.apply(null, arguments).parseZone(); + }; + + moment.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + moment.isDate = isDate; + + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d - ((this._offset || 0) * 60000); + }, + + unix : function () { + return Math.floor(+this / 1000); + }, + + toString : function () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + }, + + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + if ('function' === typeof Date.prototype.toISOString) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, + + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + + isValid : function () { + return isValid(this); + }, + + isDSTShifted : function () { + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } + + return false; + }, + + parsingFlags : function () { + return extend({}, this._pf); + }, + + invalidAt: function () { + return this._pf.overflow; + }, + + utc : function (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + }, + + local : function (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(this._dateUtcOffset(), 'm'); + } + } + return this; + }, + + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.localeData().postformat(output); + }, + + add : createAdder(1, 'add'), + + subtract : createAdder(-1, 'subtract'), + + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, + anchor, diff, output, daysAdjust; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + diff = this - that; + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, + + from : function (time, withoutSuffix) { + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + }, + + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + + calendar : function (time) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're locat/utc/offset + // or not. + var now = time || moment(), + sod = makeAs(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.localeData().calendar(format, this, moment(now))); + }, + + isLeapYear : function () { + return isLeapYear(this.year()); + }, + + isDST : function () { + return (this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset()); + }, + + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + }, + + month : makeAccessor('Month', true), + + startOf : function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } + + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } + + return this; + }, + + endOf: function (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + }, + + isAfter: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this > +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return inputMs < +this.clone().startOf(units); + } + }, + + isBefore: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this < +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return +this.clone().endOf(units) < inputMs; + } + }, + + isBetween: function (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + }, + + isSame: function (input, units) { + var inputMs; + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this === +input; + } else { + inputMs = +moment(input); + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + }, + + min: deprecate( + 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', + function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + } + ), + + max: deprecate( + 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', + function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + } + ), + + zone : deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. ' + + 'https://github.com/moment/moment/issues/1779', + function (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } + } + ), + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + utcOffset : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (input != null) { + if (typeof input === 'string') { + input = utcOffsetFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._dateUtcOffset(); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addOrSubtractDurationFromMoment(this, + moment.duration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + moment.updateOffset(this, true); + this._changeInProgress = null; + } + } + + return this; + } else { + return this._isUTC ? offset : this._dateUtcOffset(); + } + }, + + isLocal : function () { + return !this._isUTC; + }, + + isUtcOffset : function () { + return this._isUTC; + }, + + isUtc : function () { + return this._isUTC && this._offset === 0; + }, + + zoneAbbr : function () { + return this._isUTC ? 'UTC' : ''; + }, + + zoneName : function () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + }, + + parseZone : function () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(utcOffsetFromString(this._i)); + } + return this; + }, + + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).utcOffset(); + } + + return (this.utcOffset() - input) % 60 === 0; + }, + + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, + + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + }, + + quarter : function (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + }, + + weekYear : function (input) { + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); + }, + + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add((input - year), 'y'); + }, + + week : function (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + }, + + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + }, + + weekday : function (input) { + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + }, + + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, + + isoWeeksInYear : function () { + return weeksInYear(this.year(), 1, 4); + }, + + weeksInYear : function () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, + + set : function (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } + else { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + } + return this; + }, + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + locale : function (key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = moment.localeData(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + }, + + lang : deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ), + + localeData : function () { + return this._locale; + }, + + _dateUtcOffset : function () { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(this._d.getTimezoneOffset() / 15) * 15; + } + + }); + + function rawMonthSetter(mom, value) { + var dayOfMonth; + + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } + + dayOfMonth = Math.min(mom.date(), + daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function rawGetter(mom, unit) { + return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); + } + + function rawSetter(mom, unit, value) { + if (unit === 'Month') { + return rawMonthSetter(mom, value); + } else { + return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + + function makeAccessor(unit, keepTime) { + return function (value) { + if (value != null) { + rawSetter(this, unit, value); + moment.updateOffset(this, keepTime); + return this; + } else { + return rawGetter(this, unit); + } + }; + } + + moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); + moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); + moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); + // moment.fn.month is defined separately + moment.fn.date = makeAccessor('Date', true); + moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); + moment.fn.year = makeAccessor('FullYear', true); + moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); + + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + moment.fn.quarters = moment.fn.quarter; + + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; + + // alias isUtc for dev-friendliness + moment.fn.isUTC = moment.fn.isUtc; + + /************************************ + Duration Prototype + ************************************/ + + + function daysToYears (days) { + // 400 years have 146097 days (taking into account leap year rules) + return days * 400 / 146097; + } + + function yearsToDays (years) { + // years * 365 + absRound(years / 4) - + // absRound(years / 100) + absRound(years / 400); + return years * 146097 / 400; + } + + extend(moment.duration.fn = Duration.prototype, { + + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years = 0; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; + + hours = absRound(minutes / 60); + data.hours = hours % 24; + + days += absRound(hours / 24); + + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); + + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. + months += absRound(days / 30); + days %= 30; + + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + }, + + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); + + this._data.milliseconds = Math.abs(this._data.milliseconds); + this._data.seconds = Math.abs(this._data.seconds); + this._data.minutes = Math.abs(this._data.minutes); + this._data.hours = Math.abs(this._data.hours); + this._data.months = Math.abs(this._data.months); + this._data.years = Math.abs(this._data.years); + + return this; + }, + + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, + + humanize : function (withSuffix) { + var output = relativeTime(this, !withSuffix, this.localeData()); + + if (withSuffix) { + output = this.localeData().pastFuture(+this, output); + } + + return this.localeData().postformat(output); + }, + + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + this._bubble(); + + return this; + }, + + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + var days, months; + units = normalizeUnits(units); + + if (units === 'month' || units === 'year') { + days = this._days + this._milliseconds / 864e5; + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(yearsToDays(this._months / 12)); + switch (units) { + case 'week': return days / 7 + this._milliseconds / 6048e5; + case 'day': return days + this._milliseconds / 864e5; + case 'hour': return days * 24 + this._milliseconds / 36e5; + case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; + case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } + }, + + lang : moment.fn.lang, + locale : moment.fn.locale, + + toIsoString : deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead ' + + '(notice the capitals)', + function () { + return this.toISOString(); + } + ), + + toISOString : function () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + }, + + localeData : function () { + return this._locale; + }, + + toJSON : function () { + return this.toISOString(); + } + }); + + moment.duration.fn.toString = moment.duration.fn.toISOString; + + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } + + for (i in unitMillisecondFactors) { + if (hasOwnProp(unitMillisecondFactors, i)) { + makeDurationGetter(i.toLowerCase()); + } + } + + moment.duration.fn.asMilliseconds = function () { + return this.as('ms'); + }; + moment.duration.fn.asSeconds = function () { + return this.as('s'); + }; + moment.duration.fn.asMinutes = function () { + return this.as('m'); + }; + moment.duration.fn.asHours = function () { + return this.as('h'); + }; + moment.duration.fn.asDays = function () { + return this.as('d'); + }; + moment.duration.fn.asWeeks = function () { + return this.as('weeks'); + }; + moment.duration.fn.asMonths = function () { + return this.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); + }; + + /************************************ + Default Locale + ************************************/ + + + // Set default locale, other locale will inherit from English. + moment.locale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + /* EMBED_LOCALES */ + + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(shouldDeprecate) { + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + oldGlobalMoment = globalScope.moment; + if (shouldDeprecate) { + globalScope.moment = deprecate( + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', + moment); + } else { + globalScope.moment = moment; + } + } + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } else if (typeof define === 'function' && define.amd) { + define(function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal === true) { + // release the global variable + globalScope.moment = oldGlobalMoment; + } + + return moment; + }); + makeGlobal(true); + } else { + makeGlobal(); + } +}).call(this); diff --git a/html/js/moment.min.js b/html/js/moment.min.js new file mode 100644 index 0000000..024d488 --- /dev/null +++ b/html/js/moment.min.js @@ -0,0 +1,7 @@ +//! moment.js +//! version : 2.9.0 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +(function(a){function b(a,b,c){switch(arguments.length){case 2:return null!=a?a:b;case 3:return null!=a?a:null!=b?b:c;default:throw new Error("Implement me")}}function c(a,b){return Bb.call(a,b)}function d(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function e(a){vb.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+a)}function f(a,b){var c=!0;return o(function(){return c&&(e(a),c=!1),b.apply(this,arguments)},b)}function g(a,b){sc[a]||(e(b),sc[a]=!0)}function h(a,b){return function(c){return r(a.call(this,c),b)}}function i(a,b){return function(c){return this.localeData().ordinal(a.call(this,c),b)}}function j(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function k(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function l(){}function m(a,b){b!==!1&&H(a),p(this,a),this._d=new Date(+a._d),uc===!1&&(uc=!0,vb.updateOffset(this),uc=!1)}function n(a){var b=A(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+36e5*h,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=vb.localeData(),this._bubble()}function o(a,b){for(var d in b)c(b,d)&&(a[d]=b[d]);return c(b,"toString")&&(a.toString=b.toString),c(b,"valueOf")&&(a.valueOf=b.valueOf),a}function p(a,b){var c,d,e;if("undefined"!=typeof b._isAMomentObject&&(a._isAMomentObject=b._isAMomentObject),"undefined"!=typeof b._i&&(a._i=b._i),"undefined"!=typeof b._f&&(a._f=b._f),"undefined"!=typeof b._l&&(a._l=b._l),"undefined"!=typeof b._strict&&(a._strict=b._strict),"undefined"!=typeof b._tzm&&(a._tzm=b._tzm),"undefined"!=typeof b._isUTC&&(a._isUTC=b._isUTC),"undefined"!=typeof b._offset&&(a._offset=b._offset),"undefined"!=typeof b._pf&&(a._pf=b._pf),"undefined"!=typeof b._locale&&(a._locale=b._locale),Kb.length>0)for(c in Kb)d=Kb[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function q(a){return 0>a?Math.ceil(a):Math.floor(a)}function r(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthd;d++)(c&&a[d]!==b[d]||!c&&C(a[d])!==C(b[d]))&&g++;return g+f}function z(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=lc[a]||mc[b]||b}return a}function A(a){var b,d,e={};for(d in a)c(a,d)&&(b=z(d),b&&(e[b]=a[d]));return e}function B(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}vb[b]=function(e,f){var g,h,i=vb._locale[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=vb().utc().set(d,a);return i.call(vb._locale,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function C(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function D(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function E(a,b,c){return jb(vb([a,11,31+b-c]),b,c).week}function F(a){return G(a)?366:365}function G(a){return a%4===0&&a%100!==0||a%400===0}function H(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[Db]<0||a._a[Db]>11?Db:a._a[Eb]<1||a._a[Eb]>D(a._a[Cb],a._a[Db])?Eb:a._a[Fb]<0||a._a[Fb]>24||24===a._a[Fb]&&(0!==a._a[Gb]||0!==a._a[Hb]||0!==a._a[Ib])?Fb:a._a[Gb]<0||a._a[Gb]>59?Gb:a._a[Hb]<0||a._a[Hb]>59?Hb:a._a[Ib]<0||a._a[Ib]>999?Ib:-1,a._pf._overflowDayOfYear&&(Cb>b||b>Eb)&&(b=Eb),a._pf.overflow=b)}function I(b){return null==b._isValid&&(b._isValid=!isNaN(b._d.getTime())&&b._pf.overflow<0&&!b._pf.empty&&!b._pf.invalidMonth&&!b._pf.nullInput&&!b._pf.invalidFormat&&!b._pf.userInvalidated,b._strict&&(b._isValid=b._isValid&&0===b._pf.charsLeftOver&&0===b._pf.unusedTokens.length&&b._pf.bigHour===a)),b._isValid}function J(a){return a?a.toLowerCase().replace("_","-"):a}function K(a){for(var b,c,d,e,f=0;f0;){if(d=L(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&y(e,c,!0)>=b-1)break;b--}f++}return null}function L(a){var b=null;if(!Jb[a]&&Lb)try{b=vb.locale(),require("./locale/"+a),vb.locale(b)}catch(c){}return Jb[a]}function M(a,b){var c,d;return b._isUTC?(c=b.clone(),d=(vb.isMoment(a)||x(a)?+a:+vb(a))-+c,c._d.setTime(+c._d+d),vb.updateOffset(c,!1),c):vb(a).local()}function N(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function O(a){var b,c,d=a.match(Pb);for(b=0,c=d.length;c>b;b++)d[b]=rc[d[b]]?rc[d[b]]:N(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function P(a,b){return a.isValid()?(b=Q(b,a.localeData()),nc[b]||(nc[b]=O(b)),nc[b](a)):a.localeData().invalidDate()}function Q(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Qb.lastIndex=0;d>=0&&Qb.test(a);)a=a.replace(Qb,c),Qb.lastIndex=0,d-=1;return a}function R(a,b){var c,d=b._strict;switch(a){case"Q":return _b;case"DDDD":return bc;case"YYYY":case"GGGG":case"gggg":return d?cc:Tb;case"Y":case"G":case"g":return ec;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?dc:Ub;case"S":if(d)return _b;case"SS":if(d)return ac;case"SSS":if(d)return bc;case"DDD":return Sb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Wb;case"a":case"A":return b._locale._meridiemParse;case"x":return Zb;case"X":return $b;case"Z":case"ZZ":return Xb;case"T":return Yb;case"SSSS":return Vb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?ac:Rb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Rb;case"Do":return d?b._locale._ordinalParse:b._locale._ordinalParseLenient;default:return c=new RegExp($(Z(a.replace("\\","")),"i"))}}function S(a){a=a||"";var b=a.match(Xb)||[],c=b[b.length-1]||[],d=(c+"").match(jc)||["-",0,0],e=+(60*d[1])+C(d[2]);return"+"===d[0]?e:-e}function T(a,b,c){var d,e=c._a;switch(a){case"Q":null!=b&&(e[Db]=3*(C(b)-1));break;case"M":case"MM":null!=b&&(e[Db]=C(b)-1);break;case"MMM":case"MMMM":d=c._locale.monthsParse(b,a,c._strict),null!=d?e[Db]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[Eb]=C(b));break;case"Do":null!=b&&(e[Eb]=C(parseInt(b.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=C(b));break;case"YY":e[Cb]=vb.parseTwoDigitYear(b);break;case"YYYY":case"YYYYY":case"YYYYYY":e[Cb]=C(b);break;case"a":case"A":c._meridiem=b;break;case"h":case"hh":c._pf.bigHour=!0;case"H":case"HH":e[Fb]=C(b);break;case"m":case"mm":e[Gb]=C(b);break;case"s":case"ss":e[Hb]=C(b);break;case"S":case"SS":case"SSS":case"SSSS":e[Ib]=C(1e3*("0."+b));break;case"x":c._d=new Date(C(b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=S(b);break;case"dd":case"ddd":case"dddd":d=c._locale.weekdaysParse(b),null!=d?(c._w=c._w||{},c._w.d=d):c._pf.invalidWeekday=b;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":a=a.substr(0,1);case"gggg":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=C(b));break;case"gg":case"GG":c._w=c._w||{},c._w[a]=vb.parseTwoDigitYear(b)}}function U(a){var c,d,e,f,g,h,i;c=a._w,null!=c.GG||null!=c.W||null!=c.E?(g=1,h=4,d=b(c.GG,a._a[Cb],jb(vb(),1,4).year),e=b(c.W,1),f=b(c.E,1)):(g=a._locale._week.dow,h=a._locale._week.doy,d=b(c.gg,a._a[Cb],jb(vb(),g,h).year),e=b(c.w,1),null!=c.d?(f=c.d,g>f&&++e):f=null!=c.e?c.e+g:g),i=kb(d,e,f,h,g),a._a[Cb]=i.year,a._dayOfYear=i.dayOfYear}function V(a){var c,d,e,f,g=[];if(!a._d){for(e=X(a),a._w&&null==a._a[Eb]&&null==a._a[Db]&&U(a),a._dayOfYear&&(f=b(a._a[Cb],e[Cb]),a._dayOfYear>F(f)&&(a._pf._overflowDayOfYear=!0),d=fb(f,0,a._dayOfYear),a._a[Db]=d.getUTCMonth(),a._a[Eb]=d.getUTCDate()),c=0;3>c&&null==a._a[c];++c)a._a[c]=g[c]=e[c];for(;7>c;c++)a._a[c]=g[c]=null==a._a[c]?2===c?1:0:a._a[c];24===a._a[Fb]&&0===a._a[Gb]&&0===a._a[Hb]&&0===a._a[Ib]&&(a._nextDay=!0,a._a[Fb]=0),a._d=(a._useUTC?fb:eb).apply(null,g),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[Fb]=24)}}function W(a){var b;a._d||(b=A(a._i),a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],V(a))}function X(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function Y(b){if(b._f===vb.ISO_8601)return void ab(b);b._a=[],b._pf.empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Q(b._f,b._locale).match(Pb)||[],c=0;c0&&b._pf.unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),rc[f]?(d?b._pf.empty=!1:b._pf.unusedTokens.push(f),T(f,d,b)):b._strict&&!d&&b._pf.unusedTokens.push(f);b._pf.charsLeftOver=i-j,h.length>0&&b._pf.unusedInput.push(h),b._pf.bigHour===!0&&b._a[Fb]<=12&&(b._pf.bigHour=a),b._a[Fb]=k(b._locale,b._a[Fb],b._meridiem),V(b),H(b)}function Z(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function $(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function _(a){var b,c,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;fg)&&(e=g,c=b));o(a,c||b)}function ab(a){var b,c,d=a._i,e=fc.exec(d);if(e){for(a._pf.iso=!0,b=0,c=hc.length;c>b;b++)if(hc[b][1].exec(d)){a._f=hc[b][0]+(e[6]||" ");break}for(b=0,c=ic.length;c>b;b++)if(ic[b][1].exec(d)){a._f+=ic[b][0];break}d.match(Xb)&&(a._f+="Z"),Y(a)}else a._isValid=!1}function bb(a){ab(a),a._isValid===!1&&(delete a._isValid,vb.createFromInputFallback(a))}function cb(a,b){var c,d=[];for(c=0;ca&&h.setFullYear(a),h}function fb(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function gb(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function hb(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function ib(a,b,c){var d=vb.duration(a).abs(),e=Ab(d.as("s")),f=Ab(d.as("m")),g=Ab(d.as("h")),h=Ab(d.as("d")),i=Ab(d.as("M")),j=Ab(d.as("y")),k=e0,k[4]=c,hb.apply({},k)}function jb(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=vb(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function kb(a,b,c,d,e){var f,g,h=fb(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:F(a-1)+g}}function lb(b){var c,d=b._i,e=b._f;return b._locale=b._locale||vb.localeData(b._l),null===d||e===a&&""===d?vb.invalid({nullInput:!0}):("string"==typeof d&&(b._i=d=b._locale.preparse(d)),vb.isMoment(d)?new m(d,!0):(e?w(e)?_(b):Y(b):db(b),c=new m(b),c._nextDay&&(c.add(1,"d"),c._nextDay=a),c))}function mb(a,b){var c,d;if(1===b.length&&w(b[0])&&(b=b[0]),!b.length)return vb();for(c=b[0],d=1;d=0?"+":"-";return b+r(Math.abs(a),6)},gg:function(){return r(this.weekYear()%100,2)},gggg:function(){return r(this.weekYear(),4)},ggggg:function(){return r(this.weekYear(),5)},GG:function(){return r(this.isoWeekYear()%100,2)},GGGG:function(){return r(this.isoWeekYear(),4)},GGGGG:function(){return r(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return C(this.milliseconds()/100)},SS:function(){return r(C(this.milliseconds()/10),2)},SSS:function(){return r(this.milliseconds(),3)},SSSS:function(){return r(this.milliseconds(),3)},Z:function(){var a=this.utcOffset(),b="+";return 0>a&&(a=-a,b="-"),b+r(C(a/60),2)+":"+r(C(a)%60,2)},ZZ:function(){var a=this.utcOffset(),b="+";return 0>a&&(a=-a,b="-"),b+r(C(a/60),2)+r(C(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},sc={},tc=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"],uc=!1;pc.length;)xb=pc.pop(),rc[xb+"o"]=i(rc[xb],xb);for(;qc.length;)xb=qc.pop(),rc[xb+xb]=h(rc[xb],2);rc.DDDD=h(rc.DDD,3),o(l.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a,b,c){var d,e,f;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;12>d;d++){if(e=vb.utc([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=vb([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},longDateFormat:function(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.apply(b,[c]):d},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(a){return a},postformat:function(a){return a},week:function(a){return jb(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},firstDayOfWeek:function(){return this._week.dow},firstDayOfYear:function(){return this._week.doy},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),vb=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._i=b,g._f=c,g._l=e,g._strict=f,g._isUTC=!1,g._pf=d(),lb(g)},vb.suppressDeprecationWarnings=!1,vb.createFromInputFallback=f("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),vb.min=function(){var a=[].slice.call(arguments,0);return mb("isBefore",a)},vb.max=function(){var a=[].slice.call(arguments,0);return mb("isAfter",a)},vb.utc=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._useUTC=!0,g._isUTC=!0,g._l=e,g._i=b,g._f=c,g._strict=f,g._pf=d(),lb(g).utc()},vb.unix=function(a){return vb(1e3*a)},vb.duration=function(a,b){var d,e,f,g,h=a,i=null;return vb.isDuration(a)?h={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(h={},b?h[b]=a:h.milliseconds=a):(i=Nb.exec(a))?(d="-"===i[1]?-1:1,h={y:0,d:C(i[Eb])*d,h:C(i[Fb])*d,m:C(i[Gb])*d,s:C(i[Hb])*d,ms:C(i[Ib])*d}):(i=Ob.exec(a))?(d="-"===i[1]?-1:1,f=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*d},h={y:f(i[2]),M:f(i[3]),d:f(i[4]),h:f(i[5]),m:f(i[6]),s:f(i[7]),w:f(i[8])}):null==h?h={}:"object"==typeof h&&("from"in h||"to"in h)&&(g=t(vb(h.from),vb(h.to)),h={},h.ms=g.milliseconds,h.M=g.months),e=new n(h),vb.isDuration(a)&&c(a,"_locale")&&(e._locale=a._locale),e},vb.version=yb,vb.defaultFormat=gc,vb.ISO_8601=function(){},vb.momentProperties=Kb,vb.updateOffset=function(){},vb.relativeTimeThreshold=function(b,c){return oc[b]===a?!1:c===a?oc[b]:(oc[b]=c,!0)},vb.lang=f("moment.lang is deprecated. Use moment.locale instead.",function(a,b){return vb.locale(a,b)}),vb.locale=function(a,b){var c;return a&&(c="undefined"!=typeof b?vb.defineLocale(a,b):vb.localeData(a),c&&(vb.duration._locale=vb._locale=c)),vb._locale._abbr},vb.defineLocale=function(a,b){return null!==b?(b.abbr=a,Jb[a]||(Jb[a]=new l),Jb[a].set(b),vb.locale(a),Jb[a]):(delete Jb[a],null)},vb.langData=f("moment.langData is deprecated. Use moment.localeData instead.",function(a){return vb.localeData(a)}),vb.localeData=function(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return vb._locale;if(!w(a)){if(b=L(a))return b;a=[a]}return K(a)},vb.isMoment=function(a){return a instanceof m||null!=a&&c(a,"_isAMomentObject")},vb.isDuration=function(a){return a instanceof n};for(xb=tc.length-1;xb>=0;--xb)B(tc[xb]);vb.normalizeUnits=function(a){return z(a)},vb.invalid=function(a){var b=vb.utc(0/0);return null!=a?o(b._pf,a):b._pf.userInvalidated=!0,b},vb.parseZone=function(){return vb.apply(null,arguments).parseZone()},vb.parseTwoDigitYear=function(a){return C(a)+(C(a)>68?1900:2e3)},vb.isDate=x,o(vb.fn=m.prototype,{clone:function(){return vb(this)},valueOf:function(){return+this._d-6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=vb(this).utc();return 00:!1},parsingFlags:function(){return o({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(a){return this.utcOffset(0,a)},local:function(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(this._dateUtcOffset(),"m")),this},format:function(a){var b=P(this,a||vb.defaultFormat);return this.localeData().postformat(b)},add:u(1,"add"),subtract:u(-1,"subtract"),diff:function(a,b,c){var d,e,f=M(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=z(b),"year"===b||"month"===b||"quarter"===b?(e=j(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:q(e)},from:function(a,b){return vb.duration({to:this,from:a}).locale(this.locale()).humanize(!b)},fromNow:function(a){return this.from(vb(),a)},calendar:function(a){var b=a||vb(),c=M(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this,vb(b)))},isLeapYear:function(){return G(this.year())},isDST:function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},day:function(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=gb(a,this.localeData()),this.add(a-b,"d")):b},month:qb("Month",!0),startOf:function(a){switch(a=z(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a?this.weekday(0):"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this},endOf:function(b){return b=z(b),b===a||"millisecond"===b?this:this.startOf(b).add(1,"isoWeek"===b?"week":b).subtract(1,"ms")},isAfter:function(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=vb.isMoment(a)?a:vb(a),+this>+a):(c=vb.isMoment(a)?+a:+vb(a),c<+this.clone().startOf(b))},isBefore:function(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=vb.isMoment(a)?a:vb(a),+a>+this):(c=vb.isMoment(a)?+a:+vb(a),+this.clone().endOf(b)a?this:a}),max:f("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(a){return a=vb.apply(null,arguments),a>this?this:a}),zone:f("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",function(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}),utcOffset:function(a,b){var c,d=this._offset||0;return null!=a?("string"==typeof a&&(a=S(a)),Math.abs(a)<16&&(a=60*a),!this._isUTC&&b&&(c=this._dateUtcOffset()),this._offset=a,this._isUTC=!0,null!=c&&this.add(c,"m"),d!==a&&(!b||this._changeInProgress?v(this,vb.duration(a-d,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,vb.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?d:this._dateUtcOffset()},isLocal:function(){return!this._isUTC},isUtcOffset:function(){return this._isUTC},isUtc:function(){return this._isUTC&&0===this._offset},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(S(this._i)),this},hasAlignedHourOffset:function(a){return a=a?vb(a).utcOffset():0,(this.utcOffset()-a)%60===0},daysInMonth:function(){return D(this.year(),this.month())},dayOfYear:function(a){var b=Ab((vb(this).startOf("day")-vb(this).startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")},quarter:function(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)},weekYear:function(a){var b=jb(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")},isoWeekYear:function(a){var b=jb(this,1,4).year;return null==a?b:this.add(a-b,"y")},week:function(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")},isoWeek:function(a){var b=jb(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")},weekday:function(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},isoWeeksInYear:function(){return E(this.year(),1,4)},weeksInYear:function(){var a=this.localeData()._week;return E(this.year(),a.dow,a.doy)},get:function(a){return a=z(a),this[a]()},set:function(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else a=z(a),"function"==typeof this[a]&&this[a](b);return this},locale:function(b){var c;return b===a?this._locale._abbr:(c=vb.localeData(b),null!=c&&(this._locale=c),this)},lang:f("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(b){return b===a?this.localeData():this.locale(b)}),localeData:function(){return this._locale},_dateUtcOffset:function(){return 15*-Math.round(this._d.getTimezoneOffset()/15)}}),vb.fn.millisecond=vb.fn.milliseconds=qb("Milliseconds",!1),vb.fn.second=vb.fn.seconds=qb("Seconds",!1),vb.fn.minute=vb.fn.minutes=qb("Minutes",!1),vb.fn.hour=vb.fn.hours=qb("Hours",!0),vb.fn.date=qb("Date",!0),vb.fn.dates=f("dates accessor is deprecated. Use date instead.",qb("Date",!0)),vb.fn.year=qb("FullYear",!0),vb.fn.years=f("years accessor is deprecated. Use year instead.",qb("FullYear",!0)),vb.fn.days=vb.fn.day,vb.fn.months=vb.fn.month,vb.fn.weeks=vb.fn.week,vb.fn.isoWeeks=vb.fn.isoWeek,vb.fn.quarters=vb.fn.quarter,vb.fn.toJSON=vb.fn.toISOString,vb.fn.isUTC=vb.fn.isUtc,o(vb.duration.fn=n.prototype,{_bubble:function(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;g.milliseconds=d%1e3,a=q(d/1e3),g.seconds=a%60,b=q(a/60),g.minutes=b%60,c=q(b/60),g.hours=c%24,e+=q(c/24),h=q(rb(e)),e-=q(sb(h)),f+=q(e/30),e%=30,h+=q(f/12),f%=12,g.days=e,g.months=f,g.years=h},abs:function(){return this._milliseconds=Math.abs(this._milliseconds),this._days=Math.abs(this._days),this._months=Math.abs(this._months),this._data.milliseconds=Math.abs(this._data.milliseconds),this._data.seconds=Math.abs(this._data.seconds),this._data.minutes=Math.abs(this._data.minutes),this._data.hours=Math.abs(this._data.hours),this._data.months=Math.abs(this._data.months),this._data.years=Math.abs(this._data.years),this},weeks:function(){return q(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*C(this._months/12) +},humanize:function(a){var b=ib(this,!a,this.localeData());return a&&(b=this.localeData().pastFuture(+this,b)),this.localeData().postformat(b)},add:function(a,b){var c=vb.duration(a,b);return this._milliseconds+=c._milliseconds,this._days+=c._days,this._months+=c._months,this._bubble(),this},subtract:function(a,b){var c=vb.duration(a,b);return this._milliseconds-=c._milliseconds,this._days-=c._days,this._months-=c._months,this._bubble(),this},get:function(a){return a=z(a),this[a.toLowerCase()+"s"]()},as:function(a){var b,c;if(a=z(a),"month"===a||"year"===a)return b=this._days+this._milliseconds/864e5,c=this._months+12*rb(b),"month"===a?c:c/12;switch(b=this._days+Math.round(sb(this._months/12)),a){case"week":return b/7+this._milliseconds/6048e5;case"day":return b+this._milliseconds/864e5;case"hour":return 24*b+this._milliseconds/36e5;case"minute":return 24*b*60+this._milliseconds/6e4;case"second":return 24*b*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*b*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+a)}},lang:vb.fn.lang,locale:vb.fn.locale,toIsoString:f("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var a=Math.abs(this.years()),b=Math.abs(this.months()),c=Math.abs(this.days()),d=Math.abs(this.hours()),e=Math.abs(this.minutes()),f=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"},localeData:function(){return this._locale},toJSON:function(){return this.toISOString()}}),vb.duration.fn.toString=vb.duration.fn.toISOString;for(xb in kc)c(kc,xb)&&tb(xb.toLowerCase());vb.duration.fn.asMilliseconds=function(){return this.as("ms")},vb.duration.fn.asSeconds=function(){return this.as("s")},vb.duration.fn.asMinutes=function(){return this.as("m")},vb.duration.fn.asHours=function(){return this.as("h")},vb.duration.fn.asDays=function(){return this.as("d")},vb.duration.fn.asWeeks=function(){return this.as("weeks")},vb.duration.fn.asMonths=function(){return this.as("M")},vb.duration.fn.asYears=function(){return this.as("y")},vb.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===C(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),Lb?module.exports=vb:"function"==typeof define&&define.amd?(define(function(a,b,c){return c.config&&c.config()&&c.config().noGlobal===!0&&(zb.moment=wb),vb}),ub(!0)):ub()}).call(this); \ No newline at end of file diff --git a/html/js/rickshaw.js b/html/js/rickshaw.js new file mode 100644 index 0000000..e5d56c5 --- /dev/null +++ b/html/js/rickshaw.js @@ -0,0 +1,3994 @@ +/* jshint -W079 */ + +var Rickshaw = { + + namespace: function(namespace, obj) { + + var parts = namespace.split('.'); + + var parent = Rickshaw; + + for(var i = 1, length = parts.length; i < length; i++) { + var currentPart = parts[i]; + parent[currentPart] = parent[currentPart] || {}; + parent = parent[currentPart]; + } + return parent; + }, + + keys: function(obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; + }, + + extend: function(destination, source) { + + for (var property in source) { + destination[property] = source[property]; + } + return destination; + }, + + clone: function(obj) { + return JSON.parse(JSON.stringify(obj)); + } +}; + +if (typeof module !== 'undefined' && module.exports) { + var d3 = require('d3'); + module.exports = Rickshaw; +} + +/* Adapted from https://github.com/Jakobo/PTClass */ + +/* +Copyright (c) 2005-2010 Sam Stephenson + +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 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. +*/ +/* Based on Alex Arnell's inheritance implementation. */ +/** section: Language + * class Class + * + * Manages Prototype's class-based OOP system. + * + * Refer to Prototype's web site for a [tutorial on classes and + * inheritance](http://prototypejs.org/learn/class-inheritance). +**/ +(function(globalContext) { +/* ------------------------------------ */ +/* Import from object.js */ +/* ------------------------------------ */ +var _toString = Object.prototype.toString, + NULL_TYPE = 'Null', + UNDEFINED_TYPE = 'Undefined', + BOOLEAN_TYPE = 'Boolean', + NUMBER_TYPE = 'Number', + STRING_TYPE = 'String', + OBJECT_TYPE = 'Object', + FUNCTION_CLASS = '[object Function]'; +function isFunction(object) { + return _toString.call(object) === FUNCTION_CLASS; +} +function extend(destination, source) { + for (var property in source) if (source.hasOwnProperty(property)) // modify protect primitive slaughter + destination[property] = source[property]; + return destination; +} +function keys(object) { + if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } + var results = []; + for (var property in object) { + if (object.hasOwnProperty(property)) { + results.push(property); + } + } + return results; +} +function Type(o) { + switch(o) { + case null: return NULL_TYPE; + case (void 0): return UNDEFINED_TYPE; + } + var type = typeof o; + switch(type) { + case 'boolean': return BOOLEAN_TYPE; + case 'number': return NUMBER_TYPE; + case 'string': return STRING_TYPE; + } + return OBJECT_TYPE; +} +function isUndefined(object) { + return typeof object === "undefined"; +} +/* ------------------------------------ */ +/* Import from Function.js */ +/* ------------------------------------ */ +var slice = Array.prototype.slice; +function argumentNames(fn) { + var names = fn.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] + .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; +} +function wrap(fn, wrapper) { + var __method = fn; + return function() { + var a = update([bind(__method, this)], arguments); + return wrapper.apply(this, a); + } +} +function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; +} +function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); +} +function bind(fn, context) { + if (arguments.length < 2 && isUndefined(arguments[0])) return this; + var __method = fn, args = slice.call(arguments, 2); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } +} + +/* ------------------------------------ */ +/* Import from Prototype.js */ +/* ------------------------------------ */ +var emptyFunction = function(){}; + +var Class = (function() { + + // Some versions of JScript fail to enumerate over properties, names of which + // correspond to non-enumerable properties in the prototype chain + var IS_DONTENUM_BUGGY = (function(){ + for (var p in { toString: 1 }) { + // check actual property name, so that it works with augmented Object.prototype + if (p === 'toString') return false; + } + return true; + })(); + + function subclass() {}; + function create() { + var parent = null, properties = [].slice.apply(arguments); + if (isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + try { parent.subclasses.push(klass) } catch(e) {} + } + + for (var i = 0, length = properties.length; i < length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = emptyFunction; + + klass.prototype.constructor = klass; + return klass; + } + + function addMethods(source) { + var ancestor = this.superclass && this.superclass.prototype, + properties = keys(source); + + // IE6 doesn't enumerate `toString` and `valueOf` (among other built-in `Object.prototype`) properties, + // Force copy if they're not Object.prototype ones. + // Do not copy other Object.prototype.* for performance reasons + if (IS_DONTENUM_BUGGY) { + if (source.toString != Object.prototype.toString) + properties.push("toString"); + if (source.valueOf != Object.prototype.valueOf) + properties.push("valueOf"); + } + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && isFunction(value) && + argumentNames(value)[0] == "$super") { + var method = value; + value = wrap((function(m) { + return function() { return ancestor[m].apply(this, arguments); }; + })(property), method); + + value.valueOf = bind(method.valueOf, method); + value.toString = bind(method.toString, method); + } + this.prototype[property] = value; + } + + return this; + } + + return { + create: create, + Methods: { + addMethods: addMethods + } + }; +})(); + +if (globalContext.exports) { + globalContext.exports.Class = Class; +} +else { + globalContext.Class = Class; +} +})(Rickshaw); +Rickshaw.namespace('Rickshaw.Compat.ClassList'); + +Rickshaw.Compat.ClassList = function() { + + /* adapted from http://purl.eligrey.com/github/classList.js/blob/master/classList.js */ + + if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) { + + (function (view) { + + "use strict"; + + var + classListProp = "classList" + , protoProp = "prototype" + , elemCtrProto = (view.HTMLElement || view.Element)[protoProp] + , objCtr = Object + , strTrim = String[protoProp].trim || function () { + return this.replace(/^\s+|\s+$/g, ""); + } + , arrIndexOf = Array[protoProp].indexOf || function (item) { + var + i = 0 + , len = this.length + ; + for (; i < len; i++) { + if (i in this && this[i] === item) { + return i; + } + } + return -1; + } + // Vendors: please allow content code to instantiate DOMExceptions + , DOMEx = function (type, message) { + this.name = type; + this.code = DOMException[type]; + this.message = message; + } + , checkTokenAndGetIndex = function (classList, token) { + if (token === "") { + throw new DOMEx( + "SYNTAX_ERR" + , "An invalid or illegal string was specified" + ); + } + if (/\s/.test(token)) { + throw new DOMEx( + "INVALID_CHARACTER_ERR" + , "String contains an invalid character" + ); + } + return arrIndexOf.call(classList, token); + } + , ClassList = function (elem) { + var + trimmedClasses = strTrim.call(elem.className) + , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] + , i = 0 + , len = classes.length + ; + for (; i < len; i++) { + this.push(classes[i]); + } + this._updateClassName = function () { + elem.className = this.toString(); + }; + } + , classListProto = ClassList[protoProp] = [] + , classListGetter = function () { + return new ClassList(this); + } + ; + // Most DOMException implementations don't allow calling DOMException's toString() + // on non-DOMExceptions. Error's toString() is sufficient here. + DOMEx[protoProp] = Error[protoProp]; + classListProto.item = function (i) { + return this[i] || null; + }; + classListProto.contains = function (token) { + token += ""; + return checkTokenAndGetIndex(this, token) !== -1; + }; + classListProto.add = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.push(token); + this._updateClassName(); + } + }; + classListProto.remove = function (token) { + token += ""; + var index = checkTokenAndGetIndex(this, token); + if (index !== -1) { + this.splice(index, 1); + this._updateClassName(); + } + }; + classListProto.toggle = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.add(token); + } else { + this.remove(token); + } + }; + classListProto.toString = function () { + return this.join(" "); + }; + + if (objCtr.defineProperty) { + var classListPropDesc = { + get: classListGetter + , enumerable: true + , configurable: true + }; + try { + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } catch (ex) { // IE 8 doesn't support enumerable:true + if (ex.number === -0x7FF5EC54) { + classListPropDesc.enumerable = false; + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } + } + } else if (objCtr[protoProp].__defineGetter__) { + elemCtrProto.__defineGetter__(classListProp, classListGetter); + } + + }(window)); + + } +}; + +if ( (typeof RICKSHAW_NO_COMPAT !== "undefined" && !RICKSHAW_NO_COMPAT) || typeof RICKSHAW_NO_COMPAT === "undefined") { + new Rickshaw.Compat.ClassList(); +} +Rickshaw.namespace('Rickshaw.Graph'); + +Rickshaw.Graph = function(args) { + + var self = this; + + this.initialize = function(args) { + + if (!args.element) throw "Rickshaw.Graph needs a reference to an element"; + if (args.element.nodeType !== 1) throw "Rickshaw.Graph element was defined but not an HTML element"; + + this.element = args.element; + this.series = args.series; + this.window = {}; + + this.updateCallbacks = []; + this.configureCallbacks = []; + + this.defaults = { + interpolation: 'cardinal', + offset: 'zero', + min: undefined, + max: undefined, + preserve: false, + xScale: undefined, + yScale: undefined + }; + + this._loadRenderers(); + this.configure(args); + this.validateSeries(args.series); + + this.series.active = function() { return self.series.filter( function(s) { return !s.disabled } ) }; + this.setSize({ width: args.width, height: args.height }); + this.element.classList.add('rickshaw_graph'); + + this.vis = d3.select(this.element) + .append("svg:svg") + .attr('width', this.width) + .attr('height', this.height); + + this.discoverRange(); + }; + + this._loadRenderers = function() { + + for (var name in Rickshaw.Graph.Renderer) { + if (!name || !Rickshaw.Graph.Renderer.hasOwnProperty(name)) continue; + var r = Rickshaw.Graph.Renderer[name]; + if (!r || !r.prototype || !r.prototype.render) continue; + self.registerRenderer(new r( { graph: self } )); + } + }; + + this.validateSeries = function(series) { + + if (!Array.isArray(series) && !(series instanceof Rickshaw.Series)) { + var seriesSignature = Object.prototype.toString.apply(series); + throw "series is not an array: " + seriesSignature; + } + + var pointsCount; + + series.forEach( function(s) { + + if (!(s instanceof Object)) { + throw "series element is not an object: " + s; + } + if (!(s.data)) { + throw "series has no data: " + JSON.stringify(s); + } + if (!Array.isArray(s.data)) { + throw "series data is not an array: " + JSON.stringify(s.data); + } + + var x = s.data[0].x; + var y = s.data[0].y; + + if (typeof x != 'number' || ( typeof y != 'number' && y !== null ) ) { + throw "x and y properties of points should be numbers instead of " + + (typeof x) + " and " + (typeof y); + } + + if (s.data.length >= 3) { + // probe to sanity check sort order + if (s.data[2].x < s.data[1].x || s.data[1].x < s.data[0].x || s.data[s.data.length - 1].x < s.data[0].x) { + throw "series data needs to be sorted on x values for series name: " + s.name; + } + } + + }, this ); + }; + + this.dataDomain = function() { + + var data = this.series.map( function(s) { return s.data } ); + + var min = d3.min( data.map( function(d) { return d[0].x } ) ); + var max = d3.max( data.map( function(d) { return d[d.length - 1].x } ) ); + + return [min, max]; + }; + + this.discoverRange = function() { + + var domain = this.renderer.domain(); + + this.x = (this.xScale || d3.scale.linear()).domain(domain.x).range([0, this.width]); + this.y = (this.yScale || d3.scale.linear()).domain(domain.y).range([this.height, 0]); + + this.y.magnitude = d3.scale.linear() + .domain([domain.y[0] - domain.y[0], domain.y[1] - domain.y[0]]) + .range([0, this.height]); + }; + + this.render = function() { + + var stackedData = this.stackData(); + this.discoverRange(); + + this.renderer.render(); + + this.updateCallbacks.forEach( function(callback) { + callback(); + } ); + + }; + + this.update = this.render; + + this.stackData = function() { + + var data = this.series.active() + .map( function(d) { return d.data } ) + .map( function(d) { return d.filter( function(d) { return this._slice(d) }, this ) }, this); + + var preserve = this.preserve; + if (!preserve) { + this.series.forEach( function(series) { + if (series.scale) { + // data must be preserved when a scale is used + preserve = true; + } + } ); + } + + data = preserve ? Rickshaw.clone(data) : data; + + this.series.active().forEach( function(series, index) { + if (series.scale) { + // apply scale to each series + var seriesData = data[index]; + if(seriesData) { + seriesData.forEach( function(d) { + d.y = series.scale(d.y); + } ); + } + } + } ); + + this.stackData.hooks.data.forEach( function(entry) { + data = entry.f.apply(self, [data]); + } ); + + var stackedData; + + if (!this.renderer.unstack) { + + this._validateStackable(); + + var layout = d3.layout.stack(); + layout.offset( self.offset ); + stackedData = layout(data); + } + + stackedData = stackedData || data; + + if (this.renderer.unstack) { + stackedData.forEach( function(seriesData) { + seriesData.forEach( function(d) { + d.y0 = d.y0 === undefined ? 0 : d.y0; + } ); + } ); + } + + this.stackData.hooks.after.forEach( function(entry) { + stackedData = entry.f.apply(self, [data]); + } ); + + var i = 0; + this.series.forEach( function(series) { + if (series.disabled) return; + series.stack = stackedData[i++]; + } ); + + this.stackedData = stackedData; + return stackedData; + }; + + this._validateStackable = function() { + + var series = this.series; + var pointsCount; + + series.forEach( function(s) { + + pointsCount = pointsCount || s.data.length; + + if (pointsCount && s.data.length != pointsCount) { + throw "stacked series cannot have differing numbers of points: " + + pointsCount + " vs " + s.data.length + "; see Rickshaw.Series.fill()"; + } + + }, this ); + }; + + this.stackData.hooks = { data: [], after: [] }; + + this._slice = function(d) { + + if (this.window.xMin || this.window.xMax) { + + var isInRange = true; + + if (this.window.xMin && d.x < this.window.xMin) isInRange = false; + if (this.window.xMax && d.x > this.window.xMax) isInRange = false; + + return isInRange; + } + + return true; + }; + + this.onUpdate = function(callback) { + this.updateCallbacks.push(callback); + }; + + this.onConfigure = function(callback) { + this.configureCallbacks.push(callback); + }; + + this.registerRenderer = function(renderer) { + this._renderers = this._renderers || {}; + this._renderers[renderer.name] = renderer; + }; + + this.configure = function(args) { + + this.config = this.config || {}; + + if (args.width || args.height) { + this.setSize(args); + } + + Rickshaw.keys(this.defaults).forEach( function(k) { + this.config[k] = k in args ? args[k] + : k in this ? this[k] + : this.defaults[k]; + }, this ); + + Rickshaw.keys(this.config).forEach( function(k) { + this[k] = this.config[k]; + }, this ); + + var renderer = args.renderer || (this.renderer && this.renderer.name) || 'stack'; + this.setRenderer(renderer, args); + + this.configureCallbacks.forEach( function(callback) { + callback(args); + } ); + }; + + this.setRenderer = function(r, args) { + if (typeof r == 'function') { + this.renderer = new r( { graph: self } ); + this.registerRenderer(this.renderer); + } else { + if (!this._renderers[r]) { + throw "couldn't find renderer " + r; + } + this.renderer = this._renderers[r]; + } + + if (typeof args == 'object') { + this.renderer.configure(args); + } + }; + + this.setSize = function(args) { + + args = args || {}; + + if (typeof window !== undefined) { + var style = window.getComputedStyle(this.element, null); + var elementWidth = parseInt(style.getPropertyValue('width'), 10); + var elementHeight = parseInt(style.getPropertyValue('height'), 10); + } + + this.width = args.width || elementWidth || 400; + this.height = args.height || elementHeight || 250; + + this.vis && this.vis + .attr('width', this.width) + .attr('height', this.height); + }; + + this.initialize(args); +}; +Rickshaw.namespace('Rickshaw.Fixtures.Color'); + +Rickshaw.Fixtures.Color = function() { + + this.schemes = {}; + + this.schemes.spectrum14 = [ + '#ecb796', + '#dc8f70', + '#b2a470', + '#92875a', + '#716c49', + '#d2ed82', + '#bbe468', + '#a1d05d', + '#e7cbe6', + '#d8aad6', + '#a888c2', + '#9dc2d3', + '#649eb9', + '#387aa3' + ].reverse(); + + this.schemes.spectrum2000 = [ + '#57306f', + '#514c76', + '#646583', + '#738394', + '#6b9c7d', + '#84b665', + '#a7ca50', + '#bfe746', + '#e2f528', + '#fff726', + '#ecdd00', + '#d4b11d', + '#de8800', + '#de4800', + '#c91515', + '#9a0000', + '#7b0429', + '#580839', + '#31082b' + ]; + + this.schemes.spectrum2001 = [ + '#2f243f', + '#3c2c55', + '#4a3768', + '#565270', + '#6b6b7c', + '#72957f', + '#86ad6e', + '#a1bc5e', + '#b8d954', + '#d3e04e', + '#ccad2a', + '#cc8412', + '#c1521d', + '#ad3821', + '#8a1010', + '#681717', + '#531e1e', + '#3d1818', + '#320a1b' + ]; + + this.schemes.classic9 = [ + '#423d4f', + '#4a6860', + '#848f39', + '#a2b73c', + '#ddcb53', + '#c5a32f', + '#7d5836', + '#963b20', + '#7c2626', + '#491d37', + '#2f254a' + ].reverse(); + + this.schemes.httpStatus = { + 503: '#ea5029', + 502: '#d23f14', + 500: '#bf3613', + 410: '#efacea', + 409: '#e291dc', + 403: '#f457e8', + 408: '#e121d2', + 401: '#b92dae', + 405: '#f47ceb', + 404: '#a82a9f', + 400: '#b263c6', + 301: '#6fa024', + 302: '#87c32b', + 307: '#a0d84c', + 304: '#28b55c', + 200: '#1a4f74', + 206: '#27839f', + 201: '#52adc9', + 202: '#7c979f', + 203: '#a5b8bd', + 204: '#c1cdd1' + }; + + this.schemes.colorwheel = [ + '#b5b6a9', + '#858772', + '#785f43', + '#96557e', + '#4682b4', + '#65b9ac', + '#73c03a', + '#cb513a' + ].reverse(); + + this.schemes.cool = [ + '#5e9d2f', + '#73c03a', + '#4682b4', + '#7bc3b8', + '#a9884e', + '#c1b266', + '#a47493', + '#c09fb5' + ]; + + this.schemes.munin = [ + '#00cc00', + '#0066b3', + '#ff8000', + '#ffcc00', + '#330099', + '#990099', + '#ccff00', + '#ff0000', + '#808080', + '#008f00', + '#00487d', + '#b35a00', + '#b38f00', + '#6b006b', + '#8fb300', + '#b30000', + '#bebebe', + '#80ff80', + '#80c9ff', + '#ffc080', + '#ffe680', + '#aa80ff', + '#ee00cc', + '#ff8080', + '#666600', + '#ffbfff', + '#00ffcc', + '#cc6699', + '#999900' + ]; +}; +Rickshaw.namespace('Rickshaw.Fixtures.RandomData'); + +Rickshaw.Fixtures.RandomData = function(timeInterval) { + + var addData; + timeInterval = timeInterval || 1; + + var lastRandomValue = 200; + + var timeBase = Math.floor(new Date().getTime() / 1000); + + this.addData = function(data) { + + var randomValue = Math.random() * 100 + 15 + lastRandomValue; + var index = data[0].length; + + var counter = 1; + + data.forEach( function(series) { + var randomVariance = Math.random() * 20; + var v = randomValue / 25 + counter++ + + (Math.cos((index * counter * 11) / 960) + 2) * 15 + + (Math.cos(index / 7) + 2) * 7 + + (Math.cos(index / 17) + 2) * 1; + + series.push( { x: (index * timeInterval) + timeBase, y: v + randomVariance } ); + } ); + + lastRandomValue = randomValue * 0.85; + }; + + this.removeData = function(data) { + data.forEach( function(series) { + series.shift(); + } ); + timeBase += timeInterval; + }; +}; + +Rickshaw.namespace('Rickshaw.Fixtures.Time'); + +Rickshaw.Fixtures.Time = function() { + + var self = this; + + this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + this.units = [ + { + name: 'decade', + seconds: 86400 * 365.25 * 10, + formatter: function(d) { return (parseInt(d.getUTCFullYear() / 10, 10) * 10) } + }, { + name: 'year', + seconds: 86400 * 365.25, + formatter: function(d) { return d.getUTCFullYear() } + }, { + name: 'month', + seconds: 86400 * 30.5, + formatter: function(d) { return self.months[d.getUTCMonth()] } + }, { + name: 'week', + seconds: 86400 * 7, + formatter: function(d) { return self.formatDate(d) } + }, { + name: 'day', + seconds: 86400, + formatter: function(d) { return d.getUTCDate() } + }, { + name: '6 hour', + seconds: 3600 * 6, + formatter: function(d) { return self.formatTime(d) } + }, { + name: 'hour', + seconds: 3600, + formatter: function(d) { return self.formatTime(d) } + }, { + name: '15 minute', + seconds: 60 * 15, + formatter: function(d) { return self.formatTime(d) } + }, { + name: 'minute', + seconds: 60, + formatter: function(d) { return d.getUTCMinutes() } + }, { + name: '15 second', + seconds: 15, + formatter: function(d) { return d.getUTCSeconds() + 's' } + }, { + name: 'second', + seconds: 1, + formatter: function(d) { return d.getUTCSeconds() + 's' } + }, { + name: 'decisecond', + seconds: 1/10, + formatter: function(d) { return d.getUTCMilliseconds() + 'ms' } + }, { + name: 'centisecond', + seconds: 1/100, + formatter: function(d) { return d.getUTCMilliseconds() + 'ms' } + } + ]; + + this.unit = function(unitName) { + return this.units.filter( function(unit) { return unitName == unit.name } ).shift(); + }; + + this.formatDate = function(d) { + return d3.time.format('%b %e')(d); + }; + + this.formatTime = function(d) { + return d.toUTCString().match(/(\d+:\d+):/)[1]; + }; + + this.ceil = function(time, unit) { + + var date, floor, year; + + if (unit.name == 'month') { + + date = new Date(time * 1000); + + floor = Date.UTC(date.getUTCFullYear(), date.getUTCMonth()) / 1000; + if (floor == time) return time; + + year = date.getUTCFullYear(); + var month = date.getUTCMonth(); + + if (month == 11) { + month = 0; + year = year + 1; + } else { + month += 1; + } + + return Date.UTC(year, month) / 1000; + } + + if (unit.name == 'year') { + + date = new Date(time * 1000); + + floor = Date.UTC(date.getUTCFullYear(), 0) / 1000; + if (floor == time) return time; + + year = date.getUTCFullYear() + 1; + + return Date.UTC(year, 0) / 1000; + } + + return Math.ceil(time / unit.seconds) * unit.seconds; + }; +}; +Rickshaw.namespace('Rickshaw.Fixtures.Time.Local'); + +Rickshaw.Fixtures.Time.Local = function() { + + var self = this; + + this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + this.units = [ + { + name: 'decade', + seconds: 86400 * 365.25 * 10, + formatter: function(d) { return (parseInt(d.getFullYear() / 10, 10) * 10) } + }, { + name: 'year', + seconds: 86400 * 365.25, + formatter: function(d) { return d.getFullYear() } + }, { + name: 'month', + seconds: 86400 * 30.5, + formatter: function(d) { return self.months[d.getMonth()] } + }, { + name: 'week', + seconds: 86400 * 7, + formatter: function(d) { return self.formatDate(d) } + }, { + name: 'day', + seconds: 86400, + formatter: function(d) { return d.getDate() } + }, { + name: '6 hour', + seconds: 3600 * 6, + formatter: function(d) { return self.formatTime(d) } + }, { + name: 'hour', + seconds: 3600, + formatter: function(d) { return self.formatTime(d) } + }, { + name: '15 minute', + seconds: 60 * 15, + formatter: function(d) { return self.formatTime(d) } + }, { + name: 'minute', + seconds: 60, + formatter: function(d) { return d.getMinutes() } + }, { + name: '15 second', + seconds: 15, + formatter: function(d) { return d.getSeconds() + 's' } + }, { + name: 'second', + seconds: 1, + formatter: function(d) { return d.getSeconds() + 's' } + }, { + name: 'decisecond', + seconds: 1/10, + formatter: function(d) { return d.getMilliseconds() + 'ms' } + }, { + name: 'centisecond', + seconds: 1/100, + formatter: function(d) { return d.getMilliseconds() + 'ms' } + } + ]; + + this.unit = function(unitName) { + return this.units.filter( function(unit) { return unitName == unit.name } ).shift(); + }; + + this.formatDate = function(d) { + return d3.time.format('%b %e')(d); + }; + + this.formatTime = function(d) { + return d.toString().match(/(\d+:\d+):/)[1]; + }; + + this.ceil = function(time, unit) { + + var date, floor, year; + + if (unit.name == 'day') { + + var nearFuture = new Date((time + unit.seconds - 1) * 1000); + + var rounded = new Date(0); + rounded.setMilliseconds(0); + rounded.setSeconds(0); + rounded.setMinutes(0); + rounded.setHours(0); + rounded.setDate(nearFuture.getDate()); + rounded.setMonth(nearFuture.getMonth()); + rounded.setFullYear(nearFuture.getFullYear()); + + return rounded.getTime() / 1000; + } + + if (unit.name == 'month') { + + date = new Date(time * 1000); + + floor = new Date(date.getFullYear(), date.getMonth()).getTime() / 1000; + if (floor == time) return time; + + year = date.getFullYear(); + var month = date.getMonth(); + + if (month == 11) { + month = 0; + year = year + 1; + } else { + month += 1; + } + + return new Date(year, month).getTime() / 1000; + } + + if (unit.name == 'year') { + + date = new Date(time * 1000); + + floor = new Date(date.getUTCFullYear(), 0).getTime() / 1000; + if (floor == time) return time; + + year = date.getFullYear() + 1; + + return new Date(year, 0).getTime() / 1000; + } + + return Math.ceil(time / unit.seconds) * unit.seconds; + }; +}; +Rickshaw.namespace('Rickshaw.Fixtures.Number'); + +Rickshaw.Fixtures.Number.formatKMBT = function(y) { + var abs_y = Math.abs(y); + if (abs_y >= 1000000000000) { return y / 1000000000000 + "T" } + else if (abs_y >= 1000000000) { return y / 1000000000 + "B" } + else if (abs_y >= 1000000) { return y / 1000000 + "M" } + else if (abs_y >= 1000) { return y / 1000 + "K" } + else if (abs_y < 1 && y > 0) { return y.toFixed(2) } + else if (abs_y === 0) { return '' } + else { return y } +}; + +Rickshaw.Fixtures.Number.formatBase1024KMGTP = function(y) { + var abs_y = Math.abs(y); + if (abs_y >= 1125899906842624) { return y / 1125899906842624 + "P" } + else if (abs_y >= 1099511627776){ return y / 1099511627776 + "T" } + else if (abs_y >= 1073741824) { return y / 1073741824 + "G" } + else if (abs_y >= 1048576) { return y / 1048576 + "M" } + else if (abs_y >= 1024) { return y / 1024 + "K" } + else if (abs_y < 1 && y > 0) { return y.toFixed(2) } + else if (abs_y === 0) { return '' } + else { return y } +}; +Rickshaw.namespace("Rickshaw.Color.Palette"); + +Rickshaw.Color.Palette = function(args) { + + var color = new Rickshaw.Fixtures.Color(); + + args = args || {}; + this.schemes = {}; + + this.scheme = color.schemes[args.scheme] || args.scheme || color.schemes.colorwheel; + this.runningIndex = 0; + this.generatorIndex = 0; + + if (args.interpolatedStopCount) { + var schemeCount = this.scheme.length - 1; + var i, j, scheme = []; + for (i = 0; i < schemeCount; i++) { + scheme.push(this.scheme[i]); + var generator = d3.interpolateHsl(this.scheme[i], this.scheme[i + 1]); + for (j = 1; j < args.interpolatedStopCount; j++) { + scheme.push(generator((1 / args.interpolatedStopCount) * j)); + } + } + scheme.push(this.scheme[this.scheme.length - 1]); + this.scheme = scheme; + } + this.rotateCount = this.scheme.length; + + this.color = function(key) { + return this.scheme[key] || this.scheme[this.runningIndex++] || this.interpolateColor() || '#808080'; + }; + + this.interpolateColor = function() { + if (!Array.isArray(this.scheme)) return; + var color; + if (this.generatorIndex == this.rotateCount * 2 - 1) { + color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[0])(0.5); + this.generatorIndex = 0; + this.rotateCount *= 2; + } else { + color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[this.generatorIndex + 1])(0.5); + this.generatorIndex++; + } + this.scheme.push(color); + return color; + }; + +}; +Rickshaw.namespace('Rickshaw.Graph.Ajax'); + +Rickshaw.Graph.Ajax = Rickshaw.Class.create( { + + initialize: function(args) { + + this.dataURL = args.dataURL; + + this.onData = args.onData || function(d) { return d }; + this.onComplete = args.onComplete || function() {}; + this.onError = args.onError || function() {}; + + this.args = args; // pass through to Rickshaw.Graph + + this.request(); + }, + + request: function() { + + $.ajax( { + url: this.dataURL, + dataType: 'json', + success: this.success.bind(this), + error: this.error.bind(this) + } ); + }, + + error: function() { + + console.log("error loading dataURL: " + this.dataURL); + this.onError(this); + }, + + success: function(data, status) { + + data = this.onData(data); + this.args.series = this._splice({ data: data, series: this.args.series }); + + this.graph = this.graph || new Rickshaw.Graph(this.args); + this.graph.render(); + + this.onComplete(this); + }, + + _splice: function(args) { + + var data = args.data; + var series = args.series; + + if (!args.series) return data; + + series.forEach( function(s) { + + var seriesKey = s.key || s.name; + if (!seriesKey) throw "series needs a key or a name"; + + data.forEach( function(d) { + + var dataKey = d.key || d.name; + if (!dataKey) throw "data needs a key or a name"; + + if (seriesKey == dataKey) { + var properties = ['color', 'name', 'data']; + properties.forEach( function(p) { + if (d[p]) s[p] = d[p]; + } ); + } + } ); + } ); + + return series; + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.Annotate'); + +Rickshaw.Graph.Annotate = function(args) { + + var graph = this.graph = args.graph; + this.elements = { timeline: args.element }; + + var self = this; + + this.data = {}; + + this.elements.timeline.classList.add('rickshaw_annotation_timeline'); + + this.add = function(time, content, end_time) { + self.data[time] = self.data[time] || {'boxes': []}; + self.data[time].boxes.push({content: content, end: end_time}); + }; + + this.update = function() { + + Rickshaw.keys(self.data).forEach( function(time) { + + var annotation = self.data[time]; + var left = self.graph.x(time); + + if (left < 0 || left > self.graph.x.range()[1]) { + if (annotation.element) { + annotation.line.classList.add('offscreen'); + annotation.element.style.display = 'none'; + } + + annotation.boxes.forEach( function(box) { + if ( box.rangeElement ) box.rangeElement.classList.add('offscreen'); + }); + + return; + } + + if (!annotation.element) { + var element = annotation.element = document.createElement('div'); + element.classList.add('annotation'); + this.elements.timeline.appendChild(element); + element.addEventListener('click', function(e) { + element.classList.toggle('active'); + annotation.line.classList.toggle('active'); + annotation.boxes.forEach( function(box) { + if ( box.rangeElement ) box.rangeElement.classList.toggle('active'); + }); + }, false); + + } + + annotation.element.style.left = left + 'px'; + annotation.element.style.display = 'block'; + + annotation.boxes.forEach( function(box) { + + + var element = box.element; + + if (!element) { + element = box.element = document.createElement('div'); + element.classList.add('content'); + element.innerHTML = box.content; + annotation.element.appendChild(element); + + annotation.line = document.createElement('div'); + annotation.line.classList.add('annotation_line'); + self.graph.element.appendChild(annotation.line); + + if ( box.end ) { + box.rangeElement = document.createElement('div'); + box.rangeElement.classList.add('annotation_range'); + self.graph.element.appendChild(box.rangeElement); + } + + } + + if ( box.end ) { + + var annotationRangeStart = left; + var annotationRangeEnd = Math.min( self.graph.x(box.end), self.graph.x.range()[1] ); + + // annotation makes more sense at end + if ( annotationRangeStart > annotationRangeEnd ) { + annotationRangeEnd = left; + annotationRangeStart = Math.max( self.graph.x(box.end), self.graph.x.range()[0] ); + } + + var annotationRangeWidth = annotationRangeEnd - annotationRangeStart; + + box.rangeElement.style.left = annotationRangeStart + 'px'; + box.rangeElement.style.width = annotationRangeWidth + 'px'; + + box.rangeElement.classList.remove('offscreen'); + } + + annotation.line.classList.remove('offscreen'); + annotation.line.style.left = left + 'px'; + } ); + }, this ); + }; + + this.graph.onUpdate( function() { self.update() } ); +}; +Rickshaw.namespace('Rickshaw.Graph.Axis.Time'); + +Rickshaw.Graph.Axis.Time = function(args) { + + var self = this; + + this.graph = args.graph; + this.elements = []; + this.ticksTreatment = args.ticksTreatment || 'plain'; + this.fixedTimeUnit = args.timeUnit; + + var time = args.timeFixture || new Rickshaw.Fixtures.Time(); + + this.appropriateTimeUnit = function() { + + var unit; + var units = time.units; + + var domain = this.graph.x.domain(); + var rangeSeconds = domain[1] - domain[0]; + + units.forEach( function(u) { + if (Math.floor(rangeSeconds / u.seconds) >= 2) { + unit = unit || u; + } + } ); + + return (unit || time.units[time.units.length - 1]); + }; + + this.tickOffsets = function() { + + var domain = this.graph.x.domain(); + + var unit = this.fixedTimeUnit || this.appropriateTimeUnit(); + var count = Math.ceil((domain[1] - domain[0]) / unit.seconds); + + var runningTick = domain[0]; + + var offsets = []; + + for (var i = 0; i < count; i++) { + + var tickValue = time.ceil(runningTick, unit); + runningTick = tickValue + unit.seconds / 2; + + offsets.push( { value: tickValue, unit: unit } ); + } + + return offsets; + }; + + this.render = function() { + + this.elements.forEach( function(e) { + e.parentNode.removeChild(e); + } ); + + this.elements = []; + + var offsets = this.tickOffsets(); + + offsets.forEach( function(o) { + + if (self.graph.x(o.value) > self.graph.x.range()[1]) return; + + var element = document.createElement('div'); + element.style.left = self.graph.x(o.value) + 'px'; + element.classList.add('x_tick'); + element.classList.add(self.ticksTreatment); + + var title = document.createElement('div'); + title.classList.add('title'); + title.innerHTML = o.unit.formatter(new Date(o.value * 1000)); + element.appendChild(title); + + self.graph.element.appendChild(element); + self.elements.push(element); + + } ); + }; + + this.graph.onUpdate( function() { self.render() } ); +}; + +Rickshaw.namespace('Rickshaw.Graph.Axis.X'); + +Rickshaw.Graph.Axis.X = function(args) { + + var self = this; + var berthRate = 0.10; + + this.initialize = function(args) { + + this.graph = args.graph; + this.orientation = args.orientation || 'top'; + + this.pixelsPerTick = args.pixelsPerTick || 75; + if (args.ticks) this.staticTicks = args.ticks; + if (args.tickValues) this.tickValues = args.tickValues; + + this.tickSize = args.tickSize || 4; + this.ticksTreatment = args.ticksTreatment || 'plain'; + + if (args.element) { + + this.element = args.element; + this._discoverSize(args.element, args); + + this.vis = d3.select(args.element) + .append("svg:svg") + .attr('height', this.height) + .attr('width', this.width) + .attr('class', 'rickshaw_graph x_axis_d3'); + + this.element = this.vis[0][0]; + this.element.style.position = 'relative'; + + this.setSize({ width: args.width, height: args.height }); + + } else { + this.vis = this.graph.vis; + } + + this.graph.onUpdate( function() { self.render() } ); + }; + + this.setSize = function(args) { + + args = args || {}; + if (!this.element) return; + + this._discoverSize(this.element.parentNode, args); + + this.vis + .attr('height', this.height) + .attr('width', this.width * (1 + berthRate)); + + var berth = Math.floor(this.width * berthRate / 2); + this.element.style.left = -1 * berth + 'px'; + }; + + this.render = function() { + + if (this._renderWidth !== undefined && this.graph.width !== this._renderWidth) this.setSize({ auto: true }); + + var axis = d3.svg.axis().scale(this.graph.x).orient(this.orientation); + axis.tickFormat( args.tickFormat || function(x) { return x } ); + if (this.tickValues) axis.tickValues(this.tickValues); + + this.ticks = this.staticTicks || Math.floor(this.graph.width / this.pixelsPerTick); + + var berth = Math.floor(this.width * berthRate / 2) || 0; + var transform; + + if (this.orientation == 'top') { + var yOffset = this.height || this.graph.height; + transform = 'translate(' + berth + ',' + yOffset + ')'; + } else { + transform = 'translate(' + berth + ', 0)'; + } + + if (this.element) { + this.vis.selectAll('*').remove(); + } + + this.vis + .append("svg:g") + .attr("class", ["x_ticks_d3", this.ticksTreatment].join(" ")) + .attr("transform", transform) + .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize)); + + var gridSize = (this.orientation == 'bottom' ? 1 : -1) * this.graph.height; + + this.graph.vis + .append("svg:g") + .attr("class", "x_grid_d3") + .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)) + .selectAll('text') + .each(function() { this.parentNode.setAttribute('data-x-value', this.textContent) }); + + this._renderHeight = this.graph.height; + }; + + this._discoverSize = function(element, args) { + + if (typeof window !== 'undefined') { + + var style = window.getComputedStyle(element, null); + var elementHeight = parseInt(style.getPropertyValue('height'), 10); + + if (!args.auto) { + var elementWidth = parseInt(style.getPropertyValue('width'), 10); + } + } + + this.width = (args.width || elementWidth || this.graph.width) * (1 + berthRate); + this.height = args.height || elementHeight || 40; + }; + + this.initialize(args); +}; + +Rickshaw.namespace('Rickshaw.Graph.Axis.Y'); + +Rickshaw.Graph.Axis.Y = Rickshaw.Class.create( { + + initialize: function(args) { + + this.graph = args.graph; + this.orientation = args.orientation || 'right'; + + this.pixelsPerTick = args.pixelsPerTick || 75; + if (args.ticks) this.staticTicks = args.ticks; + if (args.tickValues) this.tickValues = args.tickValues; + + this.tickSize = args.tickSize || 4; + this.ticksTreatment = args.ticksTreatment || 'plain'; + + this.tickFormat = args.tickFormat || function(y) { return y }; + + this.berthRate = 0.10; + + if (args.element) { + + this.element = args.element; + this.vis = d3.select(args.element) + .append("svg:svg") + .attr('class', 'rickshaw_graph y_axis'); + + this.element = this.vis[0][0]; + this.element.style.position = 'relative'; + + this.setSize({ width: args.width, height: args.height }); + + } else { + this.vis = this.graph.vis; + } + + var self = this; + this.graph.onUpdate( function() { self.render() } ); + }, + + setSize: function(args) { + + args = args || {}; + + if (!this.element) return; + + if (typeof window !== 'undefined') { + + var style = window.getComputedStyle(this.element.parentNode, null); + var elementWidth = parseInt(style.getPropertyValue('width'), 10); + + if (!args.auto) { + var elementHeight = parseInt(style.getPropertyValue('height'), 10); + } + } + + this.width = args.width || elementWidth || this.graph.width * this.berthRate; + this.height = args.height || elementHeight || this.graph.height; + + this.vis + .attr('width', this.width) + .attr('height', this.height * (1 + this.berthRate)); + + var berth = this.height * this.berthRate; + + if (this.orientation == 'left') { + this.element.style.top = -1 * berth + 'px'; + } + }, + + render: function() { + + if (this._renderHeight !== undefined && this.graph.height !== this._renderHeight) this.setSize({ auto: true }); + + this.ticks = this.staticTicks || Math.floor(this.graph.height / this.pixelsPerTick); + + var axis = this._drawAxis(this.graph.y); + + this._drawGrid(axis); + + this._renderHeight = this.graph.height; + }, + + _drawAxis: function(scale) { + var axis = d3.svg.axis().scale(scale).orient(this.orientation); + axis.tickFormat(this.tickFormat); + if (this.tickValues) axis.tickValues(this.tickValues); + + if (this.orientation == 'left') { + var berth = this.height * this.berthRate; + var transform = 'translate(' + this.width + ', ' + berth + ')'; + } + + if (this.element) { + this.vis.selectAll('*').remove(); + } + + this.vis + .append("svg:g") + .attr("class", ["y_ticks", this.ticksTreatment].join(" ")) + .attr("transform", transform) + .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize)); + + return axis; + }, + + _drawGrid: function(axis) { + var gridSize = (this.orientation == 'right' ? 1 : -1) * this.graph.width; + + this.graph.vis + .append("svg:g") + .attr("class", "y_grid") + .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)) + .selectAll('text') + .each(function() { this.parentNode.setAttribute('data-y-value', this.textContent) }); + } +} ); +Rickshaw.namespace('Rickshaw.Graph.Axis.Y.Scaled'); + +Rickshaw.Graph.Axis.Y.Scaled = Rickshaw.Class.create( Rickshaw.Graph.Axis.Y, { + + initialize: function($super, args) { + + if (typeof(args.scale) === 'undefined') { + throw new Error('Scaled requires scale'); + } + + this.scale = args.scale; + + if (typeof(args.grid) === 'undefined') { + this.grid = true; + } else { + this.grid = args.grid; + } + + $super(args); + + }, + + _drawAxis: function($super, scale) { + // Adjust scale's domain to compensate for adjustments to the + // renderer's domain (e.g. padding). + var domain = this.scale.domain(); + var renderDomain = this.graph.renderer.domain().y; + + var extents = [ + Math.min.apply(Math, domain), + Math.max.apply(Math, domain)]; + + // A mapping from the ideal render domain [0, 1] to the extent + // of the original scale's domain. This is used to calculate + // the extents of the adjusted domain. + var extentMap = d3.scale.linear().domain([0, 1]).range(extents); + + var adjExtents = [ + extentMap(renderDomain[0]), + extentMap(renderDomain[1])]; + + // A mapping from the original domain to the adjusted domain. + var adjustment = d3.scale.linear().domain(extents).range(adjExtents); + + // Make a copy of the custom scale, apply the adjusted domain, and + // copy the range to match the graph's scale. + var adjustedScale = this.scale.copy() + .domain(domain.map(adjustment)) + .range(scale.range()); + + return $super(adjustedScale); + }, + + _drawGrid: function($super, axis) { + if (this.grid) { + // only draw the axis if the grid option is true + $super(axis); + } + } +} ); +Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Highlight'); + +Rickshaw.Graph.Behavior.Series.Highlight = function(args) { + + this.graph = args.graph; + this.legend = args.legend; + + var self = this; + + var colorSafe = {}; + var activeLine = null; + + var disabledColor = args.disabledColor || function(seriesColor) { + return d3.interpolateRgb(seriesColor, d3.rgb('#d8d8d8'))(0.8).toString(); + }; + + this.addHighlightEvents = function (l) { + + l.element.addEventListener( 'mouseover', function(e) { + + if (activeLine) return; + else activeLine = l; + + self.legend.lines.forEach( function(line) { + + if (l === line) { + + // if we're not in a stacked renderer bring active line to the top + if (self.graph.renderer.unstack && (line.series.renderer ? line.series.renderer.unstack : true)) { + + var seriesIndex = self.graph.series.indexOf(line.series); + line.originalIndex = seriesIndex; + + var series = self.graph.series.splice(seriesIndex, 1)[0]; + self.graph.series.push(series); + } + return; + } + + colorSafe[line.series.name] = colorSafe[line.series.name] || line.series.color; + line.series.color = disabledColor(line.series.color); + + } ); + + self.graph.update(); + + }, false ); + + l.element.addEventListener( 'mouseout', function(e) { + + if (!activeLine) return; + else activeLine = null; + + self.legend.lines.forEach( function(line) { + + // return reordered series to its original place + if (l === line && line.hasOwnProperty('originalIndex')) { + + var series = self.graph.series.pop(); + self.graph.series.splice(line.originalIndex, 0, series); + delete line.originalIndex; + } + + if (colorSafe[line.series.name]) { + line.series.color = colorSafe[line.series.name]; + } + } ); + + self.graph.update(); + + }, false ); + }; + + if (this.legend) { + this.legend.lines.forEach( function(l) { + self.addHighlightEvents(l); + } ); + } + +}; +Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Order'); + +Rickshaw.Graph.Behavior.Series.Order = function(args) { + + this.graph = args.graph; + this.legend = args.legend; + + var self = this; + + if (typeof window.$ == 'undefined') { + throw "couldn't find jQuery at window.$"; + } + + if (typeof window.$.ui == 'undefined') { + throw "couldn't find jQuery UI at window.$.ui"; + } + + $(function() { + $(self.legend.list).sortable( { + containment: 'parent', + tolerance: 'pointer', + update: function( event, ui ) { + var series = []; + $(self.legend.list).find('li').each( function(index, item) { + if (!item.series) return; + series.push(item.series); + } ); + + for (var i = self.graph.series.length - 1; i >= 0; i--) { + self.graph.series[i] = series.shift(); + } + + self.graph.update(); + } + } ); + $(self.legend.list).disableSelection(); + }); + + //hack to make jquery-ui sortable behave + this.graph.onUpdate( function() { + var h = window.getComputedStyle(self.legend.element).height; + self.legend.element.style.height = h; + } ); +}; +Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Toggle'); + +Rickshaw.Graph.Behavior.Series.Toggle = function(args) { + + this.graph = args.graph; + this.legend = args.legend; + + var self = this; + + this.addAnchor = function(line) { + var anchor = document.createElement('a'); + anchor.innerHTML = '✔'; + anchor.classList.add('action'); + line.element.insertBefore(anchor, line.element.firstChild); + + anchor.onclick = function(e) { + if (line.series.disabled) { + line.series.enable(); + line.element.classList.remove('disabled'); + } else { + if (this.graph.series.filter(function(s) { return !s.disabled }).length <= 1) return; + line.series.disable(); + line.element.classList.add('disabled'); + } + + }.bind(this); + + var label = line.element.getElementsByTagName('span')[0]; + label.onclick = function(e){ + + var disableAllOtherLines = line.series.disabled; + if ( ! disableAllOtherLines ) { + for ( var i = 0; i < self.legend.lines.length; i++ ) { + var l = self.legend.lines[i]; + if ( line.series === l.series ) { + // noop + } else if ( l.series.disabled ) { + // noop + } else { + disableAllOtherLines = true; + break; + } + } + } + + // show all or none + if ( disableAllOtherLines ) { + + // these must happen first or else we try ( and probably fail ) to make a no line graph + line.series.enable(); + line.element.classList.remove('disabled'); + + self.legend.lines.forEach(function(l){ + if ( line.series === l.series ) { + // noop + } else { + l.series.disable(); + l.element.classList.add('disabled'); + } + }); + + } else { + + self.legend.lines.forEach(function(l){ + l.series.enable(); + l.element.classList.remove('disabled'); + }); + + } + + }; + + }; + + if (this.legend) { + + if (typeof $ != 'undefined' && $(this.legend.list).sortable) { + + $(this.legend.list).sortable( { + start: function(event, ui) { + ui.item.bind('no.onclick', + function(event) { + event.preventDefault(); + } + ); + }, + stop: function(event, ui) { + setTimeout(function(){ + ui.item.unbind('no.onclick'); + }, 250); + } + }); + } + + this.legend.lines.forEach( function(l) { + self.addAnchor(l); + } ); + } + + this._addBehavior = function() { + + this.graph.series.forEach( function(s) { + + s.disable = function() { + + if (self.graph.series.length <= 1) { + throw('only one series left'); + } + + s.disabled = true; + self.graph.update(); + }; + + s.enable = function() { + s.disabled = false; + self.graph.update(); + }; + } ); + }; + this._addBehavior(); + + this.updateBehaviour = function () { this._addBehavior() }; + +}; +Rickshaw.namespace('Rickshaw.Graph.HoverDetail'); + +Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({ + + initialize: function(args) { + + var graph = this.graph = args.graph; + + this.xFormatter = args.xFormatter || function(x) { + return new Date( x * 1000 ).toUTCString(); + }; + + this.yFormatter = args.yFormatter || function(y) { + return y === null ? y : y.toFixed(2); + }; + + var element = this.element = document.createElement('div'); + element.className = 'detail'; + + this.visible = true; + graph.element.appendChild(element); + + this.lastEvent = null; + this._addListeners(); + + this.onShow = args.onShow; + this.onHide = args.onHide; + this.onRender = args.onRender; + + this.formatter = args.formatter || this.formatter; + + }, + + formatter: function(series, x, y, formattedX, formattedY, d) { + return series.name + ': ' + formattedY; + }, + + update: function(e) { + + e = e || this.lastEvent; + if (!e) return; + this.lastEvent = e; + + if (!e.target.nodeName.match(/^(path|svg|rect|circle)$/)) return; + + var graph = this.graph; + + var eventX = e.offsetX || e.layerX; + var eventY = e.offsetY || e.layerY; + + var j = 0; + var points = []; + var nearestPoint; + + this.graph.series.active().forEach( function(series) { + + var data = this.graph.stackedData[j++]; + + if (!data.length) + return; + + var domainX = graph.x.invert(eventX); + + var domainIndexScale = d3.scale.linear() + .domain([data[0].x, data.slice(-1)[0].x]) + .range([0, data.length - 1]); + + var approximateIndex = Math.round(domainIndexScale(domainX)); + if (approximateIndex == data.length - 1) approximateIndex--; + + var dataIndex = Math.min(approximateIndex || 0, data.length - 1); + + for (var i = approximateIndex; i < data.length - 1;) { + + if (!data[i] || !data[i + 1]) break; + + if (data[i].x <= domainX && data[i + 1].x > domainX) { + dataIndex = Math.abs(domainX - data[i].x) < Math.abs(domainX - data[i + 1].x) ? i : i + 1; + break; + } + + if (data[i + 1].x <= domainX) { i++ } else { i-- } + } + + if (dataIndex < 0) dataIndex = 0; + var value = data[dataIndex]; + + var distance = Math.sqrt( + Math.pow(Math.abs(graph.x(value.x) - eventX), 2) + + Math.pow(Math.abs(graph.y(value.y + value.y0) - eventY), 2) + ); + + var xFormatter = series.xFormatter || this.xFormatter; + var yFormatter = series.yFormatter || this.yFormatter; + + var point = { + formattedXValue: xFormatter(value.x), + formattedYValue: yFormatter(series.scale ? series.scale.invert(value.y) : value.y), + series: series, + value: value, + distance: distance, + order: j, + name: series.name + }; + + if (!nearestPoint || distance < nearestPoint.distance) { + nearestPoint = point; + } + + points.push(point); + + }, this ); + + if (!nearestPoint) + return; + + nearestPoint.active = true; + + var domainX = nearestPoint.value.x; + var formattedXValue = nearestPoint.formattedXValue; + + this.element.innerHTML = ''; + this.element.style.left = graph.x(domainX) + 'px'; + + this.visible && this.render( { + points: points, + detail: points, // for backwards compatibility + mouseX: eventX, + mouseY: eventY, + formattedXValue: formattedXValue, + domainX: domainX + } ); + }, + + hide: function() { + this.visible = false; + this.element.classList.add('inactive'); + + if (typeof this.onHide == 'function') { + this.onHide(); + } + }, + + show: function() { + this.visible = true; + this.element.classList.remove('inactive'); + + if (typeof this.onShow == 'function') { + this.onShow(); + } + }, + + render: function(args) { + + var graph = this.graph; + var points = args.points; + var point = points.filter( function(p) { return p.active } ).shift(); + + if (point.value.y === null) return; + + var formattedXValue = point.formattedXValue; + var formattedYValue = point.formattedYValue; + + this.element.innerHTML = ''; + this.element.style.left = graph.x(point.value.x) + 'px'; + + var xLabel = document.createElement('div'); + + xLabel.className = 'x_label'; + xLabel.innerHTML = formattedXValue; + this.element.appendChild(xLabel); + + var item = document.createElement('div'); + + item.className = 'item'; + + // invert the scale if this series displays using a scale + var series = point.series; + var actualY = series.scale ? series.scale.invert(point.value.y) : point.value.y; + + item.innerHTML = this.formatter(series, point.value.x, actualY, formattedXValue, formattedYValue, point); + item.style.top = this.graph.y(point.value.y0 + point.value.y) + 'px'; + + this.element.appendChild(item); + + var dot = document.createElement('div'); + + dot.className = 'dot'; + dot.style.top = item.style.top; + dot.style.borderColor = series.color; + + this.element.appendChild(dot); + + if (point.active) { + item.classList.add('active'); + dot.classList.add('active'); + } + + // Assume left alignment until the element has been displayed and + // bounding box calculations are possible. + var alignables = [xLabel, item]; + alignables.forEach(function(el) { + el.classList.add('left'); + }); + + this.show(); + + // If left-alignment results in any error, try right-alignment. + var leftAlignError = this._calcLayoutError(alignables); + if (leftAlignError > 0) { + alignables.forEach(function(el) { + el.classList.remove('left'); + el.classList.add('right'); + }); + + // If right-alignment is worse than left alignment, switch back. + var rightAlignError = this._calcLayoutError(alignables); + if (rightAlignError > leftAlignError) { + alignables.forEach(function(el) { + el.classList.remove('right'); + el.classList.add('left'); + }); + } + } + + if (typeof this.onRender == 'function') { + this.onRender(args); + } + }, + + _calcLayoutError: function(alignables) { + // Layout error is calculated as the number of linear pixels by which + // an alignable extends past the left or right edge of the parent. + var parentRect = this.element.parentNode.getBoundingClientRect(); + + var error = 0; + var alignRight = alignables.forEach(function(el) { + var rect = el.getBoundingClientRect(); + if (!rect.width) { + return; + } + + if (rect.right > parentRect.right) { + error += rect.right - parentRect.right; + } + + if (rect.left < parentRect.left) { + error += parentRect.left - rect.left; + } + }); + return error; + }, + + _addListeners: function() { + + this.graph.element.addEventListener( + 'mousemove', + function(e) { + this.visible = true; + this.update(e); + }.bind(this), + false + ); + + this.graph.onUpdate( function() { this.update() }.bind(this) ); + + this.graph.element.addEventListener( + 'mouseout', + function(e) { + if (e.relatedTarget && !(e.relatedTarget.compareDocumentPosition(this.graph.element) & Node.DOCUMENT_POSITION_CONTAINS)) { + this.hide(); + } + }.bind(this), + false + ); + } +}); +Rickshaw.namespace('Rickshaw.Graph.JSONP'); + +Rickshaw.Graph.JSONP = Rickshaw.Class.create( Rickshaw.Graph.Ajax, { + + request: function() { + + $.ajax( { + url: this.dataURL, + dataType: 'jsonp', + success: this.success.bind(this), + error: this.error.bind(this) + } ); + } +} ); +Rickshaw.namespace('Rickshaw.Graph.Legend'); + +Rickshaw.Graph.Legend = Rickshaw.Class.create( { + + className: 'rickshaw_legend', + + initialize: function(args) { + this.element = args.element; + this.graph = args.graph; + this.naturalOrder = args.naturalOrder; + + this.element.classList.add(this.className); + + this.list = document.createElement('ul'); + this.element.appendChild(this.list); + + this.render(); + + // we could bind this.render.bind(this) here + // but triggering the re-render would lose the added + // behavior of the series toggle + this.graph.onUpdate( function() {} ); + }, + + render: function() { + var self = this; + + while ( this.list.firstChild ) { + this.list.removeChild( this.list.firstChild ); + } + this.lines = []; + + var series = this.graph.series + .map( function(s) { return s } ); + + if (!this.naturalOrder) { + series = series.reverse(); + } + + series.forEach( function(s) { + self.addLine(s); + } ); + + + }, + + addLine: function (series) { + var line = document.createElement('li'); + line.className = 'line'; + if (series.disabled) { + line.className += ' disabled'; + } + if (series.className) { + d3.select(line).classed(series.className, true); + } + var swatch = document.createElement('div'); + swatch.className = 'swatch'; + swatch.style.backgroundColor = series.color; + + line.appendChild(swatch); + + var label = document.createElement('span'); + label.className = 'label'; + label.innerHTML = series.name; + + line.appendChild(label); + this.list.appendChild(line); + + line.series = series; + + if (series.noLegend) { + line.style.display = 'none'; + } + + var _line = { element: line, series: series }; + if (this.shelving) { + this.shelving.addAnchor(_line); + this.shelving.updateBehaviour(); + } + if (this.highlighter) { + this.highlighter.addHighlightEvents(_line); + } + this.lines.push(_line); + return line; + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.RangeSlider'); + +Rickshaw.Graph.RangeSlider = Rickshaw.Class.create({ + + initialize: function(args) { + + var element = this.element = args.element; + var graph = this.graph = args.graph; + + this.build(); + + graph.onUpdate( function() { this.update() }.bind(this) ); + }, + + build: function() { + + var element = this.element; + var graph = this.graph; + + var domain = graph.dataDomain(); + + $( function() { + $(element).slider( { + range: true, + min: domain[0], + max: domain[1], + values: [ + domain[0], + domain[1] + ], + slide: function( event, ui ) { + + if (ui.values[1] <= ui.values[0]) return; + + graph.window.xMin = ui.values[0]; + graph.window.xMax = ui.values[1]; + graph.update(); + + var domain = graph.dataDomain(); + + // if we're at an extreme, stick there + if (domain[0] == ui.values[0]) { + graph.window.xMin = undefined; + } + if (domain[1] == ui.values[1]) { + graph.window.xMax = undefined; + } + } + } ); + } ); + + $(element)[0].style.width = graph.width + 'px'; + + }, + + update: function() { + + var element = this.element; + var graph = this.graph; + + var values = $(element).slider('option', 'values'); + + var domain = graph.dataDomain(); + + $(element).slider('option', 'min', domain[0]); + $(element).slider('option', 'max', domain[1]); + + if (graph.window.xMin == null) { + values[0] = domain[0]; + } + if (graph.window.xMax == null) { + values[1] = domain[1]; + } + + $(element).slider('option', 'values', values); + } +}); + +Rickshaw.namespace('Rickshaw.Graph.RangeSlider.Preview'); + +Rickshaw.Graph.RangeSlider.Preview = Rickshaw.Class.create({ + + initialize: function(args) { + + if (!args.element) throw "Rickshaw.Graph.RangeSlider.Preview needs a reference to an element"; + if (!args.graph && !args.graphs) throw "Rickshaw.Graph.RangeSlider.Preview needs a reference to an graph or an array of graphs"; + + this.element = args.element; + this.graphs = args.graph ? [ args.graph ] : args.graphs; + + this.defaults = { + height: 75, + width: 400, + gripperColor: undefined, + frameTopThickness: 3, + frameHandleThickness: 10, + frameColor: "#d4d4d4", + frameOpacity: 1, + minimumFrameWidth: 0 + }; + + this.defaults.gripperColor = d3.rgb(this.defaults.frameColor).darker().toString(); + + this.configureCallbacks = []; + this.previews = []; + + args.width = args.width || this.graphs[0].width || this.defaults.width; + args.height = args.height || this.graphs[0].height / 5 || this.defaults.height; + + this.configure(args); + this.render(); + }, + + onConfigure: function(callback) { + this.configureCallbacks.push(callback); + }, + + configure: function(args) { + + this.config = {}; + + this.configureCallbacks.forEach(function(callback) { + callback(args); + }); + + Rickshaw.keys(this.defaults).forEach(function(k) { + this.config[k] = k in args ? args[k] + : k in this.config ? this.config[k] + : this.defaults[k]; + }, this); + + if (args.width) { + this.previews.forEach(function(preview) { + var width = args.width - this.config.frameHandleThickness * 2; + preview.setSize({ width: width }); + }, this); + } + + if (args.height) { + this.previews.forEach(function(preview) { + var height = this.previewHeight / this.graphs.length; + preview.setSize({ height: height }); + }, this); + } + }, + + render: function() { + + var self = this; + + this.svg = d3.select(this.element) + .selectAll("svg.rickshaw_range_slider_preview") + .data([null]); + + this.previewHeight = this.config.height - (this.config.frameTopThickness * 2); + this.previewWidth = this.config.width - (this.config.frameHandleThickness * 2); + + this.currentFrame = [0, this.previewWidth]; + + var buildGraph = function(parent, index) { + + var graphArgs = Rickshaw.extend({}, parent.config); + var height = self.previewHeight / self.graphs.length; + + Rickshaw.extend(graphArgs, { + element: this.appendChild(document.createElement("div")), + height: height, + width: self.previewWidth, + series: parent.series + }); + + var graph = new Rickshaw.Graph(graphArgs); + self.previews.push(graph); + + parent.onUpdate(function() { graph.render(); self.render() }); + + parent.onConfigure(function(args) { + // don't propagate height + delete args.height; + graph.configure(args); + graph.render(); + }); + + graph.render(); + }; + + var graphContainer = d3.select(this.element) + .selectAll("div.rickshaw_range_slider_preview_container") + .data(this.graphs); + + var translateCommand = "translate(" + + this.config.frameHandleThickness + "px, " + + this.config.frameTopThickness + "px)"; + + graphContainer.enter() + .append("div") + .classed("rickshaw_range_slider_preview_container", true) + .style("-webkit-transform", translateCommand) + .style("-moz-transform", translateCommand) + .style("-ms-transform", translateCommand) + .style("transform", translateCommand) + .each(buildGraph); + + graphContainer.exit() + .remove(); + + // Use the first graph as the "master" for the frame state + var masterGraph = this.graphs[0]; + + var domainScale = d3.scale.linear() + .domain([0, this.previewWidth]) + .range(masterGraph.dataDomain()); + + var currentWindow = [masterGraph.window.xMin, masterGraph.window.xMax]; + + this.currentFrame[0] = currentWindow[0] === undefined ? + 0 : Math.round(domainScale.invert(currentWindow[0])); + + if (this.currentFrame[0] < 0) this.currentFrame[0] = 0; + + this.currentFrame[1] = currentWindow[1] === undefined ? + this.previewWidth : domainScale.invert(currentWindow[1]); + + if (this.currentFrame[1] - this.currentFrame[0] < self.config.minimumFrameWidth) { + this.currentFrame[1] = (this.currentFrame[0] || 0) + self.config.minimumFrameWidth; + } + + this.svg.enter() + .append("svg") + .classed("rickshaw_range_slider_preview", true) + .style("height", this.config.height + "px") + .style("width", this.config.width + "px") + .style("position", "relative") + .style("top", -this.previewHeight + "px"); + + this._renderDimming(); + this._renderFrame(); + this._renderGrippers(); + this._renderHandles(); + this._renderMiddle(); + + this._registerMouseEvents(); + }, + + _renderDimming: function() { + + var element = this.svg + .selectAll("path.dimming") + .data([null]); + + element.enter() + .append("path") + .attr("fill", "white") + .attr("fill-opacity", "0.7") + .attr("fill-rule", "evenodd") + .classed("dimming", true); + + var path = ""; + path += " M " + this.config.frameHandleThickness + " " + this.config.frameTopThickness; + path += " h " + this.previewWidth; + path += " v " + this.previewHeight; + path += " h " + -this.previewWidth; + path += " z "; + path += " M " + Math.max(this.currentFrame[0], this.config.frameHandleThickness) + " " + this.config.frameTopThickness; + path += " H " + Math.min(this.currentFrame[1] + this.config.frameHandleThickness * 2, this.previewWidth + this.config.frameHandleThickness); + path += " v " + this.previewHeight; + path += " H " + Math.max(this.currentFrame[0], this.config.frameHandleThickness); + path += " z"; + + element.attr("d", path); + }, + + _renderFrame: function() { + + var element = this.svg + .selectAll("path.frame") + .data([null]); + + element.enter() + .append("path") + .attr("stroke", "white") + .attr("stroke-width", "1px") + .attr("stroke-linejoin", "round") + .attr("fill", this.config.frameColor) + .attr("fill-opacity", this.config.frameOpacity) + .attr("fill-rule", "evenodd") + .classed("frame", true); + + var path = ""; + path += " M " + this.currentFrame[0] + " 0"; + path += " H " + (this.currentFrame[1] + (this.config.frameHandleThickness * 2)); + path += " V " + this.config.height; + path += " H " + (this.currentFrame[0]); + path += " z"; + path += " M " + (this.currentFrame[0] + this.config.frameHandleThickness) + " " + this.config.frameTopThickness; + path += " H " + (this.currentFrame[1] + this.config.frameHandleThickness); + path += " v " + this.previewHeight; + path += " H " + (this.currentFrame[0] + this.config.frameHandleThickness); + path += " z"; + + element.attr("d", path); + }, + + _renderGrippers: function() { + + var gripper = this.svg.selectAll("path.gripper") + .data([null]); + + gripper.enter() + .append("path") + .attr("stroke", this.config.gripperColor) + .classed("gripper", true); + + var path = ""; + + [0.4, 0.6].forEach(function(spacing) { + path += " M " + Math.round((this.currentFrame[0] + (this.config.frameHandleThickness * spacing))) + " " + Math.round(this.config.height * 0.3); + path += " V " + Math.round(this.config.height * 0.7); + path += " M " + Math.round((this.currentFrame[1] + (this.config.frameHandleThickness * (1 + spacing)))) + " " + Math.round(this.config.height * 0.3); + path += " V " + Math.round(this.config.height * 0.7); + }.bind(this)); + + gripper.attr("d", path); + }, + + _renderHandles: function() { + + var leftHandle = this.svg.selectAll("rect.left_handle") + .data([null]); + + leftHandle.enter() + .append("rect") + .attr('width', this.config.frameHandleThickness) + .attr('height', this.config.height) + .style("cursor", "ew-resize") + .style("fill-opacity", "0") + .classed("left_handle", true); + + leftHandle.attr('x', this.currentFrame[0]); + + var rightHandle = this.svg.selectAll("rect.right_handle") + .data([null]); + + rightHandle.enter() + .append("rect") + .attr('width', this.config.frameHandleThickness) + .attr('height', this.config.height) + .style("cursor", "ew-resize") + .style("fill-opacity", "0") + .classed("right_handle", true); + + rightHandle.attr('x', this.currentFrame[1] + this.config.frameHandleThickness); + }, + + _renderMiddle: function() { + + var middleHandle = this.svg.selectAll("rect.middle_handle") + .data([null]); + + middleHandle.enter() + .append("rect") + .attr('height', this.config.height) + .style("cursor", "move") + .style("fill-opacity", "0") + .classed("middle_handle", true); + + middleHandle + .attr('width', Math.max(0, this.currentFrame[1] - this.currentFrame[0])) + .attr('x', this.currentFrame[0] + this.config.frameHandleThickness); + }, + + _registerMouseEvents: function() { + + var element = d3.select(this.element); + + var drag = { + target: null, + start: null, + stop: null, + left: false, + right: false, + rigid: false + }; + + var self = this; + + function onMousemove(datum, index) { + + drag.stop = self._getClientXFromEvent(d3.event, drag); + var distanceTraveled = drag.stop - drag.start; + var frameAfterDrag = self.frameBeforeDrag.slice(0); + var minimumFrameWidth = self.config.minimumFrameWidth; + + if (drag.rigid) { + minimumFrameWidth = self.frameBeforeDrag[1] - self.frameBeforeDrag[0]; + } + if (drag.left) { + frameAfterDrag[0] = Math.max(frameAfterDrag[0] + distanceTraveled, 0); + } + if (drag.right) { + frameAfterDrag[1] = Math.min(frameAfterDrag[1] + distanceTraveled, self.previewWidth); + } + + var currentFrameWidth = frameAfterDrag[1] - frameAfterDrag[0]; + + if (currentFrameWidth <= minimumFrameWidth) { + + if (drag.left) { + frameAfterDrag[0] = frameAfterDrag[1] - minimumFrameWidth; + } + if (drag.right) { + frameAfterDrag[1] = frameAfterDrag[0] + minimumFrameWidth; + } + if (frameAfterDrag[0] <= 0) { + frameAfterDrag[1] -= frameAfterDrag[0]; + frameAfterDrag[0] = 0; + } + if (frameAfterDrag[1] >= self.previewWidth) { + frameAfterDrag[0] -= (frameAfterDrag[1] - self.previewWidth); + frameAfterDrag[1] = self.previewWidth; + } + } + + self.graphs.forEach(function(graph) { + + var domainScale = d3.scale.linear() + .interpolate(d3.interpolateRound) + .domain([0, self.previewWidth]) + .range(graph.dataDomain()); + + var windowAfterDrag = [ + domainScale(frameAfterDrag[0]), + domainScale(frameAfterDrag[1]) + ]; + + if (frameAfterDrag[0] === 0) { + windowAfterDrag[0] = undefined; + } + if (frameAfterDrag[1] === self.previewWidth) { + windowAfterDrag[1] = undefined; + } + graph.window.xMin = windowAfterDrag[0]; + graph.window.xMax = windowAfterDrag[1]; + + graph.update(); + }); + } + + function onMousedown() { + drag.target = d3.event.target; + drag.start = self._getClientXFromEvent(d3.event, drag); + self.frameBeforeDrag = self.currentFrame.slice(); + d3.event.preventDefault ? d3.event.preventDefault() : d3.event.returnValue = false; + d3.select(document).on("mousemove.rickshaw_range_slider_preview", onMousemove); + d3.select(document).on("mouseup.rickshaw_range_slider_preview", onMouseup); + d3.select(document).on("touchmove.rickshaw_range_slider_preview", onMousemove); + d3.select(document).on("touchend.rickshaw_range_slider_preview", onMouseup); + d3.select(document).on("touchcancel.rickshaw_range_slider_preview", onMouseup); + } + + function onMousedownLeftHandle(datum, index) { + drag.left = true; + onMousedown(); + } + + function onMousedownRightHandle(datum, index) { + drag.right = true; + onMousedown(); + } + + function onMousedownMiddleHandle(datum, index) { + drag.left = true; + drag.right = true; + drag.rigid = true; + onMousedown(); + } + + function onMouseup(datum, index) { + d3.select(document).on("mousemove.rickshaw_range_slider_preview", null); + d3.select(document).on("mouseup.rickshaw_range_slider_preview", null); + d3.select(document).on("touchmove.rickshaw_range_slider_preview", null); + d3.select(document).on("touchend.rickshaw_range_slider_preview", null); + d3.select(document).on("touchcancel.rickshaw_range_slider_preview", null); + delete self.frameBeforeDrag; + drag.left = false; + drag.right = false; + drag.rigid = false; + } + + element.select("rect.left_handle").on("mousedown", onMousedownLeftHandle); + element.select("rect.right_handle").on("mousedown", onMousedownRightHandle); + element.select("rect.middle_handle").on("mousedown", onMousedownMiddleHandle); + element.select("rect.left_handle").on("touchstart", onMousedownLeftHandle); + element.select("rect.right_handle").on("touchstart", onMousedownRightHandle); + element.select("rect.middle_handle").on("touchstart", onMousedownMiddleHandle); + }, + + _getClientXFromEvent: function(event, drag) { + + switch (event.type) { + case 'touchstart': + case 'touchmove': + var touchList = event.changedTouches; + var touch = null; + for (var touchIndex = 0; touchIndex < touchList.length; touchIndex++) { + if (touchList[touchIndex].target === drag.target) { + touch = touchList[touchIndex]; + break; + } + } + return touch !== null ? touch.clientX : undefined; + + default: + return event.clientX; + } + } +}); + +Rickshaw.namespace("Rickshaw.Graph.Renderer"); + +Rickshaw.Graph.Renderer = Rickshaw.Class.create( { + + initialize: function(args) { + this.graph = args.graph; + this.tension = args.tension || this.tension; + this.configure(args); + }, + + seriesPathFactory: function() { + //implement in subclass + }, + + seriesStrokeFactory: function() { + // implement in subclass + }, + + defaults: function() { + return { + tension: 0.8, + strokeWidth: 2, + unstack: true, + padding: { top: 0.01, right: 0, bottom: 0.01, left: 0 }, + stroke: false, + fill: false + }; + }, + + domain: function(data) { + + var stackedData = data || this.graph.stackedData || this.graph.stackData(); + var firstPoint = stackedData[0][0]; + + if (firstPoint === undefined) { + return { x: [null, null], y: [null, null] }; + } + + var xMin = firstPoint.x; + var xMax = firstPoint.x; + + var yMin = firstPoint.y + firstPoint.y0; + var yMax = firstPoint.y + firstPoint.y0; + + stackedData.forEach( function(series) { + + series.forEach( function(d) { + + if (d.y == null) return; + + var y = d.y + d.y0; + + if (y < yMin) yMin = y; + if (y > yMax) yMax = y; + } ); + + if (!series.length) return; + + if (series[0].x < xMin) xMin = series[0].x; + if (series[series.length - 1].x > xMax) xMax = series[series.length - 1].x; + } ); + + xMin -= (xMax - xMin) * this.padding.left; + xMax += (xMax - xMin) * this.padding.right; + + yMin = this.graph.min === 'auto' ? yMin : this.graph.min || 0; + yMax = this.graph.max === undefined ? yMax : this.graph.max; + + if (this.graph.min === 'auto' || yMin < 0) { + yMin -= (yMax - yMin) * this.padding.bottom; + } + + if (this.graph.max === undefined) { + yMax += (yMax - yMin) * this.padding.top; + } + + return { x: [xMin, xMax], y: [yMin, yMax] }; + }, + + render: function(args) { + + args = args || {}; + + var graph = this.graph; + var series = args.series || graph.series; + + var vis = args.vis || graph.vis; + vis.selectAll('*').remove(); + + var data = series + .filter(function(s) { return !s.disabled }) + .map(function(s) { return s.stack }); + + var pathNodes = vis.selectAll("path.path") + .data(data) + .enter().append("svg:path") + .classed('path', true) + .attr("d", this.seriesPathFactory()); + + if (this.stroke) { + var strokeNodes = vis.selectAll('path.stroke') + .data(data) + .enter().append("svg:path") + .classed('stroke', true) + .attr("d", this.seriesStrokeFactory()); + } + + var i = 0; + series.forEach( function(series) { + if (series.disabled) return; + series.path = pathNodes[0][i]; + if (this.stroke) series.stroke = strokeNodes[0][i]; + this._styleSeries(series); + i++; + }, this ); + + }, + + _styleSeries: function(series) { + + var fill = this.fill ? series.color : 'none'; + var stroke = this.stroke ? series.color : 'none'; + + series.path.setAttribute('fill', fill); + series.path.setAttribute('stroke', stroke); + series.path.setAttribute('stroke-width', this.strokeWidth); + + if (series.className) { + d3.select(series.path).classed(series.className, true); + } + if (series.className && this.stroke) { + d3.select(series.stroke).classed(series.className, true); + } + }, + + configure: function(args) { + + args = args || {}; + + Rickshaw.keys(this.defaults()).forEach( function(key) { + + if (!args.hasOwnProperty(key)) { + this[key] = this[key] || this.graph[key] || this.defaults()[key]; + return; + } + + if (typeof this.defaults()[key] == 'object') { + + Rickshaw.keys(this.defaults()[key]).forEach( function(k) { + + this[key][k] = + args[key][k] !== undefined ? args[key][k] : + this[key][k] !== undefined ? this[key][k] : + this.defaults()[key][k]; + }, this ); + + } else { + this[key] = + args[key] !== undefined ? args[key] : + this[key] !== undefined ? this[key] : + this.graph[key] !== undefined ? this.graph[key] : + this.defaults()[key]; + } + + }, this ); + }, + + setStrokeWidth: function(strokeWidth) { + if (strokeWidth !== undefined) { + this.strokeWidth = strokeWidth; + } + }, + + setTension: function(tension) { + if (tension !== undefined) { + this.tension = tension; + } + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.Renderer.Line'); + +Rickshaw.Graph.Renderer.Line = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { + + name: 'line', + + defaults: function($super) { + + return Rickshaw.extend( $super(), { + unstack: true, + fill: false, + stroke: true + } ); + }, + + seriesPathFactory: function() { + + var graph = this.graph; + + var factory = d3.svg.line() + .x( function(d) { return graph.x(d.x) } ) + .y( function(d) { return graph.y(d.y) } ) + .interpolate(this.graph.interpolation).tension(this.tension); + + factory.defined && factory.defined( function(d) { return d.y !== null } ); + return factory; + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.Renderer.Stack'); + +Rickshaw.Graph.Renderer.Stack = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { + + name: 'stack', + + defaults: function($super) { + + return Rickshaw.extend( $super(), { + fill: true, + stroke: false, + unstack: false + } ); + }, + + seriesPathFactory: function() { + + var graph = this.graph; + + var factory = d3.svg.area() + .x( function(d) { return graph.x(d.x) } ) + .y0( function(d) { return graph.y(d.y0) } ) + .y1( function(d) { return graph.y(d.y + d.y0) } ) + .interpolate(this.graph.interpolation).tension(this.tension); + + factory.defined && factory.defined( function(d) { return d.y !== null } ); + return factory; + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.Renderer.Bar'); + +Rickshaw.Graph.Renderer.Bar = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { + + name: 'bar', + + defaults: function($super) { + + var defaults = Rickshaw.extend( $super(), { + gapSize: 0.05, + unstack: false + } ); + + delete defaults.tension; + return defaults; + }, + + initialize: function($super, args) { + args = args || {}; + this.gapSize = args.gapSize || this.gapSize; + $super(args); + }, + + domain: function($super) { + + var domain = $super(); + + var frequentInterval = this._frequentInterval(this.graph.stackedData.slice(-1).shift()); + domain.x[1] += Number(frequentInterval.magnitude); + + return domain; + }, + + barWidth: function(series) { + + var frequentInterval = this._frequentInterval(series.stack); + var barWidth = this.graph.x(series.stack[0].x + frequentInterval.magnitude * (1 - this.gapSize)); + + return barWidth; + }, + + render: function(args) { + + args = args || {}; + + var graph = this.graph; + var series = args.series || graph.series; + + var vis = args.vis || graph.vis; + vis.selectAll('*').remove(); + + var barWidth = this.barWidth(series.active()[0]); + var barXOffset = 0; + + var activeSeriesCount = series.filter( function(s) { return !s.disabled; } ).length; + var seriesBarWidth = this.unstack ? barWidth / activeSeriesCount : barWidth; + + var transform = function(d) { + // add a matrix transform for negative values + var matrix = [ 1, 0, 0, (d.y < 0 ? -1 : 1), 0, (d.y < 0 ? graph.y.magnitude(Math.abs(d.y)) * 2 : 0) ]; + return "matrix(" + matrix.join(',') + ")"; + }; + + series.forEach( function(series) { + + if (series.disabled) return; + + var barWidth = this.barWidth(series); + + var nodes = vis.selectAll("path") + .data(series.stack.filter( function(d) { return d.y !== null } )) + .enter().append("svg:rect") + .attr("x", function(d) { return graph.x(d.x) + barXOffset }) + .attr("y", function(d) { return (graph.y(d.y0 + Math.abs(d.y))) * (d.y < 0 ? -1 : 1 ) }) + .attr("width", seriesBarWidth) + .attr("height", function(d) { return graph.y.magnitude(Math.abs(d.y)) }) + .attr("transform", transform); + + Array.prototype.forEach.call(nodes[0], function(n) { + n.setAttribute('fill', series.color); + } ); + + if (this.unstack) barXOffset += seriesBarWidth; + + }, this ); + }, + + _frequentInterval: function(data) { + + var intervalCounts = {}; + + for (var i = 0; i < data.length - 1; i++) { + var interval = data[i + 1].x - data[i].x; + intervalCounts[interval] = intervalCounts[interval] || 0; + intervalCounts[interval]++; + } + + var frequentInterval = { count: 0, magnitude: 1 }; + + Rickshaw.keys(intervalCounts).forEach( function(i) { + if (frequentInterval.count < intervalCounts[i]) { + frequentInterval = { + count: intervalCounts[i], + magnitude: i + }; + } + } ); + + return frequentInterval; + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.Renderer.Area'); + +Rickshaw.Graph.Renderer.Area = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { + + name: 'area', + + defaults: function($super) { + + return Rickshaw.extend( $super(), { + unstack: false, + fill: false, + stroke: false + } ); + }, + + seriesPathFactory: function() { + + var graph = this.graph; + + var factory = d3.svg.area() + .x( function(d) { return graph.x(d.x) } ) + .y0( function(d) { return graph.y(d.y0) } ) + .y1( function(d) { return graph.y(d.y + d.y0) } ) + .interpolate(graph.interpolation).tension(this.tension); + + factory.defined && factory.defined( function(d) { return d.y !== null } ); + return factory; + }, + + seriesStrokeFactory: function() { + + var graph = this.graph; + + var factory = d3.svg.line() + .x( function(d) { return graph.x(d.x) } ) + .y( function(d) { return graph.y(d.y + d.y0) } ) + .interpolate(graph.interpolation).tension(this.tension); + + factory.defined && factory.defined( function(d) { return d.y !== null } ); + return factory; + }, + + render: function(args) { + + args = args || {}; + + var graph = this.graph; + var series = args.series || graph.series; + + var vis = args.vis || graph.vis; + vis.selectAll('*').remove(); + + // insert or stacked areas so strokes lay on top of areas + var method = this.unstack ? 'append' : 'insert'; + + var data = series + .filter(function(s) { return !s.disabled }) + .map(function(s) { return s.stack }); + + var nodes = vis.selectAll("path") + .data(data) + .enter()[method]("svg:g", 'g'); + + nodes.append("svg:path") + .attr("d", this.seriesPathFactory()) + .attr("class", 'area'); + + if (this.stroke) { + nodes.append("svg:path") + .attr("d", this.seriesStrokeFactory()) + .attr("class", 'line'); + } + + var i = 0; + series.forEach( function(series) { + if (series.disabled) return; + series.path = nodes[0][i++]; + this._styleSeries(series); + }, this ); + }, + + _styleSeries: function(series) { + + if (!series.path) return; + + d3.select(series.path).select('.area') + .attr('fill', series.color); + + if (this.stroke) { + d3.select(series.path).select('.line') + .attr('fill', 'none') + .attr('stroke', series.stroke || d3.interpolateRgb(series.color, 'black')(0.125)) + .attr('stroke-width', this.strokeWidth); + } + + if (series.className) { + series.path.setAttribute('class', series.className); + } + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.Renderer.ScatterPlot'); + +Rickshaw.Graph.Renderer.ScatterPlot = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { + + name: 'scatterplot', + + defaults: function($super) { + + return Rickshaw.extend( $super(), { + unstack: true, + fill: true, + stroke: false, + padding:{ top: 0.01, right: 0.01, bottom: 0.01, left: 0.01 }, + dotSize: 4 + } ); + }, + + initialize: function($super, args) { + $super(args); + }, + + render: function(args) { + + args = args || {}; + + var graph = this.graph; + + var series = args.series || graph.series; + var vis = args.vis || graph.vis; + + var dotSize = this.dotSize; + + vis.selectAll('*').remove(); + + series.forEach( function(series) { + + if (series.disabled) return; + + var nodes = vis.selectAll("path") + .data(series.stack.filter( function(d) { return d.y !== null } )) + .enter().append("svg:circle") + .attr("cx", function(d) { return graph.x(d.x) }) + .attr("cy", function(d) { return graph.y(d.y) }) + .attr("r", function(d) { return ("r" in d) ? d.r : dotSize}); + if (series.className) { + nodes.classed(series.className, true); + } + + Array.prototype.forEach.call(nodes[0], function(n) { + n.setAttribute('fill', series.color); + } ); + + }, this ); + } +} ); +Rickshaw.namespace('Rickshaw.Graph.Renderer.Multi'); + +Rickshaw.Graph.Renderer.Multi = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { + + name: 'multi', + + initialize: function($super, args) { + + $super(args); + }, + + defaults: function($super) { + + return Rickshaw.extend( $super(), { + unstack: true, + fill: false, + stroke: true + } ); + }, + + configure: function($super, args) { + + args = args || {}; + this.config = args; + $super(args); + }, + + domain: function($super) { + + this.graph.stackData(); + + var domains = []; + + var groups = this._groups(); + this._stack(groups); + + groups.forEach( function(group) { + + var data = group.series + .filter( function(s) { return !s.disabled } ) + .map( function(s) { return s.stack }); + + if (!data.length) return; + + var domain = $super(data); + domains.push(domain); + }); + + var xMin = d3.min(domains.map( function(d) { return d.x[0] } )); + var xMax = d3.max(domains.map( function(d) { return d.x[1] } )); + var yMin = d3.min(domains.map( function(d) { return d.y[0] } )); + var yMax = d3.max(domains.map( function(d) { return d.y[1] } )); + + return { x: [xMin, xMax], y: [yMin, yMax] }; + }, + + _groups: function() { + + var graph = this.graph; + + var renderGroups = {}; + + graph.series.forEach( function(series) { + + if (series.disabled) return; + + if (!renderGroups[series.renderer]) { + + var ns = "http://www.w3.org/2000/svg"; + var vis = document.createElementNS(ns, 'g'); + + graph.vis[0][0].appendChild(vis); + + var renderer = graph._renderers[series.renderer]; + + var config = {}; + + var defaults = [ this.defaults(), renderer.defaults(), this.config, this.graph ]; + defaults.forEach(function(d) { Rickshaw.extend(config, d) }); + + renderer.configure(config); + + renderGroups[series.renderer] = { + renderer: renderer, + series: [], + vis: d3.select(vis) + }; + } + + renderGroups[series.renderer].series.push(series); + + }, this); + + var groups = []; + + Object.keys(renderGroups).forEach( function(key) { + var group = renderGroups[key]; + groups.push(group); + }); + + return groups; + }, + + _stack: function(groups) { + + groups.forEach( function(group) { + + var series = group.series + .filter( function(series) { return !series.disabled } ); + + var data = series + .map( function(series) { return series.stack } ); + + if (!group.renderer.unstack) { + + var layout = d3.layout.stack(); + var stackedData = Rickshaw.clone(layout(data)); + + series.forEach( function(series, index) { + series._stack = Rickshaw.clone(stackedData[index]); + }); + } + + }, this ); + + return groups; + + }, + + render: function() { + + this.graph.series.forEach( function(series) { + if (!series.renderer) { + throw new Error("Each series needs a renderer for graph 'multi' renderer"); + } + }); + + this.graph.vis.selectAll('*').remove(); + + var groups = this._groups(); + groups = this._stack(groups); + + groups.forEach( function(group) { + + var series = group.series + .filter( function(series) { return !series.disabled } ); + + series.active = function() { return series }; + + group.renderer.render({ series: series, vis: group.vis }); + series.forEach(function(s) { s.stack = s._stack || s.stack || s.data; }); + }); + } + +} ); +Rickshaw.namespace('Rickshaw.Graph.Renderer.LinePlot'); + +Rickshaw.Graph.Renderer.LinePlot = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { + + name: 'lineplot', + + defaults: function($super) { + + return Rickshaw.extend( $super(), { + unstack: true, + fill: false, + stroke: true, + padding:{ top: 0.01, right: 0.01, bottom: 0.01, left: 0.01 }, + dotSize: 3, + strokeWidth: 2 + } ); + }, + + initialize: function($super, args) { + $super(args); + }, + + seriesPathFactory: function() { + + var graph = this.graph; + + var factory = d3.svg.line() + .x( function(d) { return graph.x(d.x) } ) + .y( function(d) { return graph.y(d.y) } ) + .interpolate(this.graph.interpolation).tension(this.tension); + + factory.defined && factory.defined( function(d) { return d.y !== null } ); + return factory; + }, + + _renderDots: function() { + + var graph = this.graph; + + graph.series.forEach(function(series) { + + if (series.disabled) return; + + var nodes = graph.vis.selectAll("x") + .data(series.stack.filter( function(d) { return d.y !== null } )) + .enter().append("svg:circle") + .attr("cx", function(d) { return graph.x(d.x) }) + .attr("cy", function(d) { return graph.y(d.y) }) + .attr("r", function(d) { return ("r" in d) ? d.r : graph.renderer.dotSize}); + + Array.prototype.forEach.call(nodes[0], function(n) { + if (!n) return; + n.setAttribute('data-color', series.color); + n.setAttribute('fill', 'white'); + n.setAttribute('stroke', series.color); + n.setAttribute('stroke-width', this.strokeWidth); + + }.bind(this)); + + }, this); + }, + + _renderLines: function() { + + var graph = this.graph; + + var nodes = graph.vis.selectAll("path") + .data(this.graph.stackedData) + .enter().append("svg:path") + .attr("d", this.seriesPathFactory()); + + var i = 0; + graph.series.forEach(function(series) { + if (series.disabled) return; + series.path = nodes[0][i++]; + this._styleSeries(series); + }, this); + }, + + render: function() { + + var graph = this.graph; + + graph.vis.selectAll('*').remove(); + + this._renderLines(); + this._renderDots(); + } +} ); + +Rickshaw.namespace('Rickshaw.Graph.Smoother'); + +Rickshaw.Graph.Smoother = Rickshaw.Class.create({ + + initialize: function(args) { + + this.graph = args.graph; + this.element = args.element; + this.aggregationScale = 1; + + this.build(); + + this.graph.stackData.hooks.data.push( { + name: 'smoother', + orderPosition: 50, + f: this.transformer.bind(this) + } ); + }, + + build: function() { + + var self = this; + + if (this.element) { + $( function() { + $(self.element).slider( { + min: 1, + max: 100, + slide: function( event, ui ) { + self.setScale(ui.value); + self.graph.update(); + } + } ); + } ); + } + }, + + setScale: function(scale) { + + if (scale < 1) { + throw "scale out of range: " + scale; + } + + this.aggregationScale = scale; + this.graph.update(); + }, + + transformer: function(data) { + + if (this.aggregationScale == 1) return data; + + var aggregatedData = []; + + data.forEach( function(seriesData) { + + var aggregatedSeriesData = []; + + while (seriesData.length) { + + var avgX = 0, avgY = 0; + var slice = seriesData.splice(0, this.aggregationScale); + + slice.forEach( function(d) { + avgX += d.x / slice.length; + avgY += d.y / slice.length; + } ); + + aggregatedSeriesData.push( { x: avgX, y: avgY } ); + } + + aggregatedData.push(aggregatedSeriesData); + + }.bind(this) ); + + return aggregatedData; + } +}); + +Rickshaw.namespace('Rickshaw.Graph.Socketio'); + +Rickshaw.Graph.Socketio = Rickshaw.Class.create( Rickshaw.Graph.Ajax, { + request: function() { + var socket = io.connect(this.dataURL); + var self = this; + socket.on('rickshaw', function (data) { + self.success(data); + }); + } +} ); +Rickshaw.namespace('Rickshaw.Series'); + +Rickshaw.Series = Rickshaw.Class.create( Array, { + + initialize: function (data, palette, options) { + + options = options || {}; + + this.palette = new Rickshaw.Color.Palette(palette); + + this.timeBase = typeof(options.timeBase) === 'undefined' ? + Math.floor(new Date().getTime() / 1000) : + options.timeBase; + + var timeInterval = typeof(options.timeInterval) == 'undefined' ? + 1000 : + options.timeInterval; + + this.setTimeInterval(timeInterval); + + if (data && (typeof(data) == "object") && Array.isArray(data)) { + data.forEach( function(item) { this.addItem(item) }, this ); + } + }, + + addItem: function(item) { + + if (typeof(item.name) === 'undefined') { + throw('addItem() needs a name'); + } + + item.color = (item.color || this.palette.color(item.name)); + item.data = (item.data || []); + + // backfill, if necessary + if ((item.data.length === 0) && this.length && (this.getIndex() > 0)) { + this[0].data.forEach( function(plot) { + item.data.push({ x: plot.x, y: 0 }); + } ); + } else if (item.data.length === 0) { + item.data.push({ x: this.timeBase - (this.timeInterval || 0), y: 0 }); + } + + this.push(item); + + if (this.legend) { + this.legend.addLine(this.itemByName(item.name)); + } + }, + + addData: function(data, x) { + + var index = this.getIndex(); + + Rickshaw.keys(data).forEach( function(name) { + if (! this.itemByName(name)) { + this.addItem({ name: name }); + } + }, this ); + + this.forEach( function(item) { + item.data.push({ + x: x || (index * this.timeInterval || 1) + this.timeBase, + y: (data[item.name] || 0) + }); + }, this ); + }, + + getIndex: function () { + return (this[0] && this[0].data && this[0].data.length) ? this[0].data.length : 0; + }, + + itemByName: function(name) { + + for (var i = 0; i < this.length; i++) { + if (this[i].name == name) + return this[i]; + } + }, + + setTimeInterval: function(iv) { + this.timeInterval = iv / 1000; + }, + + setTimeBase: function (t) { + this.timeBase = t; + }, + + dump: function() { + + var data = { + timeBase: this.timeBase, + timeInterval: this.timeInterval, + items: [] + }; + + this.forEach( function(item) { + + var newItem = { + color: item.color, + name: item.name, + data: [] + }; + + item.data.forEach( function(plot) { + newItem.data.push({ x: plot.x, y: plot.y }); + } ); + + data.items.push(newItem); + } ); + + return data; + }, + + load: function(data) { + + if (data.timeInterval) { + this.timeInterval = data.timeInterval; + } + + if (data.timeBase) { + this.timeBase = data.timeBase; + } + + if (data.items) { + data.items.forEach( function(item) { + this.push(item); + if (this.legend) { + this.legend.addLine(this.itemByName(item.name)); + } + + }, this ); + } + } +} ); + +Rickshaw.Series.zeroFill = function(series) { + Rickshaw.Series.fill(series, 0); +}; + +Rickshaw.Series.fill = function(series, fill) { + + var x; + var i = 0; + + var data = series.map( function(s) { return s.data } ); + + while ( i < Math.max.apply(null, data.map( function(d) { return d.length } )) ) { + + x = Math.min.apply( null, + data + .filter(function(d) { return d[i] }) + .map(function(d) { return d[i].x }) + ); + + data.forEach( function(d) { + if (!d[i] || d[i].x != x) { + d.splice(i, 0, { x: x, y: fill }); + } + } ); + + i++; + } +}; + +Rickshaw.namespace('Rickshaw.Series.FixedDuration'); + +Rickshaw.Series.FixedDuration = Rickshaw.Class.create(Rickshaw.Series, { + + initialize: function (data, palette, options) { + + options = options || {}; + + if (typeof(options.timeInterval) === 'undefined') { + throw new Error('FixedDuration series requires timeInterval'); + } + + if (typeof(options.maxDataPoints) === 'undefined') { + throw new Error('FixedDuration series requires maxDataPoints'); + } + + this.palette = new Rickshaw.Color.Palette(palette); + this.timeBase = typeof(options.timeBase) === 'undefined' ? Math.floor(new Date().getTime() / 1000) : options.timeBase; + this.setTimeInterval(options.timeInterval); + + if (this[0] && this[0].data && this[0].data.length) { + this.currentSize = this[0].data.length; + this.currentIndex = this[0].data.length; + } else { + this.currentSize = 0; + this.currentIndex = 0; + } + + this.maxDataPoints = options.maxDataPoints; + + + if (data && (typeof(data) == "object") && Array.isArray(data)) { + data.forEach( function (item) { this.addItem(item) }, this ); + this.currentSize += 1; + this.currentIndex += 1; + } + + // reset timeBase for zero-filled values if needed + this.timeBase -= (this.maxDataPoints - this.currentSize) * this.timeInterval; + + // zero-fill up to maxDataPoints size if we don't have that much data yet + if ((typeof(this.maxDataPoints) !== 'undefined') && (this.currentSize < this.maxDataPoints)) { + for (var i = this.maxDataPoints - this.currentSize - 1; i > 1; i--) { + this.currentSize += 1; + this.currentIndex += 1; + this.forEach( function (item) { + item.data.unshift({ x: ((i-1) * this.timeInterval || 1) + this.timeBase, y: 0, i: i }); + }, this ); + } + } + }, + + addData: function($super, data, x) { + + $super(data, x); + + this.currentSize += 1; + this.currentIndex += 1; + + if (this.maxDataPoints !== undefined) { + while (this.currentSize > this.maxDataPoints) { + this.dropData(); + } + } + }, + + dropData: function() { + + this.forEach(function(item) { + item.data.splice(0, 1); + } ); + + this.currentSize -= 1; + }, + + getIndex: function () { + return this.currentIndex; + } +} ); + diff --git a/html/js/rickshaw.min.js b/html/js/rickshaw.min.js new file mode 100644 index 0000000..e9924a4 --- /dev/null +++ b/html/js/rickshaw.min.js @@ -0,0 +1,3 @@ +var Rickshaw={namespace:function(namespace,obj){var parts=namespace.split(".");var parent=Rickshaw;for(var i=1,length=parts.length;i=3){if(s.data[2].xthis.window.xMax)isInRange=false;return isInRange}return true};this.onUpdate=function(callback){this.updateCallbacks.push(callback)};this.onConfigure=function(callback){this.configureCallbacks.push(callback)};this.registerRenderer=function(renderer){this._renderers=this._renderers||{};this._renderers[renderer.name]=renderer};this.configure=function(args){this.config=this.config||{};if(args.width||args.height){this.setSize(args)}Rickshaw.keys(this.defaults).forEach(function(k){this.config[k]=k in args?args[k]:k in this?this[k]:this.defaults[k]},this);Rickshaw.keys(this.config).forEach(function(k){this[k]=this.config[k]},this);var renderer=args.renderer||this.renderer&&this.renderer.name||"stack";this.setRenderer(renderer,args);this.configureCallbacks.forEach(function(callback){callback(args)})};this.setRenderer=function(r,args){if(typeof r=="function"){this.renderer=new r({graph:self});this.registerRenderer(this.renderer)}else{if(!this._renderers[r]){throw"couldn't find renderer "+r}this.renderer=this._renderers[r]}if(typeof args=="object"){this.renderer.configure(args)}};this.setSize=function(args){args=args||{};if(typeof window!==undefined){var style=window.getComputedStyle(this.element,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);var elementHeight=parseInt(style.getPropertyValue("height"),10)}this.width=args.width||elementWidth||400;this.height=args.height||elementHeight||250;this.vis&&this.vis.attr("width",this.width).attr("height",this.height)};this.initialize(args)};Rickshaw.namespace("Rickshaw.Fixtures.Color");Rickshaw.Fixtures.Color=function(){this.schemes={};this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse();this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"];this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"];this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse();this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"};this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse();this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"];this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]};Rickshaw.namespace("Rickshaw.Fixtures.RandomData");Rickshaw.Fixtures.RandomData=function(timeInterval){var addData;timeInterval=timeInterval||1;var lastRandomValue=200;var timeBase=Math.floor((new Date).getTime()/1e3);this.addData=function(data){var randomValue=Math.random()*100+15+lastRandomValue;var index=data[0].length;var counter=1;data.forEach(function(series){var randomVariance=Math.random()*20;var v=randomValue/25+counter++ +(Math.cos(index*counter*11/960)+2)*15+(Math.cos(index/7)+2)*7+(Math.cos(index/17)+2)*1;series.push({x:index*timeInterval+timeBase,y:v+randomVariance})});lastRandomValue=randomValue*.85};this.removeData=function(data){data.forEach(function(series){series.shift()});timeBase+=timeInterval}};Rickshaw.namespace("Rickshaw.Fixtures.Time");Rickshaw.Fixtures.Time=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getUTCFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getUTCFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getUTCMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getUTCDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getUTCMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getUTCMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toUTCString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="month"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),date.getUTCMonth())/1e3;if(floor==time)return time;year=date.getUTCFullYear();var month=date.getUTCMonth();if(month==11){month=0;year=year+1}else{month+=1}return Date.UTC(year,month)/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),0)/1e3;if(floor==time)return time;year=date.getUTCFullYear()+1;return Date.UTC(year,0)/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Time.Local");Rickshaw.Fixtures.Time.Local=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="day"){var nearFuture=new Date((time+unit.seconds-1)*1e3);var rounded=new Date(0);rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);rounded.setDate(nearFuture.getDate());rounded.setMonth(nearFuture.getMonth());rounded.setFullYear(nearFuture.getFullYear());return rounded.getTime()/1e3}if(unit.name=="month"){date=new Date(time*1e3);floor=new Date(date.getFullYear(),date.getMonth()).getTime()/1e3;if(floor==time)return time;year=date.getFullYear();var month=date.getMonth();if(month==11){month=0;year=year+1}else{month+=1}return new Date(year,month).getTime()/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=new Date(date.getUTCFullYear(),0).getTime()/1e3;if(floor==time)return time;year=date.getFullYear()+1;return new Date(year,0).getTime()/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Number");Rickshaw.Fixtures.Number.formatKMBT=function(y){var abs_y=Math.abs(y);if(abs_y>=1e12){return y/1e12+"T"}else if(abs_y>=1e9){return y/1e9+"B"}else if(abs_y>=1e6){return y/1e6+"M"}else if(abs_y>=1e3){return y/1e3+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(y){var abs_y=Math.abs(y);if(abs_y>=0x4000000000000){return y/0x4000000000000+"P"}else if(abs_y>=1099511627776){return y/1099511627776+"T"}else if(abs_y>=1073741824){return y/1073741824+"G"}else if(abs_y>=1048576){return y/1048576+"M"}else if(abs_y>=1024){return y/1024+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.namespace("Rickshaw.Color.Palette");Rickshaw.Color.Palette=function(args){var color=new Rickshaw.Fixtures.Color;args=args||{};this.schemes={};this.scheme=color.schemes[args.scheme]||args.scheme||color.schemes.colorwheel;this.runningIndex=0;this.generatorIndex=0;if(args.interpolatedStopCount){var schemeCount=this.scheme.length-1;var i,j,scheme=[];for(i=0;iself.graph.x.range()[1]){if(annotation.element){annotation.line.classList.add("offscreen");annotation.element.style.display="none"}annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.add("offscreen")});return}if(!annotation.element){var element=annotation.element=document.createElement("div");element.classList.add("annotation");this.elements.timeline.appendChild(element);element.addEventListener("click",function(e){element.classList.toggle("active");annotation.line.classList.toggle("active");annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.toggle("active")})},false)}annotation.element.style.left=left+"px";annotation.element.style.display="block";annotation.boxes.forEach(function(box){var element=box.element;if(!element){element=box.element=document.createElement("div");element.classList.add("content");element.innerHTML=box.content;annotation.element.appendChild(element);annotation.line=document.createElement("div");annotation.line.classList.add("annotation_line");self.graph.element.appendChild(annotation.line);if(box.end){box.rangeElement=document.createElement("div");box.rangeElement.classList.add("annotation_range");self.graph.element.appendChild(box.rangeElement)}}if(box.end){var annotationRangeStart=left;var annotationRangeEnd=Math.min(self.graph.x(box.end),self.graph.x.range()[1]);if(annotationRangeStart>annotationRangeEnd){annotationRangeEnd=left;annotationRangeStart=Math.max(self.graph.x(box.end),self.graph.x.range()[0])}var annotationRangeWidth=annotationRangeEnd-annotationRangeStart;box.rangeElement.style.left=annotationRangeStart+"px";box.rangeElement.style.width=annotationRangeWidth+"px";box.rangeElement.classList.remove("offscreen")}annotation.line.classList.remove("offscreen");annotation.line.style.left=left+"px"})},this)};this.graph.onUpdate(function(){self.update()})};Rickshaw.namespace("Rickshaw.Graph.Axis.Time");Rickshaw.Graph.Axis.Time=function(args){var self=this;this.graph=args.graph;this.elements=[];this.ticksTreatment=args.ticksTreatment||"plain";this.fixedTimeUnit=args.timeUnit;var time=args.timeFixture||new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var unit;var units=time.units;var domain=this.graph.x.domain();var rangeSeconds=domain[1]-domain[0];units.forEach(function(u){if(Math.floor(rangeSeconds/u.seconds)>=2){unit=unit||u}});return unit||time.units[time.units.length-1]};this.tickOffsets=function(){var domain=this.graph.x.domain();var unit=this.fixedTimeUnit||this.appropriateTimeUnit();var count=Math.ceil((domain[1]-domain[0])/unit.seconds);var runningTick=domain[0];var offsets=[];for(var i=0;iself.graph.x.range()[1])return;var element=document.createElement("div");element.style.left=self.graph.x(o.value)+"px";element.classList.add("x_tick");element.classList.add(self.ticksTreatment);var title=document.createElement("div");title.classList.add("title");title.innerHTML=o.unit.formatter(new Date(o.value*1e3));element.appendChild(title);self.graph.element.appendChild(element);self.elements.push(element)})};this.graph.onUpdate(function(){self.render()})};Rickshaw.namespace("Rickshaw.Graph.Axis.X");Rickshaw.Graph.Axis.X=function(args){var self=this;var berthRate=.1;this.initialize=function(args){this.graph=args.graph;this.orientation=args.orientation||"top";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";if(args.element){this.element=args.element;this._discoverSize(args.element,args);this.vis=d3.select(args.element).append("svg:svg").attr("height",this.height).attr("width",this.width).attr("class","rickshaw_graph x_axis_d3");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}this.graph.onUpdate(function(){self.render()})};this.setSize=function(args){args=args||{};if(!this.element)return;this._discoverSize(this.element.parentNode,args);this.vis.attr("height",this.height).attr("width",this.width*(1+berthRate));var berth=Math.floor(this.width*berthRate/2);this.element.style.left=-1*berth+"px"};this.render=function(){if(this._renderWidth!==undefined&&this.graph.width!==this._renderWidth)this.setSize({auto:true});var axis=d3.svg.axis().scale(this.graph.x).orient(this.orientation);axis.tickFormat(args.tickFormat||function(x){return x});if(this.tickValues)axis.tickValues(this.tickValues);this.ticks=this.staticTicks||Math.floor(this.graph.width/this.pixelsPerTick);var berth=Math.floor(this.width*berthRate/2)||0;var transform;if(this.orientation=="top"){var yOffset=this.height||this.graph.height;transform="translate("+berth+","+yOffset+")"}else{transform="translate("+berth+", 0)"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["x_ticks_d3",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var gridSize=(this.orientation=="bottom"?1:-1)*this.graph.height;this.graph.vis.append("svg:g").attr("class","x_grid_d3").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-x-value",this.textContent)});this._renderHeight=this.graph.height};this._discoverSize=function(element,args){if(typeof window!=="undefined"){var style=window.getComputedStyle(element,null);var elementHeight=parseInt(style.getPropertyValue("height"),10);if(!args.auto){var elementWidth=parseInt(style.getPropertyValue("width"),10)}}this.width=(args.width||elementWidth||this.graph.width)*(1+berthRate);this.height=args.height||elementHeight||40};this.initialize(args)};Rickshaw.namespace("Rickshaw.Graph.Axis.Y");Rickshaw.Graph.Axis.Y=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.orientation=args.orientation||"right";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";this.tickFormat=args.tickFormat||function(y){return y};this.berthRate=.1;if(args.element){this.element=args.element;this.vis=d3.select(args.element).append("svg:svg").attr("class","rickshaw_graph y_axis");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}var self=this;this.graph.onUpdate(function(){self.render()})},setSize:function(args){args=args||{};if(!this.element)return;if(typeof window!=="undefined"){var style=window.getComputedStyle(this.element.parentNode,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);if(!args.auto){var elementHeight=parseInt(style.getPropertyValue("height"),10)}}this.width=args.width||elementWidth||this.graph.width*this.berthRate;this.height=args.height||elementHeight||this.graph.height;this.vis.attr("width",this.width).attr("height",this.height*(1+this.berthRate));var berth=this.height*this.berthRate;if(this.orientation=="left"){this.element.style.top=-1*berth+"px"}},render:function(){if(this._renderHeight!==undefined&&this.graph.height!==this._renderHeight)this.setSize({auto:true});this.ticks=this.staticTicks||Math.floor(this.graph.height/this.pixelsPerTick);var axis=this._drawAxis(this.graph.y);this._drawGrid(axis);this._renderHeight=this.graph.height},_drawAxis:function(scale){var axis=d3.svg.axis().scale(scale).orient(this.orientation);axis.tickFormat(this.tickFormat);if(this.tickValues)axis.tickValues(this.tickValues);if(this.orientation=="left"){var berth=this.height*this.berthRate;var transform="translate("+this.width+", "+berth+")"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));return axis},_drawGrid:function(axis){var gridSize=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-y-value",this.textContent)})}});Rickshaw.namespace("Rickshaw.Graph.Axis.Y.Scaled");Rickshaw.Graph.Axis.Y.Scaled=Rickshaw.Class.create(Rickshaw.Graph.Axis.Y,{initialize:function($super,args){if(typeof args.scale==="undefined"){throw new Error("Scaled requires scale")}this.scale=args.scale;if(typeof args.grid==="undefined"){this.grid=true +}else{this.grid=args.grid}$super(args)},_drawAxis:function($super,scale){var domain=this.scale.domain();var renderDomain=this.graph.renderer.domain().y;var extents=[Math.min.apply(Math,domain),Math.max.apply(Math,domain)];var extentMap=d3.scale.linear().domain([0,1]).range(extents);var adjExtents=[extentMap(renderDomain[0]),extentMap(renderDomain[1])];var adjustment=d3.scale.linear().domain(extents).range(adjExtents);var adjustedScale=this.scale.copy().domain(domain.map(adjustment)).range(scale.range());return $super(adjustedScale)},_drawGrid:function($super,axis){if(this.grid){$super(axis)}}});Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight");Rickshaw.Graph.Behavior.Series.Highlight=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;var colorSafe={};var activeLine=null;var disabledColor=args.disabledColor||function(seriesColor){return d3.interpolateRgb(seriesColor,d3.rgb("#d8d8d8"))(.8).toString()};this.addHighlightEvents=function(l){l.element.addEventListener("mouseover",function(e){if(activeLine)return;else activeLine=l;self.legend.lines.forEach(function(line){if(l===line){if(self.graph.renderer.unstack&&(line.series.renderer?line.series.renderer.unstack:true)){var seriesIndex=self.graph.series.indexOf(line.series);line.originalIndex=seriesIndex;var series=self.graph.series.splice(seriesIndex,1)[0];self.graph.series.push(series)}return}colorSafe[line.series.name]=colorSafe[line.series.name]||line.series.color;line.series.color=disabledColor(line.series.color)});self.graph.update()},false);l.element.addEventListener("mouseout",function(e){if(!activeLine)return;else activeLine=null;self.legend.lines.forEach(function(line){if(l===line&&line.hasOwnProperty("originalIndex")){var series=self.graph.series.pop();self.graph.series.splice(line.originalIndex,0,series);delete line.originalIndex}if(colorSafe[line.series.name]){line.series.color=colorSafe[line.series.name]}});self.graph.update()},false)};if(this.legend){this.legend.lines.forEach(function(l){self.addHighlightEvents(l)})}};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order");Rickshaw.Graph.Behavior.Series.Order=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;if(typeof window.$=="undefined"){throw"couldn't find jQuery at window.$"}if(typeof window.$.ui=="undefined"){throw"couldn't find jQuery UI at window.$.ui"}$(function(){$(self.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(event,ui){var series=[];$(self.legend.list).find("li").each(function(index,item){if(!item.series)return;series.push(item.series)});for(var i=self.graph.series.length-1;i>=0;i--){self.graph.series[i]=series.shift()}self.graph.update()}});$(self.legend.list).disableSelection()});this.graph.onUpdate(function(){var h=window.getComputedStyle(self.legend.element).height;self.legend.element.style.height=h})};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle");Rickshaw.Graph.Behavior.Series.Toggle=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;this.addAnchor=function(line){var anchor=document.createElement("a");anchor.innerHTML="✔";anchor.classList.add("action");line.element.insertBefore(anchor,line.element.firstChild);anchor.onclick=function(e){if(line.series.disabled){line.series.enable();line.element.classList.remove("disabled")}else{if(this.graph.series.filter(function(s){return!s.disabled}).length<=1)return;line.series.disable();line.element.classList.add("disabled")}}.bind(this);var label=line.element.getElementsByTagName("span")[0];label.onclick=function(e){var disableAllOtherLines=line.series.disabled;if(!disableAllOtherLines){for(var i=0;idomainX){dataIndex=Math.abs(domainX-data[i].x)0){alignables.forEach(function(el){el.classList.remove("left");el.classList.add("right")});var rightAlignError=this._calcLayoutError(alignables);if(rightAlignError>leftAlignError){alignables.forEach(function(el){el.classList.remove("right");el.classList.add("left")})}}if(typeof this.onRender=="function"){this.onRender(args)}},_calcLayoutError:function(alignables){var parentRect=this.element.parentNode.getBoundingClientRect();var error=0;var alignRight=alignables.forEach(function(el){var rect=el.getBoundingClientRect();if(!rect.width){return}if(rect.right>parentRect.right){error+=rect.right-parentRect.right}if(rect.left=self.previewWidth){frameAfterDrag[0]-=frameAfterDrag[1]-self.previewWidth;frameAfterDrag[1]=self.previewWidth}}self.graphs.forEach(function(graph){var domainScale=d3.scale.linear().interpolate(d3.interpolateRound).domain([0,self.previewWidth]).range(graph.dataDomain());var windowAfterDrag=[domainScale(frameAfterDrag[0]),domainScale(frameAfterDrag[1])];if(frameAfterDrag[0]===0){windowAfterDrag[0]=undefined}if(frameAfterDrag[1]===self.previewWidth){windowAfterDrag[1]=undefined}graph.window.xMin=windowAfterDrag[0];graph.window.xMax=windowAfterDrag[1];graph.update()})}function onMousedown(){drag.target=d3.event.target;drag.start=self._getClientXFromEvent(d3.event,drag);self.frameBeforeDrag=self.currentFrame.slice();d3.event.preventDefault?d3.event.preventDefault():d3.event.returnValue=false;d3.select(document).on("mousemove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("mouseup.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchmove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("touchend.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",onMouseup)}function onMousedownLeftHandle(datum,index){drag.left=true;onMousedown()}function onMousedownRightHandle(datum,index){drag.right=true;onMousedown()}function onMousedownMiddleHandle(datum,index){drag.left=true;drag.right=true;drag.rigid=true;onMousedown()}function onMouseup(datum,index){d3.select(document).on("mousemove.rickshaw_range_slider_preview",null);d3.select(document).on("mouseup.rickshaw_range_slider_preview",null);d3.select(document).on("touchmove.rickshaw_range_slider_preview",null);d3.select(document).on("touchend.rickshaw_range_slider_preview",null);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",null);delete self.frameBeforeDrag;drag.left=false;drag.right=false;drag.rigid=false}element.select("rect.left_handle").on("mousedown",onMousedownLeftHandle);element.select("rect.right_handle").on("mousedown",onMousedownRightHandle);element.select("rect.middle_handle").on("mousedown",onMousedownMiddleHandle);element.select("rect.left_handle").on("touchstart",onMousedownLeftHandle);element.select("rect.right_handle").on("touchstart",onMousedownRightHandle);element.select("rect.middle_handle").on("touchstart",onMousedownMiddleHandle)},_getClientXFromEvent:function(event,drag){switch(event.type){case"touchstart":case"touchmove":var touchList=event.changedTouches;var touch=null;for(var touchIndex=0;touchIndexyMax)yMax=y});if(!series.length)return;if(series[0].xxMax)xMax=series[series.length-1].x});xMin-=(xMax-xMin)*this.padding.left;xMax+=(xMax-xMin)*this.padding.right;yMin=this.graph.min==="auto"?yMin:this.graph.min||0;yMax=this.graph.max===undefined?yMax:this.graph.max;if(this.graph.min==="auto"||yMin<0){yMin-=(yMax-yMin)*this.padding.bottom}if(this.graph.max===undefined){yMax+=(yMax-yMin)*this.padding.top}return{x:[xMin,xMax],y:[yMin,yMax]}},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var pathNodes=vis.selectAll("path.path").data(data).enter().append("svg:path").classed("path",true).attr("d",this.seriesPathFactory());if(this.stroke){var strokeNodes=vis.selectAll("path.stroke").data(data).enter().append("svg:path").classed("stroke",true).attr("d",this.seriesStrokeFactory())}var i=0;series.forEach(function(series){if(series.disabled)return;series.path=pathNodes[0][i];if(this.stroke)series.stroke=strokeNodes[0][i];this._styleSeries(series);i++},this)},_styleSeries:function(series){var fill=this.fill?series.color:"none";var stroke=this.stroke?series.color:"none";series.path.setAttribute("fill",fill);series.path.setAttribute("stroke",stroke);series.path.setAttribute("stroke-width",this.strokeWidth);if(series.className){d3.select(series.path).classed(series.className,true)}if(series.className&&this.stroke){d3.select(series.stroke).classed(series.className,true)}},configure:function(args){args=args||{};Rickshaw.keys(this.defaults()).forEach(function(key){if(!args.hasOwnProperty(key)){this[key]=this[key]||this.graph[key]||this.defaults()[key];return}if(typeof this.defaults()[key]=="object"){Rickshaw.keys(this.defaults()[key]).forEach(function(k){this[key][k]=args[key][k]!==undefined?args[key][k]:this[key][k]!==undefined?this[key][k]:this.defaults()[key][k]},this)}else{this[key]=args[key]!==undefined?args[key]:this[key]!==undefined?this[key]:this.graph[key]!==undefined?this.graph[key]:this.defaults()[key]}},this)},setStrokeWidth:function(strokeWidth){if(strokeWidth!==undefined){this.strokeWidth=strokeWidth}},setTension:function(tension){if(tension!==undefined){this.tension=tension}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Line");Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack");Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:true,stroke:false,unstack:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar");Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var defaults=Rickshaw.extend($super(),{gapSize:.05,unstack:false});delete defaults.tension;return defaults},initialize:function($super,args){args=args||{};this.gapSize=args.gapSize||this.gapSize;$super(args)},domain:function($super){var domain=$super();var frequentInterval=this._frequentInterval(this.graph.stackedData.slice(-1).shift());domain.x[1]+=Number(frequentInterval.magnitude);return domain},barWidth:function(series){var frequentInterval=this._frequentInterval(series.stack);var barWidth=this.graph.x(series.stack[0].x+frequentInterval.magnitude*(1-this.gapSize));return barWidth},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var barWidth=this.barWidth(series.active()[0]);var barXOffset=0;var activeSeriesCount=series.filter(function(s){return!s.disabled}).length;var seriesBarWidth=this.unstack?barWidth/activeSeriesCount:barWidth;var transform=function(d){var matrix=[1,0,0,d.y<0?-1:1,0,d.y<0?graph.y.magnitude(Math.abs(d.y))*2:0];return"matrix("+matrix.join(",")+")"};series.forEach(function(series){if(series.disabled)return;var barWidth=this.barWidth(series);var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:rect").attr("x",function(d){return graph.x(d.x)+barXOffset}).attr("y",function(d){return graph.y(d.y0+Math.abs(d.y))*(d.y<0?-1:1)}).attr("width",seriesBarWidth).attr("height",function(d){return graph.y.magnitude(Math.abs(d.y))}).attr("transform",transform);Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)});if(this.unstack)barXOffset+=seriesBarWidth},this)},_frequentInterval:function(data){var intervalCounts={};for(var i=0;i0){this[0].data.forEach(function(plot){item.data.push({x:plot.x,y:0})})}else if(item.data.length===0){item.data.push({x:this.timeBase-(this.timeInterval||0),y:0})}this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},addData:function(data,x){var index=this.getIndex();Rickshaw.keys(data).forEach(function(name){if(!this.itemByName(name)){this.addItem({name:name})}},this);this.forEach(function(item){item.data.push({x:x||(index*this.timeInterval||1)+this.timeBase,y:data[item.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(name){for(var i=0;i1;i--){this.currentSize+=1;this.currentIndex+=1;this.forEach(function(item){item.data.unshift({x:((i-1)*this.timeInterval||1)+this.timeBase,y:0,i:i})},this)}}},addData:function($super,data,x){$super(data,x);this.currentSize+=1;this.currentIndex+=1;if(this.maxDataPoints!==undefined){while(this.currentSize>this.maxDataPoints){this.dropData()}}},dropData:function(){this.forEach(function(item){item.data.splice(0,1)});this.currentSize-=1},getIndex:function(){return this.currentIndex}}); \ No newline at end of file diff --git a/html/js/underscore-min.js b/html/js/underscore-min.js new file mode 100644 index 0000000..7ed6e52 --- /dev/null +++ b/html/js/underscore-min.js @@ -0,0 +1 @@ +(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,v=e.reduce,h=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.3";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduce===v)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduceRight===h)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:g&&n.filter===g?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:d&&n.every===d?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?-1!=n.indexOf(t):E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2);return w.map(n,function(n){return(w.isFunction(t)?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t){return w.isEmpty(t)?[]:w.filter(n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var F=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=F(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||void 0===r)return 1;if(e>r||void 0===e)return-1}return n.indexi;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i};var I=function(){};w.bind=function(n,t){var r,e;if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));if(!w.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));I.prototype=n.prototype;var u=new I;I.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},w.bindAll=function(n){var t=o.call(arguments,1);return 0==t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=S(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&S(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return S(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),w.isFunction=function(n){return"function"==typeof n},w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return void 0===n},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+(0|Math.random()*(t-n+1))};var T={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};T.unescape=w.invert(T.escape);var M={escape:RegExp("["+w.keys(T.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(T.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(M[n],function(t){return T[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=""+ ++N;return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){r=w.defaults({},r,w.templateSettings);var e=RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,a,o){return i+=n.slice(u,o).replace(D,function(n){return"\\"+B[n]}),r&&(i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(i+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),a&&(i+="';\n"+a+"\n__p+='"),u=o+t.length,t}),i+="';\n",r.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var a=Function(r.variable||"obj","_",i)}catch(o){throw o.source=i,o}if(t)return a(t,w);var c=function(n){return a.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+i+"}",c},w.chain=function(n){return w(n).chain()};var z=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); \ No newline at end of file diff --git a/html/js/underscore.js b/html/js/underscore.js new file mode 100644 index 0000000..b29332f --- /dev/null +++ b/html/js/underscore.js @@ -0,0 +1,1548 @@ +// Underscore.js 1.8.3 +// http://underscorejs.org +// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `exports` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind, + nativeCreate = Object.create; + + // Naked function reference for surrogate-prototype-swapping. + var Ctor = function(){}; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root._ = _; + } + + // Current version. + _.VERSION = '1.8.3'; + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + var optimizeCb = function(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + case 2: return function(value, other) { + return func.call(context, value, other); + }; + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + }; + + // A mostly-internal function to generate callbacks that can be applied + // to each element in a collection, returning the desired result — either + // identity, an arbitrary callback, a property matcher, or a property accessor. + var cb = function(value, context, argCount) { + if (value == null) return _.identity; + if (_.isFunction(value)) return optimizeCb(value, context, argCount); + if (_.isObject(value)) return _.matcher(value); + return _.property(value); + }; + _.iteratee = function(value, context) { + return cb(value, context, Infinity); + }; + + // An internal function for creating assigner functions. + var createAssigner = function(keysFunc, undefinedOnly) { + return function(obj) { + var length = arguments.length; + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + }; + + // An internal function for creating a new object that inherits from another. + var baseCreate = function(prototype) { + if (!_.isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + }; + + var property = function(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + }; + + // Helper for collection methods to determine whether a collection + // should be iterated as an array or as an object + // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + var getLength = property('length'); + var isArrayLike = function(collection) { + var length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; + }; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + _.each = _.forEach = function(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var keys = _.keys(obj); + for (i = 0, length = keys.length; i < length; i++) { + iteratee(obj[keys[i]], keys[i], obj); + } + } + return obj; + }; + + // Return the results of applying the iteratee to each element. + _.map = _.collect = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Create a reducing function iterating left or right. + function createReduce(dir) { + // Optimized iterator function as using arguments.length + // in the main function will deoptimize the, see #1991. + function iterator(obj, iteratee, memo, keys, index, length) { + for (; index >= 0 && index < length; index += dir) { + var currentKey = keys ? keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + } + + return function(obj, iteratee, memo, context) { + iteratee = optimizeCb(iteratee, context, 4); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + index = dir > 0 ? 0 : length - 1; + // Determine the initial value if none is provided. + if (arguments.length < 3) { + memo = obj[keys ? keys[index] : index]; + index += dir; + } + return iterator(obj, iteratee, memo, keys, index, length); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + _.reduce = _.foldl = _.inject = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + _.reduceRight = _.foldr = createReduce(-1); + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, predicate, context) { + var key; + if (isArrayLike(obj)) { + key = _.findIndex(obj, predicate, context); + } else { + key = _.findKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) return obj[key]; + }; + + // Return all the elements that pass a truth test. + // Aliased as `select`. + _.filter = _.select = function(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + _.each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, predicate, context) { + return _.filter(obj, _.negate(cb(predicate)), context); + }; + + // Determine whether all of the elements match a truth test. + // Aliased as `all`. + _.every = _.all = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + }; + + // Determine if at least one element in the object matches a truth test. + // Aliased as `any`. + _.some = _.any = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + }; + + // Determine if the array or object contains a given item (using `===`). + // Aliased as `includes` and `include`. + _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return _.indexOf(obj, item, fromIndex) >= 0; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + var func = isFunc ? method : value[method]; + return func == null ? func : func.apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, _.property(key)); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + _.where = function(obj, attrs) { + return _.filter(obj, _.matcher(attrs)); + }; + + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + _.findWhere = function(obj, attrs) { + return _.find(obj, _.matcher(attrs)); + }; + + // Return the maximum element (or element-based computation). + _.max = function(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Shuffle a collection, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + _.shuffle = function(obj) { + var set = isArrayLike(obj) ? obj : _.values(obj); + var length = set.length; + var shuffled = Array(length); + for (var index = 0, rand; index < length; index++) { + rand = _.random(0, index); + if (rand !== index) shuffled[index] = shuffled[rand]; + shuffled[rand] = set[index]; + } + return shuffled; + }; + + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + + // Sort the object's values by a criterion produced by an iteratee. + _.sortBy = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value: value, + index: index, + criteria: iteratee(value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(behavior) { + return function(obj, iteratee, context) { + var result = {}; + iteratee = cb(iteratee, context); + _.each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = group(function(result, value, key) { + if (_.has(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = group(function(result, value, key) { + if (_.has(result, key)) result[key]++; else result[key] = 1; + }); + + // Safely create a real, live array from anything iterable. + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (isArrayLike(obj)) return _.map(obj, _.identity); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : _.keys(obj).length; + }; + + // Split a collection into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(obj, predicate, context) { + predicate = cb(predicate, context); + var pass = [], fail = []; + _.each(obj, function(value, key, obj) { + (predicate(value, key, obj) ? pass : fail).push(value); + }); + return [pass, fail]; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[0]; + return _.initial(array, array.length - n); + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + _.initial = function(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + _.last = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[array.length - 1]; + return _.rest(array, Math.max(0, array.length - n)); + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, _.identity); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, strict, startIndex) { + var output = [], idx = 0; + for (var i = startIndex || 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { + //flatten current level of array or arguments object + if (!shallow) value = flatten(value, shallow, strict); + var j = 0, len = value.length; + output.length += len; + while (j < len) { + output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + }; + + // Flatten out an array, either recursively (by default), or just one level. + _.flatten = function(array, shallow) { + return flatten(array, shallow, false); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iteratee, context) { + if (!_.isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!_.contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!_.contains(result, value)) { + result.push(value); + } + } + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(flatten(arguments, true, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (_.contains(result, item)) continue; + for (var j = 1; j < argsLength; j++) { + if (!_.contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = flatten(arguments, true, true, 1); + return _.filter(array, function(value){ + return !_.contains(rest, value); + }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + return _.unzip(arguments); + }; + + // Complement of _.zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices + _.unzip = function(array) { + var length = array && _.max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = _.pluck(array, index); + } + return result; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // Generator function to create the findIndex and findLastIndex functions + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a predicate test + _.findIndex = createPredicateIndexFinder(1); + _.findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + }; + + // Generator function to create the indexOf and lastIndexOf functions + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), _.isNaN); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); + _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + step = step || 1; + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Determines whether to execute a function as a constructor + // or a normal function with the provided arguments + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (_.isObject(result)) return result; + return self; + }; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + _.bind = function(func, context) { + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); + var args = slice.call(arguments, 2); + var bound = function() { + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); + }; + return bound; + }; + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. + _.partial = function(func) { + var boundArgs = slice.call(arguments, 1); + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }; + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + _.bindAll = function(obj) { + var i, length = arguments.length, key; + if (length <= 1) throw new Error('bindAll must be passed function names'); + for (i = 1; i < length; i++) { + key = arguments[i]; + obj[key] = _.bind(obj[key], obj); + } + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ + return func.apply(null, args); + }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = _.partial(_.delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + if (!timeout) context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); + var callNow = immediate && !timeout; + if (!timeout) timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return _.partial(wrapper, func); + }; + + // Returns a negated version of the passed-in predicate. + _.negate = function(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + }; + + // Returns a function that will only be executed on and after the Nth call. + _.after = function(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Returns a function that will only be executed up to (but not including) the Nth call. + _.before = function(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = _.partial(_.before, 2); + + // Object Functions + // ---------------- + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + function collectNonEnumProps(obj, keys) { + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve all the property names of an object. + _.allKeys = function(obj) { + if (!_.isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } + return values; + }; + + // Returns the results of applying the iteratee to each element of the object + // In contrast to _.map it returns an object + _.mapObject = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = _.keys(obj), + length = keys.length, + results = {}, + currentKey; + for (var index = 0; index < length; index++) { + currentKey = keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = createAssigner(_.allKeys); + + // Assigns a given object with all the own properties in the passed-in object(s) + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + _.extendOwn = _.assign = createAssigner(_.keys); + + // Returns the first key on an object that passes a predicate test + _.findKey = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = _.keys(obj), key; + for (var i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(object, oiteratee, context) { + var result = {}, obj = object, iteratee, keys; + if (obj == null) return result; + if (_.isFunction(oiteratee)) { + keys = _.allKeys(obj); + iteratee = optimizeCb(oiteratee, context); + } else { + keys = flatten(arguments, false, false, 1); + iteratee = function(value, key, obj) { return key in obj; }; + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj, iteratee, context) { + if (_.isFunction(iteratee)) { + iteratee = _.negate(iteratee); + } else { + var keys = _.map(flatten(arguments, false, false, 1), String); + iteratee = function(value, key) { + return !_.contains(keys, key); + }; + } + return _.pick(obj, iteratee, context); + }; + + // Fill in a given object with default properties. + _.defaults = createAssigner(_.allKeys, true); + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + _.create = function(prototype, props) { + var result = baseCreate(prototype); + if (props) _.extendOwn(result, props); + return result; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Returns whether an object has a given set of `key:value` pairs. + _.isMatch = function(object, attrs) { + var keys = _.keys(attrs), length = keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + }; + + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && + _.isFunction(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var keys = _.keys(a), key; + length = keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (_.keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = keys[length]; + if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; + return _.keys(obj).length === 0; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. + _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) === '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return _.has(obj, 'callee'); + }; + } + + // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, + // IE 11 (#1621), and in Safari 8 (#1929). + if (typeof /./ != 'function' && typeof Int8Array != 'object') { + _.isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj !== +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iteratees. + _.identity = function(value) { + return value; + }; + + // Predicate-generating functions. Often useful outside of Underscore. + _.constant = function(value) { + return function() { + return value; + }; + }; + + _.noop = function(){}; + + _.property = property; + + // Generates a function for a given object that returns a given property. + _.propertyOf = function(obj) { + return obj == null ? function(){} : function(key) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + _.matcher = _.matches = function(attrs) { + attrs = _.extendOwn({}, attrs); + return function(obj) { + return _.isMatch(obj, attrs); + }; + }; + + // Run a function **n** times. + _.times = function(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { + return new Date().getTime(); + }; + + // List of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + var unescapeMap = _.invert(escapeMap); + + // Functions for escaping and unescaping strings to/from HTML interpolation. + var createEscaper = function(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped + var source = '(?:' + _.keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + }; + _.escape = createEscaper(escapeMap); + _.unescape = createEscaper(unescapeMap); + + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. + _.result = function(object, property, fallback) { + var value = object == null ? void 0 : object[property]; + if (value === void 0) { + value = fallback; + } + return _.isFunction(value) ? value.call(object) : value; + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + + var escapeChar = function(match) { + return '\\' + escapes[match]; + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + _.template = function(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escaper, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offest. + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + try { + var render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function. Start chaining a wrapped Underscore object. + _.chain = function(obj) { + var instance = _(obj); + instance._chain = true; + return instance; + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(instance, obj) { + return instance._chain ? _(obj).chain() : obj; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + _.each(_.functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result(this, func.apply(_, args)); + }; + }); + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + return result(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + _.each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result(this, method.apply(this._wrapped, arguments)); + }; + }); + + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxy for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + + _.prototype.toString = function() { + return '' + this._wrapped; + }; + + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } +}.call(this)); diff --git a/html/legend.css b/html/legend.css new file mode 100644 index 0000000..a78eaae --- /dev/null +++ b/html/legend.css @@ -0,0 +1,73 @@ +.rickshaw_legend { + font-family: Arial; + font-size: 12px; + color: white; + background: #404040; + display: inline-block; + padding: 12px 5px; + border-radius: 2px; + position: relative; +} +.rickshaw_legend:hover { + z-index: 10; +} +.rickshaw_legend .swatch { + width: 10px; + height: 10px; + border: 1px solid rgba(0, 0, 0, 0.2); +} +.rickshaw_legend .line { + clear: both; + line-height: 140%; + padding-right: 15px; +} +.rickshaw_legend .line .swatch { + display: inline-block; + margin-right: 3px; + border-radius: 2px; +} +.rickshaw_legend .label { + margin: 0; + white-space: nowrap; + display: inline; + font-size: inherit; + background-color: transparent; + color: inherit; + font-weight: normal; + line-height: normal; + padding: 0px; + text-shadow: none; +} +.rickshaw_legend .action:hover { + opacity: 0.6; +} +.rickshaw_legend .action { + margin-right: 0.2em; + font-size: 10px; + opacity: 0.2; + cursor: pointer; + font-size: 14px; +} +.rickshaw_legend .line.disabled { + opacity: 0.4; +} +.rickshaw_legend ul { + list-style-type: none; + margin: 0; + padding: 0; + margin: 2px; + cursor: pointer; +} +.rickshaw_legend li { + padding: 0 0 0 2px; + min-width: 80px; + white-space: nowrap; +} +.rickshaw_legend li:hover { + background: rgba(255, 255, 255, 0.08); + border-radius: 3px; +} +.rickshaw_legend li:active { + background: rgba(255, 255, 255, 0.2); + border-radius: 3px; +} diff --git a/html/lines.css b/html/lines.css new file mode 100644 index 0000000..56a88e4 --- /dev/null +++ b/html/lines.css @@ -0,0 +1,20 @@ +div, span, p, td { + font-family: Arial, sans-serif; +} +#chart { + display: inline-block; +} +#legend { + display: inline-block; + position: relative; + left: 8px; +} +#legend_container { + position: absolute; + right: 0; + bottom: 26px; + width: 0; +} +.chart_container { + position: relative; +} diff --git a/html/local.js b/html/local.js new file mode 100644 index 0000000..087ce68 --- /dev/null +++ b/html/local.js @@ -0,0 +1,219 @@ +"use strict"; + +// var moment= require('moment'); +var gdata = {}; + +$(document).ready(function () { + $.ajaxSetup({cache: false}); + + var getTemplate = function (name) { + var template = $('#' + name + '-template').html(); + return Handlebars.compile(template); + }; + var cachedTemplates = {}; + var render = function (name, ctx) { + var t = cachedTemplates[name]; + if (!t) { + t = getTemplate(name); + cachedTemplates[name] = t; + } + var h = t(ctx); + $('#' + name).html(h); + }; + + var password = $("#password").val(); + $("#password").change(function (e) { + password = $("#password").val(); + update(); + }); + + var qpsgraph = new Rickshaw.Graph({ + element: document.getElementById("qpschart"), + width: 400, + height: 200, + renderer: 'line', + series: new Rickshaw.Series.FixedDuration([{name: 'servfailps'}, {name: 'qps'}], undefined, { + timeInterval: 1000, + maxDataPoints: 100, + timeBase: new Date().getTime() / 1000 + }) + }); + var y_ticks = new Rickshaw.Graph.Axis.Y({ + graph: qpsgraph, + orientation: 'left', + tickFormat: Rickshaw.Fixtures.Number.formatKMBT, + element: document.getElementById('qpsy_axis') + }); + + qpsgraph.render(); + + var cpugraph = new Rickshaw.Graph({ + element: document.getElementById("cpuchart"), + width: 400, + height: 200, + renderer: 'line', + series: new Rickshaw.Series.FixedDuration([{name: 'one'}], undefined, { + timeInterval: 1000, + maxDataPoints: 100, + timeBase: new Date().getTime() / 1000 + }) + }); + var cpu_y_ticks = new Rickshaw.Graph.Axis.Y({ + graph: cpugraph, + orientation: 'left', + tickFormat: Rickshaw.Fixtures.Number.formatKMBT, + element: document.getElementById('cpuy_axis') + }); + + cpugraph.render(); + var intervalcount = 0; + + var jsonstatParams = function (command, name, filtered) { + var d = { + 'api-key': password, + 'command': command, + 'name': name + }; + if (filtered) { + d['public-filtered'] = '1'; + } + return d; + }; + + var makeRingRows = function (data) { + var num = 0; + var total = 0, rest = 0; + var rows = []; + $.each(data["entries"], function (a, b) { + total += b[0]; + if (num++ > 10) { + rest += b[0]; + return; + } + if (b[1].length > 25) + b[1] = b[1].substring(0, 25); + rows.push(b); + }); + while (rows.length < 10) { + rows.push([]); + } + rows.push([rest, 'REST', '']); + return rows; + }; + + function updateRingBuffers() { + $.getJSON('jsonstat', jsonstatParams('get-query-ring', 'queries', $("#filter1").is(':checked')), + function (data) { + var rows = makeRingRows(data); + render('queryring', {rows: rows}); + }); + + $.getJSON('jsonstat', jsonstatParams('get-query-ring', 'servfail-queries', $("#filter1").is(':checked')), + function (data) { + var rows = makeRingRows(data); + render('servfailqueryring', {rows: rows}); + }); + + $.getJSON('jsonstat', jsonstatParams('get-remote-ring', 'remotes', false), + function (data) { + var rows = makeRingRows(data); + render('remotering', {rows: rows}); + }); + + $.getJSON('jsonstat', jsonstatParams('get-remote-ring', 'servfail-remotes', false), + function (data) { + var rows = makeRingRows(data); + render('servfailremotering', {rows: rows}); + }); + } + + var connectionOK = function (ok, o) { + if (ok) { + $("#connection-status").hide(); + $("#connection-error").html(""); + $("#content-hidden-on-load").show(); + } else { + $("#connection-status").show(); + $("#connection-error").html(o.status + " " + o.statusText); + } + }; + + var version = null; + + function update() { + $.ajax({ + url: 'api/v1/servers/localhost/statistics?api-key=' + password, + type: 'GET', + dataType: 'json', + success: function (adata, x, y) { + connectionOK(true); + + var data = {}; + $.each(adata, function (key, val) { + data[val.name] = val.value; + }); + + if (!gdata["sys-msec"]) + gdata = data; + + var cpu = 0.1 * (1.0 * data["sys-msec"] + 1.0 * data["user-msec"] + - 1.0 * gdata["sys-msec"] - 1.0 * gdata["user-msec"]); + var qps = 1.0 * data["questions"] - 1.0 * gdata["questions"]; + var servfailps = 1.0 * data["servfail-answers"] - 1.0 * gdata["servfail-answers"]; + var totpcache = 1.0 * data["packetcache-hits"] - 1.0 * gdata["packetcache-hits"] + + 1.0 * data["packetcache-misses"] - 1.0 * gdata["packetcache-misses"]; + var phitrate = 0; + if (totpcache > 0) { + phitrate = 100.0 * (data["packetcache-hits"] - 1.0 * gdata["packetcache-hits"]) / totpcache; + } + + var stats = { + version: version || '...', + questions: data["questions"], + over_capacity_drops: data["over-capacity-drops"], + too_old: data["too-old-drops"], + uptime: moment.duration(data["uptime"] * 1000.0).humanize(), + latency: data["qa-latency"] / 1000.0, + cpu: cpu.toFixed(2), + qps: qps, + phitrate: phitrate.toFixed(2) + }; + render('top-stats', stats); + + qpsgraph.series.addData({qps: qps, servfailps: servfailps}); + qpsgraph.render(); + + cpugraph.series.addData({one: cpu}); + cpugraph.render(); + + gdata = data; + }, + error: function (o) { + connectionOK(false, o); + }, + beforeSend: function (xhr) { + xhr.setRequestHeader('X-API-Key', 'changeme'); + return true; + } + }); + + if (!version) { + $.ajax({ + url: 'api/v1/servers/localhost?api-key=' + password, type: 'GET', dataType: 'json', + success: function (data) { + version = "PowerDNS " + data["daemon_type"] + " " + data["version"]; + } + }); + } + + if ((intervalcount++) % 5) + return; + updateRingBuffers(); + } + + $("#filter1").click(updateRingBuffers); + $("#filter2").click(updateRingBuffers); + + update(); + setInterval(update, 1000); +}); diff --git a/html/powerdns-logo-220px.png b/html/powerdns-logo-220px.png new file mode 100644 index 0000000..7c299c0 Binary files /dev/null and b/html/powerdns-logo-220px.png differ diff --git a/html/styling.css b/html/styling.css new file mode 100644 index 0000000..60b3992 --- /dev/null +++ b/html/styling.css @@ -0,0 +1,82 @@ +.pdns-chart { + position: relative; + left: 40px; + z-index: -10; /* don't steal clicks from stuff it overlaps with */ +} +.pdns-axis { + position: absolute; + top: 0; + bottom: 0; + width: 40px; +} +#connection-status, #connection-error { + color: red; +} +.topbar { + background: url(powerdns-logo-220px.png) no-repeat; + height: 30px; + padding-left: 250px; + padding-top: 5px; +} +.charts-container { + display: inline-block; + width: 500px; + vertical-align: top; +} +.charts-container .chart { +} +.charts-container h2 { + padding-left: 40px; + text-align: center; +} +.all-tables { + display: inline-block; + min-width: 700px; + vertical-align: top; +} +.table-container { + display: inline-block; + width: 330px; + vertical-align: top; + margin-right: 20px; +} +.table-container .filter { + height: 20px; +} +h2 { + font-size: 16pt; +} +.stats-table { +} +.stats-table table, +.stats-table th, +.stats-table td { + /*border: 1px solid #aaaaaa;*/ + border-left: 1px solid #aaaaaa; + border-right: 1px solid #aaaaaa; + border-collapse: collapse; + text-overflow: ellipsis; +} +.stats-table td, +.stats-table th { + padding-left: 4px; + padding-right: 4px; +} +.stats-table th { + text-align: left; + border: 1px solid #aaaaaa; +} +.stats-table table { + width: 100%; + margin-top: 30px; + border: 1px solid #aaaaaa; +} +.stats-table table tr:last-child { + border: 1px solid #aaaaaa; +} +table.two-col th:first-child { width: 25%; } +table.three-col th:first-child { width: 25%; } +table.three-col th:last-child { width: 20%; } +.stats-table td:empty:after{ + content: "\00a0"; /* non-breaking space */ +} diff --git a/incfiles b/incfiles new file mode 100755 index 0000000..da12741 --- /dev/null +++ b/incfiles @@ -0,0 +1,24 @@ +#!/bin/sh + +export LC_ALL=C.UTF-8 +export LANG=C.UTF-8 + +if [ -n "$1" ] +then + DIR=$1/ +fi + +for a in $(find ${DIR}html -type f | grep -v \~ | sort) +do + c=$(echo $a | sed s:${DIR}html/:: | tr "/.-" "___") + echo "INCBIN(${c}, \"$a\");" +done + +echo "map g_urlmap={" +for a in $(find ${DIR}html -type f | grep -v \~ | sort) +do + b=$(echo $a | sed s:${DIR}html/::g) + c=$(echo $b | tr "/.-" "___") + echo "{\"$b\", string((const char*)g${c}Data, g${c}Size)}," +done +echo "};" diff --git a/iputils.cc b/iputils.cc new file mode 100644 index 0000000..9099d85 --- /dev/null +++ b/iputils.cc @@ -0,0 +1,446 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "iputils.hh" +#include + +/** these functions provide a very lightweight wrapper to the Berkeley sockets API. Errors -> exceptions! */ + +static void RuntimeError(const boost::format& fmt) +{ + throw runtime_error(fmt.str()); +} + + +int SSocket(int family, int type, int flags) +{ + int ret = socket(family, type, flags); + if(ret < 0) + RuntimeError(boost::format("creating socket of type %d: %s") % family % strerror(errno)); + return ret; +} + +int SConnect(int sockfd, const ComboAddress& remote) +{ + int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen()); + if(ret < 0) { + int savederrno = errno; + RuntimeError(boost::format("connecting socket to %s: %s") % remote.toStringWithPort() % strerror(savederrno)); + } + return ret; +} + +int SConnectWithTimeout(int sockfd, const ComboAddress& remote, int timeout) +{ + int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen()); + if(ret < 0) { + int savederrno = errno; + if (savederrno == EINPROGRESS) { + /* we wait until the connection has been established */ + bool error = false; + bool disconnected = false; + int res = waitForRWData(sockfd, false, timeout, 0, &error, &disconnected); + if (res == 1) { + if (error) { + savederrno = 0; + socklen_t errlen = sizeof(savederrno); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&savederrno, &errlen) == 0) { + RuntimeError(boost::format("connecting to %s failed: %s") % remote.toStringWithPort() % string(strerror(savederrno))); + } + else { + RuntimeError(boost::format("connecting to %s failed") % remote.toStringWithPort()); + } + } + if (disconnected) { + RuntimeError(boost::format("%s closed the connection") % remote.toStringWithPort()); + } + return 0; + } + else if (res == 0) { + RuntimeError(boost::format("timeout while connecting to %s") % remote.toStringWithPort()); + } else if (res < 0) { + savederrno = errno; + RuntimeError(boost::format("waiting to connect to %s: %s") % remote.toStringWithPort() % string(strerror(savederrno))); + } + } + else { + RuntimeError(boost::format("connecting to %s: %s") % remote.toStringWithPort() % string(strerror(savederrno))); + } + } + + return ret; +} + +int SBind(int sockfd, const ComboAddress& local) +{ + int ret = bind(sockfd, (struct sockaddr*)&local, local.getSocklen()); + if(ret < 0) { + int savederrno = errno; + RuntimeError(boost::format("binding socket to %s: %s") % local.toStringWithPort() % strerror(savederrno)); + } + return ret; +} + +int SAccept(int sockfd, ComboAddress& remote) +{ + socklen_t remlen = remote.getSocklen(); + + int ret = accept(sockfd, (struct sockaddr*)&remote, &remlen); + if(ret < 0) + RuntimeError(boost::format("accepting new connection on socket: %s") % strerror(errno)); + return ret; +} + +int SListen(int sockfd, int limit) +{ + int ret = listen(sockfd, limit); + if(ret < 0) + RuntimeError(boost::format("setting socket to listen: %s") % strerror(errno)); + return ret; +} + +int SSetsockopt(int sockfd, int level, int opname, int value) +{ + int ret = setsockopt(sockfd, level, opname, &value, sizeof(value)); + if(ret < 0) + RuntimeError(boost::format("setsockopt for level %d and opname %d to %d failed: %s") % level % opname % value % strerror(errno)); + return ret; +} + + +bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv) +{ +#ifdef SO_TIMESTAMP + struct cmsghdr *cmsg; + for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh,cmsg)) { + if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP || cmsg->cmsg_type == SCM_TIMESTAMP) && + CMSG_LEN(sizeof(*tv)) == cmsg->cmsg_len) { + memcpy(tv, CMSG_DATA(cmsg), sizeof(*tv)); + return true; + } + } +#endif + return false; +} +bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination) +{ + destination->reset(); + const struct cmsghdr* cmsg; + for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(const_cast(msgh), const_cast(cmsg))) { +#if defined(IP_PKTINFO) + if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { + struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg); + destination->sin4.sin_addr = i->ipi_addr; + destination->sin4.sin_family = AF_INET; + return true; + } +#elif defined(IP_RECVDSTADDR) + if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) { + struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg); + destination->sin4.sin_addr = *i; + destination->sin4.sin_family = AF_INET; + return true; + } +#endif + + if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type == IPV6_PKTINFO)) { + struct in6_pktinfo *i = (struct in6_pktinfo *) CMSG_DATA(cmsg); + destination->sin6.sin6_addr = i->ipi6_addr; + destination->sin4.sin_family = AF_INET6; + return true; + } + } + return false; +} + +bool IsAnyAddress(const ComboAddress& addr) +{ + if(addr.sin4.sin_family == AF_INET) + return addr.sin4.sin_addr.s_addr == 0; + else if(addr.sin4.sin_family == AF_INET6) + return !memcmp(&addr.sin6.sin6_addr, &in6addr_any, sizeof(addr.sin6.sin6_addr)); + + return false; +} + +ssize_t sendfromto(int sock, const char* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to) +{ + struct msghdr msgh; + struct iovec iov; + char cbuf[256]; + + /* Set up iov and msgh structures. */ + memset(&msgh, 0, sizeof(struct msghdr)); + iov.iov_base = (void*)data; + iov.iov_len = len; + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + msgh.msg_name = (struct sockaddr*)&to; + msgh.msg_namelen = to.getSocklen(); + + if(from.sin4.sin_family) { + addCMsgSrcAddr(&msgh, cbuf, &from, 0); + } + else { + msgh.msg_control=NULL; + } + return sendmsg(sock, &msgh, flags); +} + +// be careful: when using this for receive purposes, make sure addr->sin4.sin_family is set appropriately so getSocklen works! +// be careful: when using this function for *send* purposes, be sure to set cbufsize to 0! +// be careful: if you don't call addCMsgSrcAddr after fillMSGHdr, make sure to set msg_control to NULL +void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr) +{ + iov->iov_base = data; + iov->iov_len = datalen; + + memset(msgh, 0, sizeof(struct msghdr)); + + msgh->msg_control = cbuf; + msgh->msg_controllen = cbufsize; + msgh->msg_name = addr; + msgh->msg_namelen = addr->getSocklen(); + msgh->msg_iov = iov; + msgh->msg_iovlen = 1; + msgh->msg_flags = 0; +} + +// warning: various parts of PowerDNS assume 'truncate' will never throw +void ComboAddress::truncate(unsigned int bits) noexcept +{ + uint8_t* start; + int len=4; + if(sin4.sin_family==AF_INET) { + if(bits >= 32) + return; + start = (uint8_t*)&sin4.sin_addr.s_addr; + len=4; + } + else { + if(bits >= 128) + return; + start = (uint8_t*)&sin6.sin6_addr.s6_addr; + len=16; + } + + auto tozero= len*8 - bits; // if set to 22, this will clear 1 byte, as it should + + memset(start + len - tozero/8, 0, tozero/8); // blot out the whole bytes on the right + + auto bitsleft=tozero % 8; // 2 bits left to clear + + // a b c d, to truncate to 22 bits, we just zeroed 'd' and need to zero 2 bits from c + // so and by '11111100', which is ~((1<<2)-1) = ~3 + uint8_t* place = start + len - 1 - tozero/8; + *place &= (~((1<(buffer), len, &dest); + addCMsgSrcAddr(&msgh, cbuf, &local, localItf); + + do { + ssize_t written = sendmsg(fd, &msgh, 0); + + if (written > 0) + return written; + + if (errno == EAGAIN) { + if (firstTry) { + int res = waitForRWData(fd, false, timeout, 0); + if (res > 0) { + /* there is room available */ + firstTry = false; + } + else if (res == 0) { + throw runtime_error("Timeout while waiting to write data"); + } else { + throw runtime_error("Error while waiting for room to write data"); + } + } + else { + throw runtime_error("Timeout while waiting to write data"); + } + } + else { + unixDie("failed in write2WithTimeout"); + } + } + while (firstTry); + + return 0; +} + +template class NetmaskTree; + +bool sendSizeAndMsgWithTimeout(int sock, uint16_t bufferLen, const char* buffer, int idleTimeout, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int totalTimeout, int flags) +{ + uint16_t size = htons(bufferLen); + char cbuf[256]; + struct msghdr msgh; + struct iovec iov[2]; + int remainingTime = totalTimeout; + time_t start = 0; + if (totalTimeout) { + start = time(NULL); + } + + /* Set up iov and msgh structures. */ + memset(&msgh, 0, sizeof(struct msghdr)); + msgh.msg_control = nullptr; + msgh.msg_controllen = 0; + if (dest) { + msgh.msg_name = reinterpret_cast(const_cast(dest)); + msgh.msg_namelen = dest->getSocklen(); + } + else { + msgh.msg_name = nullptr; + msgh.msg_namelen = 0; + } + + msgh.msg_flags = 0; + + if (localItf != 0 && local) { + addCMsgSrcAddr(&msgh, cbuf, local, localItf); + } + + iov[0].iov_base = &size; + iov[0].iov_len = sizeof(size); + iov[1].iov_base = reinterpret_cast(const_cast(buffer)); + iov[1].iov_len = bufferLen; + + size_t pos = 0; + size_t sent = 0; + size_t nbElements = sizeof(iov)/sizeof(*iov); + while (true) { + msgh.msg_iov = &iov[pos]; + msgh.msg_iovlen = nbElements - pos; + + ssize_t res = sendmsg(sock, &msgh, flags); + if (res > 0) { + size_t written = static_cast(res); + sent += written; + + if (sent == (sizeof(size) + bufferLen)) { + return true; + } + /* partial write, we need to keep only the (parts of) elements + that have not been written. + */ + do { + if (written < iov[pos].iov_len) { + iov[pos].iov_len -= written; + iov[pos].iov_base = reinterpret_cast(reinterpret_cast(iov[pos].iov_base) + written); + written = 0; + } + else { + written -= iov[pos].iov_len; + iov[pos].iov_len = 0; + pos++; + } + } + while (written > 0 && pos < nbElements); + } + else if (res == -1) { + if (errno == EINTR) { + continue; + } + else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { + /* EINPROGRESS might happen with non blocking socket, + especially with TCP Fast Open */ + int ret = waitForRWData(sock, false, (totalTimeout == 0 || idleTimeout <= remainingTime) ? idleTimeout : remainingTime, 0); + if (ret > 0) { + /* there is room available */ + } + else if (ret == 0) { + throw runtime_error("Timeout while waiting to send data"); + } else { + throw runtime_error("Error while waiting for room to send data"); + } + } + else { + unixDie("failed in sendSizeAndMsgWithTimeout"); + } + } + if (totalTimeout) { + time_t now = time(NULL); + int elapsed = now - start; + if (elapsed >= remainingTime) { + throw runtime_error("Timeout while sending data"); + } + start = now; + remainingTime -= elapsed; + } + } + + return false; +} + +/* requires a non-blocking socket. + On Linux, we could use MSG_DONTWAIT on a blocking socket + but this is not portable. +*/ +bool isTCPSocketUsable(int sock) +{ + int err = 0; + char buf = '\0'; + size_t buf_size = sizeof(buf); + + do { + ssize_t got = recv(sock, &buf, buf_size, MSG_PEEK); + + if (got > 0) { + /* socket is usable, some data is even waiting to be read */ + return true; + } + else if (got == 0) { + /* other end has closed the socket */ + return false; + } + else { + err = errno; + + if (err == EAGAIN || err == EWOULDBLOCK) { + /* socket is usable, no data waiting */ + return true; + } + else { + if (err != EINTR) { + /* something is wrong, could be ECONNRESET, + ENOTCONN, EPIPE, but anyway this socket is + not usable. */ + return false; + } + } + } + } while (err == EINTR); + + return false; +} diff --git a/iputils.hh b/iputils.hh new file mode 100644 index 0000000..40829bb --- /dev/null +++ b/iputils.hh @@ -0,0 +1,1013 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_IPUTILSHH +#define PDNS_IPUTILSHH + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pdnsexception.hh" +#include "misc.hh" +#include +#include +#include +#include +#include + +#include "namespaces.hh" + +#ifdef __APPLE__ +#include + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define htole16(x) OSSwapHostToLittleInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define le16toh(x) OSSwapLittleToHostInt16(x) + +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) + +#define htobe64(x) OSSwapHostToBigInt64(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) +#endif + +#ifdef __sun + +#define htobe16(x) BE_16(x) +#define htole16(x) LE_16(x) +#define be16toh(x) BE_IN16(&(x)) +#define le16toh(x) LE_IN16(&(x)) + +#define htobe32(x) BE_32(x) +#define htole32(x) LE_32(x) +#define be32toh(x) BE_IN32(&(x)) +#define le32toh(x) LE_IN32(&(x)) + +#define htobe64(x) BE_64(x) +#define htole64(x) LE_64(x) +#define be64toh(x) BE_IN64(&(x)) +#define le64toh(x) LE_IN64(&(x)) + +#endif + +#ifdef __FreeBSD__ +#include +#endif + +union ComboAddress { + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + + bool operator==(const ComboAddress& rhs) const + { + if(boost::tie(sin4.sin_family, sin4.sin_port) != boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return false; + if(sin4.sin_family == AF_INET) + return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr; + else + return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr))==0; + } + + bool operator!=(const ComboAddress& rhs) const + { + return(!operator==(rhs)); + } + + bool operator<(const ComboAddress& rhs) const + { + if(sin4.sin_family == 0) { + return false; + } + if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return true; + if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return false; + + if(sin4.sin_family == AF_INET) + return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr; + else + return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0; + } + + bool operator>(const ComboAddress& rhs) const + { + return rhs.operator<(*this); + } + + struct addressOnlyHash + { + uint32_t operator()(const ComboAddress& ca) const + { + const unsigned char* start; + int len; + if(ca.sin4.sin_family == AF_INET) { + start =(const unsigned char*)&ca.sin4.sin_addr.s_addr; + len=4; + } + else { + start =(const unsigned char*)&ca.sin6.sin6_addr.s6_addr; + len=16; + } + return burtle(start, len, 0); + } + }; + + struct addressOnlyLessThan: public std::binary_function + { + bool operator()(const ComboAddress& a, const ComboAddress& b) const + { + if(a.sin4.sin_family < b.sin4.sin_family) + return true; + if(a.sin4.sin_family > b.sin4.sin_family) + return false; + if(a.sin4.sin_family == AF_INET) + return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr; + else + return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr)) < 0; + } + }; + + struct addressOnlyEqual: public std::binary_function + { + bool operator()(const ComboAddress& a, const ComboAddress& b) const + { + if(a.sin4.sin_family != b.sin4.sin_family) + return false; + if(a.sin4.sin_family == AF_INET) + return a.sin4.sin_addr.s_addr == b.sin4.sin_addr.s_addr; + else + return !memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr)); + } + }; + + + socklen_t getSocklen() const + { + if(sin4.sin_family == AF_INET) + return sizeof(sin4); + else + return sizeof(sin6); + } + + ComboAddress() + { + sin4.sin_family=AF_INET; + sin4.sin_addr.s_addr=0; + sin4.sin_port=0; + } + + ComboAddress(const struct sockaddr *sa, socklen_t salen) { + setSockaddr(sa, salen); + }; + + ComboAddress(const struct sockaddr_in6 *sa) { + setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in6)); + }; + + ComboAddress(const struct sockaddr_in *sa) { + setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in)); + }; + + void setSockaddr(const struct sockaddr *sa, socklen_t salen) { + if (salen > sizeof(struct sockaddr_in6)) throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6"); + memcpy(this, sa, salen); + } + + // 'port' sets a default value in case 'str' does not set a port + explicit ComboAddress(const string& str, uint16_t port=0) + { + memset(&sin6, 0, sizeof(sin6)); + sin4.sin_family = AF_INET; + sin4.sin_port = 0; + if(makeIPv4sockaddr(str, &sin4)) { + sin6.sin6_family = AF_INET6; + if(makeIPv6sockaddr(str, &sin6) < 0) + throw PDNSException("Unable to convert presentation address '"+ str +"'"); + + } + if(!sin4.sin_port) // 'str' overrides port! + sin4.sin_port=htons(port); + } + + bool isIPv6() const + { + return sin4.sin_family == AF_INET6; + } + bool isIPv4() const + { + return sin4.sin_family == AF_INET; + } + + bool isMappedIPv4() const + { + if(sin4.sin_family!=AF_INET6) + return false; + + int n=0; + const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr; + for(n=0; n < 10; ++n) + if(ptr[n]) + return false; + + for(; n < 12; ++n) + if(ptr[n]!=0xff) + return false; + + return true; + } + + ComboAddress mapToIPv4() const + { + if(!isMappedIPv4()) + throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4"); + ComboAddress ret; + ret.sin4.sin_family=AF_INET; + ret.sin4.sin_port=sin4.sin_port; + + const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr; + ptr+=(sizeof(sin6.sin6_addr.s6_addr) - sizeof(ret.sin4.sin_addr.s_addr)); + memcpy(&ret.sin4.sin_addr.s_addr, ptr, sizeof(ret.sin4.sin_addr.s_addr)); + return ret; + } + + string toString() const + { + char host[1024]; + if(sin4.sin_family && !getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST)) + return host; + else + return "invalid"; + } + + string toStringWithPort() const + { + if(sin4.sin_family==AF_INET) + return toString() + ":" + std::to_string(ntohs(sin4.sin_port)); + else + return "["+toString() + "]:" + std::to_string(ntohs(sin4.sin_port)); + } + + void truncate(unsigned int bits) noexcept; + + uint16_t getPort() const + { + return ntohs(sin4.sin_port); + } + + void reset() + { + memset(&sin4, 0, sizeof(sin4)); + memset(&sin6, 0, sizeof(sin6)); + } + +}; + +/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */ +class NetmaskException: public PDNSException +{ +public: + NetmaskException(const string &a) : PDNSException(a) {} +}; + +inline ComboAddress makeComboAddress(const string& str) +{ + ComboAddress address; + address.sin4.sin_family=AF_INET; + if(inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) { + address.sin4.sin_family=AF_INET6; + if(makeIPv6sockaddr(str, &address.sin6) < 0) + throw NetmaskException("Unable to convert '"+str+"' to a netmask"); + } + return address; +} + +/** This class represents a netmask and can be queried to see if a certain + IP address is matched by this mask */ +class Netmask +{ +public: + Netmask() + { + d_network.sin4.sin_family=0; // disable this doing anything useful + d_network.sin4.sin_port = 0; // this guarantees d_network compares identical + d_mask=0; + d_bits=0; + } + + Netmask(const ComboAddress& network, uint8_t bits=0xff) + { + d_network = network; + d_network.sin4.sin_port=0; + if(bits > 128) + bits = (network.sin4.sin_family == AF_INET) ? 32 : 128; + + d_bits = bits; + if(d_bits<32) + d_mask=~(0xFFFFFFFF>>d_bits); + else + d_mask=0xFFFFFFFF; // not actually used for IPv6 + } + + //! Constructor supplies the mask, which cannot be changed + Netmask(const string &mask) + { + pair split=splitField(mask,'/'); + d_network=makeComboAddress(split.first); + + if(!split.second.empty()) { + d_bits = (uint8_t)pdns_stou(split.second); + if(d_bits<32) + d_mask=~(0xFFFFFFFF>>d_bits); + else + d_mask=0xFFFFFFFF; + } + else if(d_network.sin4.sin_family==AF_INET) { + d_bits = 32; + d_mask = 0xFFFFFFFF; + } + else { + d_bits=128; + d_mask=0; // silence silly warning - d_mask is unused for IPv6 + } + } + + bool match(const ComboAddress& ip) const + { + return match(&ip); + } + + //! If this IP address in socket address matches + bool match(const ComboAddress *ip) const + { + if(d_network.sin4.sin_family != ip->sin4.sin_family) { + return false; + } + if(d_network.sin4.sin_family == AF_INET) { + return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr)); + } + if(d_network.sin6.sin6_family == AF_INET6) { + uint8_t bytes=d_bits/8, n; + const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr; + const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr; + + for(n=0; n < bytes; ++n) { + if(us[n]!=them[n]) { + return false; + } + } + // still here, now match remaining bits + uint8_t bits= d_bits % 8; + uint8_t mask= (uint8_t) ~(0xFF>>bits); + + return((us[n] & mask) == (them[n] & mask)); + } + return false; + } + + //! If this ASCII IP address matches + bool match(const string &ip) const + { + ComboAddress address=makeComboAddress(ip); + return match(&address); + } + + //! If this IP address in native format matches + bool match4(uint32_t ip) const + { + return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask); + } + + string toString() const + { + return d_network.toString()+"/"+std::to_string((unsigned int)d_bits); + } + + string toStringNoMask() const + { + return d_network.toString(); + } + const ComboAddress& getNetwork() const + { + return d_network; + } + const ComboAddress getMaskedNetwork() const + { + ComboAddress result(d_network); + if(isIpv4()) { + result.sin4.sin_addr.s_addr = htonl(ntohl(result.sin4.sin_addr.s_addr) & d_mask); + } + else if(isIpv6()) { + size_t idx; + uint8_t bytes=d_bits/8; + uint8_t *us=(uint8_t*) &result.sin6.sin6_addr.s6_addr; + uint8_t bits= d_bits % 8; + uint8_t mask= (uint8_t) ~(0xFF>>bits); + + if (bytes < sizeof(result.sin6.sin6_addr.s6_addr)) { + us[bytes] &= mask; + } + + for(idx = bytes + 1; idx < sizeof(result.sin6.sin6_addr.s6_addr); ++idx) { + us[idx] = 0; + } + } + return result; + } + uint8_t getBits() const + { + return d_bits; + } + bool isIpv6() const + { + return d_network.sin6.sin6_family == AF_INET6; + } + bool isIpv4() const + { + return d_network.sin4.sin_family == AF_INET; + } + + bool operator<(const Netmask& rhs) const + { + if (empty() && !rhs.empty()) + return false; + + if (!empty() && rhs.empty()) + return true; + + if (d_bits > rhs.d_bits) + return true; + if (d_bits < rhs.d_bits) + return false; + + return d_network < rhs.d_network; + } + + bool operator>(const Netmask& rhs) const + { + return rhs.operator<(*this); + } + + bool operator==(const Netmask& rhs) const + { + return tie(d_network, d_bits) == tie(rhs.d_network, rhs.d_bits); + } + + bool empty() const + { + return d_network.sin4.sin_family==0; + } + +private: + ComboAddress d_network; + uint32_t d_mask; + uint8_t d_bits; +}; + +/** Per-bit binary tree map implementation with pair. + * + * This is an binary tree implementation for storing attributes for IPv4 and IPv6 prefixes. + * The most simple use case is simple NetmaskTree used by NetmaskGroup, which only + * wants to know if given IP address is matched in the prefixes stored. + * + * This element is useful for anything that needs to *STORE* prefixes, and *MATCH* IP addresses + * to a *LIST* of *PREFIXES*. Not the other way round. + * + * You can store IPv4 and IPv6 addresses to same tree, separate payload storage is kept per AFI. + * + * To erase something copy values to new tree sans the value you want to erase. + * + * Use swap if you need to move the tree to another NetmaskTree instance, it is WAY faster + * than using copy ctor or assignment operator, since it moves the nodes and tree root to + * new home instead of actually recreating the tree. + * + * Please see NetmaskGroup for example of simple use case. Other usecases can be found + * from GeoIPBackend and Sortlist, and from dnsdist. + */ +template +class NetmaskTree { +public: + typedef Netmask key_type; + typedef T value_type; + typedef std::pair node_type; + typedef size_t size_type; + +private: + /** Single node in tree, internal use only. + */ + class TreeNode : boost::noncopyable { + public: + explicit TreeNode(int bits) noexcept : parent(NULL),d_bits(bits) { + } + + //(new TreeNode(d_bits+1)); + left->parent = this; + } + return left.get(); + } + + //(new TreeNode(d_bits+1)); + right->parent = this; + } + return right.get(); + } + + unique_ptr left; + unique_ptr right; + TreeNode* parent; + + unique_ptr node4; // node6; //first).second = node->second; + } + + NetmaskTree& operator=(const NetmaskTree& rhs) { + clear(); + // see above. + for(auto const& node: rhs._nodes) + insert(node->first).second = node->second; + return *this; + } + + const typename std::vector::const_iterator begin() const { return _nodes.begin(); } + const typename std::vector::const_iterator end() const { return _nodes.end(); } + + typename std::vector::iterator begin() { return _nodes.begin(); } + typename std::vector::iterator end() { return _nodes.end(); } + + node_type& insert(const string &mask) { + return insert(key_type(mask)); + } + + //(new TreeNode(0)); + TreeNode* node = root.get(); + node_type* value = nullptr; + + if (key.getNetwork().sin4.sin_family == AF_INET) { + std::bitset<32> addr(be32toh(key.getNetwork().sin4.sin_addr.s_addr)); + int bits = 0; + // we turn left on 0 and right on 1 + while(bits < key.getBits()) { + uint8_t val = addr[31-bits]; + if (val) + node = node->make_right(); + else + node = node->make_left(); + bits++; + } + // only create node if not yet assigned + if (!node->node4) { + node->node4 = unique_ptr(new node_type()); + _nodes.push_back(node->node4.get()); + } + value = node->node4.get(); + } else { + uint64_t* addr = (uint64_t*)key.getNetwork().sin6.sin6_addr.s6_addr; + std::bitset<64> addr_low(be64toh(addr[1])); + std::bitset<64> addr_high(be64toh(addr[0])); + int bits = 0; + while(bits < key.getBits()) { + uint8_t val; + // we use high address until we are + if (bits < 64) val = addr_high[63-bits]; + // past 64 bits, and start using low address + else val = addr_low[127-bits]; + + // we turn left on 0 and right on 1 + if (val) + node = node->make_right(); + else + node = node->make_left(); + bits++; + } + // only create node if not yet assigned + if (!node->node6) { + node->node6 = unique_ptr(new node_type()); + _nodes.push_back(node->node6.get()); + } + value = node->node6.get(); + } + // assign key + value->first = key; + return *value; + } + + //first == key; + } + + // addr(be32toh(value.sin4.sin_addr.s_addr)); + int bits = 0; + + while(bits < max_bits) { + // ...we keep track of last non-empty node + if (node->node4) ret = node->node4.get(); + uint8_t val = addr[31-bits]; + // ...and we don't create left/right hand + if (val) { + if (node->right) node = node->right.get(); + // ..and we break when road ends + else break; + } else { + if (node->left) node = node->left.get(); + else break; + } + bits++; + } + // needed if we did not find one in loop + if (node->node4) ret = node->node4.get(); + } else { + uint64_t* addr = (uint64_t*)value.sin6.sin6_addr.s6_addr; + max_bits = std::max(0,std::min(max_bits,128)); + std::bitset<64> addr_low(be64toh(addr[1])); + std::bitset<64> addr_high(be64toh(addr[0])); + int bits = 0; + while(bits < max_bits) { + if (node->node6) ret = node->node6.get(); + uint8_t val; + if (bits < 64) val = addr_high[63-bits]; + else val = addr_low[127-bits]; + if (val) { + if (node->right) node = node->right.get(); + else break; + } else { + if (node->left) node = node->left.get(); + else break; + } + bits++; + } + if (node->node6) ret = node->node6.get(); + } + + // this can be nullptr. + return ret; + } + + void cleanup_tree(TreeNode* node) + { + // only cleanup this node if it has no children and node4 and node6 are both empty + if (!(node->left || node->right || node->node6 || node->node4)) { + // get parent node ptr + TreeNode* parent = node->parent; + // delete this node + if (parent) { + if (parent->left.get() == node) + parent->left.reset(); + else + parent->right.reset(); + // now recurse up to the parent + cleanup_tree(parent); + } + } + } + + // addr(be32toh(key.getNetwork().sin4.sin_addr.s_addr)); + int bits = 0; + while(node && bits < key.getBits()) { + uint8_t val = addr[31-bits]; + if (val) { + node = node->right.get(); + } else { + node = node->left.get(); + } + bits++; + } + if (node) { + for(auto it = _nodes.begin(); it != _nodes.end(); ) { + if (node->node4.get() == *it) + it = _nodes.erase(it); + else + it++; + } + + node->node4.reset(); + + if (d_cleanup_tree) + cleanup_tree(node); + } + } else { + uint64_t* addr = (uint64_t*)key.getNetwork().sin6.sin6_addr.s6_addr; + std::bitset<64> addr_low(be64toh(addr[1])); + std::bitset<64> addr_high(be64toh(addr[0])); + int bits = 0; + while(node && bits < key.getBits()) { + uint8_t val; + if (bits < 64) val = addr_high[63-bits]; + else val = addr_low[127-bits]; + if (val) { + node = node->right.get(); + } else { + node = node->left.get(); + } + bits++; + } + if (node) { + for(auto it = _nodes.begin(); it != _nodes.end(); ) { + if (node->node6.get() == *it) + it = _nodes.erase(it); + else + it++; + } + + node->node6.reset(); + + if (d_cleanup_tree) + cleanup_tree(node); + } + } + } + + void erase(const string& key) { + erase(key_type(key)); + } + + // root; // _nodes; //second; + return false; + } + + bool match(const ComboAddress& ip) const + { + return match(&ip); + } + + bool lookup(const ComboAddress* ip, Netmask* nmp) const + { + const auto &ret = tree.lookup(*ip); + if (ret) { + if (nmp != nullptr) + *nmp = ret->first; + + return ret->second; + } + return false; + } + + bool lookup(const ComboAddress& ip, Netmask* nmp) const + { + return lookup(&ip, nmp); + } + + //! Add this string to the list of possible matches + void addMask(const string &ip, bool positive=true) + { + if(!ip.empty() && ip[0] == '!') { + addMask(Netmask(ip.substr(1)), false); + } else { + addMask(Netmask(ip), positive); + } + } + + //! Add this Netmask to the list of possible matches + void addMask(const Netmask& nm, bool positive=true) + { + tree.insert(nm).second=positive; + } + + //! Delete this Netmask from the list of possible matches + void deleteMask(const Netmask& nm) + { + tree.erase(nm); + } + + void deleteMask(const std::string& ip) + { + if (!ip.empty()) + deleteMask(Netmask(ip)); + } + + void clear() + { + tree.clear(); + } + + bool empty() const + { + return tree.empty(); + } + + size_t size() const + { + return tree.size(); + } + + string toString() const + { + ostringstream str; + for(auto iter = tree.begin(); iter != tree.end(); ++iter) { + if(iter != tree.begin()) + str <<", "; + if(!((*iter)->second)) + str<<"!"; + str<<(*iter)->first.toString(); + } + return str.str(); + } + + void toStringVector(vector* vec) const + { + for(auto iter = tree.begin(); iter != tree.end(); ++iter) { + vec->push_back(((*iter)->second ? "" : "!") + (*iter)->first.toString()); + } + } + + void toMasks(const string &ips) + { + vector parts; + stringtok(parts, ips, ", \t"); + + for (vector::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) + addMask(*iter); + } + +private: + NetmaskTree tree; +}; + + +struct SComboAddress +{ + SComboAddress(const ComboAddress& orig) : ca(orig) {} + ComboAddress ca; + bool operator<(const SComboAddress& rhs) const + { + return ComboAddress::addressOnlyLessThan()(ca, rhs.ca); + } + operator const ComboAddress&() + { + return ca; + } +}; + + +int SSocket(int family, int type, int flags); +int SConnect(int sockfd, const ComboAddress& remote); +/* tries to connect to remote for a maximum of timeout seconds. + sockfd should be set to non-blocking beforehand. + returns 0 on success (the socket is writable), throw a + runtime_error otherwise */ +int SConnectWithTimeout(int sockfd, const ComboAddress& remote, int timeout); +int SBind(int sockfd, const ComboAddress& local); +int SAccept(int sockfd, ComboAddress& remote); +int SListen(int sockfd, int limit); +int SSetsockopt(int sockfd, int level, int opname, int value); + +#if defined(IP_PKTINFO) + #define GEN_IP_PKTINFO IP_PKTINFO +#elif defined(IP_RECVDSTADDR) + #define GEN_IP_PKTINFO IP_RECVDSTADDR +#endif +bool IsAnyAddress(const ComboAddress& addr); +bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination); +bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv); +void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr); +ssize_t sendfromto(int sock, const char* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to); +ssize_t sendMsgWithTimeout(int fd, const char* buffer, size_t len, int timeout, ComboAddress& dest, const ComboAddress& local, unsigned int localItf); +bool sendSizeAndMsgWithTimeout(int sock, uint16_t bufferLen, const char* buffer, int idleTimeout, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int totalTimeout, int flags); +/* requires a non-blocking, connected TCP socket */ +bool isTCPSocketUsable(int sock); + +extern template class NetmaskTree; + +#endif diff --git a/ixfr.cc b/ixfr.cc new file mode 100644 index 0000000..7df8844 --- /dev/null +++ b/ixfr.cc @@ -0,0 +1,252 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "ixfr.hh" +#include "sstuff.hh" +#include "dns_random.hh" +#include "dnsrecords.hh" +#include "dnssecinfra.hh" +#include "tsigverifier.hh" + +vector, vector > > processIXFRRecords(const ComboAddress& master, const DNSName& zone, + const vector& records, const std::shared_ptr masterSOA) +{ + vector, vector > > ret; + + if (records.size() == 0 || masterSOA == nullptr) { + return ret; + } + + // we start at 1 to skip the first SOA record + // we don't increase pos because the final SOA + // of the previous sequence is also the first SOA + // of this one + for(unsigned int pos = 1; pos < records.size(); ) { + vector remove, add; + + // cerr<<"Looking at record in position "<(records[pos]); + if (!sr) { + throw std::runtime_error("Error getting the content of the first SOA record of this IXFR sequence for zone '"+zone.toString()+"' from master '"+master.toStringWithPort()+"'"); + } + + // cerr<<"Serial is "<d_st.serial<<", final serial is "<d_st.serial<d_st.serial == masterSOA->d_st.serial) { + // if it's the final SOA, there is nothing for us to see + break; + } + + remove.push_back(records[pos]); // this adds the SOA + + // process removals + for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) { + remove.push_back(records[pos]); + } + + if (pos >= records.size()) { + throw std::runtime_error("No SOA record to finish the removals part of the IXFR sequence of zone '" + zone.toString() + "' from " + master.toStringWithPort()); + } + + sr = getRR(records[pos]); + if (!sr) { + throw std::runtime_error("Invalid SOA record to finish the removals part of the IXFR sequence of zone '" + zone.toString() + "' from " + master.toStringWithPort()); + } + + // this is the serial of the zone after the removals + // and updates, but that might not be the final serial + // because there might be several sequences + uint32_t newSerial = sr->d_st.serial; + add.push_back(records[pos]); // this adds the new SOA + + // process additions + for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) { + add.push_back(records[pos]); + } + + if (pos >= records.size()) { + throw std::runtime_error("No SOA record to finish the additions part of the IXFR sequence of zone '" + zone.toString() + "' from " + master.toStringWithPort()); + } + + sr = getRR(records[pos]); + if (!sr) { + throw std::runtime_error("Invalid SOA record to finish the additions part of the IXFR sequence of zone '" + zone.toString() + "' from " + master.toStringWithPort()); + } + + if (sr->d_st.serial != newSerial) { + throw std::runtime_error("Invalid serial (" + std::to_string(sr->d_st.serial) + ", expecting " + std::to_string(newSerial) + ") in the SOA record finishing the additions part of the IXFR sequence of zone '" + zone.toString() + "' from " + master.toStringWithPort()); + } + + if (newSerial == masterSOA->d_st.serial) { + // this was the last sequence + if (pos != (records.size() - 1)) { + throw std::runtime_error("Trailing records after the last IXFR sequence of zone '" + zone.toString() + "' from " + master.toStringWithPort()); + } + } + + ret.push_back(make_pair(remove,add)); + } + + return ret; +} + +// Returns pairs of "remove & add" vectors. If you get an empty remove, it means you got an AXFR! +vector, vector > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr, + const TSIGTriplet& tt, const ComboAddress* laddr, size_t maxReceivedBytes) +{ + vector, vector > > ret; + vector packet; + DNSPacketWriter pw(packet, zone, QType::IXFR); + pw.getHeader()->qr=0; + pw.getHeader()->rd=0; + pw.getHeader()->id=dns_random(0xffff); + pw.startRecord(zone, QType::SOA, 0, QClass::IN, DNSResourceRecord::AUTHORITY); + oursr.d_content->toPacket(pw); + + pw.commit(); + TSIGRecordContent trc; + TSIGTCPVerifier tsigVerifier(tt, master, trc); + if(!tt.algo.empty()) { + TSIGHashEnum the; + getTSIGHashEnum(tt.algo, the); + try { + trc.d_algoName = getTSIGAlgoName(the); + } catch(PDNSException& pe) { + throw std::runtime_error("TSIG algorithm '"+tt.algo.toString()+"' is unknown."); + } + trc.d_time = time((time_t*)NULL); + trc.d_fudge = 300; + trc.d_origID=ntohs(pw.getHeader()->id); + trc.d_eRcode=0; + addTSIG(pw, trc, tt.name, tt.secret, "", false); + } + uint16_t len=htons(packet.size()); + string msg((const char*)&len, 2); + msg.append((const char*)&packet[0], packet.size()); + + Socket s(master.sin4.sin_family, SOCK_STREAM); + // cout<<"going to connect"< masterSOA = nullptr; + vector records; + size_t receivedBytes = 0; + int8_t ixfrInProgress = -2; + + for(;;) { + // IXFR end + if (ixfrInProgress >= 0) + break; + + if(s.read((char*)&len, sizeof(len)) != sizeof(len)) + break; + + len=ntohs(len); + // cout<<"Got chunk of "< 0 && (maxReceivedBytes - receivedBytes) < (size_t) len) + throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toString()+"' from master "+master.toStringWithPort()); + + char reply[len]; + readn2(s.getHandle(), reply, len); + receivedBytes += len; + + MOADNSParser mdp(false, string(reply, len)); + if(mdp.d_header.rcode) + throw std::runtime_error("Got an error trying to IXFR zone '"+zone.toString()+"' from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode)); + + // cout<<"Got a response, rcode: "<getZoneRepresentation()<(r.first); + if (!sr) { + throw std::runtime_error("Error getting the content of the first SOA record of the IXFR answer for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"'"); + } + + if(sr->d_st.serial == std::dynamic_pointer_cast(oursr.d_content)->d_st.serial) { + // we are up to date + return ret; + } + masterSOA = sr; + } else if (r.first.d_type == QType::SOA) { + auto sr = getRR(r.first); + if (!sr) { + throw std::runtime_error("Error getting the content of SOA record of IXFR answer for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"'"); + } + + // we hit the last SOA record + // IXFR is considered to be done if we hit the last SOA record twice + if (masterSOA->d_st.serial == sr->d_st.serial) { + ixfrInProgress++; + } + } + + if(r.first.d_place != DNSResourceRecord::ANSWER) { + if(r.first.d_type == QType::TSIG) + continue; + + if(r.first.d_type == QType::OPT) + continue; + + throw std::runtime_error("Unexpected record (" +QType(r.first.d_type).getName()+") in non-answer section ("+std::to_string(r.first.d_place)+")in IXFR response for zone '"+zone.toString()+"' from master '"+master.toStringWithPort()); + } + + r.first.d_name.makeUsRelative(zone); + records.push_back(r.first); + } + } + + // cout<<"Got "<, vector > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, + const DNSRecord& sr, const TSIGTriplet& tt=TSIGTriplet(), + const ComboAddress* laddr=0, size_t maxReceivedBytes=0); + +vector, vector > > processIXFRRecords(const ComboAddress& master, const DNSName& zone, + const vector& records, const std::shared_ptr masterSOA); diff --git a/json.cc b/json.cc new file mode 100644 index 0000000..3435465 --- /dev/null +++ b/json.cc @@ -0,0 +1,107 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "json.hh" +#include "namespaces.hh" +#include "misc.hh" + +using json11::Json; + +int intFromJson(const Json container, const std::string& key) +{ + auto val = container[key]; + if (val.is_number()) { + return val.int_value(); + } else if (val.is_string()) { + return std::stoi(val.string_value()); + } else { + throw JsonException("Key '" + string(key) + "' not an Integer or not present"); + } +} + +int intFromJson(const Json container, const std::string& key, const int default_value) +{ + auto val = container[key]; + if (val.is_number()) { + return val.int_value(); + } else if (val.is_string()) { + return std::stoi(val.string_value()); + } else { + // TODO: check if value really isn't present + return default_value; + } +} + +double doubleFromJson(const Json container, const std::string& key) +{ + auto val = container[key]; + if (val.is_number()) { + return val.number_value(); + } else if (val.is_string()) { + return std::stod(val.string_value()); + } else { + throw JsonException("Key '" + string(key) + "' not an Integer or not present"); + } +} + +double doubleFromJson(const Json container, const std::string& key, const double default_value) +{ + auto val = container[key]; + if (val.is_number()) { + return val.number_value(); + } else if (val.is_string()) { + return std::stod(val.string_value()); + } else { + // TODO: check if value really isn't present + return default_value; + } +} + +string stringFromJson(const Json container, const std::string &key) +{ + const Json val = container[key]; + if (val.is_string()) { + return val.string_value(); + } else { + throw JsonException("Key '" + string(key) + "' not present or not a String"); + } +} + +bool boolFromJson(const Json container, const std::string& key) +{ + auto val = container[key]; + if (val.is_bool()) { + return val.bool_value(); + } + throw JsonException("Key '" + string(key) + "' not present or not a Bool"); +} + +bool boolFromJson(const Json container, const std::string& key, const bool default_value) +{ + auto val = container[key]; + if (val.is_bool()) { + return val.bool_value(); + } + return default_value; +} diff --git a/json.hh b/json.hh new file mode 100644 index 0000000..69deb48 --- /dev/null +++ b/json.hh @@ -0,0 +1,41 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once // it is 2012, deal with it + +#include +#include +#include "json11.hpp" + +int intFromJson(const json11::Json container, const std::string& key); +int intFromJson(const json11::Json container, const std::string& key, const int default_value); +double doubleFromJson(const json11::Json container, const std::string& key); +double doubleFromJson(const json11::Json container, const std::string& key, const double default_value); +std::string stringFromJson(const json11::Json container, const std::string &key); +bool boolFromJson(const json11::Json container, const std::string& key); +bool boolFromJson(const json11::Json container, const std::string& key, const bool default_value); + +class JsonException : public std::runtime_error +{ +public: + JsonException(const std::string& what) : std::runtime_error(what) { + } +}; diff --git a/kqueuemplexer.cc b/kqueuemplexer.cc new file mode 100644 index 0000000..b3510c5 --- /dev/null +++ b/kqueuemplexer.cc @@ -0,0 +1,176 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include +#include "misc.hh" +#include +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include +#endif +#include + +#include "namespaces.hh" + +class KqueueFDMultiplexer : public FDMultiplexer +{ +public: + KqueueFDMultiplexer(); + virtual ~KqueueFDMultiplexer() + { + close(d_kqueuefd); + } + + virtual int run(struct timeval* tv, int timeout=500); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "kqueue"; + } +private: + int d_kqueuefd; + boost::shared_array d_kevents; + static unsigned int s_maxevents; // not a hard maximum +}; + +unsigned int KqueueFDMultiplexer::s_maxevents=1024; + +static FDMultiplexer* make() +{ + return new KqueueFDMultiplexer(); +} + +static struct KqueueRegisterOurselves +{ + KqueueRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &make)); // priority 0! + } +} kQueuedoIt; + +KqueueFDMultiplexer::KqueueFDMultiplexer() : d_kevents(new struct kevent[s_maxevents]) +{ + d_kqueuefd=kqueue(); + if(d_kqueuefd < 0) + throw FDMultiplexerException("Setting up kqueue: "+stringerror()); +} + +void KqueueFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + struct kevent kqevent; + EV_SET(&kqevent, fd, (&cbmap == &d_readCallbacks) ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0,0,0); + + if(kevent(d_kqueuefd, &kqevent, 1, 0, 0, 0) < 0) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to kqueue set: "+stringerror()); + } +} + +void KqueueFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + accountingRemoveFD(cbmap, fd); + + struct kevent kqevent; + EV_SET(&kqevent, fd, (&cbmap == &d_readCallbacks) ? EVFILT_READ : EVFILT_WRITE, EV_DELETE, 0,0,0); + + if(kevent(d_kqueuefd, &kqevent, 1, 0, 0, 0) < 0) // ponder putting Callback back on the map.. + throw FDMultiplexerException("Removing fd from kqueue set: "+stringerror()); +} + +int KqueueFDMultiplexer::run(struct timeval* now, int timeout) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + + struct timespec ts; + ts.tv_sec=timeout/1000; + ts.tv_nsec=(timeout % 1000) * 1000000; + + int ret=kevent(d_kqueuefd, 0, 0, d_kevents.get(), s_maxevents, &ts); + gettimeofday(now,0); // MANDATORY! + + if(ret < 0 && errno!=EINTR) + throw FDMultiplexerException("kqueue returned error: "+stringerror()); + + if(ret < 0) // nothing - thanks AB! + return 0; + + d_inrun=true; + + for(int n=0; n < ret; ++n) { + d_iter=d_readCallbacks.find(d_kevents[n].ident); + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + continue; // so we don't find ourselves as writable again + } + + d_iter=d_writeCallbacks.find(d_kevents[n].ident); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + } + } + + d_inrun=false; + return ret; +} + +#if 0 +void acceptData(int fd, boost::any& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< +#include +#include + +template +struct lazy_allocator { + using value_type = T; + using pointer = T*; + using size_type = std::size_t; + static_assert (std::is_trivial::value, + "lazy_allocator must only be used with trivial types"); + + pointer + allocate (size_type const n) { + return static_cast(::operator new (n * sizeof(value_type))); + } + + void + deallocate (pointer const ptr, size_type const n) noexcept { +#if defined(__cpp_sized_deallocation) && (__cpp_sized_deallocation >= 201309) + ::operator delete (ptr, n * sizeof(value_type)); +#else + (void) n; + ::operator delete (ptr); +#endif + } + + void construct (T*) const noexcept {} + + template + void + construct (X* place, Args&&... args) const noexcept { + new (static_cast(place)) X (std::forward(args)...); + } +}; + +template inline +bool operator== (lazy_allocator const&, lazy_allocator const&) noexcept { + return true; +} + +template inline +bool operator!= (lazy_allocator const&, lazy_allocator const&) noexcept { + return false; +} + +#endif // LAZY_ALLOCATOR_HH diff --git a/lock.hh b/lock.hh new file mode 100644 index 0000000..a20c220 --- /dev/null +++ b/lock.hh @@ -0,0 +1,220 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 LOCK_HH +#define LOCK_HH + +#include +#include +#include "misc.hh" +#include "pdnsexception.hh" + +extern bool g_singleThreaded; + +class Lock +{ + pthread_mutex_t *d_lock; +public: + Lock(const Lock& rhs) = delete; + Lock& operator=(const Lock& rhs) = delete; + + Lock(pthread_mutex_t *lock) : d_lock(lock) + { + if(g_singleThreaded) + return; + + int err; + if((err = pthread_mutex_lock(d_lock))) { + errno = err; + throw PDNSException("error acquiring lock: "+stringerror()); + } + } + ~Lock() + { + if(g_singleThreaded) + return; + + pthread_mutex_unlock(d_lock); + } +}; + +class WriteLock +{ + pthread_rwlock_t *d_lock; +public: + + WriteLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) + return; + + int err; + if((err = pthread_rwlock_wrlock(d_lock))) { + errno = err; + throw PDNSException("error acquiring rwlock wrlock: "+stringerror()); + } + } + ~WriteLock() + { + if(g_singleThreaded) + return; + if(d_lock) // might have been moved + pthread_rwlock_unlock(d_lock); + } + + WriteLock(WriteLock&& rhs) + { + d_lock = rhs.d_lock; + rhs.d_lock=0; + } + WriteLock(const WriteLock& rhs) = delete; + WriteLock& operator=(const WriteLock& rhs) = delete; + + +}; + +class TryWriteLock +{ + pthread_rwlock_t *d_lock; + bool d_havelock; +public: + TryWriteLock(const TryWriteLock& rhs) = delete; + TryWriteLock& operator=(const TryWriteLock& rhs) = delete; + + TryWriteLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) { + d_havelock=true; + return; + } + + d_havelock=false; + int err; + if((err = pthread_rwlock_trywrlock(d_lock)) && err!=EBUSY) { + errno = err; + throw PDNSException("error acquiring rwlock tryrwlock: "+stringerror()); + } + d_havelock=(err==0); + } + + TryWriteLock(TryWriteLock&& rhs) + { + d_lock = rhs.d_lock; + rhs.d_lock=0; + } + + + ~TryWriteLock() + { + if(g_singleThreaded) + return; + + if(d_havelock && d_lock) // we might be moved + pthread_rwlock_unlock(d_lock); + } + bool gotIt() + { + if(g_singleThreaded) + return true; + + return d_havelock; + } +}; + +class TryReadLock +{ + pthread_rwlock_t *d_lock; + bool d_havelock; +public: + TryReadLock(const TryReadLock& rhs) = delete; + TryReadLock& operator=(const TryReadLock& rhs) = delete; + + TryReadLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) { + d_havelock=true; + return; + } + + int err; + if((err = pthread_rwlock_tryrdlock(d_lock)) && err!=EBUSY) { + errno = err; + throw PDNSException("error acquiring rwlock tryrdlock: "+stringerror()); + } + d_havelock=(err==0); + } + TryReadLock(TryReadLock&& rhs) + { + d_lock = rhs.d_lock; + rhs.d_lock=0; + } + + ~TryReadLock() + { + if(g_singleThreaded) + return; + + if(d_havelock && d_lock) + pthread_rwlock_unlock(d_lock); + } + bool gotIt() + { + if(g_singleThreaded) + return true; + + return d_havelock; + } +}; + + +class ReadLock +{ + pthread_rwlock_t *d_lock; +public: + + ReadLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) + return; + + int err; + if((err = pthread_rwlock_rdlock(d_lock))) { + errno = err; + throw PDNSException("error acquiring rwlock readlock: "+stringerror()); + } + } + ~ReadLock() + { + if(g_singleThreaded) + return; + if(d_lock) // may have been moved + pthread_rwlock_unlock(d_lock); + } + + ReadLock(ReadLock&& rhs) + { + d_lock = rhs.d_lock; + rhs.d_lock=0; + } + ReadLock(const ReadLock& rhs) = delete; + ReadLock& operator=(const ReadLock& rhs) = delete; +}; +#endif diff --git a/logger.cc b/logger.cc new file mode 100644 index 0000000..01eb6e4 --- /dev/null +++ b/logger.cc @@ -0,0 +1,246 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "logger.hh" +#include "misc.hh" +#ifndef RECURSOR +#include "statbag.hh" +extern StatBag S; +#endif +#include "lock.hh" +#include "namespaces.hh" + +pthread_once_t Logger::s_once; +pthread_key_t Logger::s_loggerKey; + +Logger &theL(const string &pname) +{ + static Logger l("", LOG_DAEMON); + if(!pname.empty()) + l.setName(pname); + return l; +} + +void Logger::log(const string &msg, Urgency u) +{ +#ifndef RECURSOR + bool mustAccount(false); +#endif + if(u<=consoleUrgency) { + char buffer[50] = ""; + if (d_timestamps) { + struct tm tm; + time_t t; + time(&t); + tm=*localtime(&t); + strftime(buffer,sizeof(buffer),"%b %d %H:%M:%S ", &tm); + } + + static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + Lock l(&m); // the C++-2011 spec says we need this, and OSX actually does + clog << string(buffer) + msg <d_urgency=u; + return *this; +} + +void Logger::perThreadDestructor(void* buf) +{ + PerThread* pt = (PerThread*) buf; + delete pt; +} + +Logger::PerThread* Logger::getPerThread() +{ + void *buf=pthread_getspecific(s_loggerKey); + PerThread* ret; + if(buf) + ret = (PerThread*) buf; + else { + ret = new PerThread(); + pthread_setspecific(s_loggerKey, (void*)ret); + } + return ret; +} + +Logger& Logger::operator<<(const string &s) +{ + PerThread* pt =getPerThread(); + pt->d_output.append(s); + return *this; +} + +Logger& Logger::operator<<(const char *s) +{ + *this<d_output, pt->d_urgency); + pt->d_output.clear(); + pt->d_urgency=Info; + return *this; +} + +Logger& Logger::operator<<(const DNSName &d) +{ + *this< +#include +#include +#include +#include +#include + +#include "namespaces.hh" +#include "dnsname.hh" +#include "iputils.hh" + +//! The Logger class can be used to log messages in various ways. +class Logger +{ +public: + Logger(const string &, int facility=LOG_DAEMON); //!< pass the identification you wish to appear in the log + + //! The urgency of a log message + enum Urgency {All=32767,Alert=LOG_ALERT, Critical=LOG_CRIT, Error=LOG_ERR, Warning=LOG_WARNING, + Notice=LOG_NOTICE,Info=LOG_INFO, Debug=LOG_DEBUG, None=-1}; + + /** Log a message. + \param msg Message you wish to log + \param u Urgency of the message you wish to log + */ + void log(const string &msg, Urgency u=Notice); + + void setFacility(int f){d_facility=f;open();} //!< Choose logging facility + void setFlag(int f){flags|=f;open();} //!< set a syslog flag + void setName(const string &); + + //! set lower limit of urgency needed for console display. Messages of this urgency, and higher, will be displayed + void toConsole(Urgency); + void setLoglevel( Urgency ); + + void disableSyslog(bool d) { + d_disableSyslog = d; + } + + void setTimestamps(bool t) { + d_timestamps = t; + } + + //! Log to a file. + void toFile( const string & filename ); + + void resetFlags(){flags=0;open();} //!< zero the flags + /** Use this to stream to your log, like this: + \code + L<<"This is an informational message"< +#include "syncres.hh" +#include "logger.hh" +#include "namespaces.hh" +#include "rec_channel.hh" +#include "ednsoptions.hh" +#include "ednssubnet.hh" +#include "filterpo.hh" +#include "rec-snmp.hh" +#include +#include "lua-recursor4.hh" + +static int followCNAMERecords(vector& ret, const QType& qtype) +{ + vector resolved; + DNSName target; + for(const DNSRecord& rr : ret) { + if(rr.d_type == QType::CNAME) { + auto rec = getRR(rr); + if(rec) { + target=rec->getTarget(); + break; + } + } + } + if(target.empty()) + return 0; + + int rcode=directResolve(target, qtype, 1, resolved); // 1 == class + + for(const DNSRecord& rr : resolved) { + ret.push_back(rr); + } + return rcode; + +} + +static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector& ret) +{ + int rcode=directResolve(qname, QType(QType::A), 1, ret); + + ComboAddress prefixAddress(prefix); + + for(DNSRecord& rr : ret) + { + if(rr.d_type == QType::A && rr.d_place==DNSResourceRecord::ANSWER) { + if(auto rec = getRR(rr)) { + ComboAddress ipv4(rec->getCA()); + uint32_t tmp; + memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4); + // tmp=htonl(tmp); + memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4); + rr.d_content = std::make_shared(prefixAddress); + rr.d_type = QType::AAAA; + } + } + } + return rcode; +} + +static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector& ret) +{ + /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it + and turn it into an IPv4 in-addr.arpa query */ + ret.clear(); + vector parts = qname.getRawLabels(); + + if(parts.size() < 8) + return -1; + + string newquery; + for(int n = 0; n < 4; ++n) { + newquery += + std::to_string(stoll(parts[n*2], 0, 16) + 16*stoll(parts[n*2+1], 0, 16)); + newquery.append(1,'.'); + } + newquery += "in-addr.arpa."; + + + int rcode = directResolve(DNSName(newquery), QType(QType::PTR), 1, ret); + for(DNSRecord& rr : ret) + { + if(rr.d_type == QType::PTR && rr.d_place==DNSResourceRecord::ANSWER) { + rr.d_name = qname; + } + } + return rcode; + +} + +boost::optional RecursorLua4::DNSQuestion::getDH() const +{ + if (dh) + return *dh; + return boost::optional(); +} + +vector RecursorLua4::DNSQuestion::getEDNSFlags() const +{ + vector ret; + if (ednsFlags) { + if (*ednsFlags & EDNSOpts::DNSSECOK) + ret.push_back("DO"); + } + return ret; +} + +bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag) const +{ + if (ednsFlags) { + if (flag == "DO" && (*ednsFlags & EDNSOpts::DNSSECOK)) + return true; + } + return false; +} + +vector > RecursorLua4::DNSQuestion::getEDNSOptions() const +{ + if(ednsOptions) + return *ednsOptions; + else + return vector>(); +} + +boost::optional RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const +{ + if(ednsOptions) + for(const auto& o : *ednsOptions) + if(o.first==code) + return o.second; + + return boost::optional(); +} + +boost::optional RecursorLua4::DNSQuestion::getEDNSSubnet() const +{ + + if(ednsOptions) { + for(const auto& o : *ednsOptions) { + if(o.first==EDNSOptionCode::ECS) { + EDNSSubnetOpts eso; + if(getEDNSSubnetOptsFromString(o.second, &eso)) + return eso.source; + else + break; + } + } + } + return boost::optional(); +} + + +vector > RecursorLua4::DNSQuestion::getRecords() const +{ + vector > ret; + int num=1; + for(const auto& r : records) { + ret.push_back({num++, r}); + } + return ret; +} +void RecursorLua4::DNSQuestion::setRecords(const vector >& recs) +{ + records.clear(); + for(const auto& p : recs) { + records.push_back(p.second); + } +} + +void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional ttl, boost::optional name) +{ + DNSRecord dr; + dr.d_name=name ? DNSName(*name) : qname; + dr.d_ttl=ttl.get_value_or(3600); + dr.d_type = type; + dr.d_place = place; + dr.d_content = DNSRecordContent::mastermake(type, 1, content); + records.push_back(dr); +} + +void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional ttl, boost::optional name) +{ + addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name); +} + +struct DynMetric +{ + std::atomic* ptr; + void inc() { (*ptr)++; } + void incBy(unsigned int by) { (*ptr)+= by; } + unsigned long get() { return *ptr; } + void set(unsigned long val) { *ptr =val; } +}; + +RecursorLua4::RecursorLua4(const std::string& fname) +{ + d_lw = std::unique_ptr(new LuaContext); + + d_lw->registerFunction("getID", [](dnsheader& dh) { return dh.id; }); + d_lw->registerFunction("getCD", [](dnsheader& dh) { return dh.cd; }); + d_lw->registerFunction("getTC", [](dnsheader& dh) { return dh.tc; }); + d_lw->registerFunction("getRA", [](dnsheader& dh) { return dh.ra; }); + d_lw->registerFunction("getAD", [](dnsheader& dh) { return dh.ad; }); + d_lw->registerFunction("getAA", [](dnsheader& dh) { return dh.aa; }); + d_lw->registerFunction("getRD", [](dnsheader& dh) { return dh.rd; }); + d_lw->registerFunction("getRCODE", [](dnsheader& dh) { return dh.rcode; }); + d_lw->registerFunction("getOPCODE", [](dnsheader& dh) { return dh.opcode; }); + d_lw->registerFunction("getQDCOUNT", [](dnsheader& dh) { return ntohs(dh.qdcount); }); + d_lw->registerFunction("getANCOUNT", [](dnsheader& dh) { return ntohs(dh.ancount); }); + d_lw->registerFunction("getNSCOUNT", [](dnsheader& dh) { return ntohs(dh.nscount); }); + d_lw->registerFunction("getARCOUNT", [](dnsheader& dh) { return ntohs(dh.arcount); }); + + d_lw->writeFunction("newDN", [](boost::variant dom){ + if(dom.which() == 0) + return DNSName(boost::get(dom)); + else + return DNSName(boost::get(dom)); + }); + d_lw->registerFunction("isPartOf", &DNSName::isPartOf); + d_lw->registerFunction("countLabels", [](const DNSName& name) { return name.countLabels(); }); + d_lw->registerFunction("wirelength", [](const DNSName& name) { return name.wirelength(); }); + d_lw->registerFunction( + "equal", + [](const DNSName& lhs, const std::string& rhs) { + return lhs==DNSName(rhs); + } + ); + d_lw->registerFunction("__eq", &DNSName::operator==); + + d_lw->registerFunction("toString", [](const ComboAddress& ca) { return ca.toString(); }); + d_lw->registerFunction("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); + d_lw->registerFunction("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } ); + d_lw->registerFunction("getRaw", [](const ComboAddress& ca) { + if(ca.sin4.sin_family == AF_INET) { + auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4); + } + else + return string((const char*)&ca.sin6.sin6_addr.s6_addr, 16); + } ); + d_lw->registerFunction("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; }); + d_lw->registerFunction("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; }); + d_lw->registerFunction("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); }); + d_lw->registerFunction("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); }); + d_lw->registerFunction("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); }); + + d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); }); + typedef std::unordered_set cas_t; + d_lw->writeFunction("newCAS", []{ return cas_t(); }); + + + d_lw->registerFunction > >)>( + "add", + [](cas_t& cas, const boost::variant > >& in) + { + try { + if(auto s = boost::get(&in)) { + cas.insert(ComboAddress(*s)); + } + else if(auto v = boost::get > >(&in)) { + for(const auto&entry : *v) + cas.insert(ComboAddress(entry.second)); + } + else { + cas.insert(boost::get(in)); + } + } + catch(std::exception& e) { theL() <registerFunction("check",[](const cas_t& cas, const ComboAddress&ca) { + return (bool)cas.count(ca); + }); + + d_lw->registerFunction( + "equal", + [](const ComboAddress& lhs, const ComboAddress& rhs) { + return ComboAddress::addressOnlyEqual()(lhs, rhs); + } + ); + + d_lw->writeFunction("newNetmask", [](const string& s) { return Netmask(s); }); + d_lw->registerFunction("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary + d_lw->registerFunction("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } ); + d_lw->registerFunction("isIpv4", &Netmask::isIpv4); + d_lw->registerFunction("isIpv6", &Netmask::isIpv6); + d_lw->registerFunction("getBits", &Netmask::getBits); + d_lw->registerFunction("toString", &Netmask::toString); + d_lw->registerFunction("empty", &Netmask::empty); + d_lw->registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match); + d_lw->registerFunction("__eq", &Netmask::operator==); + + d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); }); + d_lw->registerFunction( + "addMask", [](NetmaskGroup&nmg, const std::string& mask){ + nmg.addMask(mask); + } + ); + + d_lw->registerFunction>&)>( + "addMasks", + [](NetmaskGroup&nmg, const vector>& masks){ + for(const auto& mask: masks) + nmg.addMask(mask.second); + } + ); + + + d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match); + d_lw->registerFunction("toString", [](const DNSName&dn ) { return dn.toString(); }); + d_lw->registerFunction("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); }); + d_lw->registerFunction("chopOff", [](DNSName&dn ) { return dn.chopOff(); }); + + d_lw->registerMember("qname", [](const DNSQuestion& dq) -> const DNSName& { return dq.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; }); + d_lw->registerMember("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; }); + d_lw->registerMember("isTcp", [](const DNSQuestion& dq) -> bool { return dq.isTcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; }); + d_lw->registerMember("localaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.local; }, [](DNSQuestion& dq, const ComboAddress& newLocal) { (void) newLocal; }); + d_lw->registerMember("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.remote; }, [](DNSQuestion& dq, const ComboAddress& newRemote) { (void) newRemote; }); + d_lw->registerMember("validationState", [](const DNSQuestion& dq) -> vState { return dq.validationState; }, [](DNSQuestion& dq, vState newState) { (void) newState; }); + + d_lw->registerMember("variable", [](const DNSQuestion& dq) -> bool { return dq.variable; }, [](DNSQuestion& dq, bool newVariable) { dq.variable = newVariable; }); + d_lw->registerMember("wantsRPZ", [](const DNSQuestion& dq) -> bool { return dq.wantsRPZ; }, [](DNSQuestion& dq, bool newWantsRPZ) { dq.wantsRPZ = newWantsRPZ; }); + + d_lw->registerMember("rcode", &DNSQuestion::rcode); + d_lw->registerMember("tag", &DNSQuestion::tag); + d_lw->registerMember("requestorId", &DNSQuestion::requestorId); + d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction); + d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix); + d_lw->registerMember("followupName", &DNSQuestion::followupName); + d_lw->registerMember("data", &DNSQuestion::data); + d_lw->registerMember("udpQuery", &DNSQuestion::udpQuery); + d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer); + d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest); + d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback); + d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy); + d_lw->registerMember("policyName", + [](const DNSFilterEngine::Policy& pol) -> std::string { + if(pol.d_name) + return *pol.d_name; + return std::string(); + }, + [](DNSFilterEngine::Policy& pol, const std::string& name) { + pol.d_name = std::make_shared(name); + }); + d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind); + d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl); + d_lw->registerMember("policyCustom", + [](const DNSFilterEngine::Policy& pol) -> std::string { + if(pol.d_custom) + return pol.d_custom->getZoneRepresentation(); + return std::string(); + }, + [](DNSFilterEngine::Policy& pol, const std::string& content) { + // Only CNAMES for now, when we ever add a d_custom_type, there will be pain + pol.d_custom = DNSRecordContent::mastermake(QType::CNAME, 1, content); + } + ); + d_lw->registerFunction("getDH", &DNSQuestion::getDH); + d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions); + d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption); + d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet); + d_lw->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags); + d_lw->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag); + d_lw->registerMember("name", &DNSRecord::d_name); + d_lw->registerMember("type", &DNSRecord::d_type); + d_lw->registerMember("ttl", &DNSRecord::d_ttl); + d_lw->registerMember("place", &DNSRecord::d_place); + + d_lw->registerMember("size", &EDNSOptionView::size); + d_lw->registerFunction("getContent", [](const EDNSOptionView& option) { return std::string(option.content, option.size); }); + + d_lw->registerFunction("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); }); + d_lw->registerFunction(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) { + boost::optional ret; + + if(auto rec = std::dynamic_pointer_cast(dr.d_content)) + ret=rec->getCA(53); + else if(auto aaaarec = std::dynamic_pointer_cast(dr.d_content)) + ret=aaaarec->getCA(53); + return ret; + }); + + + d_lw->registerFunction("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.d_content = DNSRecordContent::mastermake(dr.d_type, 1, newContent); }); + d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer); + d_lw->registerFunction("addRecord", &DNSQuestion::addRecord); + d_lw->registerFunction("getRecords", &DNSQuestion::getRecords); + d_lw->registerFunction("setRecords", &DNSQuestion::setRecords); + + d_lw->registerFunction("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->push_back(tag); } }); + d_lw->registerFunction >&)>("setPolicyTags", [](DNSQuestion& dq, const std::vector >& tags) { + if (dq.policyTags) { + dq.policyTags->clear(); + for (const auto& tag : tags) { + dq.policyTags->push_back(tag.second); + } + } + }); + d_lw->registerFunction >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) { + std::vector > ret; + if (dq.policyTags) { + int count = 1; + for (const auto& tag : *dq.policyTags) { + ret.push_back({count++, tag}); + } + } + return ret; + }); + + d_lw->registerFunction("discardPolicy", [](DNSQuestion& dq, const std::string& policy) { + if (dq.discardedPolicies) { + (*dq.discardedPolicies)[policy] = true; + } + }); + + d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); }); + d_lw->registerFunction > >)>( + "add", + [](SuffixMatchNode&smn, const boost::variant > >& in){ + try { + if(auto s = boost::get(&in)) { + smn.add(DNSName(*s)); + } + else if(auto v = boost::get > >(&in)) { + for(const auto& entry : *v) + smn.add(DNSName(entry.second)); + } + else { + smn.add(boost::get(in)); + } + } + catch(std::exception& e) { + theL() <registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); + d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString); + + + d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional loglevel) { + theL() << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg< > in_t; + vector > > pd{ + {"DROP", (int)PolicyDecision::DROP} + }; + + vector > rcodes = {{"NOERROR", RCode::NoError }, + {"FORMERR", RCode::FormErr }, + {"SERVFAIL", RCode::ServFail }, + {"NXDOMAIN", RCode::NXDomain }, + {"NOTIMP", RCode::NotImp }, + {"REFUSED", RCode::Refused }, + {"YXDOMAIN", RCode::YXDomain }, + {"YXRRSET", RCode::YXRRSet }, + {"NXRRSET", RCode::NXRRSet }, + {"NOTAUTH", RCode::NotAuth }, + {"NOTZONE", RCode::NotZone }}; + for(const auto& rcode : rcodes) + pd.push_back({rcode.first, rcode.second}); + + pd.push_back({"loglevels", in_t{ + {"Alert", LOG_ALERT}, + {"Critical", LOG_CRIT}, + {"Debug", LOG_DEBUG}, + {"Emergency", LOG_EMERG}, + {"Info", LOG_INFO}, + {"Notice", LOG_NOTICE}, + {"Warning", LOG_WARNING}, + {"Error", LOG_ERR} + }}); + + pd.push_back({"policykinds", in_t { + {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction}, + {"Drop", (int)DNSFilterEngine::PolicyKind::Drop }, + {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN}, + {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA }, + {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate}, + {"Custom", (int)DNSFilterEngine::PolicyKind::Custom } + }}); + + for(const auto& n : QType::names) + pd.push_back({n.first, n.second}); + + pd.push_back({"validationstates", in_t{ + {"Indeterminate", Indeterminate }, + {"Bogus", Bogus }, + {"Insecure", Insecure }, + {"Secure", Secure }, + }}); + + pd.push_back({"now", &g_now}); + d_lw->registerMember("tv_sec", &timeval::tv_sec); + d_lw->registerMember("tv_usec", &timeval::tv_usec); + + d_lw->writeVariable("pdns", pd); + + d_lw->writeFunction("getMetric", [](const std::string& str) { + return DynMetric{getDynMetric(str)}; + }); + + d_lw->registerFunction("inc", &DynMetric::inc); + d_lw->registerFunction("incBy", &DynMetric::incBy); + d_lw->registerFunction("set", &DynMetric::set); + d_lw->registerFunction("get", &DynMetric::get); + + d_lw->writeFunction("getStat", [](const std::string& str) { + uint64_t result = 0; + optional value = getStatByName(str); + if (value) { + result = *value; + } + return result; + }); + + d_lw->writeFunction("getRecursorThreadId", []() { + return getRecursorThreadId(); + }); + + d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) { + if (g_snmpAgent) { + g_snmpAgent->sendCustomTrap(str); + } + }); + + ifstream ifs(fname); + if(!ifs) { + throw std::runtime_error("Unable to read configuration file from '"+fname+"': "+strerror(errno)); + } + d_lw->executeCode(ifs); + + d_prerpz = d_lw->readVariable>("prerpz").get_value_or(0); + d_preresolve = d_lw->readVariable>("preresolve").get_value_or(0); + d_nodata = d_lw->readVariable>("nodata").get_value_or(0); + d_nxdomain = d_lw->readVariable>("nxdomain").get_value_or(0); + d_postresolve = d_lw->readVariable>("postresolve").get_value_or(0); + d_preoutquery = d_lw->readVariable>("preoutquery").get_value_or(0); + + d_ipfilter = d_lw->readVariable>("ipfilter").get_value_or(0); + d_gettag = d_lw->readVariable>("gettag").get_value_or(0); + d_gettag_ffi = d_lw->readVariable>("gettag_ffi").get_value_or(0); +} + +bool RecursorLua4::prerpz(DNSQuestion& dq, int& ret) const +{ + return genhook(d_prerpz, dq, ret); +} + +bool RecursorLua4::preresolve(DNSQuestion& dq, int& ret) const +{ + return genhook(d_preresolve, dq, ret); +} + +bool RecursorLua4::nxdomain(DNSQuestion& dq, int& ret) const +{ + return genhook(d_nxdomain, dq, ret); +} + +bool RecursorLua4::nodata(DNSQuestion& dq, int& ret) const +{ + return genhook(d_nodata, dq, ret); +} + +bool RecursorLua4::postresolve(DNSQuestion& dq, int& ret) const +{ + return genhook(d_postresolve, dq, ret); +} + +bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector& res, int& ret) const +{ + bool variableAnswer = false; + bool wantsRPZ = false; + RecursorLua4::DNSQuestion dq(ns, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ); + dq.currentRecords = &res; + + return genhook(d_preoutquery, dq, ret); +} + +bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) const +{ + if(d_ipfilter) + return d_ipfilter(remote, local, dh); + return false; // don't block +} + +unsigned int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector* policyTags, LuaContext::LuaObject& data, const std::map& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId) const +{ + if(d_gettag) { + auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp); + + if (policyTags) { + const auto& tags = std::get<1>(ret); + if (tags) { + for (const auto& tag : *tags) { + policyTags->push_back(tag.second); + } + } + } + const auto dataret = std::get<2>(ret); + if (dataret) { + data = *dataret; + } + const auto reqIdret = std::get<3>(ret); + if (reqIdret) { + requestorId = *reqIdret; + } + const auto deviceIdret = std::get<4>(ret); + if (deviceIdret) { + deviceId = *deviceIdret; + } + return std::get<0>(ret); + } + return 0; +} + +struct pdns_ffi_param +{ +public: + pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector& policyTags_, const std::map& ednsOptions_, std::string& requestorId_, std::string& deviceId_, uint32_t& ttlCap_, bool& variable_, bool tcp_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), ttlCap(ttlCap_), variable(variable_), qtype(qtype_), tcp(tcp_) + { + } + + std::unique_ptr qnameStr{nullptr}; + std::unique_ptr localStr{nullptr}; + std::unique_ptr remoteStr{nullptr}; + std::unique_ptr ednssubnetStr{nullptr}; + std::vector ednsOptionsVect; + + const DNSName& qname; + const ComboAddress& local; + const ComboAddress& remote; + const Netmask& ednssubnet; + std::vector& policyTags; + const std::map& ednsOptions; + std::string& requestorId; + std::string& deviceId; + uint32_t& ttlCap; + bool& variable; + + unsigned int tag{0}; + uint16_t qtype; + bool tcp; +}; + +unsigned int RecursorLua4::gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector* policyTags, LuaContext::LuaObject& data, const std::map& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, uint32_t& ttlCap, bool& variable) const +{ + if (d_gettag_ffi) { + pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, ednsOptions, requestorId, deviceId, ttlCap, variable, tcp); + + auto ret = d_gettag_ffi(¶m); + if (ret) { + data = *ret; + } + + return param.tag; + } + return 0; +} + +bool RecursorLua4::genhook(const luacall_t& func, DNSQuestion& dq, int& ret) const +{ + if(!func) + return false; + + if (dq.currentRecords) { + dq.records = *dq.currentRecords; + } else { + dq.records.clear(); + } + + dq.followupFunction.clear(); + dq.followupPrefix.clear(); + dq.followupName.clear(); + dq.udpQuery.clear(); + dq.udpAnswer.clear(); + dq.udpCallback.clear(); + + dq.rcode = ret; + bool handled=func(&dq); + + if(handled) { +loop:; + ret=dq.rcode; + + if(!dq.followupFunction.empty()) { + if(dq.followupFunction=="followCNAMERecords") { + ret = followCNAMERecords(dq.records, QType(dq.qtype)); + } + else if(dq.followupFunction=="getFakeAAAARecords") { + ret=getFakeAAAARecords(dq.followupName, dq.followupPrefix, dq.records); + } + else if(dq.followupFunction=="getFakePTRRecords") { + ret=getFakePTRRecords(dq.followupName, dq.followupPrefix, dq.records); + } + else if(dq.followupFunction=="udpQueryResponse") { + dq.udpAnswer = GenUDPQueryResponse(dq.udpQueryDest, dq.udpQuery); + auto cbFunc = d_lw->readVariable>(dq.udpCallback).get_value_or(0); + if(!cbFunc) { + theL()<qnameStr) { + ref->qnameStr = std::unique_ptr(new std::string(ref->qname.toStringNoDot())); + } + + return ref->qnameStr->c_str(); +} + +void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t* ref, const char** qname, size_t* qnameSize) +{ + const auto& storage = ref->qname.getStorage(); + *qname = storage.data(); + *qnameSize = storage.size(); +} + +uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref) +{ + return ref->qtype; +} + +const char* pdns_ffi_param_get_remote(pdns_ffi_param_t* ref) +{ + if (!ref->remoteStr) { + ref->remoteStr = std::unique_ptr(new std::string(ref->remote.toString())); + } + + return ref->remoteStr->c_str(); +} + +static void pdns_ffi_comboaddress_to_raw(const ComboAddress& ca, const void** addr, size_t* addrSize) +{ + if (ca.isIPv4()) { + *addr = &ca.sin4.sin_addr.s_addr; + *addrSize = sizeof(ca.sin4.sin_addr.s_addr); + } + else { + *addr = &ca.sin6.sin6_addr.s6_addr; + *addrSize = sizeof(ca.sin6.sin6_addr.s6_addr); + } +} + +void pdns_ffi_param_get_remote_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize) +{ + pdns_ffi_comboaddress_to_raw(ref->remote, addr, addrSize); +} + +uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t* ref) +{ + return ref->remote.getPort(); +} + +const char* pdns_ffi_param_get_local(pdns_ffi_param_t* ref) +{ + if (!ref->localStr) { + ref->localStr = std::unique_ptr(new std::string(ref->local.toString())); + } + + return ref->localStr->c_str(); +} + +void pdns_ffi_param_get_local_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize) +{ + pdns_ffi_comboaddress_to_raw(ref->local, addr, addrSize); +} + +uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t* ref) +{ + return ref->local.getPort(); +} + +const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t* ref) +{ + if (ref->ednssubnet.empty()) { + return nullptr; + } + + if (!ref->ednssubnetStr) { + ref->ednssubnetStr = std::unique_ptr(new std::string(ref->ednssubnet.toStringNoMask())); + } + + return ref->ednssubnetStr->c_str(); +} + +void pdns_ffi_param_get_edns_cs_raw(pdns_ffi_param_t* ref, const void** net, size_t* netSize) +{ + if (ref->ednssubnet.empty()) { + *net = nullptr; + *netSize = 0; + return; + } + + pdns_ffi_comboaddress_to_raw(ref->ednssubnet.getNetwork(), net, netSize); +} + +uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t* ref) +{ + return ref->ednssubnet.getBits(); +} + +static void fill_edns_option(const EDNSOptionView& view, pdns_ednsoption_t& option) +{ + option.len = view.size; + option.data = nullptr; + + if (view.size > 0) { + option.data = view.content; + } +} + +size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t* ref, const pdns_ednsoption_t** out) +{ + if (ref->ednsOptions.empty()) { + return 0; + } + + size_t count = ref->ednsOptions.size(); + ref->ednsOptionsVect.resize(count); + + size_t pos = 0; + for (const auto& entry : ref->ednsOptions) { + fill_edns_option(entry.second, ref->ednsOptionsVect.at(pos)); + ref->ednsOptionsVect.at(pos).optionCode = entry.first; + pos++; + } + + *out = ref->ednsOptionsVect.data(); + + return count; +} + +size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out) +{ + const auto& it = ref->ednsOptions.find(optionCode); + if (it == ref->ednsOptions.cend()) { + return 0; + } + + /* the current code deals with only one entry per code, but we will fix that */ + ref->ednsOptionsVect.resize(1); + fill_edns_option(it->second, ref->ednsOptionsVect.at(0)); + ref->ednsOptionsVect.at(0).optionCode = it->first; + + *out = ref->ednsOptionsVect.data(); + + return 1; +} + +void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag) +{ + ref->tag = tag; +} + +void pdns_ffi_param_add_policytag(pdns_ffi_param_t *ref, const char* name) +{ + ref->policyTags.push_back(std::string(name)); +} + +void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name) +{ + ref->requestorId = std::string(name); +} + +void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name) +{ + ref->deviceId = std::string(name); +} + +void pdns_ffi_param_set_deviceid(pdns_ffi_param_t* ref, size_t len, const void* name) +{ + ref->deviceId = std::string(reinterpret_cast(name), len); +} + +void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable) +{ + ref->variable = variable; +} + +void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl) +{ + ref->ttlCap = ttl; +} diff --git a/lua-recursor4.hh b/lua-recursor4.hh new file mode 100644 index 0000000..39c10df --- /dev/null +++ b/lua-recursor4.hh @@ -0,0 +1,157 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "iputils.hh" +#include "dnsname.hh" +#include "namespaces.hh" +#include "dnsrecords.hh" +#include "filterpo.hh" +#include "ednsoptions.hh" +#include "validate.hh" + +#include "lua-recursor4-ffi.hh" + +string GenUDPQueryResponse(const ComboAddress& dest, const string& query); +int getRecursorThreadId(); + +class LuaContext; + +#if defined(HAVE_LUA) +#undef L +#include "ext/luawrapper/include/LuaContext.hpp" +#define L theL() +#endif + +// pdns_ffi_param_t is a lightuserdata +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, pdns_ffi_param* ptr) noexcept { + lua_pushlightuserdata(state, ptr); + return PushedObject{state, 1}; + } +}; + +class RecursorLua4 : public boost::noncopyable +{ +private: + std::unique_ptr d_lw; // this is way on top because it must get destroyed _last_ + +public: + explicit RecursorLua4(const std::string& fname); + ~RecursorLua4(); // this is so unique_ptr works with an incomplete type + + struct DNSQuestion + { + DNSQuestion(const ComboAddress& rem, const ComboAddress& loc, const DNSName& query, uint16_t type, bool tcp, bool& variable_, bool& wantsRPZ_): qname(query), qtype(type), local(loc), remote(rem), isTcp(tcp), variable(variable_), wantsRPZ(wantsRPZ_) + { + } + const DNSName& qname; + const uint16_t qtype; + const ComboAddress& local; + const ComboAddress& remote; + const struct dnsheader* dh{nullptr}; + const bool isTcp; + const std::vector>* ednsOptions{nullptr}; + const uint16_t* ednsFlags{nullptr}; + vector* currentRecords{nullptr}; + DNSFilterEngine::Policy* appliedPolicy{nullptr}; + std::vector* policyTags{nullptr}; + std::unordered_map* discardedPolicies{nullptr}; + std::string requestorId; + std::string deviceId; + vState validationState{Indeterminate}; + bool& variable; + bool& wantsRPZ; + unsigned int tag{0}; + + void addAnswer(uint16_t type, const std::string& content, boost::optional ttl, boost::optional name); + void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional ttl, boost::optional name); + vector > getRecords() const; + boost::optional getDH() const; + vector > getEDNSOptions() const; + boost::optional getEDNSOption(uint16_t code) const; + boost::optional getEDNSSubnet() const; + vector getEDNSFlags() const; + bool getEDNSFlag(string flag) const; + void setRecords(const vector >& records); + + int rcode{0}; + // struct dnsheader, packet length would be great + vector records; + + string followupFunction; + string followupPrefix; + + string udpQuery; + ComboAddress udpQueryDest; + string udpAnswer; + string udpCallback; + + LuaContext::LuaObject data; + DNSName followupName; + }; + + unsigned int gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector* policyTags, LuaContext::LuaObject& data, const std::map&, bool tcp, std::string& requestorId, std::string& deviceId) const; + unsigned int gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector* policyTags, LuaContext::LuaObject& data, const std::map&, bool tcp, std::string& requestorId, std::string& deviceId, uint32_t& ttlCap, bool& variable) const; + + bool prerpz(DNSQuestion& dq, int& ret) const; + bool preresolve(DNSQuestion& dq, int& ret) const; + bool nxdomain(DNSQuestion& dq, int& ret) const; + bool nodata(DNSQuestion& dq, int& ret) const ; + bool postresolve(DNSQuestion& dq, int& ret) const; + + bool preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector& res, int& ret) const; + bool ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader&) const; + + bool needDQ() const + { + return (d_prerpz || + d_preresolve || + d_nxdomain || + d_nodata || + d_postresolve); + } + + typedef std::function >,boost::optional,boost::optional,boost::optional >(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const std::map&, bool)> gettag_t; + gettag_t d_gettag; // public so you can query if we have this hooked + + typedef std::function(pdns_ffi_param_t*)> gettag_ffi_t; + gettag_ffi_t d_gettag_ffi; + +private: + typedef std::function luacall_t; + luacall_t d_prerpz, d_preresolve, d_nxdomain, d_nodata, d_postresolve, d_preoutquery, d_postoutquery; + bool genhook(const luacall_t& func, DNSQuestion& dq, int& ret) const; + typedef std::function ipfilter_t; + ipfilter_t d_ipfilter; +}; + diff --git a/lua_hpp.mk b/lua_hpp.mk new file mode 100644 index 0000000..70502f4 --- /dev/null +++ b/lua_hpp.mk @@ -0,0 +1,6 @@ +lua.hpp: + $(AM_V_GEN)echo 'extern "C" {' > $@ + @echo '#include "lua.h"' >> $@ + @echo '#include "lualib.h"' >> $@ + @echo '#include "lauxlib.h"' >> $@ + @echo '}' >> $@ diff --git a/lwres.cc b/lwres.cc new file mode 100644 index 0000000..0e0f9e6 --- /dev/null +++ b/lwres.cc @@ -0,0 +1,305 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "syncres.hh" +#include "utility.hh" +#include "lwres.hh" +#include +#include "dnsrecords.hh" +#include +#include "misc.hh" +#include +#include +#include +#include +#include +#include "dns.hh" +#include "qtype.hh" +#include "pdnsexception.hh" +#include "arguments.hh" +#include "sstuff.hh" +#include "dnswriter.hh" +#include "dnsparser.hh" +#include "logger.hh" +#include "dns_random.hh" +#include +#include +#include "validate-recursor.hh" +#include "ednssubnet.hh" + +#ifdef HAVE_PROTOBUF + +static void logOutgoingQuery(std::shared_ptr outgoingLogger, boost::optional initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes) +{ + if(!outgoingLogger) + return; + + RecProtoBufMessage message(DNSProtoBufMessage::OutgoingQuery, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes); + if (initialRequestId) { + message.setInitialRequestID(*initialRequestId); + } + +// cerr <queueData(str); +} + +static void logIncomingResponse(std::shared_ptr outgoingLogger, boost::optional initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes, int rcode, const std::vector& records, const struct timeval& queryTime) +{ + if(!outgoingLogger) + return; + + RecProtoBufMessage message(DNSProtoBufMessage::IncomingResponse, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes); + if (initialRequestId) { + message.setInitialRequestID(*initialRequestId); + } + message.setQueryTime(queryTime.tv_sec, queryTime.tv_usec); + message.setResponseCode(rcode); + message.addRRs(records); + +// cerr <queueData(str); +} +#endif /* HAVE_PROTOBUF */ + +//! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success +/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors + Never throws! + */ +int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult *lwr, bool* chained) +{ + size_t len; + size_t bufsize=g_outgoingEDNSBufsize; + scoped_array buf(new unsigned char[bufsize]); + vector vpacket; + // string mapped0x20=dns0x20(domain); + uint16_t qid = dns_random(0xffff); + DNSPacketWriter pw(vpacket, domain, type); + + pw.getHeader()->rd=sendRDQuery; + pw.getHeader()->id=qid; + /* RFC 6840 section 5.9: + * This document further specifies that validating resolvers SHOULD set + * the CD bit on every upstream query. This is regardless of whether + * the CD bit was set on the incoming query [...] + * + * sendRDQuery is only true if the qname is part of a forward-zone-recurse (or + * set in the forward-zone-file), so we use this as an indicator for it being + * an "upstream query". To stay true to "dnssec=off means 3.X behaviour", we + * only set +CD on forwarded query in any mode other than dnssec=off. + */ + pw.getHeader()->cd=(sendRDQuery && g_dnssecmode != DNSSECMode::Off); + + string ping; + bool weWantEDNSSubnet=false; + if(EDNS0Level > 0) { + DNSPacketWriter::optvect_t opts; + if(srcmask) { + EDNSSubnetOpts eo; + eo.source = *srcmask; + // cout<<"Adding request mask: "<d_rcode = 0; + lwr->d_haveEDNS = false; + int ret; + + DTime dt; + dt.set(); + *now=dt.getTimeval(); + +#ifdef HAVE_PROTOBUF + boost::uuids::uuid uuid; + const struct timeval queryTime = *now; + + if (outgoingLogger) { + uuid = (*t_uuidGenerator)(); + logOutgoingQuery(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size()); + } +#endif + + errno=0; + if(!doTCP) { + int queryfd; + if(ip.sin4.sin_family==AF_INET6) + g_stats.ipv6queries++; + + if((ret=asendto((const char*)&*vpacket.begin(), vpacket.size(), 0, ip, qid, + domain, type, &queryfd)) < 0) { + return ret; // passes back the -2 EMFILE + } + + if (queryfd == -1) { + *chained = true; + } + + // sleep until we see an answer to this, interface to mtasker + + ret=arecvfrom(reinterpret_cast(buf.get()), bufsize, 0, ip, &len, qid, + domain, type, queryfd, now); + } + else { + try { + Socket s(ip.sin4.sin_family, SOCK_STREAM); + + s.setNonBlocking(); + ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0); + + s.bind(local); + + s.connect(ip); + + uint16_t tlen=htons(vpacket.size()); + char *lenP=(char*)&tlen; + const char *msgP=(const char*)&*vpacket.begin(); + string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size()); + + ret=asendtcp(packet, &s); + if(!(ret>0)) + return ret; + + packet.clear(); + ret=arecvtcp(packet, 2, &s, false); + if(!(ret > 0)) + return ret; + + memcpy(&tlen, packet.c_str(), sizeof(tlen)); + len=ntohs(tlen); // switch to the 'len' shared with the rest of the function + + ret=arecvtcp(packet, len, &s, false); + if(!(ret > 0)) + return ret; + + if(len > bufsize) { + bufsize=len; + scoped_array narray(new unsigned char[bufsize]); + buf.swap(narray); + } + memcpy(buf.get(), packet.c_str(), len); + + ret=1; + } + catch(NetworkError& ne) { + ret = -2; // OS limits error + } + } + + + lwr->d_usec=dt.udiff(); + *now=dt.getTimeval(); + + if(ret <= 0) // includes 'timeout' + return ret; + + lwr->d_records.clear(); + try { + lwr->d_tcbit=0; + MOADNSParser mdp(false, (const char*)buf.get(), len); + lwr->d_aabit=mdp.d_header.aa; + lwr->d_tcbit=mdp.d_header.tc; + lwr->d_rcode=mdp.d_header.rcode; + + if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) { +#ifdef HAVE_PROTOBUF + if(outgoingLogger) { + logIncomingResponse(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime); + } +#endif + return 1; // this is "success", the error is set in lwr->d_rcode + } + + if(domain != mdp.d_qname) { + if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too + L<d_records.push_back(a.first); + + EDNSOpts edo; + if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) { + lwr->d_haveEDNS = true; + + if(weWantEDNSSubnet) { + for(const auto& opt : edo.d_options) { + if(opt.first==8) { + EDNSSubnetOpts reso; + if(getEDNSSubnetOptsFromString(opt.second, &reso)) { + // cerr<<"EDNS Subnet response: "<d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime); + } +#endif + return 1; + } + catch(std::exception &mde) { + if(::arg().mustDo("log-common-errors")) + L<d_rcode = RCode::FormErr; + g_stats.serverParseError++; +#ifdef HAVE_PROTOBUF + if(outgoingLogger) { + logIncomingResponse(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime); + } +#endif + return 1; // success - oddly enough + } + catch(...) { + L<d_rcode) + lwr->d_rcode=RCode::ServFail; + + return -1; +} + diff --git a/lwres.hh b/lwres.hh new file mode 100644 index 0000000..ad9855d --- /dev/null +++ b/lwres.hh @@ -0,0 +1,71 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_LWRES_HH +#define PDNS_LWRES_HH +#include +#include +#include +#include "misc.hh" +#include "iputils.hh" +#include +#include +#include +#include +#include +#include +#include +#include "dnsparser.hh" +#include +#undef res_mkquery + +#include "pdnsexception.hh" +#include "dns.hh" +#include "namespaces.hh" +#include "remote_logger.hh" +#include "resolve-context.hh" + +int asendto(const char *data, size_t len, int flags, const ComboAddress& ip, uint16_t id, + const DNSName& domain, uint16_t qtype, int* fd); +int arecvfrom(char *data, size_t len, int flags, const ComboAddress& ip, size_t *d_len, uint16_t id, + const DNSName& domain, uint16_t qtype, int fd, struct timeval* now); + +class LWResException : public PDNSException +{ +public: + LWResException(const string &reason_) : PDNSException(reason_){} +}; + +//! LWRes class +class LWResult +{ +public: + LWResult() : d_usec(0) {} + + vector d_records; + int d_rcode{0}; + bool d_aabit{false}, d_tcbit{false}; + uint32_t d_usec{0}; + bool d_haveEDNS{false}; +}; + +int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained); +#endif // PDNS_LWRES_HH diff --git a/m4/ax_arg_default_enable_disable.m4 b/m4/ax_arg_default_enable_disable.m4 new file mode 100644 index 0000000..66d99ab --- /dev/null +++ b/m4/ax_arg_default_enable_disable.m4 @@ -0,0 +1,21 @@ +AC_DEFUN([AX_ARG_DEFAULT_ENABLE], [ +AC_ARG_ENABLE([$1], AS_HELP_STRING([--disable-$1], [$2 (default is ENABLED$3)])) +AX_PARSE_VALUE([$1], [y]) +]) + +AC_DEFUN([AX_ARG_DEFAULT_DISABLE], [ +AC_ARG_ENABLE([$1], AS_HELP_STRING([--enable-$1], [$2 (default is DISABLED$3)])) +AX_PARSE_VALUE([$1], [n]) +]) + +dnl This function should not be called outside of this file +AC_DEFUN([AX_PARSE_VALUE], [ +AS_IF([test "x$enable_$1" = "xno"], [ + ax_cv_$1="n" +], [test "x$enable_$1" = "xyes"], [ + ax_cv_$1="y" +], [test -z $ax_cv_$1], [ + ax_cv_$1="$2" +]) +$1=$ax_cv_$1 +AC_SUBST($1)]) diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 0000000..a9a8f58 --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,165 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++11 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX11 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# +# 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 any +# warranty. + +#serial 10 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } +]]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], + [$2], [optional], [ax_cxx_compile_cxx11_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=c++11 -std=c++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + AC_MSG_NOTICE([No compiler with C++11 support was found]) + else + HAVE_CXX11=1 + AC_DEFINE(HAVE_CXX11,1, + [define if the compiler supports basic C++11 syntax]) + fi + + AC_SUBST(HAVE_CXX11) + fi +]) diff --git a/m4/boost.m4 b/m4/boost.m4 new file mode 100644 index 0000000..20c0fdc --- /dev/null +++ b/m4/boost.m4 @@ -0,0 +1,1584 @@ +# boost.m4: Locate Boost headers and libraries for autoconf-based projects. +# Copyright (C) 2007-2011, 2014 Benoit Sigoure +# +# 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. +# +# Additional permission under section 7 of the GNU General Public +# License, version 3 ("GPLv3"): +# +# If you convey this file as part of a work that contains a +# configuration script generated by Autoconf, you may do so under +# terms of your choice. +# +# 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 . + +m4_define([_BOOST_SERIAL], [m4_translit([ +# serial 26 PowerDNS modified +], [# +], [])]) + +# Original sources can be found at https://github.com/tsuna/boost.m4 +# You can fetch the latest version of the script by doing: +# wget https://github.com/tsuna/boost.m4/raw/master/build-aux/boost.m4 + +# ------ # +# README # +# ------ # + +# This file provides several macros to use the various Boost libraries. +# The first macro is BOOST_REQUIRE. It will simply check if it's possible to +# find the Boost headers of a given (optional) minimum version and it will +# define BOOST_CPPFLAGS accordingly. It will add an option --with-boost to +# your configure so that users can specify non standard locations. +# If the user's environment contains BOOST_ROOT and --with-boost was not +# specified, --with-boost=$BOOST_ROOT is implicitly used. +# For more README and documentation, go to http://github.com/tsuna/boost.m4 +# Note: THESE MACROS ASSUME THAT YOU USE LIBTOOL. If you don't, don't worry, +# simply read the README, it will show you what to do step by step. + +m4_pattern_forbid([^_?(BOOST|Boost)_]) + + +# _BOOST_SED_CPP(SED-PROGRAM, PROGRAM, +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# -------------------------------------------------------- +# Same as AC_EGREP_CPP, but leave the result in conftest.i. +# +# SED-PROGRAM is *not* overquoted, as in AC_EGREP_CPP. It is expanded +# in double-quotes, so escape your double quotes. +# +# It could be useful to turn this into a macro which extracts the +# value of any macro. +m4_define([_BOOST_SED_CPP], +[AC_LANG_PUSH([C++])dnl +AC_LANG_PREPROC_REQUIRE()dnl +AC_REQUIRE([AC_PROG_SED])dnl +AC_LANG_CONFTEST([AC_LANG_SOURCE([[$2]])]) +AS_IF([dnl eval is necessary to expand ac_cpp. +dnl Ultrix and Pyramid sh refuse to redirect output of eval, so use subshell. +dnl Beware of Windows end-of-lines, for instance if we are running +dnl some Windows programs under Wine. In that case, boost/version.hpp +dnl is certainly using "\r\n", but the regular Unix shell will only +dnl strip `\n' with backquotes, not the `\r'. This results in +dnl boost_cv_lib_version='1_37\r' for instance, which breaks +dnl everything else. +dnl Cannot use 'dnl' after [$4] because a trailing dnl may break AC_CACHE_CHECK +dnl +dnl Beware that GCC 5, when expanding macros, may embed # line directives +dnl a within single line: +dnl +dnl # 1 "conftest.cc" +dnl # 1 "" +dnl # 1 "" +dnl # 1 "conftest.cc" +dnl # 1 "/opt/local/include/boost/version.hpp" 1 3 +dnl # 2 "conftest.cc" 2 +dnl boost-lib-version = +dnl # 2 "conftest.cc" 3 +dnl "1_56" +dnl +dnl So get rid of the # and empty lines, and glue the remaining ones together. +(eval "$ac_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD | + grep -v '#' | + grep -v '^[[[:space:]]]*$' | + tr -d '\r' | + tr -s '\n' ' ' | + $SED -n -e "$1" >conftest.i 2>&1], + [$3], + [$4]) +rm -rf conftest* +AC_LANG_POP([C++])dnl +])# _BOOST_SED_CPP + + + +# BOOST_REQUIRE([VERSION], [ACTION-IF-NOT-FOUND]) +# ----------------------------------------------- +# Look for Boost. If version is given, it must either be a literal of the form +# "X.Y.Z" where X, Y and Z are integers (the ".Z" part being optional) or a +# variable "$var". +# Defines the value BOOST_CPPFLAGS. This macro only checks for headers with +# the required version, it does not check for any of the Boost libraries. +# On # success, defines HAVE_BOOST. On failure, calls the optional +# ACTION-IF-NOT-FOUND action if one was supplied. +# Otherwise aborts with an error message. +AC_DEFUN_ONCE([BOOST_REQUIRE], +[AC_REQUIRE([AC_PROG_CXX])dnl +AC_REQUIRE([AC_PROG_GREP])dnl +echo "$as_me: this is boost.m4[]_BOOST_SERIAL" >&AS_MESSAGE_LOG_FD +boost_save_IFS=$IFS +boost_version_req=$1 +IFS=. +set x $boost_version_req 0 0 0 +IFS=$boost_save_IFS +shift +boost_version_req=`expr "$[1]" '*' 100000 + "$[2]" '*' 100 + "$[3]"` +boost_version_req_string=$[1].$[2].$[3] +AC_ARG_WITH([boost], + [AS_HELP_STRING([--with-boost=DIR], + [prefix of Boost $1 @<:@guess@:>@])])dnl +AC_ARG_VAR([BOOST_ROOT],[Location of Boost installation])dnl +# If BOOST_ROOT is set and the user has not provided a value to +# --with-boost, then treat BOOST_ROOT as if it the user supplied it. +if test x"$BOOST_ROOT" != x; then + if test x"$with_boost" = x; then + AC_MSG_NOTICE([Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT]) + with_boost=$BOOST_ROOT + else + AC_MSG_NOTICE([Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost]) + fi +fi +AC_SUBST([DISTCHECK_CONFIGURE_FLAGS], + ["$DISTCHECK_CONFIGURE_FLAGS '--with-boost=$with_boost'"])dnl +boost_save_CPPFLAGS=$CPPFLAGS + AC_CACHE_CHECK([for Boost headers version >= $boost_version_req_string], + [boost_cv_inc_path], + [boost_cv_inc_path=no +AC_LANG_PUSH([C++])dnl +m4_pattern_allow([^BOOST_VERSION$])dnl + AC_LANG_CONFTEST([AC_LANG_PROGRAM([[#include +#if !defined BOOST_VERSION +# error BOOST_VERSION is not defined +#elif BOOST_VERSION < $boost_version_req +# error Boost headers version < $boost_version_req +#endif +]])]) + # If the user provided a value to --with-boost, use it and only it. + case $with_boost in #( + ''|yes) set x '' /opt/local/include /usr/local/include /opt/include \ + /usr/include C:/Boost/include;; #( + *) set x "$with_boost/include" "$with_boost";; + esac + shift + for boost_dir + do + # Without --layout=system, Boost (or at least some versions) installs + # itself in /include/boost-. This inner loop helps to + # find headers in such directories. + # + # Any ${boost_dir}/boost-x_xx directories are searched in reverse version + # order followed by ${boost_dir}. The final '.' is a sentinel for + # searching $boost_dir" itself. Entries are whitespace separated. + # + # I didn't indent this loop on purpose (to avoid over-indented code) + boost_layout_system_search_list=`cd "$boost_dir" 2>/dev/null \ + && ls -1 | "${GREP}" '^boost-' | sort -rn -t- -k2 \ + && echo .` + for boost_inc in $boost_layout_system_search_list + do + if test x"$boost_inc" != x.; then + boost_inc="$boost_dir/$boost_inc" + else + boost_inc="$boost_dir" # Uses sentinel in boost_layout_system_search_list + fi + if test x"$boost_inc" != x; then + # We are going to check whether the version of Boost installed + # in $boost_inc is usable by running a compilation that + # #includes it. But if we pass a -I/some/path in which Boost + # is not installed, the compiler will just skip this -I and + # use other locations (either from CPPFLAGS, or from its list + # of system include directories). As a result we would use + # header installed on the machine instead of the /some/path + # specified by the user. So in that precise case (trying + # $boost_inc), make sure the version.hpp exists. + # + # Use test -e as there can be symlinks. + test -e "$boost_inc/boost/version.hpp" || continue + CPPFLAGS="$CPPFLAGS -I$boost_inc" + fi + AC_COMPILE_IFELSE([], [boost_cv_inc_path=yes], [boost_cv_version=no]) + if test x"$boost_cv_inc_path" = xyes; then + if test x"$boost_inc" != x; then + boost_cv_inc_path=$boost_inc + fi + break 2 + fi + done + done +AC_LANG_POP([C++])dnl + ]) + case $boost_cv_inc_path in #( + no) + boost_errmsg="cannot find Boost headers version >= $boost_version_req_string" + m4_if([$2], [], [AC_MSG_ERROR([$boost_errmsg])], + [AC_MSG_NOTICE([$boost_errmsg])]) + $2 + ;;#( + yes) + BOOST_CPPFLAGS= + ;;#( + *) + AC_SUBST([BOOST_CPPFLAGS], ["-I$boost_cv_inc_path"])dnl + ;; + esac + if test x"$boost_cv_inc_path" != xno; then + AC_DEFINE([HAVE_BOOST], [1], + [Defined if the requested minimum BOOST version is satisfied]) + AC_CACHE_CHECK([for Boost's header version], + [boost_cv_lib_version], + [m4_pattern_allow([^BOOST_LIB_VERSION$])dnl + _BOOST_SED_CPP([[/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}]], + [#include +boost-lib-version = BOOST_LIB_VERSION], + [boost_cv_lib_version=`cat conftest.i`])]) + # e.g. "134" for 1_34_1 or "135" for 1_35 + boost_major_version=`echo "$boost_cv_lib_version" | sed 's/_//;s/_.*//'` + case $boost_major_version in #( + '' | *[[!0-9]]*) + AC_MSG_ERROR([invalid value: boost_major_version='$boost_major_version']) + ;; + esac +fi +CPPFLAGS=$boost_save_CPPFLAGS +])# BOOST_REQUIRE + + +# BOOST_STATIC() +# -------------- +# Add the "--enable-static-boost" configure argument. If this argument is given +# on the command line, static versions of the libraries will be looked up. +AC_DEFUN([BOOST_STATIC], + [AC_ARG_ENABLE([static-boost], + [AS_HELP_STRING([--enable-static-boost], + [Prefer the static boost libraries over the shared ones [no]])], + [enable_static_boost=yes], + [enable_static_boost=no])])# BOOST_STATIC + + +# BOOST_FIND_HEADER([HEADER-NAME], [ACTION-IF-NOT-FOUND], [ACTION-IF-FOUND]) +# -------------------------------------------------------------------------- +# Wrapper around AC_CHECK_HEADER for Boost headers. Useful to check for +# some parts of the Boost library which are only made of headers and don't +# require linking (such as Boost.Foreach). +# +# Default ACTION-IF-NOT-FOUND: Fail with a fatal error unless Boost couldn't be +# found in the first place, in which case by default a notice is issued to the +# user. Presumably if we haven't died already it's because it's OK to not have +# Boost, which is why only a notice is issued instead of a hard error. +# +# Default ACTION-IF-FOUND: define the preprocessor symbol HAVE_ in +# case of success # (where HEADER-NAME is written LIKE_THIS, e.g., +# HAVE_BOOST_FOREACH_HPP). +AC_DEFUN([BOOST_FIND_HEADER], +[AC_REQUIRE([BOOST_REQUIRE])dnl +if test x"$boost_cv_inc_path" = xno; then + m4_default([$2], [AC_MSG_NOTICE([Boost not available, not searching for $1])]) +else +AC_LANG_PUSH([C++])dnl +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +AC_CHECK_HEADER([$1], + [m4_default([$3], [AC_DEFINE(AS_TR_CPP([HAVE_$1]), [1], + [Define to 1 if you have <$1>])])], + [m4_default([$2], [AC_MSG_ERROR([cannot find $1])])]) +CPPFLAGS=$boost_save_CPPFLAGS +AC_LANG_POP([C++])dnl +fi +])# BOOST_FIND_HEADER + + +# BOOST_FIND_LIBS([COMPONENT-NAME], [CANDIDATE-LIB-NAMES], +# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST], +# [CXX-PROLOGUE]) +# -------------------------------------------------------------- +# Look for the Boost library COMPONENT-NAME (e.g., `thread', for +# libboost_thread) under the possible CANDIDATE-LIB-NAMES (e.g., +# "thread_win32 thread"). Check that HEADER-NAME works and check that +# libboost_LIB-NAME can link with the code CXX-TEST. The optional +# argument CXX-PROLOGUE can be used to include some C++ code before +# the `main' function. +# +# Invokes BOOST_FIND_HEADER([HEADER-NAME]) (see above). +# +# Boost libraries typically come compiled with several flavors (with different +# runtime options) so PREFERRED-RT-OPT is the preferred suffix. A suffix is one +# or more of the following letters: sgdpn (in that order). s = static +# runtime, d = debug build, g = debug/diagnostic runtime, p = STLPort build, +# n = (unsure) STLPort build without iostreams from STLPort (it looks like `n' +# must always be used along with `p'). Additionally, PREFERRED-RT-OPT can +# start with `mt-' to indicate that there is a preference for multi-thread +# builds. Some sample values for PREFERRED-RT-OPT: (nothing), mt, d, mt-d, gdp +# ... If you want to make sure you have a specific version of Boost +# (eg, >= 1.33) you *must* invoke BOOST_REQUIRE before this macro. +AC_DEFUN([BOOST_FIND_LIBS], +[AC_REQUIRE([BOOST_REQUIRE])dnl +AC_REQUIRE([_BOOST_FIND_COMPILER_TAG])dnl +AC_REQUIRE([BOOST_STATIC])dnl +AC_REQUIRE([_BOOST_GUESS_WHETHER_TO_USE_MT])dnl +if test x"$boost_cv_inc_path" = xno; then + AC_MSG_NOTICE([Boost not available, not searching for the Boost $1 library]) +else +dnl The else branch is huge and wasn't intended on purpose. +AC_LANG_PUSH([C++])dnl +AS_VAR_PUSHDEF([Boost_lib], [boost_cv_lib_$1])dnl +AS_VAR_PUSHDEF([Boost_lib_LDFLAGS], [boost_cv_lib_$1_LDFLAGS])dnl +AS_VAR_PUSHDEF([Boost_lib_LDPATH], [boost_cv_lib_$1_LDPATH])dnl +AS_VAR_PUSHDEF([Boost_lib_LIBS], [boost_cv_lib_$1_LIBS])dnl +BOOST_FIND_HEADER([$4]) +boost_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +AC_CACHE_CHECK([for the Boost $1 library], [Boost_lib], + [_BOOST_FIND_LIBS($@)]) +case $Boost_lib in #( + (yes) _AC_MSG_LOG_CONFTEST + AC_DEFINE(AS_TR_CPP([HAVE_BOOST_$1]), [1], [Defined if the Boost $1 library is available])dnl + AC_SUBST(AS_TR_CPP([BOOST_$1_LDFLAGS]), [$Boost_lib_LDFLAGS])dnl + AC_SUBST(AS_TR_CPP([BOOST_$1_LDPATH]), [$Boost_lib_LDPATH])dnl + AC_SUBST([BOOST_LDPATH], [$Boost_lib_LDPATH])dnl + AC_SUBST(AS_TR_CPP([BOOST_$1_LIBS]), [$Boost_lib_LIBS])dnl + ;; +esac +CPPFLAGS=$boost_save_CPPFLAGS +AS_VAR_POPDEF([Boost_lib])dnl +AS_VAR_POPDEF([Boost_lib_LDFLAGS])dnl +AS_VAR_POPDEF([Boost_lib_LDPATH])dnl +AS_VAR_POPDEF([Boost_lib_LIBS])dnl +AC_LANG_POP([C++])dnl +fi +]) + + +# BOOST_FIND_LIB([LIB-NAME], +# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST], +# [CXX-PROLOGUE]) +# -------------------------------------------------------------- +# Backward compatibility wrapper for BOOST_FIND_LIBS. +AC_DEFUN([BOOST_FIND_LIB], +[BOOST_FIND_LIBS([$1], $@)]) + + +# _BOOST_FIND_LIBS([LIB-NAME], [CANDIDATE-LIB-NAMES], +# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST], +# [CXX-PROLOGUE]) +# -------------------------------------------------------------- +# Real implementation of BOOST_FIND_LIBS: rely on these local macros: +# Boost_lib, Boost_lib_LDFLAGS, Boost_lib_LDPATH, Boost_lib_LIBS +# +# The algorithm is as follows: first look for a given library name +# according to the user's PREFERRED-RT-OPT. For each library name, we +# prefer to use the ones that carry the tag (toolset name). Each +# library is searched through the various standard paths were Boost is +# usually installed. If we can't find the standard variants, we try +# to enforce -mt (for instance on MacOSX, libboost_thread.dylib +# doesn't exist but there's -obviously- libboost_thread-mt.dylib). +AC_DEFUN([_BOOST_FIND_LIBS], +[Boost_lib=no + case "$3" in #( + (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( + (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X$3" : 'Xmt-*\(.*\)'`;; #( + (*) boost_mt=; boost_rtopt=$3;; + esac + if test $enable_static_boost = yes; then + boost_rtopt="s$boost_rtopt" + fi + # Find the proper debug variant depending on what we've been asked to find. + case $boost_rtopt in #( + (*d*) boost_rt_d=$boost_rtopt;; #( + (*[[sgpn]]*) # Insert the `d' at the right place (in between `sg' and `pn') + boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #( + (*) boost_rt_d='-d';; + esac + # If the PREFERRED-RT-OPT are not empty, prepend a `-'. + test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt" + $boost_guess_use_mt && boost_mt=-mt + # Look for the abs path the static archive. + # $libext is computed by Libtool but let's make sure it's non empty. + test -z "$libext" && + AC_MSG_ERROR([the libext variable is empty, did you invoke Libtool?]) + boost_save_ac_objext=$ac_objext + # Generate the test file. + AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <$4> +$6], [$5])]) +dnl Optimization hacks: compiling C++ is slow, especially with Boost. What +dnl we're trying to do here is guess the right combination of link flags +dnl (LIBS / LDFLAGS) to use a given library. This can take several +dnl iterations before it succeeds and is thus *very* slow. So what we do +dnl instead is that we compile the code first (and thus get an object file, +dnl typically conftest.o). Then we try various combinations of link flags +dnl until we succeed to link conftest.o in an executable. The problem is +dnl that the various TRY_LINK / COMPILE_IFELSE macros of Autoconf always +dnl remove all the temporary files including conftest.o. So the trick here +dnl is to temporarily change the value of ac_objext so that conftest.o is +dnl preserved accross tests. This is obviously fragile and I will burn in +dnl hell for not respecting Autoconf's documented interfaces, but in the +dnl mean time, it optimizes the macro by a factor of 5 to 30. +dnl Another small optimization: the first argument of AC_COMPILE_IFELSE left +dnl empty because the test file is generated only once above (before we +dnl start the for loops). + AC_COMPILE_IFELSE([], + [ac_objext=do_not_rm_me_plz], + [AC_MSG_ERROR([cannot compile a test that uses Boost $1])]) + ac_objext=$boost_save_ac_objext + boost_failed_libs= +# Don't bother to ident the following nested for loops, only the 2 +# innermost ones matter. +for boost_lib_ in $2; do +for boost_tag_ in -$boost_cv_lib_tag ''; do +for boost_ver_ in -$boost_cv_lib_version ''; do +for boost_mt_ in $boost_mt -mt ''; do +for boost_rtopt_ in $boost_rtopt '' -d; do + for boost_lib in \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \ + boost_$boost_lib_$boost_tag_$boost_ver_ + do + # Avoid testing twice the same lib + case $boost_failed_libs in #( + (*@$boost_lib@*) continue;; + esac + # If with_boost is empty, we'll search in /lib first, which is not quite + # right so instead we'll try to a location based on where the headers are. + boost_tmp_lib=$with_boost + test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include} + for boost_ldpath in "$boost_tmp_lib/lib" '' \ + /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \ + "$with_boost" C:/Boost/lib /lib* + do + # Don't waste time with directories that don't exist. + if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then + continue + fi + boost_save_LDFLAGS=$LDFLAGS + # Are we looking for a static library? + case $boost_ldpath:$boost_rtopt_ in #( + (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt) + Boost_lib_LIBS="$boost_ldpath/lib$boost_lib.$libext" + test -e "$Boost_lib_LIBS" || continue;; #( + (*) # No: use -lboost_foo to find the shared library. + Boost_lib_LIBS="-l$boost_lib";; + esac + boost_save_LIBS=$LIBS + LIBS="$Boost_lib_LIBS $LIBS" + test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath" +dnl First argument of AC_LINK_IFELSE left empty because the test file is +dnl generated only once above (before we start the for loops). + _BOOST_AC_LINK_IFELSE([], + [Boost_lib=yes], [Boost_lib=no]) + ac_objext=$boost_save_ac_objext + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + if test x"$Boost_lib" = xyes; then + # Check or used cached result of whether or not using -R or + # -rpath makes sense. Some implementations of ld, such as for + # Mac OSX, require -rpath but -R is the flag known to work on + # other systems. https://github.com/tsuna/boost.m4/issues/19 + AC_CACHE_VAL([boost_cv_rpath_link_ldflag], + [case $boost_ldpath in + '') # Nothing to do. + boost_cv_rpath_link_ldflag= + boost_rpath_link_ldflag_found=yes;; + *) + for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do + LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + LIBS="$boost_save_LIBS $Boost_lib_LIBS" + _BOOST_AC_LINK_IFELSE([], + [boost_rpath_link_ldflag_found=yes + break], + [boost_rpath_link_ldflag_found=no]) + done + ;; + esac + AS_IF([test "x$boost_rpath_link_ldflag_found" != "xyes"], + [AC_MSG_ERROR([Unable to determine whether to use -R or -rpath])]) + LDFLAGS=$boost_save_LDFLAGS + LIBS=$boost_save_LIBS + ]) + test x"$boost_ldpath" != x && + Boost_lib_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath" + Boost_lib_LDPATH="$boost_ldpath" + break 7 + else + boost_failed_libs="$boost_failed_libs@$boost_lib@" + fi + done + done +done +done +done +done +done # boost_lib_ +rm -f conftest.$ac_objext +]) + + + +# --------------------------------------- # +# Checks for the various Boost libraries. # +# --------------------------------------- # + +# List of boost libraries: http://www.boost.org/libs/libraries.htm +# The page http://beta.boost.org/doc/libs is useful: it gives the first release +# version of each library (among other things). + +# BOOST_DEFUN(LIBRARY, CODE) +# -------------------------- +# Define BOOST_ as a macro that runs CODE. +# +# Use indir to avoid the warning on underquoted macro name given to AC_DEFUN. +m4_define([BOOST_DEFUN], +[m4_indir([AC_DEFUN], + m4_toupper([BOOST_$1]), +[m4_pushdef([BOOST_Library], [$1])dnl +$2 +m4_popdef([BOOST_Library])dnl +]) +]) + +# BOOST_ARRAY() +# ------------- +# Look for Boost.Array +BOOST_DEFUN([Array], +[BOOST_FIND_HEADER([boost/array.hpp])]) + + +# BOOST_ASIO() +# ------------ +# Look for Boost.Asio (new in Boost 1.35). +BOOST_DEFUN([Asio], +[AC_REQUIRE([BOOST_SYSTEM])dnl +BOOST_FIND_HEADER([boost/asio.hpp])]) + + +# BOOST_ASSIGN() +# ------------- +# Look for Boost.Assign +BOOST_DEFUN([Assign], +[BOOST_FIND_HEADER([boost/assign.hpp])]) + + +# BOOST_BIND() +# ------------ +# Look for Boost.Bind. +BOOST_DEFUN([Bind], +[BOOST_FIND_HEADER([boost/bind.hpp])]) + + +# BOOST_CHRONO() +# -------------- +# Look for Boost.Chrono. +BOOST_DEFUN([Chrono], +[# Do we have to check for Boost.System? This link-time dependency was +# added as of 1.35.0. If we have a version <1.35, we must not attempt to +# find Boost.System as it didn't exist by then. +if test $boost_major_version -ge 135; then + BOOST_SYSTEM([$1]) +fi # end of the Boost.System check. +boost_filesystem_save_LIBS=$LIBS +boost_filesystem_save_LDFLAGS=$LDFLAGS +m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl +LIBS="$LIBS $BOOST_SYSTEM_LIBS" +LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS" +BOOST_FIND_LIB([chrono], [$1], + [boost/chrono.hpp], + [boost::chrono::thread_clock d;]) +if test $enable_static_boost = yes && test $boost_major_version -ge 135; then + BOOST_CHRONO_LIBS="$BOOST_CHRONO_LIBS $BOOST_SYSTEM_LIBS" +fi +LIBS=$boost_filesystem_save_LIBS +LDFLAGS=$boost_filesystem_save_LDFLAGS +])# BOOST_CHRONO + + +# BOOST_CONTEXT([PREFERRED-RT-OPT]) +# ----------------------------------- +# Look for Boost.Context. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +# +# * This library was introduced in Boost 1.51.0 +# * The signatures of make_fcontext() and jump_fcontext were changed in 1.56.0 +# * A dependency on boost_thread appears in 1.57.0 +BOOST_DEFUN([Context], +[boost_context_save_LIBS=$LIBS + boost_context_save_LDFLAGS=$LDFLAGS +if test $boost_major_version -ge 157; then + BOOST_THREAD([$1]) + m4_pattern_allow([^BOOST_THREAD_(LIBS|LDFLAGS)$])dnl + LIBS="$LIBS $BOOST_THREAD_LIBS" + LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS" +fi +BOOST_FIND_LIB([context], [$1], + [boost/context/all.hpp],[[ + +// creates a stack +void * stack_pointer = new void*[4096]; +std::size_t const size = sizeof(void*[4096]); + +#if BOOST_VERSION <= 105100 +ctx::make_fcontext(&fc, f); +return ctx::jump_fcontext(&fcm, &fc, 3) == 6; + +#else + +fc = ctx::make_fcontext(stack_pointer, size, f); +return ctx::jump_fcontext(&fcm, fc, 3) == 6; + +#endif + + +]],[dnl + +#include +#if BOOST_VERSION <= 105100 + +namespace ctx = boost::ctx; + +static ctx::fcontext_t fcm, fc; + +static void f(intptr_t i) { + ctx::jump_fcontext(&fc, &fcm, i * 2); +} + +#elif BOOST_VERSION <= 105500 + +namespace ctx = boost::context; + +// context +static ctx::fcontext_t fcm, *fc; + +// context-function +static void f(intptr_t i) { + ctx::jump_fcontext(fc, &fcm, i * 2); +} + +#else + +namespace ctx = boost::context; + +// context +static ctx::fcontext_t fcm, fc; + +// context-function +static void f(intptr_t i) { + ctx::jump_fcontext(&fc, fcm, i * 2); +} +#endif +]) +LIBS=$boost_context_save_LIBS +LDFLAGS=$boost_context_save_LDFLAGS +])# BOOST_CONTEXT + + +# BOOST_CONVERSION() +# ------------------ +# Look for Boost.Conversion (cast / lexical_cast) +BOOST_DEFUN([Conversion], +[BOOST_FIND_HEADER([boost/cast.hpp]) +BOOST_FIND_HEADER([boost/lexical_cast.hpp]) +])# BOOST_CONVERSION + + +# BOOST_COROUTINE([PREFERRED-RT-OPT]) +# ----------------------------------- +# Look for Boost.Coroutine. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. This library was introduced in Boost +# 1.53.0 +BOOST_DEFUN([Coroutine], +[ +boost_coroutine_save_LIBS=$LIBS +boost_coroutine_save_LDFLAGS=$LDFLAGS +# Link-time dependency from coroutine to context +BOOST_CONTEXT([$1]) +# Starting from Boost 1.55 a dependency on Boost.System is added +if test $boost_major_version -ge 155; then + BOOST_SYSTEM([$1]) +fi +m4_pattern_allow([^BOOST_(CONTEXT|SYSTEM)_(LIBS|LDFLAGS)]) +LIBS="$LIBS $BOOST_CONTEXT_LIBS $BOOST_SYSTEM_LIBS" +LDFLAGS="$LDFLAGS $BOOST_CONTEXT_LDFLAGS" + +# in 1.53 coroutine was a header only library +if test $boost_major_version -eq 153; then + BOOST_FIND_HEADER([boost/coroutine/coroutine.hpp]) +else + BOOST_FIND_LIB([coroutine], [$1], + [boost/coroutine/coroutine.hpp], + [ + #include + #if BOOST_VERSION <= 105500 + boost::coroutines::coroutine coro; coro.get(); + #else + boost::coroutines::asymmetric_coroutine::pull_type coro; coro.get(); + #endif + ]) +fi +# Link-time dependency from coroutine to context, existed only in 1.53, in 1.54 +# coroutine doesn't use context from its headers but from its library. +if test $boost_major_version -eq 153 || test $enable_static_boost = yes && test $boost_major_version -ge 154; then + BOOST_COROUTINE_LIBS="$BOOST_COROUTINE_LIBS $BOOST_CONTEXT_LIBS" + BOOST_COROUTINE_LDFLAGS="$BOOST_COROUTINE_LDFLAGS $BOOST_CONTEXT_LDFLAGS" +fi +if test $enable_static_boost = yes && test $boost_major_version -ge 155; then + BOOST_COROUTINE_LIBS="$BOOST_COROUTINE_LIBS $BOOST_SYSTEM_LIBS" + BOOST_COROUTINE_LDFLAGS="$BOOST_COROUTINE_LDFLAGS $BOOST_SYSTEM_LDFLAGS" +fi +LIBS=$boost_coroutine_save_LIBS +LDFLAGS=$boost_coroutine_save_LDFLAGS +])# BOOST_COROUTINE + + +# BOOST_CRC() +# ----------- +# Look for Boost.CRC +BOOST_DEFUN([CRC], +[BOOST_FIND_HEADER([boost/crc.hpp]) +])# BOOST_CRC + + +# BOOST_DATE_TIME([PREFERRED-RT-OPT]) +# ----------------------------------- +# Look for Boost.Date_Time. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Date_Time], +[BOOST_FIND_LIB([date_time], [$1], + [boost/date_time/posix_time/posix_time.hpp], + [boost::posix_time::ptime t;]) +])# BOOST_DATE_TIME + + +# BOOST_FILESYSTEM([PREFERRED-RT-OPT]) +# ------------------------------------ +# Look for Boost.Filesystem. For the documentation of PREFERRED-RT-OPT, see +# the documentation of BOOST_FIND_LIB above. +# Do not check for boost/filesystem.hpp because this file was introduced in +# 1.34. +BOOST_DEFUN([Filesystem], +[# Do we have to check for Boost.System? This link-time dependency was +# added as of 1.35.0. If we have a version <1.35, we must not attempt to +# find Boost.System as it didn't exist by then. +if test $boost_major_version -ge 135; then + BOOST_SYSTEM([$1]) +fi # end of the Boost.System check. +boost_filesystem_save_LIBS=$LIBS +boost_filesystem_save_LDFLAGS=$LDFLAGS +m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl +LIBS="$LIBS $BOOST_SYSTEM_LIBS" +LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS" +BOOST_FIND_LIB([filesystem], [$1], + [boost/filesystem/path.hpp], [boost::filesystem::path p;]) +if test $enable_static_boost = yes && test $boost_major_version -ge 135; then + BOOST_FILESYSTEM_LIBS="$BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS" +fi +LIBS=$boost_filesystem_save_LIBS +LDFLAGS=$boost_filesystem_save_LDFLAGS +])# BOOST_FILESYSTEM + + +# BOOST_FLYWEIGHT() +# ----------------- +# Look for Boost.Flyweight. +BOOST_DEFUN([Flyweight], +[dnl There's a hidden dependency on pthreads. +AC_REQUIRE([_BOOST_PTHREAD_FLAG])dnl +BOOST_FIND_HEADER([boost/flyweight.hpp]) +AC_SUBST([BOOST_FLYWEIGHT_LIBS], [$boost_cv_pthread_flag]) +]) + + +# BOOST_FOREACH() +# --------------- +# Look for Boost.Foreach. +BOOST_DEFUN([Foreach], +[BOOST_FIND_HEADER([boost/foreach.hpp])]) + + +# BOOST_FORMAT() +# -------------- +# Look for Boost.Format. +# Note: we can't check for boost/format/format_fwd.hpp because the header isn't +# standalone. It can't be compiled because it triggers the following error: +# boost/format/detail/config_macros.hpp:88: error: 'locale' in namespace 'std' +# does not name a type +BOOST_DEFUN([Format], +[BOOST_FIND_HEADER([boost/format.hpp])]) + + +# BOOST_FUNCTION() +# ---------------- +# Look for Boost.Function +BOOST_DEFUN([Function], +[BOOST_FIND_HEADER([boost/function.hpp])]) + + +# BOOST_GEOMETRY() +# ---------------- +# Look for Boost.Geometry (new since 1.47.0). +BOOST_DEFUN([Geometry], +[BOOST_FIND_HEADER([boost/geometry.hpp]) +])# BOOST_GEOMETRY + + +# BOOST_GRAPH([PREFERRED-RT-OPT]) +# ------------------------------- +# Look for Boost.Graphs. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Graph], +[boost_graph_save_LIBS=$LIBS +boost_graph_save_LDFLAGS=$LDFLAGS +# Link-time dependency from graph to regex was added as of 1.40.0. +if test $boost_major_version -ge 140; then + BOOST_REGEX([$1]) + m4_pattern_allow([^BOOST_REGEX_(LIBS|LDFLAGS)$])dnl + LIBS="$LIBS $BOOST_REGEX_LIBS" + LDFLAGS="$LDFLAGS $BOOST_REGEX_LDFLAGS" +fi +BOOST_FIND_LIB([graph], [$1], + [boost/graph/adjacency_list.hpp], [boost::adjacency_list<> g;]) +LIBS=$boost_graph_save_LIBS +LDFLAGS=$boost_graph_save_LDFLAGS +])# BOOST_GRAPH + + +# BOOST_IOSTREAMS([PREFERRED-RT-OPT]) +# ----------------------------------- +# Look for Boost.IOStreams. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([IOStreams], +[BOOST_FIND_LIB([iostreams], [$1], + [boost/iostreams/device/file_descriptor.hpp], + [boost::iostreams::file_descriptor fd; fd.close();]) +])# BOOST_IOSTREAMS + + +# BOOST_HASH() +# ------------ +# Look for Boost.Functional/Hash +BOOST_DEFUN([Hash], +[BOOST_FIND_HEADER([boost/functional/hash.hpp])]) + + +# BOOST_LAMBDA() +# -------------- +# Look for Boost.Lambda +BOOST_DEFUN([Lambda], +[BOOST_FIND_HEADER([boost/lambda/lambda.hpp])]) + + +# BOOST_LOCALE() +# -------------- +# Look for Boost.Locale +BOOST_DEFUN([Locale], +[ +boost_locale_save_LIBS=$LIBS +boost_locale_save_LDFLAGS=$LDFLAGS +# require SYSTEM for boost-1.50.0 and up +if test $boost_major_version -ge 150; then + BOOST_SYSTEM([$1]) + m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl + LIBS="$LIBS $BOOST_SYSTEM_LIBS" + LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS" +fi # end of the Boost.System check. +BOOST_FIND_LIB([locale], [$1], + [boost/locale.hpp], + [[boost::locale::generator gen; std::locale::global(gen(""));]]) +LIBS=$boost_locale_save_LIBS +LDFLAGS=$boost_locale_save_LDFLAGS +])# BOOST_LOCALE + +# BOOST_LOG([PREFERRED-RT-OPT]) +# ----------------------------- +# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Log], +[boost_log_save_LIBS=$LIBS +boost_log_save_LDFLAGS=$LDFLAGS +BOOST_SYSTEM([$1]) +BOOST_FILESYSTEM([$1]) +BOOST_DATE_TIME([$1]) +m4_pattern_allow([^BOOST_(SYSTEM|FILESYSTEM|DATE_TIME)_(LIBS|LDFLAGS)$])dnl +LIBS="$LIBS $BOOST_DATE_TIME_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS" +LDFLAGS="$LDFLAGS $BOOST_DATE_TIME_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS $BOOST_SYSTEM_LDFLAGS" +BOOST_FIND_LIB([log], [$1], + [boost/log/core/core.hpp], + [boost::log::attribute a; a.get_value();]) +LIBS=$boost_log_save_LIBS +LDFLAGS=$boost_log_save_LDFLAGS +])# BOOST_LOG + + +# BOOST_LOG_SETUP([PREFERRED-RT-OPT]) +# ----------------------------------- +# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Log_Setup], +[boost_log_setup_save_LIBS=$LIBS +boost_log_setup_save_LDFLAGS=$LDFLAGS +BOOST_LOG([$1]) +m4_pattern_allow([^BOOST_LOG_(LIBS|LDFLAGS)$])dnl +LIBS="$LIBS $BOOST_LOG_LIBS" +LDFLAGS="$LDFLAGS $BOOST_LOG_LDFLAGS" +BOOST_FIND_LIB([log_setup], [$1], + [boost/log/utility/setup/from_settings.hpp], + [boost::log::basic_settings bs; bs.empty();]) +LIBS=$boost_log_setup_save_LIBS +LDFLAGS=$boost_log_setup_save_LDFLAGS +])# BOOST_LOG_SETUP + + +# BOOST_MATH() +# ------------ +# Look for Boost.Math +# TODO: This library isn't header-only but it comes in multiple different +# flavors that don't play well with BOOST_FIND_LIB (e.g, libboost_math_c99, +# libboost_math_c99f, libboost_math_c99l, libboost_math_tr1, +# libboost_math_tr1f, libboost_math_tr1l). This macro must be fixed to do the +# right thing anyway. +BOOST_DEFUN([Math], +[BOOST_FIND_HEADER([boost/math/special_functions.hpp])]) + + +# BOOST_MPI([PREFERRED-RT-OPT]) +# ------------------------------- +# Look for Boost MPI. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. Uses MPICXX variable if it is +# set, otherwise tries CXX +# +BOOST_DEFUN([MPI], +[boost_save_CXX=${CXX} +boost_save_CXXCPP=${CXXCPP} +if test x"${MPICXX}" != x; then + CXX=${MPICXX} + CXXCPP="${MPICXX} -E" +fi +BOOST_FIND_LIB([mpi], [$1], + [boost/mpi.hpp], + [int argc = 0; + char **argv = 0; + boost::mpi::environment env(argc,argv);]) +CXX=${boost_save_CXX} +CXXCPP=${boost_save_CXXCPP} +])# BOOST_MPI + + +# BOOST_MULTIARRAY() +# ------------------ +# Look for Boost.MultiArray +BOOST_DEFUN([MultiArray], +[BOOST_FIND_HEADER([boost/multi_array.hpp])]) + + +# BOOST_NUMERIC_UBLAS() +# -------------------------- +# Look for Boost.NumericUblas (Basic Linear Algebra) +BOOST_DEFUN([Numeric_Ublas], +[BOOST_FIND_HEADER([boost/numeric/ublas/vector.hpp]) +])# BOOST_NUMERIC_UBLAS + + +# BOOST_NUMERIC_CONVERSION() +# -------------------------- +# Look for Boost.NumericConversion (policy-based numeric conversion) +BOOST_DEFUN([Numeric_Conversion], +[BOOST_FIND_HEADER([boost/numeric/conversion/converter.hpp]) +])# BOOST_NUMERIC_CONVERSION + + +# BOOST_OPTIONAL() +# ---------------- +# Look for Boost.Optional +BOOST_DEFUN([Optional], +[BOOST_FIND_HEADER([boost/optional.hpp])]) + + +# BOOST_PREPROCESSOR() +# -------------------- +# Look for Boost.Preprocessor +BOOST_DEFUN([Preprocessor], +[BOOST_FIND_HEADER([boost/preprocessor/repeat.hpp])]) + + +# BOOST_RANGE() +# -------------------- +# Look for Boost.Range +BOOST_DEFUN([Range], +[BOOST_FIND_HEADER([boost/range/adaptors.hpp])]) + +# BOOST_UNORDERED() +# ----------------- +# Look for Boost.Unordered +BOOST_DEFUN([Unordered], +[BOOST_FIND_HEADER([boost/unordered_map.hpp])]) + + +# BOOST_UUID() +# ------------ +# Look for Boost.Uuid +BOOST_DEFUN([Uuid], +[BOOST_FIND_HEADER([boost/uuid/uuid.hpp])]) + + +# BOOST_PROGRAM_OPTIONS([PREFERRED-RT-OPT]) +# ----------------------------------------- +# Look for Boost.Program_options. For the documentation of PREFERRED-RT-OPT, +# see the documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Program_Options], +[BOOST_FIND_LIB([program_options], [$1], + [boost/program_options.hpp], + [boost::program_options::options_description d("test");]) +])# BOOST_PROGRAM_OPTIONS + + + +# _BOOST_PYTHON_CONFIG(VARIABLE, FLAG) +# ------------------------------------ +# Save VARIABLE, and define it via `python-config --FLAG`. +# Substitute BOOST_PYTHON_VARIABLE. +m4_define([_BOOST_PYTHON_CONFIG], +[AC_SUBST([BOOST_PYTHON_$1], + [`python-config --$2 2>/dev/null`])dnl +boost_python_save_$1=$$1 +$1="$$1 $BOOST_PYTHON_$1"]) + + +# BOOST_PYTHON([PREFERRED-RT-OPT]) +# -------------------------------- +# Look for Boost.Python. For the documentation of PREFERRED-RT-OPT, +# see the documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Python], +[_BOOST_PYTHON_CONFIG([CPPFLAGS], [includes]) +_BOOST_PYTHON_CONFIG([LDFLAGS], [ldflags]) +_BOOST_PYTHON_CONFIG([LIBS], [libs]) +m4_pattern_allow([^BOOST_PYTHON_MODULE$])dnl +BOOST_FIND_LIBS([python], [python python3], [$1], + [boost/python.hpp], + [], [BOOST_PYTHON_MODULE(empty) {}]) +CPPFLAGS=$boost_python_save_CPPFLAGS +LDFLAGS=$boost_python_save_LDFLAGS +LIBS=$boost_python_save_LIBS +])# BOOST_PYTHON + + +# BOOST_REF() +# ----------- +# Look for Boost.Ref +BOOST_DEFUN([Ref], +[BOOST_FIND_HEADER([boost/ref.hpp])]) + + +# BOOST_REGEX([PREFERRED-RT-OPT]) +# ------------------------------- +# Look for Boost.Regex. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Regex], +[BOOST_FIND_LIB([regex], [$1], + [boost/regex.hpp], + [boost::regex exp("*"); boost::regex_match("foo", exp);]) +])# BOOST_REGEX + + +# BOOST_SERIALIZATION([PREFERRED-RT-OPT]) +# --------------------------------------- +# Look for Boost.Serialization. For the documentation of PREFERRED-RT-OPT, see +# the documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Serialization], +[BOOST_FIND_LIB([serialization], [$1], + [boost/archive/text_oarchive.hpp], + [std::ostream* o = 0; // Cheap way to get an ostream... + boost::archive::text_oarchive t(*o);]) +])# BOOST_SERIALIZATION + + +# BOOST_SIGNALS([PREFERRED-RT-OPT]) +# --------------------------------- +# Look for Boost.Signals. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Signals], +[BOOST_FIND_LIB([signals], [$1], + [boost/signal.hpp], + [boost::signal s;]) +])# BOOST_SIGNALS + + +# BOOST_SIGNALS2() +# ---------------- +# Look for Boost.Signals2 (new since 1.39.0). +BOOST_DEFUN([Signals2], +[BOOST_FIND_HEADER([boost/signals2.hpp]) +])# BOOST_SIGNALS2 + + +# BOOST_SMART_PTR() +# ----------------- +# Look for Boost.SmartPtr +BOOST_DEFUN([Smart_Ptr], +[BOOST_FIND_HEADER([boost/scoped_ptr.hpp]) +BOOST_FIND_HEADER([boost/shared_ptr.hpp]) +]) + + +# BOOST_STATICASSERT() +# -------------------- +# Look for Boost.StaticAssert +BOOST_DEFUN([StaticAssert], +[BOOST_FIND_HEADER([boost/static_assert.hpp])]) + + +# BOOST_STRING_ALGO() +# ------------------- +# Look for Boost.StringAlgo +BOOST_DEFUN([String_Algo], +[BOOST_FIND_HEADER([boost/algorithm/string.hpp]) +]) + + +# BOOST_SYSTEM([PREFERRED-RT-OPT]) +# -------------------------------- +# Look for Boost.System. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. This library was introduced in Boost +# 1.35.0. +BOOST_DEFUN([System], +[BOOST_FIND_LIB([system], [$1], + [boost/system/error_code.hpp], + [boost::system::error_code e; e.clear();]) +])# BOOST_SYSTEM + + +# BOOST_TEST([PREFERRED-RT-OPT]) +# ------------------------------ +# Look for Boost.Test. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Test], +[m4_pattern_allow([^BOOST_CHECK$])dnl +BOOST_FIND_LIB([unit_test_framework], [$1], + [boost/test/unit_test.hpp], [BOOST_CHECK(2 == 2);], + [using boost::unit_test::test_suite; + test_suite* init_unit_test_suite(int argc, char ** argv) + { return NULL; }]) +])# BOOST_TEST + + +# BOOST_THREAD([PREFERRED-RT-OPT]) +# --------------------------------- +# Look for Boost.Thread. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Thread], +[dnl Having the pthread flag is required at least on GCC3 where +dnl boost/thread.hpp would complain if we try to compile without +dnl -pthread on GNU/Linux. +AC_REQUIRE([_BOOST_PTHREAD_FLAG])dnl +boost_thread_save_LIBS=$LIBS +boost_thread_save_LDFLAGS=$LDFLAGS +boost_thread_save_CPPFLAGS=$CPPFLAGS +# Link-time dependency from thread to system was added as of 1.49.0. +if test $boost_major_version -ge 149; then +BOOST_SYSTEM([$1]) +fi # end of the Boost.System check. +m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl +LIBS="$LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag" +LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS" +CPPFLAGS="$CPPFLAGS $boost_cv_pthread_flag" + +# When compiling for the Windows platform, the threads library is named +# differently. This suffix doesn't exist in new versions of Boost, or +# possibly new versions of GCC on mingw I am assuming it's Boost's change for +# now and I am setting version to 1.48, for lack of knowledge as to when this +# change occurred. +if test $boost_major_version -lt 148; then + case $host_os in + (*mingw*) boost_thread_lib_ext=_win32;; + esac +fi +BOOST_FIND_LIBS([thread], [thread$boost_thread_lib_ext], + [$1], + [boost/thread.hpp], [boost::thread t; boost::mutex m;]) + +case $host_os in + (*mingw*) boost_thread_w32_socket_link=-lws2_32;; +esac + +BOOST_THREAD_LIBS="$BOOST_THREAD_LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag $boost_thread_w32_socket_link" +BOOST_THREAD_LDFLAGS="$BOOST_SYSTEM_LDFLAGS" +BOOST_CPPFLAGS="$BOOST_CPPFLAGS $boost_cv_pthread_flag" +LIBS=$boost_thread_save_LIBS +LDFLAGS=$boost_thread_save_LDFLAGS +CPPFLAGS=$boost_thread_save_CPPFLAGS +])# BOOST_THREAD + +AU_ALIAS([BOOST_THREADS], [BOOST_THREAD]) + + +# BOOST_TOKENIZER() +# ----------------- +# Look for Boost.Tokenizer +BOOST_DEFUN([Tokenizer], +[BOOST_FIND_HEADER([boost/tokenizer.hpp])]) + + +# BOOST_TRIBOOL() +# --------------- +# Look for Boost.Tribool +BOOST_DEFUN([Tribool], +[BOOST_FIND_HEADER([boost/logic/tribool_fwd.hpp]) +BOOST_FIND_HEADER([boost/logic/tribool.hpp]) +]) + + +# BOOST_TUPLE() +# ------------- +# Look for Boost.Tuple +BOOST_DEFUN([Tuple], +[BOOST_FIND_HEADER([boost/tuple/tuple.hpp])]) + + +# BOOST_TYPETRAITS() +# -------------------- +# Look for Boost.TypeTraits +BOOST_DEFUN([TypeTraits], +[BOOST_FIND_HEADER([boost/type_traits.hpp])]) + + +# BOOST_UTILITY() +# --------------- +# Look for Boost.Utility (noncopyable, result_of, base-from-member idiom, +# etc.) +BOOST_DEFUN([Utility], +[BOOST_FIND_HEADER([boost/utility.hpp])]) + + +# BOOST_VARIANT() +# --------------- +# Look for Boost.Variant. +BOOST_DEFUN([Variant], +[BOOST_FIND_HEADER([boost/variant/variant_fwd.hpp]) +BOOST_FIND_HEADER([boost/variant.hpp])]) + + +# BOOST_POINTER_CONTAINER() +# ------------------------ +# Look for Boost.PointerContainer +BOOST_DEFUN([Pointer_Container], +[BOOST_FIND_HEADER([boost/ptr_container/ptr_deque.hpp]) +BOOST_FIND_HEADER([boost/ptr_container/ptr_list.hpp]) +BOOST_FIND_HEADER([boost/ptr_container/ptr_vector.hpp]) +BOOST_FIND_HEADER([boost/ptr_container/ptr_array.hpp]) +BOOST_FIND_HEADER([boost/ptr_container/ptr_set.hpp]) +BOOST_FIND_HEADER([boost/ptr_container/ptr_map.hpp]) +])# BOOST_POINTER_CONTAINER + + +# BOOST_WAVE([PREFERRED-RT-OPT]) +# ------------------------------ +# NOTE: If you intend to use Wave/Spirit with thread support, make sure you +# call BOOST_THREAD first. +# Look for Boost.Wave. For the documentation of PREFERRED-RT-OPT, see the +# documentation of BOOST_FIND_LIB above. +BOOST_DEFUN([Wave], +[AC_REQUIRE([BOOST_FILESYSTEM])dnl +AC_REQUIRE([BOOST_DATE_TIME])dnl +boost_wave_save_LIBS=$LIBS +boost_wave_save_LDFLAGS=$LDFLAGS +m4_pattern_allow([^BOOST_((FILE)?SYSTEM|DATE_TIME|THREAD)_(LIBS|LDFLAGS)$])dnl +LIBS="$LIBS $BOOST_SYSTEM_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_DATE_TIME_LIBS \ +$BOOST_THREAD_LIBS" +LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS \ +$BOOST_DATE_TIME_LDFLAGS $BOOST_THREAD_LDFLAGS" +BOOST_FIND_LIB([wave], [$1], + [boost/wave.hpp], + [boost::wave::token_id id; get_token_name(id);]) +LIBS=$boost_wave_save_LIBS +LDFLAGS=$boost_wave_save_LDFLAGS +])# BOOST_WAVE + + +# BOOST_XPRESSIVE() +# ----------------- +# Look for Boost.Xpressive (new since 1.36.0). +BOOST_DEFUN([Xpressive], +[BOOST_FIND_HEADER([boost/xpressive/xpressive.hpp])]) + + +# ----------------- # +# Internal helpers. # +# ----------------- # + + +# _BOOST_PTHREAD_FLAG() +# --------------------- +# Internal helper for BOOST_THREAD. Computes boost_cv_pthread_flag +# which must be used in CPPFLAGS and LIBS. +# +# Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3, +# boost/thread.hpp will trigger a #error if -pthread isn't used: +# boost/config/requires_threads.hpp:47:5: #error "Compiler threading support +# is not turned on. Please set the correct command line options for +# threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)" +# +# Based on ACX_PTHREAD: http://autoconf-archive.cryp.to/acx_pthread.html +AC_DEFUN([_BOOST_PTHREAD_FLAG], +[AC_REQUIRE([AC_PROG_CXX])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_LANG_PUSH([C++])dnl +AC_CACHE_CHECK([for the flags needed to use pthreads], [boost_cv_pthread_flag], +[ boost_cv_pthread_flag= + # The ordering *is* (sometimes) important. Some notes on the + # individual items follow: + # (none): in case threads are in libc; should be tried before -Kthread and + # other compiler flags to prevent continual compiler warnings + # -lpthreads: AIX (must check this before -lpthread) + # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + # -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads) + # -pthreads: Solaris/GCC + # -mthreads: MinGW32/GCC, Lynx/GCC + # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it + # doesn't hurt to check since this sometimes defines pthreads too; + # also defines -D_REENTRANT) + # ... -mt is also the pthreads flag for HP/aCC + # -lpthread: GNU Linux, etc. + # --thread-safe: KAI C++ + case $host_os in #( + *solaris*) + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + boost_pthread_flags="-pthreads -lpthread -mt -pthread";; #( + *) + boost_pthread_flags="-lpthreads -Kthread -kthread -llthread -pthread \ + -pthreads -mthreads -lpthread --thread-safe -mt";; + esac + # Generate the test file. + AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0);])]) + for boost_pthread_flag in '' $boost_pthread_flags; do + boost_pthread_ok=false +dnl Re-use the test file already generated. + boost_pthreads__save_LIBS=$LIBS + LIBS="$LIBS $boost_pthread_flag" + AC_LINK_IFELSE([], + [if grep ".*$boost_pthread_flag" conftest.err; then + echo "This flag seems to have triggered warnings" >&AS_MESSAGE_LOG_FD + else + boost_pthread_ok=:; boost_cv_pthread_flag=$boost_pthread_flag + fi]) + LIBS=$boost_pthreads__save_LIBS + $boost_pthread_ok && break + done +]) +AC_LANG_POP([C++])dnl +])# _BOOST_PTHREAD_FLAG + + +# _BOOST_gcc_test(MAJOR, MINOR) +# ----------------------------- +# Internal helper for _BOOST_FIND_COMPILER_TAG. +m4_define([_BOOST_gcc_test], +["defined __GNUC__ && __GNUC__ == $1 && __GNUC_MINOR__ == $2 && !defined __ICC @ gcc$1$2"])dnl + +# _BOOST_mingw_test(MAJOR, MINOR) +# ----------------------------- +# Internal helper for _BOOST_FIND_COMPILER_TAG. +m4_define([_BOOST_mingw_test], +["defined __GNUC__ && __GNUC__ == $1 && __GNUC_MINOR__ == $2 && !defined __ICC && \ + (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw$1$2"])dnl + + +# _BOOST_FIND_COMPILER_TAG() +# -------------------------- +# Internal. When Boost is installed without --layout=system, each library +# filename will hold a suffix that encodes the compiler used during the +# build. The Boost build system seems to call this a `tag'. +AC_DEFUN([_BOOST_FIND_COMPILER_TAG], +[AC_REQUIRE([AC_PROG_CXX])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_CACHE_CHECK([for the toolset name used by Boost for $CXX], + [boost_cv_lib_tag], +[boost_cv_lib_tag=unknown +if test x$boost_cv_inc_path != xno; then + AC_LANG_PUSH([C++])dnl + # The following tests are mostly inspired by boost/config/auto_link.hpp + # The list is sorted to most recent/common to oldest compiler (in order + # to increase the likelihood of finding the right compiler with the + # least number of compilation attempt). + # Beware that some tests are sensible to the order (for instance, we must + # look for MinGW before looking for GCC3). + # I used one compilation test per compiler with a #error to recognize + # each compiler so that it works even when cross-compiling (let me know + # if you know a better approach). + # Known missing tags (known from Boost's tools/build/v2/tools/common.jam): + # como, edg, kcc, bck, mp, sw, tru, xlc + # I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines + # the same defines as GCC's). + for i in \ + _BOOST_mingw_test(7, 2) \ + _BOOST_gcc_test(7, 2) \ + _BOOST_mingw_test(7, 1) \ + _BOOST_gcc_test(7, 1) \ + _BOOST_mingw_test(7, 0) \ + _BOOST_gcc_test(7, 0) \ + _BOOST_mingw_test(6, 3) \ + _BOOST_gcc_test(6, 3) \ + _BOOST_mingw_test(6, 2) \ + _BOOST_gcc_test(6, 2) \ + _BOOST_mingw_test(6, 1) \ + _BOOST_gcc_test(6, 1) \ + _BOOST_mingw_test(6, 0) \ + _BOOST_gcc_test(6, 0) \ + _BOOST_mingw_test(5, 4) \ + _BOOST_gcc_test(5, 4) \ + _BOOST_mingw_test(5, 3) \ + _BOOST_gcc_test(5, 3) \ + _BOOST_mingw_test(5, 2) \ + _BOOST_gcc_test(5, 2) \ + _BOOST_mingw_test(5, 1) \ + _BOOST_gcc_test(5, 1) \ + _BOOST_mingw_test(5, 0) \ + _BOOST_gcc_test(5, 0) \ + _BOOST_mingw_test(4, 10) \ + _BOOST_gcc_test(4, 10) \ + _BOOST_mingw_test(4, 9) \ + _BOOST_gcc_test(4, 9) \ + _BOOST_mingw_test(4, 8) \ + _BOOST_gcc_test(4, 8) \ + _BOOST_mingw_test(4, 7) \ + _BOOST_gcc_test(4, 7) \ + _BOOST_mingw_test(4, 6) \ + _BOOST_gcc_test(4, 6) \ + _BOOST_mingw_test(4, 5) \ + _BOOST_gcc_test(4, 5) \ + _BOOST_mingw_test(4, 4) \ + _BOOST_gcc_test(4, 4) \ + _BOOST_mingw_test(4, 3) \ + _BOOST_gcc_test(4, 3) \ + _BOOST_mingw_test(4, 2) \ + _BOOST_gcc_test(4, 2) \ + _BOOST_mingw_test(4, 1) \ + _BOOST_gcc_test(4, 1) \ + _BOOST_mingw_test(4, 0) \ + _BOOST_gcc_test(4, 0) \ + "defined __GNUC__ && __GNUC__ == 3 && !defined __ICC \ + && (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \ + || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw" \ + _BOOST_gcc_test(3, 4) \ + _BOOST_gcc_test(3, 3) \ + "defined _MSC_VER && _MSC_VER >= 1500 @ vc90" \ + "defined _MSC_VER && _MSC_VER == 1400 @ vc80" \ + _BOOST_gcc_test(3, 2) \ + "defined _MSC_VER && _MSC_VER == 1310 @ vc71" \ + _BOOST_gcc_test(3, 1) \ + _BOOST_gcc_test(3, 0) \ + "defined __BORLANDC__ @ bcb" \ + "defined __ICC && (defined __unix || defined __unix__) @ il" \ + "defined __ICL @ iw" \ + "defined _MSC_VER && _MSC_VER == 1300 @ vc7" \ + _BOOST_gcc_test(2, 95) \ + "defined __MWERKS__ && __MWERKS__ <= 0x32FF @ cw9" \ + "defined _MSC_VER && _MSC_VER < 1300 && !defined UNDER_CE @ vc6" \ + "defined _MSC_VER && _MSC_VER < 1300 && defined UNDER_CE @ evc4" \ + "defined __MWERKS__ && __MWERKS__ <= 0x31FF @ cw8" + do + boost_tag_test=`expr "X$i" : 'X\([[^@]]*\) @ '` + boost_tag=`expr "X$i" : 'X[[^@]]* @ \(.*\)'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#if $boost_tag_test +/* OK */ +#else +# error $boost_tag_test +#endif +]])], [boost_cv_lib_tag=$boost_tag; break], []) + done +AC_LANG_POP([C++])dnl + case $boost_cv_lib_tag in #( + # Some newer (>= 1.35?) versions of Boost seem to only use "gcc" as opposed + # to "gcc41" for instance. + *-gcc | *'-gcc ') :;; #( Don't re-add -gcc: it's already in there. + gcc*) + boost_tag_x= + case $host_os in #( + darwin*) + if test $boost_major_version -ge 136; then + # The `x' added in r46793 of Boost. + boost_tag_x=x + fi;; + esac + # We can specify multiple tags in this variable because it's used by + # BOOST_FIND_LIB that does a `for tag in -$boost_cv_lib_tag' ... + boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc" + ;; #( + unknown) + AC_MSG_WARN([[could not figure out which toolset name to use for $CXX]]) + boost_cv_lib_tag= + ;; + esac +fi])dnl end of AC_CACHE_CHECK +])# _BOOST_FIND_COMPILER_TAG + + +# _BOOST_GUESS_WHETHER_TO_USE_MT() +# -------------------------------- +# Compile a small test to try to guess whether we should favor MT (Multi +# Thread) flavors of Boost. Sets boost_guess_use_mt accordingly. +AC_DEFUN([_BOOST_GUESS_WHETHER_TO_USE_MT], +[# Check whether we do better use `mt' even though we weren't ask to. +AC_LANG_PUSH([C++])dnl +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#if defined _REENTRANT || defined _MT || defined __MT__ +/* use -mt */ +#else +# error MT not needed +#endif +]])], [boost_guess_use_mt=:], [boost_guess_use_mt=false]) +AC_LANG_POP([C++])dnl +]) + +# _BOOST_AC_LINK_IFELSE(PROGRAM, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# ------------------------------------------------------------------- +# Fork of _AC_LINK_IFELSE that preserves conftest.o across calls. Fragile, +# will break when Autoconf changes its internals. Requires that you manually +# rm -f conftest.$ac_objext in between to really different tests, otherwise +# you will try to link a conftest.o left behind by a previous test. +# Used to aggressively optimize BOOST_FIND_LIB (see the big comment in this +# macro). +# +# Don't use "break" in the actions, as it would short-circuit some code +# this macro runs after the actions. +m4_define([_BOOST_AC_LINK_IFELSE], +[m4_ifvaln([$1], [AC_LANG_CONFTEST([$1])])dnl +rm -f conftest$ac_exeext +boost_save_ac_ext=$ac_ext +boost_use_source=: +# If we already have a .o, re-use it. We change $ac_ext so that $ac_link +# tries to link the existing object file instead of compiling from source. +test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false && + _AS_ECHO_LOG([re-using the existing conftest.$ac_objext]) +AS_IF([_AC_DO_STDERR($ac_link) && { + test -z "$ac_[]_AC_LANG_ABBREV[]_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_executable_p conftest$ac_exeext +dnl FIXME: use AS_TEST_X instead when 2.61 is widespread enough. + }], + [$2], + [if $boost_use_source; then + _AC_MSG_LOG_CONFTEST + fi + $3]) +ac_objext=$boost_save_ac_objext +ac_ext=$boost_save_ac_ext +dnl Delete also the IPA/IPO (Inter Procedural Analysis/Optimization) +dnl information created by the PGI compiler (conftest_ipa8_conftest.oo), +dnl as it would interfere with the next link command. +rm -f core conftest.err conftest_ipa8_conftest.oo \ + conftest$ac_exeext m4_ifval([$1], [conftest.$ac_ext])[]dnl +])# _BOOST_AC_LINK_IFELSE + +# Local Variables: +# mode: autoconf +# End: diff --git a/m4/libtool.m4 b/m4/libtool.m4 new file mode 100644 index 0000000..d7c043f --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,7997 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 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, 2009, 2010, 2011 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 57 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_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +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 + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +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 "$cc_temp" | $SED "s%.*/%%; 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 +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +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_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])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 + +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 + +# 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_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify 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' +]) + +# _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 "$][$1" | $SED "$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: +# +# ='`$ECHO "$" | $SED "$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' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$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 \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_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]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +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 ." + +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) 2011 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. +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) +])# 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 '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + 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)], + [Go], [_LT_LANG(GO)], + [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 + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _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([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +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)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +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], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _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 there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 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" + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + 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" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# 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 + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _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=func_echo_all + _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([TAGNAME]) +# ---------------------------------- +# 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. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`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 "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _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 '$LINENO' "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*|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*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*) + 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" + ;; + powerpcle-*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*) + 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 + ;; +*-*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*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + 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_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +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 \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_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_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _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:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 "$_lt_linker_boilerplate" | $SED '/^$/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; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + 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 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + 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" && \ + test undefined != "$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"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$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 $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#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 + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* 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:$LINENO: $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:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 +m4_require([_LT_CHECK_SHELL_FEATURES])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 + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # 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 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # 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; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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.so + # instead of lib.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=`func_echo_all "$lib" | $SED '\''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 # correct to gnu/linux during the next big refactor + 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,$cc_basename in + yes,*) + # gcc + 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}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + 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 + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + 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 + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # 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' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # 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 # correct to gnu/linux during the next big refactor + 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 + ;; + +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[[23]].*) 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 + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + 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=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + 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' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + 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], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # 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;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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_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 +m4_require([_LT_PROG_ECHO_BACKSLASH])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 &1 /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 + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + 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 + ;; + +haiku*) + 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])(-bit)?( [LM]SB)? 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | 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_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +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_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob 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. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + 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:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $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:$LINENO: 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_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-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 + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _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([AC_PROG_AWK])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};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /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 + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # 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 +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#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. */ +LT@&t@_DLSYM_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_globsym_save_LIBS=$LIBS + lt_globsym_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_globsym_save_LIBS + CFLAGS=$lt_globsym_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 + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +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_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _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)= + +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)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $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 + ;; + 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). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + 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 | 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* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _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* | sunCC*) + # 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' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + 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 + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + 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 | 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' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # 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* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _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\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # 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)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _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 ' + ;; + *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,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + 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* | sunf77* | sunf90* | sunf95*) + _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_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# 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]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# 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_PATH_MANIFEST_TOOL])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' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + 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 + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + 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") || (\$ 2 == "W")) && ([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*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | 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 +], [ + 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_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 | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = 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.19, 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 install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_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 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(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _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/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + 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 + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + 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=' $pic_flag' + 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; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # 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; func_echo_all \"$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]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + 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; func_echo_all \"$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* | bgf* | bgxlf* | mpixlf*) + # 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)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_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 $linker_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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $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 + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + 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") || (\$ 2 == "W")) && ([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([$1]) + _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 func_echo_all "${wl}${allow_undefined_flag}"; 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([$1]) + _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' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _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. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # 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 $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _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' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _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 `func_echo_all "$deplibs" | $SED '\''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(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + 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 + ;; + + # 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 $pic_flag -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 $pic_flag ${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 && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${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_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 && test "$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 $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${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' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_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 $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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 $pic_flag ${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 $pic_flag ${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_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$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_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_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* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_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_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([], [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([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_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_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], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +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 + +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_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(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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_CFLAGS=$CFLAGS + 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++"} + CFLAGS=$CXXFLAGS + 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 $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -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 -v "^Configured with:" | $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([$1]) + _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 func_echo_all "${wl}${allow_undefined_flag}"; 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([$1]) + _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' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _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 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*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # 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 + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # 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 $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _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(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _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 + ;; + esac + ;; + 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 + ;; + + freebsd2.*) + # 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 + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + 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; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${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; func_echo_all "$list"' + ;; + *) + 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 $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${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" && func_echo_all "-set_version $verstring"` -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 $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -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 | 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; func_echo_all "$list"' + + _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 | sort | $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 | sort | $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 | sort | $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 | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above 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; func_echo_all \"$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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # 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; func_echo_all \"$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='func_echo_all' + + # 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=func_echo_all + 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" && func_echo_all "${wl}-set_version $verstring"` -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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + 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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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 -v "^Configured with:" | $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* | sunCC*) + # 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='func_echo_all' + + # 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 $pic_flag -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 $pic_flag -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 -v "^Configured with:" | $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 -v "^Configured with:" | $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(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _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 + CFLAGS=$lt_save_CFLAGS + 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_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf 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). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _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 +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])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 +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +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 ${prev}${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 + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} 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 + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$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 +CFLAGS=$_lt_libdeps_save_CFLAGS + +# 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* | sunCC*) + # 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_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_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_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_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(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + 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" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _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_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_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_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(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + 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 + CFLAGS=$lt_save_CFLAGS +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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +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 +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# 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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go 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 +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +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 +CFLAGS=$lt_save_CFLAGS +])# _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_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# 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_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _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%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && 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_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # 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}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 0000000..5d9acd8 --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,384 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 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 7 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], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [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@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [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..07a8602 --- /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. + +# @configure_input@ + +# serial 3337 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.2' +macro_revision='1.3337' +_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..c573da9 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,98 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 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 5 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_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])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/m4/pdns_check_clock_gettime.m4 b/m4/pdns_check_clock_gettime.m4 new file mode 100644 index 0000000..b2d3207 --- /dev/null +++ b/m4/pdns_check_clock_gettime.m4 @@ -0,0 +1,6 @@ +AC_DEFUN([PDNS_CHECK_CLOCK_GETTIME],[ + OLD_LIBS="$LIBS"; LIBS="" + AC_SEARCH_LIBS([clock_gettime], [rt], [AC_DEFINE(HAVE_CLOCK_GETTIME, [1], [Define to 1 if you have clock_gettime])]) + AC_SUBST([RT_LIBS],[$LIBS]) + LIBS="$OLD_LIBS" +]) diff --git a/m4/pdns_check_curl.m4 b/m4/pdns_check_curl.m4 new file mode 100644 index 0000000..fbc47a6 --- /dev/null +++ b/m4/pdns_check_curl.m4 @@ -0,0 +1,9 @@ +AC_DEFUN([PDNS_CHECK_CURL], [ + AC_CHECK_PROG([CURL], [curl], [curl]) + if test "x$CURL" = "x"; then + if test ! -f "${srcdir}/effective_tld_names.dat"; then + AC_MSG_ERROR([curl is missing and you don't have ${srcdir}//effective_tld_names.dat. Install curl or download sources from www.powerdns.com]) + fi + fi +]) + diff --git a/m4/pdns_check_libcrypto.m4 b/m4/pdns_check_libcrypto.m4 new file mode 100644 index 0000000..c9034cf --- /dev/null +++ b/m4/pdns_check_libcrypto.m4 @@ -0,0 +1,122 @@ +# SYNOPSIS +# +# PDNS_CHECK_LIBCRYPTO([action-if-found[, action-if-not-found]]) +# +# DESCRIPTION +# +# Look for OpenSSL's libcrypto in a number of default spots, or in a +# user-selected spot (via --with-libcrypto). Sets +# +# LIBCRYPTO_INCLUDES to the include directives required +# LIBCRYPTO_LIBS to the -l directives required +# LIBCRYPTO_LDFLAGS to the -L or -R flags required +# +# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately +# +# This macro sets LIBCRYPTO_INCLUDES such that source files should use the +# openssl/ directory in include directives: +# +# #include +# +# LICENSE +# +# Taken and modified from AX_CHECK_OPENSSL by: +# Copyright (c) 2009,2010 Zmanda Inc. +# Copyright (c) 2009,2010 Dustin J. Mitchell +# +# 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 any +# warranty. + +#serial 1 + +AU_ALIAS([CHECK_LIBCRYPTO], [PDNS_CHECK_LIBCRYPTO]) +AC_DEFUN([PDNS_CHECK_LIBCRYPTO], [ + found=false + AC_ARG_WITH([libcrypto], + [AS_HELP_STRING([--with-libcrypto=DIR], + [root of the OpenSSL directory])], + [ + case "$withval" in + "" | y | ye | yes | n | no) + AC_MSG_ERROR([Invalid --with-libcrypto value]) + ;; + *) ssldirs="$withval" + ;; + esac + ], [ + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + AC_CHECK_TOOL([PKG_CONFIG], [pkg-config]) + if test x"$PKG_CONFIG" != x""; then + LIBCRYPTO_LDFLAGS=`$PKG_CONFIG libcrypto --libs-only-L 2>/dev/null` + if test $? = 0; then + LIBCRYPTO_LIBS=`$PKG_CONFIG libcrypto --libs-only-l 2>/dev/null` + LIBCRYPTO_INCLUDES=`$PKG_CONFIG libcrypto --cflags-only-I 2>/dev/null` + ssldir=`$PKG_CONFIG libcrypto --variable=prefix 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + ] + ) + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + LIBCRYPTO_INCLUDES= + for ssldir in $ssldirs; do + AC_MSG_CHECKING([for openssl/crypto.h in $ssldir]) + if test -f "$ssldir/include/openssl/crypto.h"; then + LIBCRYPTO_INCLUDES="-I$ssldir/include" + LIBCRYPTO_LDFLAGS="-L$ssldir/lib" + LIBCRYPTO_LIBS="-lcrypto" + found=true + AC_MSG_RESULT([yes]) + break + else + AC_MSG_RESULT([no]) + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + AC_MSG_CHECKING([whether compiling and linking against OpenSSL's libcrypto works]) + echo "Trying link with LIBCRYPTO_LDFLAGS=$LIBCRYPTO_LDFLAGS;" \ + "LIBCRYPTO_LIBS=$LIBCRYPTO_LIBS; LIBCRYPTO_INCLUDES=$LIBCRYPTO_INCLUDES" >&AS_MESSAGE_LOG_FD + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $LIBCRYPTO_LDFLAGS" + LIBS="$LIBCRYPTO_LIBS $LIBS" + CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], [ERR_load_CRYPTO_strings()])], + [ + AC_MSG_RESULT([yes]) + $1 + ], [ + AC_MSG_RESULT([no]) + $2 + ]) + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + AC_SUBST([LIBCRYPTO_INCLUDES]) + AC_SUBST([LIBCRYPTO_LIBS]) + AC_SUBST([LIBCRYPTO_LDFLAGS]) +]) diff --git a/m4/pdns_check_libcrypto_ecdsa.m4 b/m4/pdns_check_libcrypto_ecdsa.m4 new file mode 100644 index 0000000..8720a63 --- /dev/null +++ b/m4/pdns_check_libcrypto_ecdsa.m4 @@ -0,0 +1,33 @@ +AC_DEFUN([PDNS_CHECK_LIBCRYPTO_ECDSA], [ + AC_REQUIRE([PDNS_CHECK_LIBCRYPTO]) + + # Set the environment correctly for a possibly non-default OpenSSL path that was found by/supplied to PDNS_CHECK_LIBCRYPTO + save_CPPFLAGS="$CPPFLAGS" + save_LDFLAGS="$LDFLAGS" + save_LIBS="$LIBS" + + CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS" + LDFLAGS="$LIBCRYPTO_LDFLAGS $LDFLAGS" + LIBS="$LIBCRYPTO_LIBS $LIBS" + + # Find the headers we need for ECDSA + libcrypto_ecdsa=yes + AC_CHECK_HEADER([$ssldir/include/openssl/ecdsa.h], [ + AC_CHECK_DECLS([NID_X9_62_prime256v1, NID_secp384r1], [ : ], [ + libcrypto_ecdsa=no + ], [AC_INCLUDES_DEFAULT +#include <$ssldir/include/openssl/evp.h> + ]) + ], [ + libcrypto_ecdsa=no + ]) + + AS_IF([test "x$libcrypto_ecdsa" = "xyes"], [ + AC_DEFINE([HAVE_LIBCRYPTO_ECDSA], [1], [define to 1 if OpenSSL ecdsa support is available.]) + ]) + + # Restore variables + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" +]) diff --git a/m4/pdns_check_libdecaf.m4 b/m4/pdns_check_libdecaf.m4 new file mode 100644 index 0000000..e810903 --- /dev/null +++ b/m4/pdns_check_libdecaf.m4 @@ -0,0 +1,23 @@ +AC_DEFUN([PDNS_CHECK_LIBDECAF],[ + AC_MSG_CHECKING([whether we will be linking in libdecaf]) + AC_ARG_ENABLE([libdecaf], + [AS_HELP_STRING([--enable-libdecaf],[use libdecaf @<:@default=no@:>@])], + [enable_libdecaf=$enableval], + [enable_libdecaf=no] + ) + AC_MSG_RESULT([$enable_libdecaf]) + + AM_CONDITIONAL([LIBDECAF],[test "x$enable_libdecaf" != "xno"]) + + AS_IF([test "x$enable_libdecaf" != "xno"],[ + save_LIBS=$LIBS + LIBS="" + AC_SEARCH_LIBS([decaf_ed25519_sign],[decaf],[ + AC_DEFINE([HAVE_LIBDECAF],[1],[Define to 1 if you have libdecaf]) + AC_SUBST([LIBDECAF_LIBS],["$LIBS"]) + ],[ + AC_MSG_ERROR([Could not find libdecaf]) + ]) + LIBS="$save_LIBS" + ]) +]) diff --git a/m4/pdns_check_libsodium.m4 b/m4/pdns_check_libsodium.m4 new file mode 100644 index 0000000..30e961e --- /dev/null +++ b/m4/pdns_check_libsodium.m4 @@ -0,0 +1,30 @@ +AC_DEFUN([PDNS_CHECK_LIBSODIUM], [ + AC_MSG_CHECKING([whether we will be linking in libsodium]) + AC_ARG_ENABLE([libsodium], + AS_HELP_STRING([--enable-libsodium],[use libsodium @<:@default=auto@:>@]), + [enable_libsodium=$enableval], + [enable_libsodium=auto], + ) + AC_MSG_RESULT([$enable_libsodium]) + + AS_IF([test "x$enable_libsodium" != "xno"], [ + AS_IF([test "x$enable_libsodium" = "xyes" -o "x$enable_libsodium" = "xauto"], [ + PKG_CHECK_MODULES([LIBSODIUM], [libsodium], [ + AC_DEFINE([HAVE_LIBSODIUM], [1], [Define to 1 if you have libsodium]) + save_CFLAGS=$CFLAGS + save_LIBS=$LIBS + CFLAGS="$LIBSODIUM_CFLAGS $CFLAGS" + LIBS="$LIBSODIUM_LIBS $LIBS" + AC_CHECK_FUNCS([crypto_box_easy_afternm]) + CFLAGS=$save_CFLAGS + LIBS=$save_LIBS + ], [ : ]) + ]) + ]) + AM_CONDITIONAL([LIBSODIUM], [test "x$LIBSODIUM_LIBS" != "x"]) + AS_IF([test "x$enable_libsodium" = "xyes"], [ + AS_IF([test x"$LIBSODIUM_LIBS" = "x"], [ + AC_MSG_ERROR([libsodium requested but libraries were not found]) + ]) + ]) +]) diff --git a/m4/pdns_check_lua_hpp.m4 b/m4/pdns_check_lua_hpp.m4 new file mode 100644 index 0000000..7317153 --- /dev/null +++ b/m4/pdns_check_lua_hpp.m4 @@ -0,0 +1,8 @@ +AC_DEFUN([PDNS_CHECK_LUA_HPP],[ + AC_REQUIRE([PDNS_WITH_LUA]) + AC_REQUIRE([PDNS_WITH_LUAJIT]) + AS_IF([test "x$LUAPC" != "x" -o "x$LUAJITPC" != "x" ], [ + AC_CHECK_HEADER([lua.hpp], [ have_lua_hpp=y ]) + ]) + AM_CONDITIONAL([HAVE_LUA_HPP], [ test x"$have_lua_hpp" = "xy" ]) +]) diff --git a/m4/pdns_check_network_libs.m4 b/m4/pdns_check_network_libs.m4 new file mode 100644 index 0000000..d8b020c --- /dev/null +++ b/m4/pdns_check_network_libs.m4 @@ -0,0 +1,7 @@ +AC_DEFUN([PDNS_CHECK_NETWORK_LIBS],[ + AC_SEARCH_LIBS([inet_aton], [resolv]) + AC_SEARCH_LIBS([gethostbyname], [nsl]) + AC_SEARCH_LIBS([socket], [socket]) + AC_SEARCH_LIBS([gethostent], [nsl]) + AC_CHECK_FUNCS([recvmmsg sendmmsg accept4]) +]) diff --git a/m4/pdns_check_os.m4 b/m4/pdns_check_os.m4 new file mode 100644 index 0000000..860f9aa --- /dev/null +++ b/m4/pdns_check_os.m4 @@ -0,0 +1,51 @@ +AC_DEFUN([PDNS_CHECK_OS],[ + THREADFLAGS="" + + case "$host_os" in + solaris2.1*) + LIBS="-lposix4 -lpthread $LIBS" + CXXFLAGS="-D_REENTRANT $CXXFLAGS" + have_solaris="yes" + ;; + solaris2.8 | solaris2.9 ) + AC_DEFINE(NEED_POSIX_TYPEDEF,,[If POSIX typedefs need to be defined]) + AC_DEFINE(NEED_INET_NTOP_PROTO,,[If your OS is so broken that it needs an additional prototype]) + LIBS="-lposix4 -lpthread $LIBS" + CXXFLAGS="-D_REENTRANT $CXXFLAGS" + have_solaris="yes" + ;; + linux*) + THREADFLAGS="-pthread" + have_linux="yes" + ;; + darwin*) + CXXFLAGS="-D__APPLE_USE_RFC_3542 -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $CXXFLAGS" + ;; + freebsd*) + THREADFLAGS="-pthread" + have_freebsd="yes" + ;; + *) + LDFLAGS="-pthread $LDFLAGS" + CXXFLAGS="-pthread $CXXFLAGS" + ;; + esac + + AM_CONDITIONAL([HAVE_FREEBSD], [test "x$have_freebsd" = "xyes"]) + AM_CONDITIONAL([HAVE_LINUX], [test "x$have_linux" = "xyes"]) + AM_CONDITIONAL([HAVE_SOLARIS], [test "x$have_solaris" = "xyes"]) + + case "$host" in + mips* | powerpc-* ) + AC_MSG_CHECKING([whether the linker accepts -latomic]) + LDFLAGS="-latomic $LDFLAGS" + AC_LINK_IFELSE([m4_default([],[AC_LANG_PROGRAM()])], + [AC_MSG_RESULT([yes])], + [AC_MSG_ERROR([Unable to link against libatomic, cannot continue])] + ) + ;; + esac + + AC_SUBST(THREADFLAGS) + AC_SUBST([DYNLINKFLAGS], [-export-dynamic]) +]) diff --git a/m4/pdns_check_pthread_np.m4 b/m4/pdns_check_pthread_np.m4 new file mode 100644 index 0000000..7bbad93 --- /dev/null +++ b/m4/pdns_check_pthread_np.m4 @@ -0,0 +1,3 @@ +AC_DEFUN([PDNS_CHECK_PTHREAD_NP],[ + AC_SEARCH_LIBS([pthread_setaffinity_np], [pthread], [AC_DEFINE(HAVE_PTHREAD_SETAFFINITY_NP, [1], [Define to 1 if you have pthread_setaffinity_np])]) +]) diff --git a/m4/pdns_check_ragel.m4 b/m4/pdns_check_ragel.m4 new file mode 100644 index 0000000..9841807 --- /dev/null +++ b/m4/pdns_check_ragel.m4 @@ -0,0 +1,8 @@ +AC_DEFUN([PDNS_CHECK_RAGEL], [ + AC_CHECK_PROG([RAGEL], [ragel], [ragel]) + if test "x$RAGEL" = "x"; then + if test ! -f "${srcdir}/dnslabeltext.cc"; then + AC_MSG_ERROR([ragel is missing and you don't have ${srcdir}/dnslabeltext.cc. Install ragel or download sources from www.powerdns.com]) + fi + fi +]) diff --git a/m4/pdns_check_virtualenv.m4 b/m4/pdns_check_virtualenv.m4 new file mode 100644 index 0000000..8f735b2 --- /dev/null +++ b/m4/pdns_check_virtualenv.m4 @@ -0,0 +1,12 @@ +AC_DEFUN([PDNS_CHECK_VIRTUALENV], [ + AC_CHECK_PROG([VIRTUALENV], [virtualenv], [virtualenv], [no]) + + AS_IF([test "x$VIRTUALENV" = "xno"], [ + AS_IF([test ! -f "$srcdir/pdns_recursor.1"], + [AC_MSG_WARN([virtualenv is missing, unable to build manpages.])] + ) + ]) + AM_CONDITIONAL([HAVE_VIRTUALENV], [test "x$VIRTUALENV" != "xno"]) + AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/pdns_recursor.1"]) +]) + diff --git a/m4/pdns_d_fortify_source.m4 b/m4/pdns_d_fortify_source.m4 new file mode 100644 index 0000000..68e9be5 --- /dev/null +++ b/m4/pdns_d_fortify_source.m4 @@ -0,0 +1,28 @@ +dnl +dnl Check for support D_FORTIFY_SOURCE +dnl +dnl Copyright (C) 2013 Red Hat, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl . +dnl + +AC_DEFUN([AC_CC_D_FORTIFY_SOURCE],[ + OLD_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="-Wall -W -Werror $CXXFLAGS" + gl_COMPILER_OPTION_IF([-D_FORTIFY_SOURCE=2], [ + CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS" + CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $OLD_CXXFLAGS" + ], [CXXFLAGS="$OLD_CXXFLAGS"], [AC_LANG_PROGRAM([[#include ]],[])]) +]) diff --git a/m4/pdns_enable_botan.m4 b/m4/pdns_enable_botan.m4 new file mode 100644 index 0000000..6299d27 --- /dev/null +++ b/m4/pdns_enable_botan.m4 @@ -0,0 +1,17 @@ +AC_DEFUN([PDNS_ENABLE_BOTAN],[ + AC_MSG_CHECKING([whether we will be linking in Botan 2.x]) + AC_ARG_ENABLE([botan], + [AS_HELP_STRING([--enable-botan],[use Botan @<:@default=no@:>@])], + [enable_botan=$enableval], + [enable_botan=no] + ) + AC_MSG_RESULT([$enable_botan]) + AM_CONDITIONAL(BOTAN, [test "x$enable_botan" != "xno"]) + + AS_IF([test "x$enable_botan" != "xno"], [ + PKG_CHECK_MODULES([BOTAN], [botan-2], + [AC_DEFINE([HAVE_BOTAN],[1],[Define to 1 if you have botan])], + [AC_MSG_ERROR([Could not find botan])] + )] + ) +]) diff --git a/m4/pdns_enable_malloc_trace.m4 b/m4/pdns_enable_malloc_trace.m4 new file mode 100644 index 0000000..4987a53 --- /dev/null +++ b/m4/pdns_enable_malloc_trace.m4 @@ -0,0 +1,13 @@ +AC_DEFUN([PDNS_ENABLE_MALLOC_TRACE], [ + AC_MSG_CHECKING([whether to enable code malloc-trace]) + AC_ARG_ENABLE([malloc-trace], + AS_HELP_STRING([--enable-malloc-trace], + [enable malloc-trace @<:@default=no@:>@]), + [enable_malloc_trace=$enableval], + [enable_malloc_trace=no] + ) + AC_MSG_RESULT([$enable_malloc_trace]) + AM_CONDITIONAL([MALLOC_TRACE], [test "x$enable_malloc_trace" = "xyes"]) + AS_IF([test "x$enable_malloc_trace" = "xyes"], + AC_DEFINE([MALLOC_TRACE], [1], [Define to 1 if you want to benefit from malloc trace]) ) +]) diff --git a/m4/pdns_enable_reproducible.m4 b/m4/pdns_enable_reproducible.m4 new file mode 100644 index 0000000..7be3c5d --- /dev/null +++ b/m4/pdns_enable_reproducible.m4 @@ -0,0 +1,29 @@ +AC_DEFUN([PDNS_ENABLE_REPRODUCIBLE], [ + AC_REQUIRE([PDNS_CHECK_OS]) + AC_MSG_CHECKING([whether to enable reproducible builds.]) + AC_ARG_ENABLE([reproducible], + AS_HELP_STRING([--enable-reproducible], + [Create reproducible builds. Use this only if you are a distribution maintainer and need reproducible builds. If you compile PowerDNS yourself, leave this disabled, as it might make debugging harder. @<:@default=no@:>@]), + [enable_reproducible=$enableval], + [enable_reproducible=no]) + + AC_MSG_RESULT($enable_reproducible) + + AS_IF([test x"$enable_reproducible" = "xyes"],[ + AC_DEFINE([REPRODUCIBLE], [1], [Define to 1 for reproducible builds]) + ],[ + build_user=$(id -u -n) + + case "$host_os" in + solaris2.1* | SunOS | openbsd*) + build_host_host=$(hostname) + build_host_domain=$(domainname) + build_host="$build_host_host.$build_host_domain" + ;; + *) + build_host=$(hostname -f || hostname || echo 'localhost') + ;; + esac + AC_DEFINE_UNQUOTED([BUILD_HOST], ["$build_user@$build_host"], [Set to the user and host that builds PowerDNS]) + ]) +]) diff --git a/m4/pdns_enable_sanitizers.m4 b/m4/pdns_enable_sanitizers.m4 new file mode 100644 index 0000000..6773e1a --- /dev/null +++ b/m4/pdns_enable_sanitizers.m4 @@ -0,0 +1,167 @@ +AC_DEFUN([PDNS_ENABLE_SANITIZERS], [ + PDNS_ENABLE_ASAN + PDNS_ENABLE_MSAN + PDNS_ENABLE_TSAN + PDNS_ENABLE_LSAN + PDNS_ENABLE_UBSAN + + AS_IF([test "x$enable_asan" != "xno" -a "x$enable_tsan" != "xno"],[ + AC_MSG_ERROR([Address Sanitizer is not compatible with Thread Sanitizer]) + ]) + + AS_IF([test "x$enable_msan" != "xno" -a "x$enable_asan" != "xno"],[ + AC_MSG_ERROR([Memory Sanitizer is not compatible with Address Sanitizer]) + ]) + + AS_IF([test "x$enable_msan" != "xno" -a "x$enable_lsan" != "xno"],[ + AC_MSG_ERROR([Memory Sanitizer is not compatible with Leak Sanitizer]) + ]) + + AS_IF([test "x$enable_msan" != "xno" -a "x$enable_tsan" != "xno"],[ + AC_MSG_ERROR([Memory Sanitizer is not compatible with Thread Sanitizer]) + ]) + + AS_IF([test "x$enable_asan" != "xno" -o "x$enable_tsan" != "xno" -o "x$enable_lsan" != "xno" -o "x$enable_ubsan" != "xno" -o "x$enable_msan" != "xno"], [ + gl_WARN_ADD([-fno-omit-frame-pointer]) + ]) +]) + +AC_DEFUN([PDNS_ENABLE_ASAN], [ + AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS]) + AC_MSG_CHECKING([whether to enable AddressSanitizer]) + AC_ARG_ENABLE([asan], + AS_HELP_STRING([--enable-asan], + [enable AddressSanitizer @<:@default=no@:>@]), + [enable_asan=$enableval], + [enable_asan=no] + ) + AC_MSG_RESULT([$enable_asan]) + + AS_IF([test "x$enable_asan" != "xno"], [ + gl_COMPILER_OPTION_IF([-fsanitize=address], + [ + [SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"] + AC_CHECK_HEADERS([sanitizer/common_interface_defs.h], asan_headers=yes, asan_headers=no) + AS_IF([test x"$asan_headers" = "xyes" ], + [AC_CHECK_DECL(__sanitizer_start_switch_fiber, + [ + AC_MSG_CHECKING([for the exact signature of __sanitizer_finish_switch_fiber]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [#include ], + [ + __sanitizer_finish_switch_fiber(nullptr); + ]) + ], [ + AC_MSG_RESULT([a single pointer]) + AC_DEFINE([HAVE_FIBER_SANITIZER], [1], [Define if ASAN fiber annotation interface is available.]) + AC_DEFINE(HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR, [1], [Define to 1 if __sanitizer_finish_switch_fiber takes only a pointer]) + ], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [#include ], + [ + __sanitizer_finish_switch_fiber(nullptr, nullptr, nullptr); + ]) + ], [ + AC_MSG_RESULT([three pointers]) + AC_DEFINE([HAVE_FIBER_SANITIZER], [1], [Define if ASAN fiber annotation interface is available.]) + AC_DEFINE(HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS, [1], [Define to 1 if __sanitizer_finish_switch_fiber takes three pointers]) + ], [ + AC_MSG_RESULT([unknown]) + AC_MSG_NOTICE([ASAN fiber switching is not available due to an unknown API version]) + ]) + ]) + ], [ + AC_MSG_NOTICE([ASAN fiber switching is not available]) + ], + [#include ] + )] + ) + ], + [AC_MSG_ERROR([Cannot enable AddressSanitizer])] + ) + ]) + AC_SUBST([SANITIZER_FLAGS]) +]) + +AC_DEFUN([PDNS_ENABLE_TSAN], [ + AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS]) + AC_MSG_CHECKING([whether to enable ThreadSanitizer]) + AC_ARG_ENABLE([tsan], + AS_HELP_STRING([--enable-tsan], + [enable ThreadSanitizer @<:@default=no@:>@]), + [enable_tsan=$enableval], + [enable_tsan=no] + ) + AC_MSG_RESULT([$enable_tsan]) + + AS_IF([test "x$enable_tsan" != "xno"], [ + gl_COMPILER_OPTION_IF([-fsanitize=thread], + [SANITIZER_FLAGS="-fsanitize=thread $SANITIZER_FLAGS"], + [AC_MSG_ERROR([Cannot enable ThreadSanitizer])] + ) + ]) + AC_SUBST([SANITIZER_FLAGS]) +]) + +AC_DEFUN([PDNS_ENABLE_LSAN], [ + AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS]) + AC_MSG_CHECKING([whether to enable LeakSanitizer]) + AC_ARG_ENABLE([lsan], + AS_HELP_STRING([--enable-lsan], + [enable LeakSanitizer @<:@default=no@:>@]), + [enable_lsan=$enableval], + [enable_lsan=no] + ) + AC_MSG_RESULT([$enable_lsan]) + + AS_IF([test "x$enable_lsan" != "xno"], [ + gl_COMPILER_OPTION_IF([-fsanitize=leak], + [SANITIZER_FLAGS="-fsanitize=leak $SANITIZER_FLAGS"], + [AC_MSG_ERROR([Cannot enable LeakSanitizer])] + ) + ]) + AC_SUBST([SANITIZER_FLAGS]) +]) + +AC_DEFUN([PDNS_ENABLE_UBSAN], [ + AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS]) + AC_MSG_CHECKING([whether to enable Undefined Behaviour Sanitizer]) + AC_ARG_ENABLE([ubsan], + AS_HELP_STRING([--enable-ubsan], + [enable Undefined Behaviour Sanitizer @<:@default=no@:>@]), + [enable_ubsan=$enableval], + [enable_ubsan=no] + ) + AC_MSG_RESULT([$enable_ubsan]) + + AS_IF([test "x$enable_ubsan" != "xno"], [ + gl_COMPILER_OPTION_IF([-fsanitize=undefined], + [SANITIZER_FLAGS="-fsanitize=undefined $SANITIZER_FLAGS"], + [AC_MSG_ERROR([Cannot enable Undefined Behaviour Sanitizer])] + ) + ]) + AC_SUBST([SANITIZER_FLAGS]) +]) + +AC_DEFUN([PDNS_ENABLE_MSAN], [ + AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS]) + AC_MSG_CHECKING([whether to enable MemorySanitizer]) + AC_ARG_ENABLE([msan], + AS_HELP_STRING([--enable-msan], + [enable MemorySanitizer @<:@default=no@:>@]), + [enable_msan=$enableval], + [enable_msan=no] + ) + AC_MSG_RESULT([$enable_msan]) + + AS_IF([test "x$enable_msan" != "xno"], [ + gl_COMPILER_OPTION_IF([-fsanitize=memory], + [SANITIZER_FLAGS="-fsanitize=memory $SANITIZER_FLAGS"], + [AC_MSG_ERROR([Cannot enable MemorySanitizer])] + ) + ]) + AC_SUBST([SANITIZER_FLAGS]) +]) + diff --git a/m4/pdns_enable_unit_tests.m4 b/m4/pdns_enable_unit_tests.m4 new file mode 100644 index 0000000..f34fbe0 --- /dev/null +++ b/m4/pdns_enable_unit_tests.m4 @@ -0,0 +1,18 @@ +AC_DEFUN([PDNS_ENABLE_UNIT_TESTS], [ + AC_MSG_CHECKING([whether to enable unit test building]) + AC_ARG_ENABLE([unit-tests], + AS_HELP_STRING([--enable-unit-tests], + [enable unit test building @<:@default=no@:>@]), + [enable_unit_tests=$enableval], + [enable_unit_tests=no] + ) + AC_MSG_RESULT([$enable_unit_tests]) + AM_CONDITIONAL([UNIT_TESTS], [test "x$enable_unit_tests" != "xno"]) + + AS_IF([test "x$enable_unit_tests" != "xno"], [ + BOOST_TEST([mt]) + AS_IF([test "$boost_cv_lib_unit_test_framework" = "no"], [ + AC_MSG_ERROR([Boost Unit Test library not found]) + ]) + ]) +]) diff --git a/m4/pdns_enable_valgrind.m4 b/m4/pdns_enable_valgrind.m4 new file mode 100644 index 0000000..40313b7 --- /dev/null +++ b/m4/pdns_enable_valgrind.m4 @@ -0,0 +1,24 @@ +AC_DEFUN([PDNS_ENABLE_VALGRIND],[ + AC_MSG_CHECKING([whether to enable Valgrind support]) + AC_ARG_ENABLE([valgrind], + AS_HELP_STRING([--enable-valgrind],[enable Valgrind support @<:@default=no@:>@]), + [enable_valgrind=$enableval], + [enable_valgrind=no], + ) + AC_MSG_RESULT([$enable_valgrind]) + + AS_IF([test "x$enable_valgrind" != "xno"], [ + AS_IF([test "x$enable_valgrind" = "xyes" -o "x$enable_valgrind" = "xauto"], [ + AC_CHECK_HEADERS([valgrind/valgrind.h], valgrind_headers=yes, valgrind_headers=no) + ]) + ]) + AS_IF([test "x$enable_valgrind" = "xyes"], [ + AS_IF([test x"$valgrind_headers" = "no"], [ + AC_MSG_ERROR([Valgrind support requested but required Valgrind headers were not found]) + ]) + ]) + AM_CONDITIONAL([PDNS_USE_VALGRIND], [test x"$valgrind_headers" = "xyes" ]) + AS_IF([test x"$valgrind_headers" = "xyes" ], + [ AC_DEFINE([PDNS_USE_VALGRIND], [1], [Define if using Valgrind.]) ], + ) +]) diff --git a/m4/pdns_enable_verbose_logging.m4 b/m4/pdns_enable_verbose_logging.m4 new file mode 100644 index 0000000..0104f43 --- /dev/null +++ b/m4/pdns_enable_verbose_logging.m4 @@ -0,0 +1,17 @@ +AC_DEFUN([PDNS_ENABLE_VERBOSE_LOGGING],[ + AC_MSG_CHECKING([whether to enable verbose logging]) + + AC_ARG_ENABLE([verbose-logging], + AS_HELP_STRING([--enable-verbose-logging], + [enable verbose logging @<:@default=no@:>@] + ), + [enable_verbose_logging=$enableval], + [enable_verbose_logging=no] + ) + + AS_IF([test "x$enable_verbose_logging" != "xno"], + [AC_DEFINE([VERBOSELOG], [1], [Define to 1 if verbose logging is enabled])] + ) + + AC_MSG_RESULT([$enable_verbose_logging]) +]) diff --git a/m4/pdns_param_ssp_buffer_size.m4 b/m4/pdns_param_ssp_buffer_size.m4 new file mode 100644 index 0000000..05c1bae --- /dev/null +++ b/m4/pdns_param_ssp_buffer_size.m4 @@ -0,0 +1,26 @@ +dnl +dnl Check for support for ssp parameter buffer size +dnl +dnl Copyright (C) 2013 Red Hat, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl . +dnl + +AC_DEFUN([AC_CC_PARAM_SSP_BUFFER_SIZE],[ + gl_COMPILER_OPTION_IF([--param ssp-buffer-size=$1], [ + CFLAGS="--param ssp-buffer-size=$1 $CFLAGS" + CXXFLAGS="--param ssp-buffer-size=$1 $CXXFLAGS" + ]) +]) diff --git a/m4/pdns_pie.m4 b/m4/pdns_pie.m4 new file mode 100644 index 0000000..98d3923 --- /dev/null +++ b/m4/pdns_pie.m4 @@ -0,0 +1,55 @@ +dnl +dnl Check for support for position independent executables +dnl +dnl Copyright (C) 2013 Red Hat, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl . +dnl + +AC_DEFUN([AC_CC_PIE],[ + AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS]) + PIE_CFLAGS= + PIE_LDFLAGS= + OLD_CXXFLAGS=$CXXFLAGS + case "$host" in + *-*-mingw* | *-*-msvc* | *-*-cygwin* ) + ;; dnl All code is position independent on Win32 target + *) + CXXFLAGS="-fPIE -DPIE" + gl_COMPILER_OPTION_IF([-pie], [ + PIE_CFLAGS="-fPIE -DPIE" + PIE_LDFLAGS="-pie" + ], [ + dnl some versions of clang require -Wl,-pie instead of -pie + gl_COMPILER_OPTION_IF([[-Wl,-pie]], [ + PIE_CFLAGS="-fPIE -DPIE" + PIE_LDFLAGS="-Wl,-pie" + ], [], + [AC_LANG_PROGRAM([[ +#include +__thread unsigned int t_id; + ]], [[t_id = 1;]])] + ) + ], + [AC_LANG_PROGRAM([[ +#include +__thread unsigned int t_id; + ]], [[t_id = 1;]])] + ) + esac + CXXFLAGS=$OLD_CXXFLAGS + AC_SUBST([PIE_CFLAGS]) + AC_SUBST([PIE_LDFLAGS]) +]) diff --git a/m4/pdns_relro.m4 b/m4/pdns_relro.m4 new file mode 100644 index 0000000..4f93629 --- /dev/null +++ b/m4/pdns_relro.m4 @@ -0,0 +1,37 @@ +dnl +dnl Check for -z now and -z relro linker flags +dnl +dnl Copyright (C) 2013 Red Hat, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl . +dnl + +AC_DEFUN([AC_LD_RELRO],[ + AC_MSG_CHECKING([for how to force completely read-only GOT table]) + + RELRO_LDFLAGS= + ld_help=`$CXX -Wl,-help 2>&1` + case $ld_help in + *"-z relro"*) RELRO_LDFLAGS="-Wl,-z -Wl,relro" ;; + esac + case $ld_help in + *"-z now"*) RELRO_LDFLAGS="$RELRO_LDFLAGS -Wl,-z -Wl,now" ;; + esac + AC_SUBST([RELRO_LDFLAGS]) + AS_IF([test "x$RELRO_LDFLAGS" != "x"], + [AC_MSG_RESULT([$RELRO_LDFLAGS])], + [AC_MSG_RESULT([unknown])] + ) +]) diff --git a/m4/pdns_stack_protector.m4 b/m4/pdns_stack_protector.m4 new file mode 100644 index 0000000..388035c --- /dev/null +++ b/m4/pdns_stack_protector.m4 @@ -0,0 +1,26 @@ +dnl +dnl Check for support for enabling stack protector +dnl +dnl Copyright (C) 2013 Red Hat, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl . +dnl + +AC_DEFUN([AC_CC_STACK_PROTECTOR],[ + gl_COMPILER_OPTION_IF([-fstack-protector], [ + CFLAGS="-fstack-protector $CFLAGS" + CXXFLAGS="-fstack-protector $CXXFLAGS" + ]) +]) diff --git a/m4/pdns_with_lua.m4 b/m4/pdns_with_lua.m4 new file mode 100644 index 0000000..18bb1b9 --- /dev/null +++ b/m4/pdns_with_lua.m4 @@ -0,0 +1,36 @@ +AC_DEFUN([PDNS_WITH_LUA],[ + AC_MSG_CHECKING([whether we will be linking in Lua]) + AC_ARG_WITH([lua], + [AS_HELP_STRING([--with-lua], [build Lua Bindings @<:@default=auto@:>@])], + [with_lua=$withval], + [with_lua=auto] + ) + AC_MSG_RESULT([$with_lua]) + + AS_IF([test "x$with_lua" != "xno"],[ + AS_IF([test "x$with_lua" = "xyes" -o "x$with_lua" = "xauto"], + [for LUAPC in lua5.3 lua-5.3 lua53 lua5.2 lua-5.2 lua52 lua5.1 lua-5.1 lua51 lua; do + PKG_CHECK_MODULES([LUA], $LUAPC >= 5.1, [ + AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have lua]) + with_lua=yes + ], [LUAPC=""]) # otherwise pkg_check will fail + if test "x$LUA_LIBS" != "x"; then break; fi + done + ], + [LUAPC="$with_lua" + PKG_CHECK_MODULES([LUA], $LUAPC >= 5.1, [ + AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have lua]) + with_lua=yes + ]) + ]) + AC_MSG_CHECKING([for chosen LUA]) + AS_IF([test "x$LUAPC" = "x"], [ + AS_IF([test "x$with_lua" = "xyes"], + [AC_MSG_ERROR([cannot find lua])], + [AC_MSG_RESULT([not found])] + )],[ + AC_MSG_RESULT([$LUAPC]) + ]) + ]) + AM_CONDITIONAL([LUA], [test "x$with_lua" = "xyes"]) +]) diff --git a/m4/pdns_with_luajit.m4 b/m4/pdns_with_luajit.m4 new file mode 100644 index 0000000..6639473 --- /dev/null +++ b/m4/pdns_with_luajit.m4 @@ -0,0 +1,22 @@ +AC_DEFUN([PDNS_WITH_LUAJIT],[ + AC_MSG_CHECKING([whether we will be linking in LuaJIT]) + AC_ARG_WITH([luajit], + [AS_HELP_STRING([--with-luajit], [build LuaJIT bindings @<:@default=auto@:>@])], + [with_luajit=$withval], + [with_luajit=no] + ) + AC_MSG_RESULT([$with_luajit]) + + AS_IF([test "x$with_luajit" = "xyes"], [ + LUAJITPC="$with_luajit" + PKG_CHECK_MODULES([LUA], [luajit], + [AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have LuaJIT])], + [LUAJITPC=""] + ) + AS_IF([test "x$LUAJITPC" = "x"], [ + AC_MSG_ERROR([LuaJIT not found])] + ) + ]) + + AM_CONDITIONAL([LUA], [test "x$with_luajit" = "xyes"]) +]) diff --git a/m4/pdns_with_net_snmp.m4 b/m4/pdns_with_net_snmp.m4 new file mode 100644 index 0000000..8040672 --- /dev/null +++ b/m4/pdns_with_net_snmp.m4 @@ -0,0 +1,32 @@ +AC_DEFUN([PDNS_WITH_NET_SNMP], [ + AC_MSG_CHECKING([if we need to link in Net SNMP]) + AC_ARG_WITH([net-snmp], + AS_HELP_STRING([--with-net-snmp],[enable net snmp support @<:@default=auto@:>@]), + [with_net_snmp=$withval], + [with_net_snmp=auto], + ) + AC_MSG_RESULT([$with_net_snmp]) + + AS_IF([test "x$with_net_snmp" != "xno"], [ + AS_IF([test "x$with_net_snmp" = "xyes" -o "x$with_net_snmp" = "xauto"], [ + AC_CHECK_PROG([NET_SNMP_CFLAGS], [net-snmp-config], [`net-snmp-config --cflags`]) + AC_CHECK_PROG([NET_SNMP_LIBS], [net-snmp-config], [`net-snmp-config --agent-libs`]) + AC_CHECK_DECLS([snmp_select_info2], [ : ], [ : ], + [AC_INCLUDES_DEFAULT + #include + #include + #include + #include + #include + #include + ]) + ]) + ]) + AS_IF([test "x$with_net_snmp" = "xyes"], [ + AS_IF([test x"$NET_SNMP_LIBS" = "x"], [ + AC_MSG_ERROR([Net SNMP requested but libraries were not found]) + ]) + ]) + AM_CONDITIONAL([HAVE_NET_SNMP], [test x"$NET_SNMP_LIBS" != "x"]) + AS_IF([test x"$NET_SNMP_LIBS" != "x"], [AC_DEFINE([HAVE_NET_SNMP], [1], [Define if using Net SNMP.])]) +]) diff --git a/m4/pdns_with_protobuf.m4 b/m4/pdns_with_protobuf.m4 new file mode 100644 index 0000000..f106c58 --- /dev/null +++ b/m4/pdns_with_protobuf.m4 @@ -0,0 +1,27 @@ +AC_DEFUN([PDNS_WITH_PROTOBUF], [ + AC_MSG_CHECKING([if we need to link in protobuf]) + AC_ARG_WITH([protobuf], + AS_HELP_STRING([--with-protobuf],[enable protobuf support @<:@default=auto@:>@]), + [with_protobuf=$withval], + [with_protobuf=auto], + ) + AC_MSG_RESULT([$with_protobuf]) + + AS_IF([test "x$with_protobuf" != "xno"], [ + AS_IF([test "x$with_protobuf" = "xyes" -o "x$with_protobuf" = "xauto"], [ + PKG_CHECK_MODULES([PROTOBUF], [protobuf], [ : ], [ : ]) + AC_CHECK_PROG([PROTOC], [protoc], [protoc]) + ]) + ]) + AS_IF([test "x$with_protobuf" = "xyes"], [ + AS_IF([test x"$PROTOBUF_LIBS" = "x"], [ + AC_MSG_ERROR([Protobuf requested but libraries were not found]) + ]) + AS_IF([test x"$PROTOC" = "x"], [ + AC_MSG_ERROR([Protobuf requested but the protobuf compiler was not found]) + ]) + ]) + AM_CONDITIONAL([HAVE_PROTOBUF], [test x"$PROTOBUF_LIBS" != "x"]) + AM_CONDITIONAL([HAVE_PROTOC], [test x"$PROTOC" != "x"]) + AS_IF([test x"$PROTOBUF_LIBS" != "x"], [AC_DEFINE([HAVE_PROTOBUF], [1], [Define if using protobuf.])]) +]) diff --git a/m4/systemd.m4 b/m4/systemd.m4 new file mode 100644 index 0000000..ec2a195 --- /dev/null +++ b/m4/systemd.m4 @@ -0,0 +1,130 @@ +# systemd.m4 - Macros to check for and enable systemd -*- Autoconf -*- +# +# Copyright (C) 2014 Luis R. Rodriguez +# Copyright (C) 2016 Pieter Lexis +# +# 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 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. + +#serial 2 + +dnl Some optional path options +AC_DEFUN([AX_SYSTEMD_OPTIONS], [ + AC_ARG_WITH(systemd, [ --with-systemd set directory for systemd service files], + SYSTEMD_DIR="$withval", SYSTEMD_DIR="") + AC_SUBST(SYSTEMD_DIR) + + AC_ARG_WITH(systemd, [ --with-systemd-modules-load set directory for systemd modules load files], + SYSTEMD_MODULES_LOAD="$withval", SYSTEMD_MODULES_LOAD="") + AC_SUBST(SYSTEMD_MODULES_LOAD) +]) + +AC_DEFUN([AX_ENABLE_SYSTEMD_OPTS], [ + AX_ARG_DEFAULT_ENABLE([systemd], [Disable systemd support]) + AX_SYSTEMD_OPTIONS() +]) + +AC_DEFUN([AX_ALLOW_SYSTEMD_OPTS], [ + AX_ARG_DEFAULT_DISABLE([systemd], [Enable systemd support], [$1]) + AX_SYSTEMD_OPTIONS() +]) + +AC_DEFUN([AX_CHECK_SYSTEMD_LIBS], [ + AC_REQUIRE([AX_CHECK_SYSTEMD_DETECT_AND_ENABLE]) + AS_IF([test "x$libsystemd" = x], [ + AC_MSG_ERROR([Unable to find a suitable libsystemd library]) + ]) + + PKG_CHECK_MODULES([SYSTEMD], [$libsystemd_daemon]) + dnl pkg-config older than 0.24 does not set these for + dnl PKG_CHECK_MODULES() worth also noting is that as of version 208 + dnl of systemd pkg-config --cflags currently yields no extra flags yet. + AC_SUBST([SYSTEMD_CFLAGS]) + AC_SUBST([SYSTEMD_LIBS]) + + AS_IF([test "x$SYSTEMD_DIR" = x], [ + dnl In order to use the line below we need to fix upstream systemd + dnl to properly ${prefix} for child variables in + dnl src/core/systemd.pc.in but this is a bit complex at the + dnl moment as they depend on another rootprefix, which can vary + dnl from prefix in practice. We provide our own definition as we + dnl *know* where systemd will dump this to, but this does limit + dnl us to stick to a non custom systemdsystemunitdir, dnl to work + dnl around this we provide the additional configure option + dnl --with-systemd where you can specify the directory for the unit + dnl files. It would also be best to just extend the upstream + dnl pkg-config pkg.m4 with an AC_DEFUN() to do this neatly. + dnl SYSTEMD_DIR="`$PKG_CONFIG --define-variable=prefix=$PREFIX --variable=systemdsystemunitdir systemd`" + SYSTEMD_DIR="\$(prefix)/lib/systemd/system/" + ], []) + + AS_IF([test "x$SYSTEMD_DIR" = x], [ + AC_MSG_ERROR([SYSTEMD_DIR is unset]) + ], []) + + dnl There is no variable for this yet for some reason + AS_IF([test "x$SYSTEMD_MODULES_LOAD" = x], [ + SYSTEMD_MODULES_LOAD="\$(prefix)/lib/modules-load.d/" + ], []) + + AS_IF([test "x$SYSTEMD_MODULES_LOAD" = x], [ + AC_MSG_ERROR([SYSTEMD_MODULES_LOAD is unset]) + ], []) +]) + +AC_DEFUN([AX_CHECK_SYSTEMD], [ + dnl Respect user override to disable + AS_IF([test "x$enable_systemd" != "xno"], [ + AS_IF([test "x$systemd" = "xy" ], [ + AC_DEFINE([HAVE_SYSTEMD], [1], [Systemd available and enabled]) + systemd=y + AX_CHECK_SYSTEMD_LIBS() + ],[systemd=n]) + ],[systemd=n]) +]) + +AC_DEFUN([AX_CHECK_SYSTEMD_DETECT_AND_ENABLE], [ + AC_CHECK_HEADER([systemd/sd-daemon.h], [ + for libname in systemd-daemon systemd; do + AC_CHECK_LIB([$libname], [sd_listen_fds], [ + libsystemd_daemon="lib$libname" + systemd=y + libsystemd=y + ]) + done + ]) +]) + +dnl Enables systemd by default and requires a --disable-systemd option flag +dnl to configure if you want to disable. +AC_DEFUN([AX_ENABLE_SYSTEMD], [ + AX_ENABLE_SYSTEMD_OPTS() + AX_CHECK_SYSTEMD() +]) + +dnl Systemd will be disabled by default and requires you to run configure with +dnl --enable-systemd to look for and enable systemd. +AC_DEFUN([AX_ALLOW_SYSTEMD], [ + AX_ALLOW_SYSTEMD_OPTS() + AX_CHECK_SYSTEMD() +]) + +dnl Systemd will be disabled by default but if your build system is detected +dnl to have systemd build libraries it will be enabled. You can always force +dnl disable with --disable-systemd +AC_DEFUN([AX_AVAILABLE_SYSTEMD], [ + AX_ALLOW_SYSTEMD_OPTS([, but will be enabled when libraries are found]) + AX_CHECK_SYSTEMD_DETECT_AND_ENABLE() + AX_CHECK_SYSTEMD() +]) diff --git a/m4/warnings.m4 b/m4/warnings.m4 new file mode 100644 index 0000000..5ae01de --- /dev/null +++ b/m4/warnings.m4 @@ -0,0 +1,79 @@ +# warnings.m4 serial 11 +dnl Copyright (C) 2008-2015 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Simon Josefsson + +# gl_AS_VAR_APPEND(VAR, VALUE) +# ---------------------------- +# Provide the functionality of AS_VAR_APPEND if Autoconf does not have it. +m4_ifdef([AS_VAR_APPEND], +[m4_copy([AS_VAR_APPEND], [gl_AS_VAR_APPEND])], +[m4_define([gl_AS_VAR_APPEND], +[AS_VAR_SET([$1], [AS_VAR_GET([$1])$2])])]) + + +# gl_COMPILER_OPTION_IF(OPTION, [IF-SUPPORTED], [IF-NOT-SUPPORTED], +# [PROGRAM = AC_LANG_PROGRAM()]) +# ----------------------------------------------------------------- +# Check if the compiler supports OPTION when compiling PROGRAM. +# +# FIXME: gl_Warn must be used unquoted until we can assume Autoconf +# 2.64 or newer. +AC_DEFUN([gl_COMPILER_OPTION_IF], +[AS_VAR_PUSHDEF([gl_Warn], [gl_cv_warn_[]_AC_LANG_ABBREV[]_$1])dnl +AS_VAR_PUSHDEF([gl_Flags], [_AC_LANG_PREFIX[]FLAGS])dnl +AS_LITERAL_IF([$1], + [m4_pushdef([gl_Positive], m4_bpatsubst([$1], [^-Wno-], [-W]))], + [gl_positive="$1" +case $gl_positive in + -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;; +esac +m4_pushdef([gl_Positive], [$gl_positive])])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler handles $1], m4_defn([gl_Warn]), [ + gl_save_compiler_FLAGS="$gl_Flags" + gl_AS_VAR_APPEND(m4_defn([gl_Flags]), + [" $gl_unknown_warnings_are_errors ]m4_defn([gl_Positive])["]) + AC_LINK_IFELSE([m4_default([$4], [AC_LANG_PROGRAM([])])], + [AS_VAR_SET(gl_Warn, [yes])], + [AS_VAR_SET(gl_Warn, [no])]) + gl_Flags="$gl_save_compiler_FLAGS" +]) +AS_VAR_IF(gl_Warn, [yes], [$2], [$3]) +m4_popdef([gl_Positive])dnl +AS_VAR_POPDEF([gl_Flags])dnl +AS_VAR_POPDEF([gl_Warn])dnl +]) + +# gl_UNKNOWN_WARNINGS_ARE_ERRORS +# ------------------------------ +# Clang doesn't complain about unknown warning options unless one also +# specifies -Wunknown-warning-option -Werror. Detect this. +AC_DEFUN([gl_UNKNOWN_WARNINGS_ARE_ERRORS], +[gl_COMPILER_OPTION_IF([-Werror -Wunknown-warning-option], + [gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror'], + [gl_unknown_warnings_are_errors=])]) + +# gl_WARN_ADD(OPTION, [VARIABLE = WARN_CFLAGS], +# [PROGRAM = AC_LANG_PROGRAM()]) +# --------------------------------------------- +# Adds parameter to WARN_CFLAGS if the compiler supports it when +# compiling PROGRAM. For example, gl_WARN_ADD([-Wparentheses]). +# +# If VARIABLE is a variable name, AC_SUBST it. +AC_DEFUN([gl_WARN_ADD], +[AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS]) +gl_COMPILER_OPTION_IF([$1], + [gl_AS_VAR_APPEND(m4_if([$2], [], [[WARN_CFLAGS]], [[$2]]), [" $1"])], + [], + [$3]) +m4_ifval([$2], + [AS_LITERAL_IF([$2], [AC_SUBST([$2])])], + [AC_SUBST([WARN_CFLAGS])])dnl +]) + +# Local Variables: +# mode: autoconf +# End: diff --git a/malloctrace.cc b/malloctrace.cc new file mode 100644 index 0000000..961629b --- /dev/null +++ b/malloctrace.cc @@ -0,0 +1,151 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "malloctrace.hh" +#include +#include + +using std::string; +using std::map; +using std::vector; + +MallocTracer* g_mtracer; + +#if 1 +#include +vector MallocTracer::makeBacktrace() +{ + void *array[20]; //only care about last 17 functions (3 taken with tracing support) + size_t size = backtrace (array, 20); + return vector(array, array+size); +} + + +extern "C" { +extern void *__libc_malloc(size_t size); +extern void __libc_free(void* ptr); + +void* malloc (size_t size) +{ + if(!g_mtracer) { + void *mem = __libc_malloc(sizeof(MallocTracer)); + g_mtracer = new(mem) MallocTracer; + } + return g_mtracer->malloc(size); +} + +void free(void* ptr) +{ + if(ptr) + g_mtracer->free(ptr); +} +} + +#endif + +static thread_local bool l_active; +void* MallocTracer::malloc(size_t size) +{ + void* ret = __libc_malloc(size); + if(!l_active) { + l_active=true; + + d_allocflux+=size; + d_allocs++; + d_totAllocated += size; + + + std::lock_guard lock(d_mut); + auto& ent=d_stats[makeBacktrace()]; + ent.count++; + ent.sizes[size]++; + d_sizes[ret]=size; + + l_active=false; + } + return ret; +} + +void MallocTracer::free(void* ptr) +{ + __libc_free(ptr); + if(!l_active) { + l_active=true; + std::lock_guard lock(d_mut); + auto f = d_sizes.find(ptr); + if(f != d_sizes.end()) { + d_totAllocated -= f->second; + d_sizes.erase(f); + } + l_active=false; + } +} + +MallocTracer::allocators_t MallocTracer::topAllocators(int num) +{ + l_active=true; + allocators_t ret; + for(const auto& e : d_stats) { + ret.push_back(make_pair(e.second, e.first)); + } + std::sort(ret.begin(), ret.end(), + [](const allocators_t::value_type& a, + const allocators_t::value_type& b) { + return a.first.count < b.first.count; + }); + if((unsigned int)num > ret.size()) + ret.clear(); + else if(num > 0) + ret.erase(ret.begin(), ret.begin() + (ret.size() - num)); + l_active=false; + return ret; +} + +std::string MallocTracer::topAllocatorsString(int num) +{ + l_active=true; + auto raw = topAllocators(num); + l_active=true; + std::ostringstream ret; + for(const auto& e : raw) { + ret<<"Called "< lock(d_mut); + d_stats.clear(); + l_active=false; +} + diff --git a/malloctrace.hh b/malloctrace.hh new file mode 100644 index 0000000..22b531a --- /dev/null +++ b/malloctrace.hh @@ -0,0 +1,63 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include +#include +#include +#include +#include +#include + +/* please do NOT add PowerDNS specific includes/things to this file, we're trying + to make it useful for other projects as well! */ + +/* Goal: you can compile this in safely, but it won't do anything unless PDNS_TRACE_MEMORY is defined. */ + +class MallocTracer +{ +public: + void* malloc (size_t size); + void free(void*); + uint64_t getAllocs(const std::string& = std::string()) const { return d_allocs; } + uint64_t getAllocFlux(const std::string& = std::string()) const { return d_allocflux; } + uint64_t getTotAllocated(const std::string& = std::string()) const { return d_totAllocated; } + uint64_t getNumOut() { std::lock_guard lock(d_mut); return d_sizes.size(); } + struct AllocStats + { + int count; + std::map sizes; + }; + typedef std::vector > > allocators_t; + allocators_t topAllocators(int num=-1); + std::string topAllocatorsString(int num=-1); + void clearAllocators(); + +private: + static std::vector makeBacktrace(); + std::atomic d_allocs{0}, d_allocflux{0}, d_totAllocated{0}; + std::map, AllocStats> d_stats; + std::map d_sizes; + std::mutex d_mut; +}; + +extern MallocTracer* g_mtracer; diff --git a/misc.cc b/misc.cc new file mode 100644 index 0000000..5f4b991 --- /dev/null +++ b/misc.cc @@ -0,0 +1,1339 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "misc.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pdnsexception.hh" +#include +#include +#include "iputils.hh" +#include "dnsparser.hh" +#include +#include +#include +#ifdef __FreeBSD__ +# include +#endif + +bool g_singleThreaded; + +size_t writen2(int fd, const void *buf, size_t count) +{ + const char *ptr = (char*)buf; + const char *eptr = ptr + count; + + ssize_t res; + while(ptr != eptr) { + res = ::write(fd, ptr, eptr - ptr); + if(res < 0) { + if (errno == EAGAIN) + throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN"); + else + unixDie("failed in writen2"); + } + else if (res == 0) + throw std::runtime_error("could not write all bytes, got eof in writen2"); + + ptr += (size_t) res; + } + + return count; +} + +size_t readn2(int fd, void* buffer, size_t len) +{ + size_t pos=0; + ssize_t res; + for(;;) { + res = read(fd, (char*)buffer + pos, len - pos); + if(res == 0) + throw runtime_error("EOF while reading message"); + if(res < 0) { + if (errno == EAGAIN) + throw std::runtime_error("used readn2 on non-blocking socket, got EAGAIN"); + else + unixDie("failed in readn2"); + } + + pos+=(size_t)res; + if(pos == len) + break; + } + return len; +} + +size_t readn2WithTimeout(int fd, void* buffer, size_t len, int idleTimeout, int totalTimeout) +{ + size_t pos = 0; + time_t start = 0; + int remainingTime = totalTimeout; + if (totalTimeout) { + start = time(NULL); + } + + do { + ssize_t got = read(fd, (char *)buffer + pos, len - pos); + if (got > 0) { + pos += (size_t) got; + } + else if (got == 0) { + throw runtime_error("EOF while reading message"); + } + else { + if (errno == EAGAIN) { + int res = waitForData(fd, (totalTimeout == 0 || idleTimeout <= remainingTime) ? idleTimeout : remainingTime); + if (res > 0) { + /* there is data available */ + } + else if (res == 0) { + throw runtime_error("Timeout while waiting for data to read"); + } else { + throw runtime_error("Error while waiting for data to read"); + } + } + else { + unixDie("failed in readn2WithTimeout"); + } + } + + if (totalTimeout) { + time_t now = time(NULL); + int elapsed = now - start; + if (elapsed >= remainingTime) { + throw runtime_error("Timeout while reading data"); + } + start = now; + remainingTime -= elapsed; + } + } + while (pos < len); + + return len; +} + +size_t writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout) +{ + size_t pos = 0; + do { + ssize_t written = write(fd, (char *)buffer + pos, len - pos); + + if (written > 0) { + pos += (size_t) written; + } + else if (written == 0) + throw runtime_error("EOF while writing message"); + else { + if (errno == EAGAIN) { + int res = waitForRWData(fd, false, timeout, 0); + if (res > 0) { + /* there is room available */ + } + else if (res == 0) { + throw runtime_error("Timeout while waiting to write data"); + } else { + throw runtime_error("Error while waiting for room to write data"); + } + } + else { + unixDie("failed in write2WithTimeout"); + } + } + } + while (pos < len); + + return len; +} + +string nowTime() +{ + time_t now = time(nullptr); + struct tm* tm = localtime(&now); + char buffer[30]; + // YYYY-mm-dd HH:MM:SS TZOFF + strftime(buffer, sizeof(buffer), "%F %T %z", tm); + buffer[sizeof(buffer)-1] = '\0'; + return buffer; +} + +uint16_t getShort(const unsigned char *p) +{ + return p[0] * 256 + p[1]; +} + + +uint16_t getShort(const char *p) +{ + return getShort((const unsigned char *)p); +} + +uint32_t getLong(const unsigned char* p) +{ + return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; +} + +uint32_t getLong(const char* p) +{ + return getLong((unsigned char *)p); +} + +static bool ciEqual(const string& a, const string& b) +{ + if(a.size()!=b.size()) + return false; + + string::size_type pos=0, epos=a.size(); + for(;pos < epos; ++pos) + if(dns_tolower(a[pos])!=dns_tolower(b[pos])) + return false; + return true; +} + +/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */ +static bool endsOn(const string &domain, const string &suffix) +{ + if( suffix.empty() || ciEqual(domain, suffix) ) + return true; + + if(domain.size()<=suffix.size()) + return false; + + string::size_type dpos=domain.size()-suffix.size()-1, spos=0; + + if(domain[dpos++]!='.') + return false; + + for(; dpos < domain.size(); ++dpos, ++spos) + if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos])) + return false; + + return true; +} + +/** strips a domain suffix from a domain, returns true if it stripped */ +bool stripDomainSuffix(string *qname, const string &domain) +{ + if(!endsOn(*qname, domain)) + return false; + + if(toLower(*qname)==toLower(domain)) + *qname="@"; + else { + if((*qname)[qname->size()-domain.size()-1]!='.') + return false; + + qname->resize(qname->size()-domain.size()-1); + } + return true; +} + +static void parseService4(const string &descr, ServiceTuple &st) +{ + vectorparts; + stringtok(parts,descr,":"); + if(parts.empty()) + throw PDNSException("Unable to parse '"+descr+"' as a service"); + st.host=parts[0]; + if(parts.size()>1) + st.port=pdns_stou(parts[1]); +} + +static void parseService6(const string &descr, ServiceTuple &st) +{ + string::size_type pos=descr.find(']'); + if(pos == string::npos) + throw PDNSException("Unable to parse '"+descr+"' as an IPv6 service"); + + st.host=descr.substr(1, pos-1); + if(pos + 2 < descr.length()) + st.port=pdns_stou(descr.substr(pos+2)); +} + + +void parseService(const string &descr, ServiceTuple &st) +{ + if(descr.empty()) + throw PDNSException("Unable to parse '"+descr+"' as a service"); + + vector parts; + stringtok(parts, descr, ":"); + + if(descr[0]=='[') { + parseService6(descr, st); + } + else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) { + st.host=descr; + } + else { + parseService4(descr, st); + } +} + +// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set +int waitForData(int fd, int seconds, int useconds) +{ + return waitForRWData(fd, true, seconds, useconds); +} + +int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error, bool* disconnected) +{ + int ret; + + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = fd; + + if(waitForRead) + pfd.events=POLLIN; + else + pfd.events=POLLOUT; + + ret = poll(&pfd, 1, seconds * 1000 + useconds/1000); + if (ret > 0) { + if (error && (pfd.revents & POLLERR)) { + *error = true; + } + if (disconnected && (pfd.revents & POLLHUP)) { + *disconnected = true; + } + } + + return ret; +} + +// returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set +int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd) +{ + int ret; + + struct pollfd pfds[2]; + memset(&pfds[0], 0, 2*sizeof(struct pollfd)); + pfds[0].fd = fd1; + pfds[1].fd = fd2; + + pfds[0].events= pfds[1].events = POLLIN; + + int nsocks = 1 + (fd2 >= 0); // fd2 can optionally be -1 + + if(seconds >= 0) + ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000); + else + ret = poll(pfds, nsocks, -1); + if(!ret || ret < 0) + return ret; + + if((pfds[0].revents & POLLIN) && !(pfds[1].revents & POLLIN)) + *fd = pfds[0].fd; + else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN)) + *fd = pfds[1].fd; + else if(ret == 2) { + *fd = pfds[random()%2].fd; + } + else + *fd = -1; // should never happen + + return 1; +} + + +string humanDuration(time_t passed) +{ + ostringstream ret; + if(passed<60) + ret<> 24)&0xff, + (val >> 16)&0xff, + (val >> 8)&0xff, + (val )&0xff); + return tmp; +} + + +string makeHexDump(const string& str) +{ + char tmp[5]; + string ret; + ret.reserve((int)(str.size()*2.2)); + + for(string::size_type n=0;n& rrs) +{ + vector::iterator first, second; + for(first=rrs.begin();first!=rrs.end();++first) + if(first->dr.d_place==DNSResourceRecord::ANSWER && first->dr.d_type != QType::CNAME) // CNAME must come first + break; + for(second=first;second!=rrs.end();++second) + if(second->dr.d_place!=DNSResourceRecord::ANSWER) + break; + + if(second-first > 1) + random_shuffle(first,second); + + // now shuffle the additional records + for(first=second;first!=rrs.end();++first) + if(first->dr.d_place==DNSResourceRecord::ADDITIONAL && first->dr.d_type != QType::CNAME) // CNAME must come first + break; + for(second=first;second!=rrs.end();++second) + if(second->dr.d_place!=DNSResourceRecord::ADDITIONAL) + break; + + if(second-first>1) + random_shuffle(first,second); + + // we don't shuffle the rest +} + + +// shuffle, maintaining some semblance of order +void shuffle(vector& rrs) +{ + vector::iterator first, second; + for(first=rrs.begin();first!=rrs.end();++first) + if(first->d_place==DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) // CNAME must come first + break; + for(second=first;second!=rrs.end();++second) + if(second->d_place!=DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) // leave RRSIGs at the end + break; + + if(second-first>1) + random_shuffle(first,second); + + // now shuffle the additional records + for(first=second;first!=rrs.end();++first) + if(first->d_place==DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) // CNAME must come first + break; + for(second=first; second!=rrs.end(); ++second) + if(second->d_place!=DNSResourceRecord::ADDITIONAL) + break; + + if(second-first>1) + random_shuffle(first,second); + + // we don't shuffle the rest +} + +static uint16_t mapTypesToOrder(uint16_t type) +{ + if(type == QType::CNAME) + return 0; + if(type == QType::RRSIG) + return 65535; + else + return 1; +} + +// make sure rrs is sorted in d_place order to avoid surprises later +// then shuffle the parts that desire shuffling +void orderAndShuffle(vector& rrs) +{ + std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord&a, const DNSRecord& b) { + return std::make_tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::make_tuple(b.d_place, mapTypesToOrder(b.d_type)); + }); + shuffle(rrs); +} + +void normalizeTV(struct timeval& tv) +{ + if(tv.tv_usec > 1000000) { + ++tv.tv_sec; + tv.tv_usec-=1000000; + } + else if(tv.tv_usec < 0) { + --tv.tv_sec; + tv.tv_usec+=1000000; + } +} + +const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs) +{ + struct timeval ret; + ret.tv_sec=lhs.tv_sec + rhs.tv_sec; + ret.tv_usec=lhs.tv_usec + rhs.tv_usec; + normalizeTV(ret); + return ret; +} + +const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs) +{ + struct timeval ret; + ret.tv_sec=lhs.tv_sec - rhs.tv_sec; + ret.tv_usec=lhs.tv_usec - rhs.tv_usec; + normalizeTV(ret); + return ret; +} + +pair splitField(const string& inp, char sepa) +{ + pair ret; + string::size_type cpos=inp.find(sepa); + if(cpos==string::npos) + ret.first=inp; + else { + ret.first=inp.substr(0, cpos); + ret.second=inp.substr(cpos+1); + } + return ret; +} + +int logFacilityToLOG(unsigned int facility) +{ + switch(facility) { + case 0: + return LOG_LOCAL0; + case 1: + return(LOG_LOCAL1); + case 2: + return(LOG_LOCAL2); + case 3: + return(LOG_LOCAL3); + case 4: + return(LOG_LOCAL4); + case 5: + return(LOG_LOCAL5); + case 6: + return(LOG_LOCAL6); + case 7: + return(LOG_LOCAL7); + default: + return -1; + } +} + +string stripDot(const string& dom) +{ + if(dom.empty()) + return dom; + + if(dom[dom.size()-1]!='.') + return dom; + + return dom.substr(0,dom.size()-1); +} + + + +int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret) +{ + if(addr.empty()) + return -1; + string ourAddr(addr); + bool portSet = false; + unsigned int port; + if(addr[0]=='[') { // [::]:53 style address + string::size_type pos = addr.find(']'); + if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':') + return -1; + ourAddr.assign(addr.c_str() + 1, pos-1); + try { + port = pdns_stou(addr.substr(pos+2)); + portSet = true; + } + catch(const std::out_of_range&) { + return -1; + } + } + ret->sin6_scope_id=0; + ret->sin6_family=AF_INET6; + + if(inet_pton(AF_INET6, ourAddr.c_str(), (void*)&ret->sin6_addr) != 1) { + struct addrinfo* res; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + + int error; + // getaddrinfo has anomalous return codes, anything nonzero is an error, positive or negative + if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { + return -1; + } + + memcpy(ret, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } + + if(portSet) { + if(port > 65535) + return -1; + + ret->sin6_port = htons(port); + } + + return 0; +} + +int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret) +{ + if(str.empty()) { + return -1; + } + struct in_addr inp; + + string::size_type pos = str.find(':'); + if(pos == string::npos) { // no port specified, not touching the port + if(inet_aton(str.c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; + } + if(!*(str.c_str() + pos + 1)) // trailing : + return -1; + + char *eptr = (char*)str.c_str() + str.size(); + int port = strtol(str.c_str() + pos + 1, &eptr, 10); + if (port < 0 || port > 65535) + return -1; + + if(*eptr) + return -1; + + ret->sin_port = htons(port); + if(inet_aton(str.substr(0, pos).c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; +} + +int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret) +{ + if (path.empty()) + return -1; + + memset(ret, 0, sizeof(struct sockaddr_un)); + ret->sun_family = AF_UNIX; + if (path.length() >= sizeof(ret->sun_path)) + return -1; + + path.copy(ret->sun_path, sizeof(ret->sun_path), 0); + return 0; +} + +//! read a line of text from a FILE* to a std::string, returns false on 'no data' +bool stringfgets(FILE* fp, std::string& line) +{ + char buffer[1024]; + line.clear(); + + do { + if(!fgets(buffer, sizeof(buffer), fp)) + return !line.empty(); + + line.append(buffer); + } while(!strchr(buffer, '\n')); + return true; +} + +bool readFileIfThere(const char* fname, std::string* line) +{ + line->clear(); + FILE* fp = fopen(fname, "r"); + if(!fp) + return false; + stringfgets(fp, *line); + fclose(fp); + return true; +} + +Regex::Regex(const string &expr) +{ + if(regcomp(&d_preg, expr.c_str(), REG_ICASE|REG_NOSUB|REG_EXTENDED)) + throw PDNSException("Regular expression did not compile"); +} + +// if you end up here because valgrind told you were are doing something wrong +// with msgh->msg_controllen, please refer to https://github.com/PowerDNS/pdns/pull/3962 +// first. +void addCMsgSrcAddr(struct msghdr* msgh, void* cmsgbuf, const ComboAddress* source, int itfIndex) +{ + struct cmsghdr *cmsg = NULL; + + if(source->sin4.sin_family == AF_INET6) { + struct in6_pktinfo *pkt; + + msgh->msg_control = cmsgbuf; + msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt)); + + cmsg = CMSG_FIRSTHDR(msgh); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt)); + + pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg); + memset(pkt, 0, sizeof(*pkt)); + pkt->ipi6_addr = source->sin6.sin6_addr; + pkt->ipi6_ifindex = itfIndex; + } + else { +#ifdef IP_PKTINFO + struct in_pktinfo *pkt; + + msgh->msg_control = cmsgbuf; + msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt)); + + cmsg = CMSG_FIRSTHDR(msgh); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt)); + + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + memset(pkt, 0, sizeof(*pkt)); + pkt->ipi_spec_dst = source->sin4.sin_addr; + pkt->ipi_ifindex = itfIndex; +#endif +#ifdef IP_SENDSRCADDR + struct in_addr *in; + + msgh->msg_control = cmsgbuf; + msgh->msg_controllen = CMSG_SPACE(sizeof(*in)); + + cmsg = CMSG_FIRSTHDR(msgh); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_SENDSRCADDR; + cmsg->cmsg_len = CMSG_LEN(sizeof(*in)); + + in = (struct in_addr *) CMSG_DATA(cmsg); + *in = source->sin4.sin_addr; +#endif + } +} + +unsigned int getFilenumLimit(bool hardOrSoft) +{ + struct rlimit rlim; + if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) + unixDie("Requesting number of available file descriptors"); + return hardOrSoft ? rlim.rlim_max : rlim.rlim_cur; +} + +void setFilenumLimit(unsigned int lim) +{ + struct rlimit rlim; + + if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) + unixDie("Requesting number of available file descriptors"); + rlim.rlim_cur=lim; + if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) + unixDie("Setting number of available file descriptors"); +} + +#define burtlemix(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); \ +} + +uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t initval) +{ + uint32_t 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] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); + b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); + c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); + burtlemix(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+=((uint32_t)k[10]<<24); + case 10: c+=((uint32_t)k[9]<<16); + case 9 : c+=((uint32_t)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((uint32_t)k[7]<<24); + case 7 : b+=((uint32_t)k[6]<<16); + case 6 : b+=((uint32_t)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3]<<24); + case 3 : a+=((uint32_t)k[2]<<16); + case 2 : a+=((uint32_t)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + burtlemix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + +uint32_t burtleCI(const unsigned char* k, uint32_t length, uint32_t initval) +{ + uint32_t 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 += (dns_tolower(k[0]) +((uint32_t)dns_tolower(k[1])<<8) +((uint32_t)dns_tolower(k[2])<<16) +((uint32_t)dns_tolower(k[3])<<24)); + b += (dns_tolower(k[4]) +((uint32_t)dns_tolower(k[5])<<8) +((uint32_t)dns_tolower(k[6])<<16) +((uint32_t)dns_tolower(k[7])<<24)); + c += (dns_tolower(k[8]) +((uint32_t)dns_tolower(k[9])<<8) +((uint32_t)dns_tolower(k[10])<<16)+((uint32_t)dns_tolower(k[11])<<24)); + burtlemix(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+=((uint32_t)dns_tolower(k[10])<<24); + case 10: c+=((uint32_t)dns_tolower(k[9])<<16); + case 9 : c+=((uint32_t)dns_tolower(k[8])<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((uint32_t)dns_tolower(k[7])<<24); + case 7 : b+=((uint32_t)dns_tolower(k[6])<<16); + case 6 : b+=((uint32_t)dns_tolower(k[5])<<8); + case 5 : b+=dns_tolower(k[4]); + case 4 : a+=((uint32_t)dns_tolower(k[3])<<24); + case 3 : a+=((uint32_t)dns_tolower(k[2])<<16); + case 2 : a+=((uint32_t)dns_tolower(k[1])<<8); + case 1 : a+=dns_tolower(k[0]); + /* case 0: nothing left to add */ + } + burtlemix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + + +bool setSocketTimestamps(int fd) +{ +#ifdef SO_TIMESTAMP + int on=1; + return setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, (char*)&on, sizeof(on)) == 0; +#endif + return true; // we pretend this happened. +} + +bool setTCPNoDelay(int sock) +{ + int flag = 1; + return setsockopt(sock, /* socket affected */ + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (char *) &flag, /* the cast is historical cruft */ + sizeof(flag)) == 0; /* length of option value */ +} + + +bool setNonBlocking(int sock) +{ + int flags=fcntl(sock,F_GETFL,0); + if(flags<0 || fcntl(sock, F_SETFL,flags|O_NONBLOCK) <0) + return false; + return true; +} + +bool setBlocking(int sock) +{ + int flags=fcntl(sock,F_GETFL,0); + if(flags<0 || fcntl(sock, F_SETFL,flags&(~O_NONBLOCK)) <0) + return false; + return true; +} + +bool isNonBlocking(int sock) +{ + int flags=fcntl(sock,F_GETFL,0); + return flags & O_NONBLOCK; +} + +// Closes a socket. +int closesocket( int socket ) +{ + int ret=::close(socket); + if(ret < 0 && errno == ECONNRESET) // see ticket 192, odd BSD behaviour + return 0; + if(ret < 0) + throw PDNSException("Error closing socket: "+stringerror()); + return ret; +} + +bool setCloseOnExec(int sock) +{ + int flags=fcntl(sock,F_GETFD,0); + if(flags<0 || fcntl(sock, F_SETFD,flags|FD_CLOEXEC) <0) + return false; + return true; +} + +string getMACAddress(const ComboAddress& ca) +{ + string ret; +#ifdef __linux__ + ifstream ifs("/proc/net/arp"); + if(!ifs) + return ret; + string line; + string match=ca.toString()+' '; + while(getline(ifs, line)) { + if(boost::starts_with(line, match)) { + vector parts; + stringtok(parts, line, " \n\t\r"); + if(parts.size() < 4) + return ret; + unsigned int tmp[6]; + sscanf(parts[3].c_str(), "%02x:%02x:%02x:%02x:%02x:%02x", tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5); + for(int i = 0 ; i< 6 ; ++i) + ret.append(1, (char)tmp[i]); + return ret; + } + } +#endif + return ret; +} + +uint64_t udpErrorStats(const std::string& str) +{ +#ifdef __linux__ + ifstream ifs("/proc/net/snmp"); + if(!ifs) + return 0; + string line; + vector parts; + while(getline(ifs,line)) { + if(boost::starts_with(line, "Udp: ") && isdigit(line[5])) { + stringtok(parts, line, " \n\t\r"); + if(parts.size() < 7) + break; + if(str=="udp-rcvbuf-errors") + return std::stoull(parts[5]); + else if(str=="udp-sndbuf-errors") + return std::stoull(parts[6]); + else if(str=="udp-noport-errors") + return std::stoull(parts[2]); + else if(str=="udp-in-errors") + return std::stoull(parts[3]); + else + return 0; + } + } +#endif + return 0; +} + +bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum) +{ + if (algoName == DNSName("hmac-md5.sig-alg.reg.int") || algoName == DNSName("hmac-md5")) + algoEnum = TSIG_MD5; + else if (algoName == DNSName("hmac-sha1")) + algoEnum = TSIG_SHA1; + else if (algoName == DNSName("hmac-sha224")) + algoEnum = TSIG_SHA224; + else if (algoName == DNSName("hmac-sha256")) + algoEnum = TSIG_SHA256; + else if (algoName == DNSName("hmac-sha384")) + algoEnum = TSIG_SHA384; + else if (algoName == DNSName("hmac-sha512")) + algoEnum = TSIG_SHA512; + else if (algoName == DNSName("gss-tsig")) + algoEnum = TSIG_GSS; + else { + return false; + } + return true; +} + +DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum) +{ + switch(algoEnum) { + case TSIG_MD5: return DNSName("hmac-md5.sig-alg.reg.int."); + case TSIG_SHA1: return DNSName("hmac-sha1."); + case TSIG_SHA224: return DNSName("hmac-sha224."); + case TSIG_SHA256: return DNSName("hmac-sha256."); + case TSIG_SHA384: return DNSName("hmac-sha384."); + case TSIG_SHA512: return DNSName("hmac-sha512."); + case TSIG_GSS: return DNSName("gss-tsig."); + } + throw PDNSException("getTSIGAlgoName does not understand given algorithm, please fix!"); +} + +uint64_t getOpenFileDescriptors(const std::string&) +{ +#ifdef __linux__ + DIR* dirhdl=opendir(("/proc/"+std::to_string(getpid())+"/fd/").c_str()); + if(!dirhdl) + return 0; + + struct dirent *entry; + int ret=0; + while((entry = readdir(dirhdl))) { + uint32_t num; + try { + num = pdns_stou(entry->d_name); + } catch (...) { + continue; // was not a number. + } + if(std::to_string(num) == entry->d_name) + ret++; + } + closedir(dirhdl); + return ret; + +#else + return 0; +#endif +} + +uint64_t getRealMemoryUsage(const std::string&) +{ +#ifdef __linux__ + ifstream ifs("/proc/"+std::to_string(getpid())+"/smaps"); + if(!ifs) + return 0; + string line; + uint64_t bytes=0; + string header("Private_Dirty:"); + while(getline(ifs, line)) { + if(boost::starts_with(line, header)) { + bytes += std::stoull(line.substr(header.length() + 1))*1024; + } + } + return bytes; +#else + return 0; +#endif +} + +uint64_t getCPUTimeUser(const std::string&) +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000); +} + +uint64_t getCPUTimeSystem(const std::string&) +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000); +} + +double DiffTime(const struct timespec& first, const struct timespec& second) +{ + int seconds=second.tv_sec - first.tv_sec; + int nseconds=second.tv_nsec - first.tv_nsec; + + if(nseconds < 0) { + seconds-=1; + nseconds+=1000000000; + } + return seconds + nseconds/1000000000.0; +} + +double DiffTime(const struct timeval& first, const struct timeval& second) +{ + int seconds=second.tv_sec - first.tv_sec; + int useconds=second.tv_usec - first.tv_usec; + + if(useconds < 0) { + seconds-=1; + useconds+=1000000; + } + return seconds + useconds/1000000.0; +} + +uid_t strToUID(const string &str) +{ + uid_t result = 0; + const char * cstr = str.c_str(); + struct passwd * pwd = getpwnam(cstr); + + if (pwd == NULL) { + long long val; + + try { + val = stoll(str); + } + catch(std::exception& e) { + throw runtime_error((boost::format("Error: Unable to parse user ID %s") % cstr).str() ); + } + + if (val < std::numeric_limits::min() || val > std::numeric_limits::max()) { + throw runtime_error((boost::format("Error: Unable to parse user ID %s") % cstr).str() ); + } + + result = static_cast(val); + } + else { + result = pwd->pw_uid; + } + + return result; +} + +gid_t strToGID(const string &str) +{ + gid_t result = 0; + const char * cstr = str.c_str(); + struct group * grp = getgrnam(cstr); + + if (grp == NULL) { + long long val; + + try { + val = stoll(str); + } + catch(std::exception& e) { + throw runtime_error((boost::format("Error: Unable to parse group ID %s") % cstr).str() ); + } + + if (val < std::numeric_limits::min() || val > std::numeric_limits::max()) { + throw runtime_error((boost::format("Error: Unable to parse group ID %s") % cstr).str() ); + } + + result = static_cast(val); + } + else { + result = grp->gr_gid; + } + + return result; +} + +unsigned int pdns_stou(const std::string& str, size_t * idx, int base) +{ + if (str.empty()) return 0; // compatibility + unsigned long result = std::stoul(str, idx, base); + if (result > std::numeric_limits::max()) { + throw std::out_of_range("stou"); + } + return static_cast(result); +} + +bool isSettingThreadCPUAffinitySupported() +{ +#ifdef HAVE_PTHREAD_SETAFFINITY_NP + return true; +#else + return false; +#endif +} + +int mapThreadToCPUList(pthread_t tid, const std::set& cpus) +{ +#ifdef HAVE_PTHREAD_SETAFFINITY_NP +# ifdef __FreeBSD__ +# define cpu_set_t cpuset_t +# endif + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + for (const auto cpuID : cpus) { + CPU_SET(cpuID, &cpuset); + } + + return pthread_setaffinity_np(tid, + sizeof(cpuset), + &cpuset); +#endif /* HAVE_PTHREAD_SETAFFINITY_NP */ + return ENOSYS; +} diff --git a/misc.hh b/misc.hh new file mode 100644 index 0000000..f9db931 --- /dev/null +++ b/misc.hh @@ -0,0 +1,599 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::boost::multi_index; + +#include "dns.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "namespaces.hh" +#include "dnsname.hh" + +typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum; + +string nowTime(); +const string unquotify(const string &item); +string humanDuration(time_t passed); +bool stripDomainSuffix(string *qname, const string &domain); +void stripLine(string &line); +string getHostname(); +string urlEncode(const string &text); +int waitForData(int fd, int seconds, int useconds=0); +int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd); +int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error=nullptr, bool* disconnected=nullptr); +uint16_t getShort(const unsigned char *p); +uint16_t getShort(const char *p); +uint32_t getLong(const unsigned char *p); +uint32_t getLong(const char *p); +bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum); +DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum); + +int logFacilityToLOG(unsigned int facility); + +struct ServiceTuple +{ + string host; + uint16_t port; +}; +void parseService(const string &descr, ServiceTuple &st); + +template +void +stringtok (Container &container, string const &in, + const char * const delimiters = " \t\n") +{ + const string::size_type len = in.length(); + string::size_type i = 0; + + while (i bool rfc1982LessThan(T a, T b) +{ + return ((signed)(a - b)) < 0; +} + +// fills container with ranges, so {posbegin,posend} +template +void +vstringtok (Container &container, string const &in, + const char * const delimiters = " \t\n") +{ + const string::size_type len = in.length(); + string::size_type i = 0; + + while (i& rrs); +void shuffle(vector& rrs); + +void orderAndShuffle(vector& rrs); + +void normalizeTV(struct timeval& tv); +const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs); +const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs); +inline float makeFloat(const struct timeval& tv) +{ + return tv.tv_sec + tv.tv_usec/1000000.0f; +} + +inline bool operator<(const struct timeval& lhs, const struct timeval& rhs) +{ + return make_pair(lhs.tv_sec, lhs.tv_usec) < make_pair(rhs.tv_sec, rhs.tv_usec); +} + +inline bool operator<(const struct timespec& lhs, const struct timespec& rhs) +{ + return tie(lhs.tv_sec, lhs.tv_nsec) < tie(rhs.tv_sec, rhs.tv_nsec); +} + + +inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure)); +inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) +{ + const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str(); + const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length(); + while(aPtr != aEptr && bPtr != bEptr) { + if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr))) + return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0; + aPtr++; + bPtr++; + } + if(aPtr == aEptr && bPtr == bEptr) // strings are equal (in length) + return false; + return aPtr == aEptr; // true if first string was shorter +} + +inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure)); +inline bool pdns_iequals(const std::string& a, const std::string& b) +{ + if (a.length() != b.length()) + return false; + + const char *aPtr = a.c_str(), *bPtr = b.c_str(); + const char *aEptr = aPtr + a.length(); + while(aPtr != aEptr) { + if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr))) + return false; + aPtr++; + bPtr++; + } + return true; +} + +inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure)); +inline bool pdns_iequals_ch(const char a, const char b) +{ + if ((a != b) && (dns_tolower(a) != dns_tolower(b))) + return false; + + return true; +} + + +typedef unsigned long AtomicCounterInner; +typedef std::atomic AtomicCounter ; + +// FIXME400 this should probably go? +struct CIStringCompare: public std::binary_function +{ + bool operator()(const string& a, const string& b) const + { + return pdns_ilexicographical_compare(a, b); + } +}; + +struct CIStringComparePOSIX +{ + bool operator() (const std::string& lhs, const std::string& rhs) + { + std::string::const_iterator a,b; + const std::locale &loc = std::locale("POSIX"); + a=lhs.begin();b=rhs.begin(); + while(a!=lhs.end()) { + if (b==rhs.end() || std::tolower(*b,loc), pair, bool> +{ + bool operator()(const pair& a, const pair& b) const + { + if(pdns_ilexicographical_compare(a.first, b.first)) + return true; + if(pdns_ilexicographical_compare(b.first, a.first)) + return false; + return a.second < b.second; + } +}; + +inline size_t pdns_ci_find(const string& haystack, const string& needle) +{ + string::const_iterator it = std::search(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), pdns_iequals_ch); + if (it == haystack.end()) { + // not found + return string::npos; + } else { + return it - haystack.begin(); + } +} + +pair splitField(const string& inp, char sepa); + +inline bool isCanonical(const string& qname) +{ + if(qname.empty()) + return false; + return qname[qname.size()-1]=='.'; +} + +inline DNSName toCanonic(const DNSName& zone, const string& qname) +{ + if(qname.size()==1 && qname[0]=='@') + return zone; + if(isCanonical(qname)) + return DNSName(qname); + return DNSName(qname) += zone; +} + +string stripDot(const string& dom); + +void seedRandom(const string& source); +int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret); +int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret); +int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret); +bool stringfgets(FILE* fp, std::string& line); + +template +std::pair +replacing_insert(Index& i,const typename Index::value_type& x) +{ + std::pair res=i.insert(x); + if(!res.second)res.second=i.replace(res.first,x); + return res; +} + +/** very small regex wrapper */ +class Regex +{ +public: + /** constructor that accepts the expression to regex */ + Regex(const string &expr); + + ~Regex() + { + regfree(&d_preg); + } + /** call this to find out if 'line' matches your expression */ + bool match(const string &line) const + { + return regexec(&d_preg,line.c_str(),0,0,0)==0; + } + bool match(const DNSName& name) const + { + return match(name.toStringNoDot()); + } + +private: + regex_t d_preg; +}; + +class SimpleMatch +{ +public: + SimpleMatch(const string &mask, bool caseFold = false) + { + this->d_mask = mask; + this->d_fold = caseFold; + } + + bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend) + { + for(;;mi++) { + if (mi == mend) { + return vi == vend; + } else if (*mi == '?') { + if (vi == vend) return false; + vi++; + } else if (*mi == '*') { + while(*mi == '*') mi++; + if (mi == d_mask.end()) return true; + while(vi != vend) { + if (match(mi,mend,vi,vend)) return true; + vi++; + } + return false; + } else { + if ((mi == mend && vi != vend)|| + (mi != mend && vi == vend)) return false; + if (d_fold) { + if (dns_tolower(*mi) != dns_tolower(*vi)) return false; + } else { + if (*mi != *vi) return false; + } + vi++; + } + } + } + + bool match(const string& value) { + return match(d_mask.begin(), d_mask.end(), value.begin(), value.end()); + } + + bool match(const DNSName& name) { + return match(name.toStringNoDot()); + } + +private: + string d_mask; + bool d_fold; +}; + +union ComboAddress; +/* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */ +void addCMsgSrcAddr(struct msghdr* msgh, void* cmsgbuf, const ComboAddress* source, int itfIndex); + +unsigned int getFilenumLimit(bool hardOrSoft=0); +void setFilenumLimit(unsigned int lim); +bool readFileIfThere(const char* fname, std::string* line); +uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t init); +bool setSocketTimestamps(int fd); + +//! Sets the socket into blocking mode. +bool setBlocking( int sock ); + +//! Sets the socket into non-blocking mode. +bool setNonBlocking( int sock ); +bool setTCPNoDelay(int sock); +bool isNonBlocking(int sock); +int closesocket(int fd); +bool setCloseOnExec(int sock); +uint64_t udpErrorStats(const std::string& str); + +uint64_t getRealMemoryUsage(const std::string&); +uint64_t getOpenFileDescriptors(const std::string&); +uint64_t getCPUTimeUser(const std::string&); +uint64_t getCPUTimeSystem(const std::string&); +std::string getMACAddress(const ComboAddress& ca); +template +std::unique_ptr make_unique(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + + +template +const T& defTer(const T& a, const T& b) +{ + return a ? a : b; +} + +template +T valueOrEmpty(const P val) { + if (!val) return T{}; + return T(val); +} + + +// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-) +template +const char* addS(Integer siz, typename std::enable_if::value>::type*P=0) +{ + if(!siz || siz > 1) + return "s"; + else return ""; +} + +template +const char* addS(const C& c, typename std::enable_if::value>::type*P=0) +{ + return addS(c.size()); +} + +template +const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key) +{ + auto fnd = c.find(key); + if(fnd == c.end()) + return 0; + return &fnd->second; +} + +double DiffTime(const struct timespec& first, const struct timespec& second); +double DiffTime(const struct timeval& first, const struct timeval& second); +uid_t strToUID(const string &str); +gid_t strToGID(const string &str); + +unsigned int pdns_stou(const std::string& str, size_t * idx = 0, int base = 10); + +bool isSettingThreadCPUAffinitySupported(); +int mapThreadToCPUList(pthread_t tid, const std::set& cpus); diff --git a/mkpubsuffixcc b/mkpubsuffixcc new file mode 100755 index 0000000..a65e97a --- /dev/null +++ b/mkpubsuffixcc @@ -0,0 +1,8 @@ +#!/bin/sh + +(echo "const char* g_pubsuffix[]={"; + for a in $(grep -v "//" effective_tld_names.dat | grep \\. | egrep "^[.0-9a-z-]*$") + do + echo \"$a\", + done +echo "0};") > pubsuffix.cc diff --git a/mplexer.hh b/mplexer.hh new file mode 100644 index 0000000..880abd1 --- /dev/null +++ b/mplexer.hh @@ -0,0 +1,182 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_MPLEXER_HH +#define PDNS_MPLEXER_HH +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class FDMultiplexerException : public std::runtime_error +{ +public: + FDMultiplexerException(const std::string& str) : std::runtime_error(str) + {} +}; + + +/** Very simple FD multiplexer, based on callbacks and boost::any parameters + As a special service, this parameter is kept around and can be modified, + allowing for state to be stored inside the multiplexer. + + It has some "interesting" semantics +*/ + +class FDMultiplexer +{ +public: + typedef boost::any funcparam_t; +protected: + + typedef boost::function< void(int, funcparam_t&) > callbackfunc_t; + struct Callback + { + callbackfunc_t d_callback; + funcparam_t d_parameter; + struct timeval d_ttd; + }; + +public: + FDMultiplexer() : d_inrun(false) + {} + virtual ~FDMultiplexer() + {} + + /* tv will be updated to 'now' before run returns */ + /* timeout is in ms */ + virtual int run(struct timeval* tv, int timeout=500) = 0; + + //! Add an fd to the read watch list - currently an fd can only be on one list at a time! + virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t()) + { + this->addFD(d_readCallbacks, fd, toDo, parameter); + } + + //! Add an fd to the write watch list - currently an fd can only be on one list at a time! + virtual void addWriteFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t()) + { + this->addFD(d_writeCallbacks, fd, toDo, parameter); + } + + //! Remove an fd from the read watch list. You can't call this function on an fd that is closed already! + /** WARNING: references to 'parameter' become invalid after this function! */ + virtual void removeReadFD(int fd) + { + this->removeFD(d_readCallbacks, fd); + } + + //! Remove an fd from the write watch list. You can't call this function on an fd that is closed already! + /** WARNING: references to 'parameter' become invalid after this function! */ + virtual void removeWriteFD(int fd) + { + this->removeFD(d_writeCallbacks, fd); + } + + virtual void setReadTTD(int fd, struct timeval tv, int timeout) + { + if(!d_readCallbacks.count(fd)) + throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer"); + tv.tv_sec += timeout; + d_readCallbacks[fd].d_ttd=tv; + } + + virtual funcparam_t& getReadParameter(int fd) + { + if(!d_readCallbacks.count(fd)) + throw FDMultiplexerException("attempt to look up data in multiplexer for unlisted fd "+std::to_string(fd)); + return d_readCallbacks[fd].d_parameter; + } + + virtual std::vector > getTimeouts(const struct timeval& tv) + { + std::vector > ret; + for(callbackmap_t::iterator i=d_readCallbacks.begin(); i!=d_readCallbacks.end(); ++i) + if(i->second.d_ttd.tv_sec && boost::tie(tv.tv_sec, tv.tv_usec) > boost::tie(i->second.d_ttd.tv_sec, i->second.d_ttd.tv_usec)) + ret.push_back(std::make_pair(i->first, i->second.d_parameter)); + return ret; + } + + typedef FDMultiplexer* getMultiplexer_t(); + typedef std::multimap FDMultiplexermap_t; + + static FDMultiplexermap_t& getMultiplexerMap() + { + static FDMultiplexermap_t theMap; + return theMap; + } + + virtual std::string getName() = 0; + +protected: + typedef std::map callbackmap_t; + callbackmap_t d_readCallbacks, d_writeCallbacks; + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)=0; + virtual void removeFD(callbackmap_t& cbmap, int fd)=0; + bool d_inrun; + callbackmap_t::iterator d_iter; + + void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter) + { + Callback cb; + cb.d_callback=toDo; + cb.d_parameter=parameter; + memset(&cb.d_ttd, 0, sizeof(cb.d_ttd)); + + if(cbmap.count(fd)) + throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice"); + cbmap[fd]=cb; + } + + void accountingRemoveFD(callbackmap_t& cbmap, int fd) + { + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); + } +}; + +class SelectFDMultiplexer : public FDMultiplexer +{ +public: + SelectFDMultiplexer() + {} + virtual ~SelectFDMultiplexer() + {} + + virtual int run(struct timeval* tv, int timeout=500); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + std::string getName() + { + return "select"; + } +}; + +#endif + diff --git a/mtasker.cc b/mtasker.cc new file mode 100644 index 0000000..16027b6 --- /dev/null +++ b/mtasker.cc @@ -0,0 +1,410 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "mtasker.hh" +#include "misc.hh" +#include +#include + +#ifdef PDNS_USE_VALGRIND +#include +#endif /* PDNS_USE_VALGRIND */ + +/** \page MTasker + Simple system for implementing cooperative multitasking of functions, with + support for waiting on events which can return values. + + \section copyright Copyright and License + MTasker is (c) 2002 - 2009 by bert hubert. It is licensed to you under the terms of the GPL version 2. + + \section overview High level overview + MTasker is designed to support very simple cooperative multitasking to facilitate writing + code that would ordinarily require a statemachine, for which the author does not consider + himself smart enough. + + This class does not perform any magic it only makes calls to makecontext() and swapcontext(). + Getting the details right however is complicated and MTasker does that for you. + + If preemptive multitasking or more advanced concepts such as semaphores, locks or mutexes + are required, the use of POSIX threads is advised. + + MTasker is designed to offer the performance of statemachines while maintaining simple thread semantics. It is not + a replacement for a full threading system. + + \section compatibility Compatibility + MTasker is only guaranteed to work on Linux with glibc 2.2.5 and higher. It does not work on FreeBSD and notably, + not on Red Hat 6.0. It may work on Solaris, please test. + + \section concepts Concepts + + There are two important concepts, the 'kernel' and the 'thread'. Each thread starts out as a function, + which is passed to MTasker::makeThread(), together with a possible argument. + + This function is now free to do whatever it wants, but realise that MTasker implements cooperative + multitasking, which means that the coder has the responsibility of not taking the CPU overly long. + Other threads can only get the CPU if MTasker::yield() is called or if a thread sleeps to wait for an event, + using the MTasker::waitEvent() method. + + \section kernel The Kernel + The Kernel consists of functions that do housekeeping, but also of code that the client coder + can call to report events. A minimal kernel loop looks like this: + \code + for(;;) { + MT.schedule(); + if(MT.noProcesses()) // exit if no processes are left + break; + } + \endcode + + The kernel typically starts from the main() function of your program. New threads are also + created from the kernel. This can also happen before entering the main loop. To start a thread, + the method MTasker::makeThread is provided. + + \section events Events + By default, Events are recognized by an int and their value is also an int. + This can be overridden by specifying the EventKey and EventVal template parameters. + + An event can be a keypress, but also a UDP packet, or a bit of data from a TCP socket. The + sample code provided works with keypresses, but that is just a not very useful example. + + A thread can also wait for an event only for a limited time, and receive a timeout of that + event did not occur within the specified timeframe. + + \section example A simple menu system + \code +MTasker<> MT; + +void menuHandler(void *p) +{ + int num=(int)p; + cout<<"Key handler for key "<int MTasker::waitEvent(EventKey &key, EventVal *val, unsigned int timeoutMsec, struct timeval* now) +{ + if(d_waiters.count(key)) { // there was already an exact same waiter + return -1; + } + + Waiter w; + w.context=std::make_shared(); + w.ttd.tv_sec = 0; w.ttd.tv_usec = 0; + if(timeoutMsec) { + struct timeval increment; + increment.tv_sec = timeoutMsec / 1000; + increment.tv_usec = 1000 * (timeoutMsec % 1000); + if(now) + w.ttd = increment + *now; + else { + struct timeval realnow; + gettimeofday(&realnow, 0); + w.ttd = increment + realnow; + } + } + + w.tid=d_tid; + w.key=key; + + d_waiters.insert(w); +#ifdef MTASKERTIMING + unsigned int diff=d_threads[d_tid].dt.ndiff()/1000; + d_threads[d_tid].totTime+=diff; +#endif + notifyStackSwitchToKernel(); + pdns_swapcontext(*d_waiters.find(key)->context,d_kernel); // 'A' will return here when 'key' has arrived, hands over control to kernel first + notifyStackSwitchDone(); +#ifdef MTASKERTIMING + d_threads[d_tid].dt.start(); +#endif + if(val && d_waitstatus==Answer) + *val=d_waitval; + d_tid=w.tid; + if((char*)&w < d_threads[d_tid].highestStackSeen) { + d_threads[d_tid].highestStackSeen = (char*)&w; + } + key=d_eventkey; + return d_waitstatus; +} + +//! yields control to the kernel or other threads +/** Hands over control to the kernel, allowing other processes to run, or events to arrive */ + +templatevoid MTasker::yield() +{ + d_runQueue.push(d_tid); + notifyStackSwitchToKernel(); + pdns_swapcontext(*d_threads[d_tid].context ,d_kernel); // give control to the kernel + notifyStackSwitchDone(); +} + +//! reports that an event took place for which threads may be waiting +/** From the kernel loop, sendEvent can be called to report that something occurred for which there may be waiters. + \param key Key of the event for which threads may be waiting + \param val If non-zero, pointer to the content of the event + \return Returns -1 in case of error, 0 if there were no waiters, 1 if a thread was woken up. + + WARNING: when passing val as zero, d_waitval is undefined, and hence waitEvent will return undefined! +*/ +templateint MTasker::sendEvent(const EventKey& key, const EventVal* val) +{ + typename waiters_t::iterator waiter=d_waiters.find(key); + + if(waiter == d_waiters.end()) { + // cout<<"Event sent nobody was waiting for!"<tid; // set tid + d_eventkey=waiter->key; // pass waitEvent the exact key it was woken for + auto userspace=std::move(waiter->context); + d_waiters.erase(waiter); // removes the waitpoint + notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize); + pdns_swapcontext(d_kernel,*userspace); // swaps back to the above point 'A' + notifyStackSwitchDone(); + return 1; +} + +//! launches a new thread +/** The kernel can call this to make a new thread, which starts at the function start and gets passed the val void pointer. + \param start Pointer to the function which will form the start of the thread + \param val A void pointer that can be used to pass data to the thread +*/ +templatevoid MTasker::makeThread(tfunc_t *start, void* val) +{ + auto uc=std::make_shared(); + + uc->uc_link = &d_kernel; // come back to kernel after dying + uc->uc_stack.resize (d_stacksize+1); +#ifdef PDNS_USE_VALGRIND + uc->valgrind_id = VALGRIND_STACK_REGISTER(&uc->uc_stack[0], + &uc->uc_stack[uc->uc_stack.size()-1]); +#endif /* PDNS_USE_VALGRIND */ + + auto& thread = d_threads[d_maxtid]; + auto mt = this; + thread.start = [start, val, mt]() { + char dummy; + mt->d_threads[mt->d_tid].startOfStack = mt->d_threads[mt->d_tid].highestStackSeen = &dummy; + auto const tid = mt->d_tid; + start (val); + mt->d_zombiesQueue.push(tid); + }; + pdns_makecontext (*uc, thread.start); + + thread.context = std::move(uc); + d_runQueue.push(d_maxtid++); // will run at next schedule invocation +} + + +//! needs to be called periodically so threads can run and housekeeping can be performed +/** The kernel should call this function every once in a while. It makes sense + to call this function if you: + - reported an event + - called makeThread + - want to have threads running waitEvent() to get a timeout if enough time passed + + \return Returns if there is more work scheduled and recalling schedule now would be useful + +*/ +templatebool MTasker::schedule(struct timeval* now) +{ + if(!d_runQueue.empty()) { + d_tid=d_runQueue.front(); +#ifdef MTASKERTIMING + d_threads[d_tid].dt.start(); +#endif + notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize); + pdns_swapcontext(d_kernel, *d_threads[d_tid].context); + notifyStackSwitchDone(); + + d_runQueue.pop(); + return true; + } + if(!d_zombiesQueue.empty()) { + d_threads.erase(d_zombiesQueue.front()); + d_zombiesQueue.pop(); + return true; + } + if(!d_waiters.empty()) { + struct timeval rnow; + if(!now) + gettimeofday(&rnow, 0); + else + rnow = *now; + + typedef typename waiters_t::template index::type waiters_by_ttd_index_t; + // waiters_by_ttd_index_t& ttdindex=d_waiters.template get(); + waiters_by_ttd_index_t& ttdindex=boost::multi_index::get(d_waiters); + + for(typename waiters_by_ttd_index_t::iterator i=ttdindex.begin(); i != ttdindex.end(); ) { + if(i->ttd.tv_sec && i->ttd < rnow) { + d_waitstatus=TimeOut; + d_eventkey=i->key; // pass waitEvent the exact key it was woken for + auto uc = i->context; + d_tid = i->tid; + ttdindex.erase(i++); // removes the waitpoint + + notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize); + pdns_swapcontext(d_kernel, *uc); // swaps back to the above point 'A' + notifyStackSwitchDone(); + } + else if(i->ttd.tv_sec) + break; + else + ++i; + } + } + return false; +} + +//! returns true if there are no processes +/** Call this to check if no processes are running anymore + \return true if no processes are left + */ +templatebool MTasker::noProcesses() const +{ + return d_threads.empty(); +} + +//! returns the number of processes running +/** Call this to perhaps limit activities if too many threads are running + \return number of processes running + */ +templateunsigned int MTasker::numProcesses() const +{ + return d_threads.size(); +} + +//! gives access to the list of Events threads are waiting for +/** The kernel can call this to get a list of Events threads are waiting for. This is very useful + to setup 'select' or 'poll' or 'aio' events needed to satisfy these requests. + getEvents clears the events parameter before filling it. + + \param events Vector which is to be filled with keys threads are waiting for +*/ +templatevoid MTasker::getEvents(std::vector& events) +{ + events.clear(); + for(typename waiters_t::const_iterator i=d_waiters.begin();i!=d_waiters.end();++i) { + events.push_back(i->first); + } +} + +//! Returns the current Thread ID (tid) +/** Processes can call this to get a numerical representation of their current thread ID. + This can be useful for logging purposes. +*/ +templateint MTasker::getTid() const +{ + return d_tid; +} + +//! Returns the maximum stack usage so far of this MThread +templateunsigned int MTasker::getMaxStackUsage() +{ + return d_threads[d_tid].startOfStack - d_threads[d_tid].highestStackSeen; +} + +//! Returns the maximum stack usage so far of this MThread +templateunsigned int MTasker::getUsec() +{ +#ifdef MTASKERTIMING + return d_threads[d_tid].totTime + d_threads[d_tid].dt.ndiff()/1000; +#else + return 0; +#endif +} diff --git a/mtasker.hh b/mtasker.hh new file mode 100644 index 0000000..313d18f --- /dev/null +++ b/mtasker.hh @@ -0,0 +1,137 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 MTASKER_HH +#define MTASKER_HH +#include +#include +#include +#include +#include +#include +#include +#include +#include "namespaces.hh" +#include "misc.hh" +#include "mtasker_context.hh" +#include +#include +using namespace ::boost::multi_index; + +// #define MTASKERTIMING 1 + +struct KeyTag {}; + +//! The main MTasker class +/** The main MTasker class. See the main page for more information. + \tparam EventKey Type of the key with which events are to be identified. Defaults to int. + \tparam EventVal Type of the content or value of an event. Defaults to int. Cannot be set to void. + \note The EventKey needs to have an operator< defined because it is used as the key of an associative array +*/ + +template class MTasker +{ +private: + pdns_ucontext_t d_kernel; + std::queue d_runQueue; + std::queue d_zombiesQueue; + + struct ThreadInfo + { + std::shared_ptr context; + boost::function start; + char* startOfStack; + char* highestStackSeen; +#ifdef MTASKERTIMING + CPUTime dt; + unsigned int totTime; +#endif + }; + + typedef std::map mthreads_t; + mthreads_t d_threads; + int d_tid; + int d_maxtid; + size_t d_stacksize; + + EventVal d_waitval; + enum waitstatusenum {Error=-1,TimeOut=0,Answer} d_waitstatus; + +public: + struct Waiter + { + EventKey key; + std::shared_ptr context; + struct timeval ttd; + int tid; + }; + + typedef multi_index_container< + Waiter, + indexed_by < + ordered_unique >, + ordered_non_unique, member > + > + > waiters_t; + + waiters_t d_waiters; + + void initMainStackBounds() + { +#ifdef HAVE_FIBER_SANITIZER + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_getattr_np(pthread_self(), &attr); + pthread_attr_getstack(&attr, &t_mainStack, &t_mainStackSize); + pthread_attr_destroy(&attr); +#endif /* HAVE_FIBER_SANITIZER */ + } + + //! Constructor + /** Constructor with a small default stacksize. If any of your threads exceeds this stack, your application will crash. + This limit applies solely to the stack, the heap is not limited in any way. If threads need to allocate a lot of data, + the use of new/delete is suggested. + */ + MTasker(size_t stacksize=16*8192) : d_tid(0), d_maxtid(0), d_stacksize(stacksize), d_waitstatus(Error) + { + initMainStackBounds(); + } + + typedef void tfunc_t(void *); //!< type of the pointer that starts a thread + int waitEvent(EventKey &key, EventVal *val=0, unsigned int timeoutMsec=0, struct timeval* now=0); + void yield(); + int sendEvent(const EventKey& key, const EventVal* val=0); + void getEvents(std::vector& events); + void makeThread(tfunc_t *start, void* val); + bool schedule(struct timeval* now=0); + bool noProcesses() const; + unsigned int numProcesses() const; + int getTid() const; + unsigned int getMaxStackUsage(); + unsigned int getUsec(); + +private: + EventKey d_eventkey; // for waitEvent, contains exact key it was awoken for +}; +#include "mtasker.cc" + +#endif // MTASKER_HH + diff --git a/mtasker_context.cc b/mtasker_context.cc new file mode 100644 index 0000000..615af05 --- /dev/null +++ b/mtasker_context.cc @@ -0,0 +1,30 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(HAVE_BOOST_CONTEXT) +#include "mtasker_fcontext.cc" +#else +#include "mtasker_ucontext.cc" +#endif diff --git a/mtasker_context.hh b/mtasker_context.hh new file mode 100644 index 0000000..2e35fed --- /dev/null +++ b/mtasker_context.hh @@ -0,0 +1,90 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 MTASKER_CONTEXT_HH +#define MTASKER_CONTEXT_HH + +#include "lazy_allocator.hh" +#include +#include +#include + +struct pdns_ucontext_t { + pdns_ucontext_t (); + pdns_ucontext_t (pdns_ucontext_t const&) = delete; + pdns_ucontext_t& operator= (pdns_ucontext_t const&) = delete; + ~pdns_ucontext_t (); + + void* uc_mcontext; + pdns_ucontext_t* uc_link; + std::vector> uc_stack; + std::exception_ptr exception; +#ifdef PDNS_USE_VALGRIND + int valgrind_id; +#endif /* PDNS_USE_VALGRIND */ +}; + +void +pdns_swapcontext +(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx); + +void +pdns_makecontext +(pdns_ucontext_t& ctx, boost::function& start); + +#ifdef HAVE_FIBER_SANITIZER +#include +#endif /* HAVE_FIBER_SANITIZER */ + +#ifdef HAVE_FIBER_SANITIZER +extern __thread void* t_mainStack; +extern __thread size_t t_mainStackSize; +#endif /* HAVE_FIBER_SANITIZER */ + +static inline void notifyStackSwitch(void* startOfStack, size_t stackSize) +{ +#ifdef HAVE_FIBER_SANITIZER + __sanitizer_start_switch_fiber(nullptr, startOfStack, stackSize); +#endif /* HAVE_FIBER_SANITIZER */ +} + +static inline void notifyStackSwitchToKernel() +{ +#ifdef HAVE_FIBER_SANITIZER + notifyStackSwitch(t_mainStack, t_mainStackSize); +#endif /* HAVE_FIBER_SANITIZER */ +} + +static inline void notifyStackSwitchDone() +{ +#ifdef HAVE_FIBER_SANITIZER +#ifdef HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR + __sanitizer_finish_switch_fiber(nullptr); +#else /* HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR */ +#ifdef HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS + __sanitizer_finish_switch_fiber(nullptr, nullptr, nullptr); +#endif /* HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS */ +#endif /* HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR */ +#endif /* HAVE_FIBER_SANITIZER */ +} + + +#endif // MTASKER_CONTEXT_HH diff --git a/mtasker_fcontext.cc b/mtasker_fcontext.cc new file mode 100644 index 0000000..72627a7 --- /dev/null +++ b/mtasker_fcontext.cc @@ -0,0 +1,238 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "mtasker_context.hh" +#include +#include +#include +#include +#if BOOST_VERSION < 106100 +#include +using boost::context::make_fcontext; +#else +#include +using boost::context::detail::make_fcontext; +#endif /* BOOST_VERSION < 106100 */ + +#ifdef PDNS_USE_VALGRIND +#include +#endif /* PDNS_USE_VALGRIND */ + +#ifdef HAVE_FIBER_SANITIZER +__thread void* t_mainStack{nullptr}; +__thread size_t t_mainStackSize{0}; +#endif /* HAVE_FIBER_SANITIZER */ + +#if BOOST_VERSION < 105600 +/* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(), + * now require a reinterpret_cast rather than a static_cast, since we're + * casting from pdns_context_t->uc_mcontext, which is void**, to + * some_opaque_struct**. In later versions fcontext_t is already void*. So if + * you remove this, then fix the ugly. + */ +using fcontext_t = boost::context::fcontext_t*; + +/* Emulate the >= 1.56 API for Boost 1.52 through 1.55 */ +static inline intptr_t +jump_fcontext (fcontext_t* const ofc, fcontext_t const nfc, + intptr_t const arg) { + /* If the fcontext_t is preallocated then use it, otherwise allocate one + * on the stack ('self') and stash a pointer away in *ofc so the returning + * MThread can access it. This is safe because we're suspended, so the + * context object always outlives the jump. + */ + if (*ofc) { + return boost::context::jump_fcontext (*ofc, nfc, arg); + } else { + boost::context::fcontext_t self; + *ofc = &self; + auto ret = boost::context::jump_fcontext (*ofc, nfc, arg); + *ofc = nullptr; + return ret; + } +} +#else + +#if BOOST_VERSION < 106100 +using boost::context::fcontext_t; +using boost::context::jump_fcontext; +#else +using boost::context::detail::fcontext_t; +using boost::context::detail::jump_fcontext; +using boost::context::detail::transfer_t; +#endif /* BOOST_VERSION < 106100 */ + +static_assert (std::is_pointer::value, + "Boost Context has changed the fcontext_t type again :-("); +#endif + +/* Boost context only provides a means of passing a single argument across a + * jump. args_t simply provides a way to pass more by reference. + */ +struct args_t { +#if BOOST_VERSION < 106100 + fcontext_t prev_ctx = nullptr; +#endif + pdns_ucontext_t* self = nullptr; + boost::function* work = nullptr; +}; + +extern "C" { +static +void +#if BOOST_VERSION < 106100 +threadWrapper (intptr_t const xargs) { +#else +threadWrapper (transfer_t const t) { +#endif + /* Access the args passed from pdns_makecontext, and copy them directly from + * the calling stack on to ours (we're now using the MThreads stack). + * This saves heap allocating an args object, at the cost of an extra + * context switch to fashion this constructor-like init phase. The work + * function object is still only moved after we're (re)started, so may + * still be set or changed after a call to pdns_makecontext. This matches + * the behaviour of the System V implementation, which can inherently only + * be passed ints and pointers. + */ + notifyStackSwitchDone(); +#if BOOST_VERSION < 106100 + auto args = reinterpret_cast(xargs); +#else + auto args = reinterpret_cast(t.data); +#endif + auto ctx = args->self; + auto work = args->work; + /* we switch back to pdns_makecontext() */ + notifyStackSwitchToKernel(); +#if BOOST_VERSION < 106100 + jump_fcontext (reinterpret_cast(&ctx->uc_mcontext), + static_cast(args->prev_ctx), 0); +#else + transfer_t res = jump_fcontext (t.fctx, 0); + /* we got switched back from pdns_swapcontext() */ + if (res.data) { + /* if res.data is not a nullptr, it holds a pointer to the context + we just switched from, and we need to fill it to be able to + switch back to it later. */ + fcontext_t* ptr = static_cast(res.data); + *ptr = res.fctx; + } +#endif + notifyStackSwitchDone(); + args = nullptr; + + try { + auto start = std::move (*work); + start(); + } catch (...) { + ctx->exception = std::current_exception(); + } + + notifyStackSwitchToKernel(); + /* Emulate the System V uc_link feature. */ + auto const next_ctx = ctx->uc_link->uc_mcontext; +#if BOOST_VERSION < 106100 + jump_fcontext (reinterpret_cast(&ctx->uc_mcontext), + static_cast(next_ctx), + reinterpret_cast(ctx)); +#else + jump_fcontext (static_cast(next_ctx), 0); +#endif + +#ifdef NDEBUG + __builtin_unreachable(); +#endif +} +} + +pdns_ucontext_t::pdns_ucontext_t +(): uc_mcontext(nullptr), uc_link(nullptr) { +#ifdef PDNS_USE_VALGRIND + valgrind_id = 0; +#endif /* PDNS_USE_VALGRIND */ +} + +pdns_ucontext_t::~pdns_ucontext_t +() { + /* There's nothing to delete here since fcontext doesn't require anything + * to be heap allocated. + */ +#ifdef PDNS_USE_VALGRIND + if (valgrind_id != 0) { + VALGRIND_STACK_DEREGISTER(valgrind_id); + } +#endif /* PDNS_USE_VALGRIND */ +} + +void +pdns_swapcontext +(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx) { + /* we either switch back to threadwrapper() if it's the first time, + or we switch back to pdns_swapcontext(), + in both case we will be returning from a call to jump_fcontext(). */ +#if BOOST_VERSION < 106100 + intptr_t ptr = jump_fcontext(reinterpret_cast(&octx.uc_mcontext), + static_cast(ctx.uc_mcontext), 0); + + auto origctx = reinterpret_cast(ptr); + if(origctx && origctx->exception) + std::rethrow_exception (origctx->exception); +#else + transfer_t res = jump_fcontext (static_cast(ctx.uc_mcontext), &octx.uc_mcontext); + if (res.data) { + /* if res.data is not a nullptr, it holds a pointer to the context + we just switched from, and we need to fill it to be able to + switch back to it later. */ + fcontext_t* ptr = static_cast(res.data); + *ptr = res.fctx; + } + if (ctx.exception) { + std::rethrow_exception (ctx.exception); + } +#endif +} + +void +pdns_makecontext +(pdns_ucontext_t& ctx, boost::function& start) { + assert (ctx.uc_link); + assert (ctx.uc_stack.size() >= 8192); + assert (!ctx.uc_mcontext); + ctx.uc_mcontext = make_fcontext (&ctx.uc_stack[ctx.uc_stack.size()-1], + ctx.uc_stack.size()-1, &threadWrapper); + args_t args; + args.self = &ctx; + args.work = &start; + /* jumping to threadwrapper */ + notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size()-1], ctx.uc_stack.size()-1); +#if BOOST_VERSION < 106100 + jump_fcontext (reinterpret_cast(&args.prev_ctx), + static_cast(ctx.uc_mcontext), + reinterpret_cast(&args)); +#else + transfer_t res = jump_fcontext (static_cast(ctx.uc_mcontext), + &args); + /* back from threadwrapper, updating the context */ + ctx.uc_mcontext = res.fctx; +#endif + notifyStackSwitchDone(); + +} diff --git a/mtasker_ucontext.cc b/mtasker_ucontext.cc new file mode 100644 index 0000000..d7663e3 --- /dev/null +++ b/mtasker_ucontext.cc @@ -0,0 +1,145 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "mtasker_context.hh" +#include +#include +#include +#include +#include +#include + +#ifdef PDNS_USE_VALGRIND +#include +#endif /* PDNS_USE_VALGRIND */ + +#ifdef HAVE_FIBER_SANITIZER +__thread void* t_mainStack{nullptr}; +__thread size_t t_mainStackSize{0}; +#endif /* HAVE_FIBER_SANITIZER */ + +template static __attribute__((noinline, cold, noreturn)) +void +throw_errno (Message&& msg) { + throw std::system_error + (errno, std::system_category(), std::forward(msg)); +} + +static inline +std::pair +splitPointer (void* const ptr) noexcept { + static_assert (sizeof(int) == 4, "splitPointer() requires an 4 byte 'int'"); +// In theory, we need this assertion. In practice, it prevents compilation +// on EL6 i386. Without the assertion, everything works. +// If you ever run into trouble with this code, please heed the warnings at +// http://man7.org/linux/man-pages/man3/makecontext.3.html#NOTES +// static_assert (sizeof(uintptr_t) == 8, +// "splitPointer() requires an 8 byte 'uintptr_t'"); + std::pair words; + auto rep = reinterpret_cast(ptr); + uint32_t const hw = rep >> 32; + auto const lw = static_cast(rep); + std::memcpy (&words.first, &hw, 4); + std::memcpy (&words.second, &lw, 4); + return words; +} + +template static inline +T* +joinPtr (int const first, int const second) noexcept { + static_assert (sizeof(int) == 4, "joinPtr() requires an 4 byte 'int'"); +// See above. +// static_assert (sizeof(uintptr_t) == 8, +// "joinPtr() requires an 8 byte 'uintptr_t'"); + uint32_t hw; + uint32_t lw; + std::memcpy (&hw, &first, 4); + std::memcpy (&lw, &second, 4); + return reinterpret_cast((static_cast(hw) << 32) | lw); +} + +extern "C" { +static +void +threadWrapper (int const ctx0, int const ctx1, int const fun0, int const fun1) { + notifyStackSwitchDone(); + auto ctx = joinPtr(ctx0, ctx1); + try { + auto start = std::move(*joinPtr>(fun0, fun1)); + start(); + } catch (...) { + ctx->exception = std::current_exception(); + } + notifyStackSwitchToKernel(); +} +} // extern "C" + +pdns_ucontext_t::pdns_ucontext_t() { + uc_mcontext = new ::ucontext_t(); + uc_link = nullptr; +#ifdef PDNS_USE_VALGRIND + valgrind_id = 0; +#endif /* PDNS_USE_VALGRIND */ +} + +pdns_ucontext_t::~pdns_ucontext_t() { + delete static_cast(uc_mcontext); +#ifdef PDNS_USE_VALGRIND + if (valgrind_id != 0) { + VALGRIND_STACK_DEREGISTER(valgrind_id); + } +#endif /* PDNS_USE_VALGRIND */ +} + +void +pdns_swapcontext +(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx) { + if (::swapcontext (static_cast(octx.uc_mcontext), + static_cast(ctx.uc_mcontext))) { + throw_errno ("swapcontext() failed"); + } + if (ctx.exception) { + std::rethrow_exception (ctx.exception); + } +} + +void +pdns_makecontext +(pdns_ucontext_t& ctx, boost::function& start) { + assert (ctx.uc_link); + assert (ctx.uc_stack.size()); + + auto const mcp = static_cast(ctx.uc_mcontext); + auto const next = static_cast(ctx.uc_link->uc_mcontext); + if (::getcontext (mcp)) { + throw_errno ("getcontext() failed"); + } + mcp->uc_link = next; + mcp->uc_stack.ss_sp = ctx.uc_stack.data(); + mcp->uc_stack.ss_size = ctx.uc_stack.size(); + mcp->uc_stack.ss_flags = 0; + + auto ctxarg = splitPointer (&ctx); + auto funarg = splitPointer (&start); + return ::makecontext (mcp, reinterpret_cast(&threadWrapper), + 4, ctxarg.first, ctxarg.second, + funarg.first, funarg.second); +} diff --git a/namespaces.hh b/namespaces.hh new file mode 100644 index 0000000..2d5cd8c --- /dev/null +++ b/namespaces.hh @@ -0,0 +1,81 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_NAMESPACES_HH +#define PDNS_NAMESPACES_HH +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::map; +using std::pair; +using std::make_pair; +using std::runtime_error; +using std::ostringstream; +using std::set; +using std::deque; +using std::cerr; +using std::cout; +using std::clog; +using std::endl; +using std::ifstream; +using std::ofstream; +using std::ostream; +using std::min; // these are a bit scary, everybody uses 'min' +using std::max; +using std::string; + +using boost::tie; +using std::shared_ptr; +using std::unique_ptr; +using boost::shared_array; +using boost::scoped_array; +using boost::tuple; +using boost::format; +using boost::make_tuple; +using boost::optional; +using boost::any_cast; +using boost::any; +using boost::function; +using boost::trim; +using boost::trim_copy; +using boost::trim_left; +using boost::trim_right; +using boost::is_any_of; +using boost::trim_right_copy_if; +using boost::equals; +using boost::ends_with; +using boost::iends_with; +#endif diff --git a/negcache.cc b/negcache.cc new file mode 100644 index 0000000..2853192 --- /dev/null +++ b/negcache.cc @@ -0,0 +1,198 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include + +#include "negcache.hh" +#include "misc.hh" +#include "cachecleaner.hh" + +/*! + * Set ne to the NegCacheEntry for the last label in qname and return true if there + * was one. + * + * \param qname The name to look up (only the last label is used) + * \param now A timeval with the current time, to check if an entry is expired + * \param ne A NegCacheEntry that is filled when there is a cache entry + * \return true if ne was filled out, false otherwise + */ +bool NegCache::getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& ne) { + // Never deny the root. + if (qname.isRoot()) + return false; + + // An 'ENT' QType entry, used as "whole name" in the neg-cache context. + static const QType qtnull(0); + DNSName lastLabel = qname.getLastLabel(); + negcache_t::const_iterator ni = d_negcache.find(tie(lastLabel, qtnull)); + + while (ni != d_negcache.end() && + ni->d_name == lastLabel && + ni->d_auth.isRoot() && + ni->d_qtype == qtnull) { + // We have something + if ((uint32_t)now.tv_sec < ni->d_ttd) { + ne = *ni; + moveCacheItemToBack(d_negcache, ni); + return true; + } + moveCacheItemToFront(d_negcache, ni); + ni++; + } + return false; +} + +/*! + * Set ne to the NegCacheEntry for the qname|qtype tuple and return true + * + * \param qname The name to look up + * \param qtype The qtype to look up + * \param now A timeval with the current time, to check if an entry is expired + * \param ne A NegCacheEntry that is filled when there is a cache entry + * \return true if ne was filled out, false otherwise + */ +bool NegCache::get(const DNSName& qname, const QType& qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch) { + auto range = d_negcache.equal_range(tie(qname)); + negcache_t::iterator ni = range.first; + + while (ni != range.second) { + // We have an entry + if ((!typeMustMatch && ni->d_qtype.getCode() == 0) || ni->d_qtype == qtype) { + // We match the QType or the whole name is denied + if((uint32_t) now.tv_sec < ni->d_ttd) { + // Not expired + ne = *ni; + moveCacheItemToBack(d_negcache, ni); + return true; + } + // expired + moveCacheItemToFront(d_negcache, ni); + } + ni++; + } + return false; +} + +/*! + * Places ne into the negative cache, possibly overriding an existing entry. + * + * \param ne The NegCacheEntry to add to the cache + */ +void NegCache::add(const NegCacheEntry& ne) { + replacing_insert(d_negcache, ne); +} + +/*! + * Update the validation state of an existing entry with the provided state. + * + * \param qname The name of the entry to replace + * \param qtype The type of the entry to replace + * \param newState The new validation state + */ +void NegCache::updateValidationStatus(const DNSName& qname, const QType& qtype, const vState newState) { + auto range = d_negcache.equal_range(tie(qname, qtype)); + + if (range.first != range.second) { + range.first->d_validationState = newState; + } +} + +/*! + * Returns the amount of entries in the cache + * + * \param qname The name of the entries to be counted + */ +uint64_t NegCache::count(const DNSName& qname) const { + return d_negcache.count(tie(qname)); +} + +/*! + * Returns the amount of entries in the cache for qname+qtype + * + * \param qname The name of the entries to be counted + * \param qtype The type of the entries to be counted + */ +uint64_t NegCache::count(const DNSName& qname, const QType qtype) const { + return d_negcache.count(tie(qname, qtype)); +} + +/*! + * Remove all entries for name from the cache. If subtree is true, wipe all names + * underneath it. + * + * \param name The DNSName of the entries to wipe + * \param subtree Should all entries under name be removed? + */ +uint64_t NegCache::wipe(const DNSName& name, bool subtree) { + uint64_t ret(0); + if (subtree) { + for (auto i = d_negcache.lower_bound(tie(name)); i != d_negcache.end();) { + if(!i->d_name.isPartOf(name)) + break; + i = d_negcache.erase(i); + ret++; + } + return ret; + } + + ret = count(name); + auto range = d_negcache.equal_range(tie(name)); + d_negcache.erase(range.first, range.second); + return ret; +} + +/*! + * Clear the negative cache + */ +void NegCache::clear() { + d_negcache.clear(); +} + +/*! + * Perform some cleanup in the cache, removing stale entries + * + * \param maxEntries The maximum number of entries that may exist in the cache. + */ +void NegCache::prune(unsigned int maxEntries) { + pruneCollection(*this, d_negcache, maxEntries, 200); +} + +/*! + * Writes the whole negative cache to fp + * + * \param fp A pointer to an open FILE object + */ +uint64_t NegCache::dumpToFile(FILE* fp) { + uint64_t ret(0); + time_t now = time(0); + negcache_sequence_t& sidx = d_negcache.get<1>(); + for(const NegCacheEntry& ne : sidx) { + ret++; + fprintf(fp, "%s %d IN %s VIA %s ; (%s)\n", ne.d_name.toString().c_str(), (unsigned int) (ne.d_ttd - now), ne.d_qtype.getName().c_str(), ne.d_auth.toString().c_str(), vStates[ne.d_validationState]); + for (const auto& rec : ne.DNSSECRecords.records) { + fprintf(fp, "%s %" PRId64 " IN %s %s ; (%s)\n", ne.d_name.toString().c_str(), static_cast(ne.d_ttd - now), DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.d_content->getZoneRepresentation().c_str(), vStates[ne.d_validationState]); + } + for (const auto& sig : ne.DNSSECRecords.signatures) { + fprintf(fp, "%s %" PRId64 " IN RRSIG %s ;\n", ne.d_name.toString().c_str(), static_cast(ne.d_ttd - now), sig.d_content->getZoneRepresentation().c_str()); + } + } + return ret; +} diff --git a/negcache.hh b/negcache.hh new file mode 100644 index 0000000..d1a742d --- /dev/null +++ b/negcache.hh @@ -0,0 +1,102 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +#include +#include "dnsparser.hh" +#include "dnsname.hh" +#include "dns.hh" +#include "validate.hh" + +using namespace ::boost::multi_index; + +/* FIXME should become part of the normal cache (I think) and shoudl become more like + * struct { + * vector records; + * vector signatures; + * } recsig_t; + * + * typedef vector recordsAndSignatures; + */ +typedef struct { + vector records; + vector signatures; +} recordsAndSignatures; + +class NegCache : public boost::noncopyable { + public: + struct NegCacheEntry { + DNSName d_name; // The denied name + QType d_qtype; // The denied type + DNSName d_auth; // The denying name (aka auth) + uint32_t d_ttd; // Timestamp when this entry should die + recordsAndSignatures authoritySOA; // The upstream SOA record and RRSIGs + recordsAndSignatures DNSSECRecords; // The upstream NSEC(3) and RRSIGs + mutable vState d_validationState{Indeterminate}; + uint32_t getTTD() const { + return d_ttd; + }; + }; + + void add(const NegCacheEntry& ne); + void updateValidationStatus(const DNSName& qname, const QType& qtype, const vState newState); + bool get(const DNSName& qname, const QType& qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch=false); + bool getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& ne); + uint64_t count(const DNSName& qname) const; + uint64_t count(const DNSName& qname, const QType qtype) const; + void prune(unsigned int maxEntries); + void clear(); + uint64_t dumpToFile(FILE* fd); + uint64_t wipe(const DNSName& name, bool subtree = false); + + uint64_t size() { + return d_negcache.size(); + }; + + void preRemoval(const NegCacheEntry& entry) + { + } + + private: + typedef boost::multi_index_container < + NegCacheEntry, + indexed_by < + ordered_unique < + composite_key < + NegCacheEntry, + member, + member + >, + composite_key_compare < + CanonDNSNameCompare, std::less + > + >, + sequenced<> + > + > negcache_t; + + // Required for the cachecleaner + typedef negcache_t::nth_index<1>::type negcache_sequence_t; + + // Stores the negative cache entries + negcache_t d_negcache; +}; diff --git a/nsecrecords.cc b/nsecrecords.cc new file mode 100644 index 0000000..ab6a468 --- /dev/null +++ b/nsecrecords.cc @@ -0,0 +1,321 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "dnsrecords.hh" + +void NSECRecordContent::report(void) +{ + regist(1, 47, &make, &make, "NSEC"); +} + +DNSRecordContent* NSECRecordContent::make(const string& content) +{ + return new NSECRecordContent(content); +} + +NSECRecordContent::NSECRecordContent(const string& content, const string& zone) +{ + RecordTextReader rtr(content, zone); + rtr.xfrName(d_next); + + while(!rtr.eof()) { + uint16_t type; + rtr.xfrType(type); + d_set.insert(type); + } +} + +void NSECRecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfrName(d_next); + + uint8_t res[34]; + set::const_iterator i; + int oldWindow = -1; + int window = 0; + int len = 0; + string tmp; + + for(i=d_set.begin(); i != d_set.end(); ++i){ + uint16_t bit = (*i)%256; + window = static_cast((*i) / 256); + + if (window != oldWindow) { + if (oldWindow > -1) { + res[0] = static_cast(oldWindow); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); + } + memset(res, 0, 34); + oldWindow = window; + } + res[2+bit/8] |= 1 << (7-(bit%8)); + len=1+bit/8; + } + + res[0] = static_cast(window); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); +} + +NSECRecordContent::DNSRecordContent* NSECRecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + NSECRecordContent* ret=new NSECRecordContent(); + pr.xfrName(ret->d_next); + string bitmap; + pr.xfrBlob(bitmap); + + // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left + if(bitmap.empty()) + return ret; + + if(bitmap.size() < 2) + throw MOADNSException("NSEC record with impossibly small bitmap"); + + for(unsigned int n = 0; n+1 < bitmap.size();) { + unsigned int window=static_cast(bitmap[n++]); + unsigned int blen=static_cast(bitmap[n++]); + + // end if zero padding and ensure packet length + if(window == 0 && blen == 0) break; + if(n + blen > bitmap.size()) + throw MOADNSException("NSEC record with bitmap length > packet length"); + + for(unsigned int k=0; k < blen; k++) { + uint8_t val=bitmap[n++]; + for(int bit = 0; bit < 8 ; ++bit , val>>=1) + if(val & 1) { + ret->d_set.insert((7-bit) + 8*(k) + 256*window); + } + } + } + return ret; +} + +string NSECRecordContent::getZoneRepresentation(bool noDot) const +{ + string ret; + RecordTextWriter rtw(ret); + rtw.xfrName(d_next); + + for(set::const_iterator i=d_set.begin(); i!=d_set.end(); ++i) { + ret+=" "; + ret+=NumberToType(*i); + } + + return ret; +} + +////// begin of NSEC3 + +void NSEC3RecordContent::report(void) +{ + regist(1, 50, &make, &make, "NSEC3"); +} + +DNSRecordContent* NSEC3RecordContent::make(const string& content) +{ + return new NSEC3RecordContent(content); +} + +NSEC3RecordContent::NSEC3RecordContent(const string& content, const string& zone) +{ + RecordTextReader rtr(content, zone); + rtr.xfr8BitInt(d_algorithm); + rtr.xfr8BitInt(d_flags); + rtr.xfr16BitInt(d_iterations); + + rtr.xfrHexBlob(d_salt); + rtr.xfrBase32HexBlob(d_nexthash); + + while(!rtr.eof()) { + uint16_t type; + rtr.xfrType(type); + d_set.insert(type); + } +} + +void NSEC3RecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfr8BitInt(d_algorithm); + pw.xfr8BitInt(d_flags); + pw.xfr16BitInt(d_iterations); + pw.xfr8BitInt(d_salt.length()); + pw.xfrBlob(d_salt); + + pw.xfr8BitInt(d_nexthash.length()); + pw.xfrBlob(d_nexthash); + + uint8_t res[34]; + set::const_iterator i; + int oldWindow = -1; + int window = 0; + int len = 0; + string tmp; + + for(i=d_set.begin(); i != d_set.end(); ++i){ + uint16_t bit = (*i)%256; + window = static_cast((*i) / 256); + + if (window != oldWindow) { + if (oldWindow > -1) { + res[0] = static_cast(oldWindow); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); + } + memset(res, 0, 34); + oldWindow = window; + } + res[2+bit/8] |= 1 << (7-(bit%8)); + len=1+bit/8; + } + + res[0] = static_cast(window); + res[1] = static_cast(len); + + if (len) { + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); + } +} + +NSEC3RecordContent::DNSRecordContent* NSEC3RecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + NSEC3RecordContent* ret=new NSEC3RecordContent(); + pr.xfr8BitInt(ret->d_algorithm); + pr.xfr8BitInt(ret->d_flags); + pr.xfr16BitInt(ret->d_iterations); + uint8_t len; + pr.xfr8BitInt(len); + pr.xfrBlob(ret->d_salt, len); + + pr.xfr8BitInt(len); + pr.xfrBlob(ret->d_nexthash, len); + + string bitmap; + pr.xfrBlob(bitmap); + + // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left + + if(bitmap.empty()) + return ret; + + if(bitmap.size() < 2) + throw MOADNSException("NSEC3 record with impossibly small bitmap"); + + for(unsigned int n = 0; n+1 < bitmap.size();) { + unsigned int window=static_cast(bitmap[n++]); + unsigned int innerlen=static_cast(bitmap[n++]); + + // end if zero padding and ensure packet length + if(window == 0&&innerlen == 0) break; + if(n+innerlen>bitmap.size()) + throw MOADNSException("NSEC record with bitmap length > packet length"); + + for(unsigned int k=0; k < innerlen; k++) { + uint8_t val=bitmap[n++]; + for(int bit = 0; bit < 8 ; ++bit , val>>=1) + if(val & 1) { + ret->d_set.insert((7-bit) + 8*(k) + 256*window); + } + } + } + return ret; +} + +string NSEC3RecordContent::getZoneRepresentation(bool noDot) const +{ + string ret; + RecordTextWriter rtw(ret); + rtw.xfr8BitInt(d_algorithm); + rtw.xfr8BitInt(d_flags); + rtw.xfr16BitInt(d_iterations); + + rtw.xfrHexBlob(d_salt); + rtw.xfrBase32HexBlob(d_nexthash); + for(set::const_iterator i=d_set.begin(); i!=d_set.end(); ++i) { + ret+=" "; + ret+=NumberToType(*i); + } + + return ret; +} + + +void NSEC3PARAMRecordContent::report(void) +{ + regist(1, 51, &make, &make, "NSEC3PARAM"); + regist(254, 51, &make, &make, "NSEC3PARAM"); +} + +DNSRecordContent* NSEC3PARAMRecordContent::make(const string& content) +{ + return new NSEC3PARAMRecordContent(content); +} + +NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const string& zone) +{ + RecordTextReader rtr(content, zone); + rtr.xfr8BitInt(d_algorithm); + rtr.xfr8BitInt(d_flags); + rtr.xfr16BitInt(d_iterations); + rtr.xfrHexBlob(d_salt); +} + +void NSEC3PARAMRecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfr8BitInt(d_algorithm); + pw.xfr8BitInt(d_flags); + pw.xfr16BitInt(d_iterations); + pw.xfr8BitInt(d_salt.length()); + // cerr<<"salt: '"<d_algorithm); + pr.xfr8BitInt(ret->d_flags); + pr.xfr16BitInt(ret->d_iterations); + uint8_t len; + pr.xfr8BitInt(len); + pr.xfrHexBlob(ret->d_salt, len); + return ret; +} + +string NSEC3PARAMRecordContent::getZoneRepresentation(bool noDot) const +{ + string ret; + RecordTextWriter rtw(ret); + rtw.xfr8BitInt(d_algorithm); + rtw.xfr8BitInt(d_flags); + rtw.xfr16BitInt(d_iterations); + rtw.xfrHexBlob(d_salt); + return ret; +} + diff --git a/opensslsigners.cc b/opensslsigners.cc new file mode 100644 index 0000000..8e3bb54 --- /dev/null +++ b/opensslsigners.cc @@ -0,0 +1,906 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_LIBCRYPTO_ECDSA +#include +#endif +#include +#include +#include +#include +#include "opensslsigners.hh" +#include "dnssecinfra.hh" + +#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || defined LIBRESSL_VERSION_NUMBER) +/* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */ +static pthread_mutex_t *openssllocks; + +extern "C" { +void openssl_pthreads_locking_callback(int mode, int type, const char *file, int line) +{ + if (mode & CRYPTO_LOCK) { + pthread_mutex_lock(&(openssllocks[type])); + + }else { + pthread_mutex_unlock(&(openssllocks[type])); + } +} + +unsigned long openssl_pthreads_id_callback() +{ + return (unsigned long)pthread_self(); +} +} + +void openssl_thread_setup() +{ + openssllocks = (pthread_mutex_t*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); + + for (int i = 0; i < CRYPTO_num_locks(); i++) + pthread_mutex_init(&(openssllocks[i]), NULL); + + CRYPTO_set_id_callback(openssl_pthreads_id_callback); + CRYPTO_set_locking_callback(openssl_pthreads_locking_callback); +} + +void openssl_thread_cleanup() +{ + CRYPTO_set_locking_callback(NULL); + + for (int i=0; in; + *e = rsakey->e; + *d = rsakey->d; +} + +static inline int RSA_set0_key(RSA* rsakey, BIGNUM* n, BIGNUM* e, BIGNUM* d) { + if (n) { + BN_clear_free(rsakey->n); + rsakey->n = n; + } + if (e) { + BN_clear_free(rsakey->e); + rsakey->e = e; + } + if (d) { + BN_clear_free(rsakey->d); + rsakey->d = d; + } + return 1; +} + +static inline void RSA_get0_factors(const RSA* rsakey, const BIGNUM** p, const BIGNUM** q) { + *p = rsakey->p; + *q = rsakey->q; +} + +static inline int RSA_set0_factors(RSA* rsakey, BIGNUM* p, BIGNUM* q) { + BN_clear_free(rsakey->p); + rsakey->p = p; + BN_clear_free(rsakey->q); + rsakey->q = q; + return 1; +} + +static inline void RSA_get0_crt_params(const RSA* rsakey, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp) { + *dmp1 = rsakey->dmp1; + *dmq1 = rsakey->dmq1; + *iqmp = rsakey->iqmp; +} + +static inline int RSA_set0_crt_params(RSA* rsakey, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp) { + BN_clear_free(rsakey->dmp1); + rsakey->dmp1 = dmp1; + BN_clear_free(rsakey->dmq1); + rsakey->dmq1 = dmq1; + BN_clear_free(rsakey->iqmp); + rsakey->iqmp = iqmp; + return 1; +} + +#ifdef HAVE_LIBCRYPTO_ECDSA +static inline void ECDSA_SIG_get0(const ECDSA_SIG* signature, const BIGNUM** pr, const BIGNUM** ps) { + *pr = signature->r; + *ps = signature->s; +} + +static inline int ECDSA_SIG_set0(ECDSA_SIG* signature, BIGNUM* pr, BIGNUM* ps) { + BN_clear_free(signature->r); + BN_clear_free(signature->s); + signature->r = pr; + signature->s = ps; + return 1; +} +#endif /* HAVE_LIBCRYPTO_ECDSA */ + +#else +void openssl_thread_setup() {} +void openssl_thread_cleanup() {} +#endif + + +/* seeding PRNG */ + +void openssl_seed() +{ + std::string entropy; + entropy.reserve(1024); + + unsigned int r; + for(int i=0; i<1024; i+=4) { + r=dns_random(0xffffffff); + entropy.append((const char*)&r, 4); + } + + RAND_seed((const unsigned char*)entropy.c_str(), 1024); +} + + +class OpenSSLRSADNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo) + { + int ret = RAND_status(); + if (ret != 1) { + throw runtime_error(getName()+" insufficient entropy"); + } + } + + ~OpenSSLRSADNSCryptoKeyEngine() + { + if (d_key) + RSA_free(d_key); + } + + string getName() const override { return "OpenSSL RSA"; } + int getBits() const override { return RSA_size(d_key) << 3; } + + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string hash(const std::string& hash) const override; + std::string sign(const std::string& hash) const override; + bool verify(const std::string& hash, const std::string& signature) const override; + std::string getPubKeyHash() const override; + std::string getPublicKeyString() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; + bool checkKey() const override; + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + static int hashSizeToKind(size_t hashSize); + + RSA* d_key{NULL}; +}; + + +void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits) +{ + BIGNUM *e = BN_new(); + if (!e) { + throw runtime_error(getName()+" key generation failed, unable to allocate e"); + } + + /* RSA_F4 is a public exponent value of 65537 */ + int res = BN_set_word(e, RSA_F4); + + if (res == 0) { + BN_free(e); + throw runtime_error(getName()+" key generation failed while setting e"); + } + + RSA* key = RSA_new(); + if (key == NULL) { + BN_free(e); + throw runtime_error(getName()+" allocation of key structure failed"); + } + + res = RSA_generate_key_ex(key, bits, e, NULL); + BN_free(e); + if (res == 0) { + RSA_free(key); + throw runtime_error(getName()+" key generation failed"); + } + + if (d_key) + RSA_free(d_key); + + d_key = key; +} + + +DNSCryptoKeyEngine::storvector_t OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const +{ + storvector_t storvect; + typedef vector > outputs_t; + outputs_t outputs; + const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; + RSA_get0_key(d_key, &n, &e, &d); + RSA_get0_factors(d_key, &p, &q); + RSA_get0_crt_params(d_key, &dmp1, &dmq1, &iqmp); + outputs.push_back(make_pair("Modulus", n)); + outputs.push_back(make_pair("PublicExponent", e)); + outputs.push_back(make_pair("PrivateExponent", d)); + outputs.push_back(make_pair("Prime1", p)); + outputs.push_back(make_pair("Prime2", q)); + outputs.push_back(make_pair("Exponent1", dmp1)); + outputs.push_back(make_pair("Exponent2", dmq1)); + outputs.push_back(make_pair("Coefficient", iqmp)); + + string algorithm=std::to_string(d_algorithm); + switch(d_algorithm) { + case 5: + case 7: + algorithm += " (RSASHA1)"; + break; + case 8: + algorithm += " (RSASHA256)"; + break; + case 10: + algorithm += " (RSASHA512)"; + break; + default: + algorithm += " (?)"; + } + storvect.push_back(make_pair("Algorithm", algorithm)); + + for(outputs_t::value_type value : outputs) { + unsigned char tmp[BN_num_bytes(value.second)]; + int len = BN_bn2bin(value.second, tmp); + storvect.push_back(make_pair(value.first, string((char*) tmp, len))); + } + + return storvect; +} + + +std::string OpenSSLRSADNSCryptoKeyEngine::hash(const std::string& orig) const +{ + if (d_algorithm == 5 || d_algorithm == 7) { + /* RSA SHA1 */ + unsigned char hash[SHA_DIGEST_LENGTH]; + SHA1((unsigned char*) orig.c_str(), orig.length(), hash); + return string((char*) hash, sizeof(hash)); + } + else if (d_algorithm == 8) { + /* RSA SHA256 */ + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256((unsigned char*) orig.c_str(), orig.length(), hash); + return string((char*) hash, sizeof(hash)); + } + else if (d_algorithm == 10) { + /* RSA SHA512 */ + unsigned char hash[SHA512_DIGEST_LENGTH]; + SHA512((unsigned char*) orig.c_str(), orig.length(), hash); + return string((char*) hash, sizeof(hash)); + } + + throw runtime_error(getName()+" does not support hash operation for algorithm "+std::to_string(d_algorithm)); +} + +int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize) +{ + switch(hashSize) { + case SHA_DIGEST_LENGTH: + return NID_sha1; + case SHA256_DIGEST_LENGTH: + return NID_sha256; + case SHA384_DIGEST_LENGTH: + return NID_sha384; + case SHA512_DIGEST_LENGTH: + return NID_sha512; + default: + throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize)); + } +} + +std::string OpenSSLRSADNSCryptoKeyEngine::sign(const std::string& msg) const +{ + string hash = this->hash(msg); + int hashKind = hashSizeToKind(hash.size()); + unsigned char signature[RSA_size(d_key)]; + unsigned int signatureLen = 0; + + int res = RSA_sign(hashKind, (unsigned char*) hash.c_str(), hash.length(), signature, &signatureLen, d_key); + if (res != 1) { + throw runtime_error(getName()+" failed to generate signature"); + } + + return string((char*) signature, signatureLen); +} + + +bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const +{ + string hash = this->hash(msg); + int hashKind = hashSizeToKind(hash.size()); + + int ret = RSA_verify(hashKind, (const unsigned char*) hash.c_str(), hash.length(), (unsigned char*) signature.c_str(), signature.length(), d_key); + + return (ret == 1); +} + + +std::string OpenSSLRSADNSCryptoKeyEngine::getPubKeyHash() const +{ + const BIGNUM *n, *e, *d; + RSA_get0_key(d_key, &n, &e, &d); + unsigned char tmp[std::max(BN_num_bytes(e), BN_num_bytes(n))]; + unsigned char hash[SHA_DIGEST_LENGTH]; + SHA_CTX ctx; + + int res = SHA1_Init(&ctx); + + if (res != 1) { + throw runtime_error(getName()+" failed to init hash context for generating the public key hash"); + } + + int len = BN_bn2bin(e, tmp); + res = SHA1_Update(&ctx, tmp, len); + if (res != 1) { + throw runtime_error(getName()+" failed to update hash context for generating the public key hash"); + } + + len = BN_bn2bin(n, tmp); + res = SHA1_Update(&ctx, tmp, len); + if (res != 1) { + throw runtime_error(getName()+" failed to update hash context for generating the public key hash"); + } + + res = SHA1_Final(hash, &ctx); + if (res != 1) { + throw runtime_error(getName()+" failed to finish hash context for generating the public key hash"); + } + + return string((char*) hash, sizeof(hash)); +} + + +std::string OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const +{ + const BIGNUM *n, *e, *d; + RSA_get0_key(d_key, &n, &e, &d); + string keystring; + unsigned char tmp[std::max(BN_num_bytes(e), BN_num_bytes(n))]; + + int len = BN_bn2bin(e, tmp); + if (len < 255) { + keystring.assign(1, (char) (unsigned int) len); + } else { + keystring.assign(1, 0); + uint16_t tempLen = len; + tempLen = htons(tempLen); + keystring.append((char*)&tempLen, 2); + } + keystring.append((char *) tmp, len); + + len = BN_bn2bin(n, tmp); + keystring.append((char *) tmp, len); + + return keystring; +} + + +void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) +{ + typedef map places_t; + places_t places; + RSA* key = RSA_new(); + if (key == NULL) { + throw runtime_error(getName()+" allocation of key structure failed"); + } + + BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; + n = BN_new(); + if (n == NULL) { + RSA_free(key); + throw runtime_error(getName()+" allocation of BIGNUM n failed"); + } + e = BN_new(); + if (e == NULL) { + RSA_free(key); + BN_clear_free(n); + throw runtime_error(getName()+" allocation of BIGNUM e failed"); + } + d = BN_new(); + if (d == NULL) { + RSA_free(key); + BN_clear_free(n); + BN_clear_free(e); + throw runtime_error(getName()+" allocation of BIGNUM d failed"); + } + RSA_set0_key(key, n, e, d); + + p = BN_new(); + if (p == NULL) { + RSA_free(key); + throw runtime_error(getName()+" allocation of BIGNUM p failed"); + } + q = BN_new(); + if (q == NULL) { + RSA_free(key); + BN_clear_free(p); + throw runtime_error(getName()+" allocation of BIGNUM q failed"); + } + RSA_set0_factors(key, p, q); + + dmp1 = BN_new(); + if (dmp1 == NULL) { + RSA_free(key); + throw runtime_error(getName()+" allocation of BIGNUM dmp1 failed"); + } + dmq1 = BN_new(); + if (dmq1 == NULL) { + RSA_free(key); + BN_clear_free(dmp1); + throw runtime_error(getName()+" allocation of BIGNUM dmq1 failed"); + } + iqmp = BN_new(); + if (iqmp == NULL) { + RSA_free(key); + BN_clear_free(dmq1); + BN_clear_free(dmp1); + throw runtime_error(getName()+" allocation of BIGNUM iqmp failed"); + } + RSA_set0_crt_params(key, dmp1, dmq1, iqmp); + + places["Modulus"]=&n; + places["PublicExponent"]=&e; + places["PrivateExponent"]=&d; + places["Prime1"]=&p; + places["Prime2"]=&q; + places["Exponent1"]=&dmp1; + places["Exponent2"]=&dmq1; + places["Coefficient"]=&iqmp; + + drc.d_algorithm = pdns_stou(stormap["algorithm"]); + + string raw; + for(const places_t::value_type& val : places) { + raw=stormap[toLower(val.first)]; + + if (!val.second) + continue; + + *val.second = BN_bin2bn((unsigned char*) raw.c_str(), raw.length(), *val.second); + if (!*val.second) { + RSA_free(key); + throw runtime_error(getName()+" error loading " + val.first); + } + } + + if (drc.d_algorithm != d_algorithm) { + RSA_free(key); + throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key"); + } + + if (d_key) + RSA_free(d_key); + + d_key = key; +} + +bool OpenSSLRSADNSCryptoKeyEngine::checkKey() const +{ + return (RSA_check_key(d_key) == 1); +} + +void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + string exponent, modulus; + const size_t inputLen = input.length(); + const unsigned char* raw = (const unsigned char*)input.c_str(); + + if (inputLen < 1) { + throw runtime_error(getName()+" invalid input size for the public key"); + } + + if (raw[0] != 0) { + const size_t exponentSize = raw[0]; + if (inputLen < (exponentSize + 2)) { + throw runtime_error(getName()+" invalid input size for the public key"); + } + exponent = input.substr(1, exponentSize); + modulus = input.substr(exponentSize + 1); + } else { + if (inputLen < 3) { + throw runtime_error(getName()+" invalid input size for the public key"); + } + const size_t exponentSize = raw[1]*0xff + raw[2]; + if (inputLen < (exponentSize + 4)) { + throw runtime_error(getName()+" invalid input size for the public key"); + } + exponent = input.substr(3, exponentSize); + modulus = input.substr(exponentSize + 3); + } + + RSA* key = RSA_new(); + if (key == NULL) { + throw runtime_error(getName()+" allocation of key structure failed"); + } + + BIGNUM *e = BN_bin2bn((unsigned char*)exponent.c_str(), exponent.length(), NULL); + if (!e) { + RSA_free(key); + throw runtime_error(getName()+" error loading e value of public key"); + } + BIGNUM *n = BN_bin2bn((unsigned char*)modulus.c_str(), modulus.length(), NULL); + if (!n) { + RSA_free(key); + BN_clear_free(e); + throw runtime_error(getName()+" error loading n value of public key"); + } + + if (d_key) + RSA_free(d_key); + + RSA_set0_key(key, n, e, NULL); + d_key = key; +} + +#ifdef HAVE_LIBCRYPTO_ECDSA +class OpenSSLECDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit OpenSSLECDSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo) + { + + int ret = RAND_status(); + if (ret != 1) { + throw runtime_error(getName()+" insufficient entropy"); + } + + d_eckey = EC_KEY_new(); + if (d_eckey == NULL) { + throw runtime_error(getName()+" allocation of key structure failed"); + } + + if(d_algorithm == 13) { + d_ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + d_len = 32; + } else if (d_algorithm == 14) { + d_ecgroup = EC_GROUP_new_by_curve_name(NID_secp384r1); + d_len = 48; + } else { + throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm)); + } + if (d_ecgroup == NULL) { + throw runtime_error(getName()+" allocation of group structure failed"); + } + + ret = EC_KEY_set_group(d_eckey,d_ecgroup); + if (ret != 1) { + throw runtime_error(getName()+" setting key group failed"); + } + + } + + ~OpenSSLECDSADNSCryptoKeyEngine() + { + EC_KEY_free(d_eckey); + EC_GROUP_free(d_ecgroup); + BN_CTX_free(d_ctx); + } + + string getName() const override { return "OpenSSL ECDSA"; } + int getBits() const override { return d_len << 3; } + + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string hash(const std::string& hash) const override; + std::string sign(const std::string& hash) const override; + bool verify(const std::string& hash, const std::string& signature) const override; + std::string getPubKeyHash() const override; + std::string getPublicKeyString() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; + bool checkKey() const override; + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + unsigned int d_len; + + EC_KEY *d_eckey = NULL; + EC_GROUP *d_ecgroup = NULL; + BN_CTX *d_ctx = NULL; +}; + + +void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits) +{ + if (bits >> 3 != d_len) { + throw runtime_error(getName()+" unknown key length of "+std::to_string(bits)+" bits requested"); + } + + int res = EC_KEY_generate_key(d_eckey); + if (res == 0) { + throw runtime_error(getName()+" key generation failed"); + } +} + + +DNSCryptoKeyEngine::storvector_t OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const +{ + storvector_t storvect; + string algorithm; + + if(d_algorithm == 13) + algorithm = "13 (ECDSAP256SHA256)"; + else if(d_algorithm == 14) + algorithm = "14 (ECDSAP384SHA384)"; + else + algorithm = " ? (?)"; + + storvect.push_back(make_pair("Algorithm", algorithm)); + + const BIGNUM *key = EC_KEY_get0_private_key(d_eckey); + if (key == NULL) { + throw runtime_error(getName()+" private key not set"); + } + + unsigned char tmp[BN_num_bytes(key)]; + int len = BN_bn2bin(key, tmp); + + string prefix; + if (d_len - len) + prefix.append(d_len - len, 0x00); + + storvect.push_back(make_pair("PrivateKey", prefix + string((char*) tmp, sizeof(tmp)))); + + return storvect; +} + + +std::string OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string& orig) const +{ + if(getBits() == 256) { + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256((unsigned char*) orig.c_str(), orig.length(), hash); + return string((char*) hash, sizeof(hash)); + } + else if(getBits() == 384) { + unsigned char hash[SHA384_DIGEST_LENGTH]; + SHA384((unsigned char*) orig.c_str(), orig.length(), hash); + return string((char*) hash, sizeof(hash)); + } + + throw runtime_error(getName()+" does not support a hash size of "+std::to_string(getBits())+" bits"); +} + + +std::string OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string& msg) const +{ + string hash = this->hash(msg); + + ECDSA_SIG *signature = ECDSA_do_sign((unsigned char*) hash.c_str(), hash.length(), d_eckey); + if (NULL == signature) { + throw runtime_error(getName()+" failed to generate signature"); + } + + string ret; + unsigned char tmp[d_len]; + + const BIGNUM *pr, *ps; + ECDSA_SIG_get0(signature, &pr, &ps); + int len = BN_bn2bin(pr, tmp); + if (d_len - len) + ret.append(d_len - len, 0x00); + ret.append(string((char*) tmp, len)); + + len = BN_bn2bin(ps, tmp); + if (d_len - len) + ret.append(d_len - len, 0x00); + ret.append(string((char*) tmp, len)); + + ECDSA_SIG_free(signature); + + return ret; +} + + +bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const +{ + if (signature.length() != (d_len * 2)) { + throw runtime_error(getName()+" invalid signature size "+std::to_string(signature.length())); + } + + string hash = this->hash(msg); + + ECDSA_SIG *sig; + sig = ECDSA_SIG_new(); + if (sig == NULL) { + throw runtime_error(getName()+" allocation of signature structure failed"); + } + + BIGNUM *r, *s; + r = BN_bin2bn((unsigned char*) signature.c_str(), d_len, NULL); + s = BN_bin2bn((unsigned char*) signature.c_str() + d_len, d_len, NULL); + if (!r || !s) { + if (r) { + BN_clear_free(r); + } + if (s) { + BN_clear_free(s); + } + ECDSA_SIG_free(sig); + throw runtime_error(getName()+" invalid signature"); + } + + ECDSA_SIG_set0(sig, r, s); + int ret = ECDSA_do_verify((unsigned char*) hash.c_str(), hash.length(), sig, d_eckey); + + ECDSA_SIG_free(sig); + + if (ret == -1){ + throw runtime_error(getName()+" verify error"); + } + + return (ret == 1); +} + + +std::string OpenSSLECDSADNSCryptoKeyEngine::getPubKeyHash() const +{ + string pubKey = getPublicKeyString(); + unsigned char hash[SHA_DIGEST_LENGTH]; + SHA1((unsigned char*) pubKey.c_str(), pubKey.length(), hash); + return string((char*) hash, sizeof(hash)); +} + + +std::string OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const +{ + unsigned char binaryPoint[(d_len * 2) + 1]; + + int ret = EC_POINT_point2oct(d_ecgroup, EC_KEY_get0_public_key(d_eckey), POINT_CONVERSION_UNCOMPRESSED, binaryPoint, sizeof(binaryPoint), d_ctx); + if (ret == 0) { + throw runtime_error(getName()+" exporting point to binary failed"); + } + + /* we skip the first byte as the other backends use + raw field elements, as opposed to the format described in + SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" */ + return string((const char *)(binaryPoint + 1), sizeof(binaryPoint) - 1); +} + + +void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) +{ + drc.d_algorithm = atoi(stormap["algorithm"].c_str()); + + if (drc.d_algorithm != d_algorithm) { + throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key"); + } + + string privateKey = stormap["privatekey"]; + + BIGNUM *prv_key = BN_bin2bn((unsigned char*) privateKey.c_str(), privateKey.length(), NULL); + if (prv_key == NULL) { + throw runtime_error(getName()+" reading private key from binary failed"); + } + + int ret = EC_KEY_set_private_key(d_eckey, prv_key); + if (ret != 1) { + BN_clear_free(prv_key); + throw runtime_error(getName()+" setting private key failed"); + } + + EC_POINT *pub_key = EC_POINT_new(d_ecgroup); + if (pub_key == NULL) { + BN_clear_free(prv_key); + throw runtime_error(getName()+" allocation of public key point failed"); + } + + ret = EC_POINT_mul(d_ecgroup, pub_key, prv_key, NULL, NULL, d_ctx); + if (ret != 1) { + EC_POINT_free(pub_key); + BN_clear_free(prv_key); + throw runtime_error(getName()+" computing public key from private failed"); + } + + BN_clear_free(prv_key); + + ret = EC_KEY_set_public_key(d_eckey, pub_key); + if (ret != 1) { + EC_POINT_free(pub_key); + throw runtime_error(getName()+" setting public key failed"); + } + + EC_POINT_free(pub_key); +} + +bool OpenSSLECDSADNSCryptoKeyEngine::checkKey() const +{ + return (EC_KEY_check_key(d_eckey) == 1); +} + +void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + /* uncompressed point, from SEC1: + "2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion" */ + string ecdsaPoint= "\x04"; + ecdsaPoint.append(input); + + EC_POINT *pub_key = EC_POINT_new(d_ecgroup); + if (pub_key == NULL) { + throw runtime_error(getName()+" allocation of point structure failed"); + } + + int ret = EC_POINT_oct2point(d_ecgroup, pub_key, (unsigned char*) ecdsaPoint.c_str(), ecdsaPoint.length(), d_ctx); + if (ret != 1) { + EC_POINT_free(pub_key); + throw runtime_error(getName()+" reading ECP point from binary failed"); + } + + ret = EC_KEY_set_private_key(d_eckey, NULL); + if (ret == 1) { + EC_POINT_free(pub_key); + throw runtime_error(getName()+" setting private key failed"); + } + + ret = EC_KEY_set_public_key(d_eckey, pub_key); + if (ret != 1) { + EC_POINT_free(pub_key); + throw runtime_error(getName()+" setting public key failed"); + } + + EC_POINT_free(pub_key); +} +#endif + + +namespace { + struct LoaderStruct + { + LoaderStruct() + { + DNSCryptoKeyEngine::report(5, &OpenSSLRSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(7, &OpenSSLRSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(8, &OpenSSLRSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(10, &OpenSSLRSADNSCryptoKeyEngine::maker); +#ifdef HAVE_LIBCRYPTO_ECDSA + DNSCryptoKeyEngine::report(13, &OpenSSLECDSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(14, &OpenSSLECDSADNSCryptoKeyEngine::maker); +#endif + } + } loaderOpenSSL; +} diff --git a/opensslsigners.hh b/opensslsigners.hh new file mode 100644 index 0000000..9724d27 --- /dev/null +++ b/opensslsigners.hh @@ -0,0 +1,34 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include +#include +#include +#include + +#include "dns_random.hh" + +/* pthread locking */ +void openssl_thread_setup(); +void openssl_thread_cleanup(); + +/* seeding PRNG */ +void openssl_seed(); diff --git a/packetcache.hh b/packetcache.hh new file mode 100644 index 0000000..b0785fd --- /dev/null +++ b/packetcache.hh @@ -0,0 +1,78 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PACKETCACHE_HH +#define PACKETCACHE_HH + +#include "ednsoptions.hh" +#include "misc.hh" +#include "iputils.hh" + +class PacketCache : public boost::noncopyable +{ +protected: + static uint32_t canHashPacket(const std::string& packet, bool skipECS=true) + { + uint32_t ret = 0; + ret=burtle((const unsigned char*)packet.c_str() + 2, 10, ret); // rest of dnsheader, skip id + size_t packetSize = packet.size(); + size_t pos = 12; + const char* end = packet.c_str() + packetSize; + const char* p = packet.c_str() + pos; + + for(; p < end && *p; ++p) { // XXX if you embed a 0 in your qname we'll stop lowercasing there + const unsigned char l = dns_tolower(*p); // label lengths can safely be lower cased + ret=burtle(&l, 1, ret); + } // XXX the embedded 0 in the qname will break the subnet stripping + + struct dnsheader* dh = (struct dnsheader*)packet.c_str(); + const char* skipBegin = p; + const char* skipEnd = p; + /* we need at least 1 (final empty label) + 2 (QTYPE) + 2 (QCLASS) + + OPT root label (1), type (2), class (2) and ttl (4) + + the OPT RR rdlen (2) + = 16 + */ + if(skipECS && ntohs(dh->arcount)==1 && (pos+16) < packetSize) { + char* optionBegin = nullptr; + size_t optionLen = 0; + /* skip the final empty label (1), the qtype (2), qclass (2) */ + /* root label (1), type (2), class (2) and ttl (4) */ + int res = getEDNSOption((char*) p + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen); + if (res == 0) { + skipBegin = optionBegin; + skipEnd = optionBegin + optionLen; + } + } + if (skipBegin > p) { + // cerr << "Hashing from " << (p-packet.c_str()) << " for " << skipBegin-p << "bytes, end is at "<< end-packet.c_str() << endl; + ret = burtle((const unsigned char*)p, skipBegin-p, ret); + } + if (skipEnd < end) { + // cerr << "Hashing from " << (skipEnd-packet.c_str()) << " for " << end-skipEnd << "bytes, end is at " << end-packet.c_str() << endl; + ret = burtle((const unsigned char*) skipEnd, end-skipEnd, ret); + } + + return ret; + } +}; + +#endif /* PACKETCACHE_HH */ diff --git a/pdns-recursor.service.in b/pdns-recursor.service.in new file mode 100644 index 0000000..4c0d61b --- /dev/null +++ b/pdns-recursor.service.in @@ -0,0 +1,24 @@ +[Unit] +Description=PowerDNS Recursor +Documentation=man:pdns_recursor(1) man:rec_control(1) +Documentation=https://doc.powerdns.com +Wants=network-online.target nss-lookup.target +Before=nss-lookup.target +After=network-online.target + +[Service] +Type=notify +ExecStart=@sbindir@/pdns_recursor --daemon=no --write-pid=no --disable-syslog --log-timestamp=no +Restart=on-failure +StartLimitInterval=0 +PrivateTmp=true +PrivateDevices=true +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_CHOWN CAP_SYS_CHROOT +NoNewPrivileges=true +ProtectSystem=full +ProtectHome=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +LimitNOFILE=4200 + +[Install] +WantedBy=multi-user.target diff --git a/pdns_recursor.1 b/pdns_recursor.1 new file mode 100644 index 0000000..8b9f653 --- /dev/null +++ b/pdns_recursor.1 @@ -0,0 +1,205 @@ +.\" Man page generated from reStructuredText. +. +.TH "PDNS_RECURSOR" "1" "Aug 31, 2018" "4.1" "PowerDNS Recursor" +.SH NAME +pdns_recursor \- The PowerDNS Recursor binary +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.SH SYNOPSIS +.sp +\fBpdns_recursor\fP [\fIOPTION\fP]... +.SH DESCRIPTION +.sp +\fBpdns_recursor\fP is a high performance, simple and secure recursing +nameserver. It currently powers hundreds of millions internet connections. +.sp +The recursor is configured via a configuration file, but each item in +that file can be overridden on the command line. +.sp +This manpage lists the core set of features needed to get the PowerDNS Recursor +working, for full and up to date details head to \fI\%https://doc.powerdns.com/\fP\&. +.SH EXAMPLES +.sp +To listen on 192.0.2.53 and allow the 192.0.2.0/24 subnet to recurse, and run +as in the background, execute: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# pdns_recursor \-\-local\-address=192.0.2.53 \-\-allow\-from=192.0.2.0/24 \-\-daemon +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To stop the recursor by hand, run: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# rec_control quit +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +However, the recommended way of starting and stopping the recursor is to use +the init.d script or \fBsystemctl(1)\fP\&. +.SH OPTIONS +.sp +For authoritative listing of options, consult the online documentation +at \fI\fP +.INDENT 0.0 +.TP +.BI \-\-allow\-from\fB= +If set, only allow these comma separated \fInetworks\fP, +with network mask to recurse. For example: 192.0.2.0/24,203.0.113.128/25. +.TP +.BI \-\-auth\-zones\fB= +Where \fIauthzone\fP is =. +Serve \fIzonename\fP from \fIfilename\fP authoritatively. For example: +ds9a.nl=/var/zones/ds9a.nl,powerdns.com=/var/zones/powerdns.com. +.TP +.BI \-\-chroot\fB= +chroot the process to \fIdirectory\fP\&. +.TP +.BI \-\-client\-tcp\-timeout\fB= +Timeout in seconds when talking to TCP clients. +.TP +.BI \-\-config\-dir\fB= +Location of configuration directory (recursor.conf), the default +depends on the SYSCONFDIR option at build\-time, which is usually +/etc/powerdns. The default can be found with +\fBpdns_recursor \-\-config | grep \(aq config\-dir=\(aq\fP\&. +.TP +.B \-\-daemon +Operate as a daemon. +.TP +.B \-\-delegation\-only +Which domains we only accept delegations from (a Verisign special). +.TP +.BI \-\-entropy\-source\fB= +Read new entropy from \fIfile\fP, defaults to /dev/urandom. +.TP +.B \-\-export\-etc\-hosts +If set, this flag will export the hostnames and IP addresses +mentioned in /etc/hosts. +.TP +.BI \-\-forward\-zones\fB= +Where \fIforwardzone\fP is =
. +Queries for \fIzonename\fP will be forwarded to \fIaddress\fP\&. \fIaddress\fP +should be an IP address, not a hostname (to prevent chicken and egg +problems). Example: forward\-zones= ds9a.nl=213.244.168.210, +powerdns.com=127.0.0.1. +.TP +.BI \-\-forward\-zones\-file\fB= +Similar to \fI\-\-forward\-zones\fP, but read the options from \fIfilename\fP\&. +\fIfilename\fP should contain one zone per line, like: +ds9a.nl=213.244.168.210. +.TP +.B \-\-help +Show a summary of options. +.TP +.BI \-\-hint\-file\fB= +Load root hints from this \fIfilename\fP +.TP +.BI \-\-local\-address\fB=
+Listen on \fIaddress\fP, separated by spaces or commas. +.TP +.BI \-\-local\-port\fB= +Listen on \fIport\fP\&. +.TP +.B \-\-log\-common\-errors +If we should log rather common errors. +.TP +.BI \-\-max\-cache\-entries\fB= +Maximum number of entries in the main cache. +.TP +.BI \-\-max\-negative\-ttl\fB= +maximum number of seconds to keep a negative cached entry in memory. +.TP +.BI \-\-max\-tcp\-clients\fB= +Maximum number of simultaneous TCP clients. +.TP +.BI \-\-max\-tcp\-per\-client\fB= +If set, maximum number of TCP sessions per client (IP address). +.TP +.BI \-\-query\-local\-address\fB=
+Use \fIaddress\fP as Source IP address when sending queries. +.TP +.BI \-\-query\-local\-address6\fB=
+Send out local IPv6 queries from \fIaddress\fP\&. Disabled by default, +which also disables outgoing IPv6 support. A useful setting is +\(aq::0\(aq. +.TP +.B \-\-quiet +Suppress logging of questions and answers. +.TP +.BI \-\-server\-id\fB= +Return \fItext\fP WHen queried for \(aqid.server\(aq TXT, defaults to +hostname. +.TP +.B \-\-serve\-rfc1918 +On by default, this makes the server authoritatively aware of: +10.in\-addr.arpa, 168.192.in\-addr.arpa and 16\-31.172.in\-addr.arpa, +which saves load on the AS112 servers. Individual parts of these +zones can still be loaded or forwarded. +.TP +.BI \-\-setgid\fB= +If set, change group id to \fIgid\fP for more security. +.TP +.BI \-\-setuid\fB= +If set, change user id to \fIuid\fP for more security. +.TP +.B \-\-single\-socket +If set, only use a single socket for outgoing queries. +.TP +.BI \-\-socket\-dir\fB= +The controlsocket will live in \fIdirectory\fP\&. +.TP +.BI \-\-spoof\-nearmiss\-max\fB= +If non\-zero, assume spoofing after this many near misses. +.TP +.B \-\-trace +if we should output heaps of logging. +.TP +.BI \-\-version\-string\fB= +\fItext\fP WILL be reported on version.pdns or version.bind queries. +.UNINDENT +.SH SEE ALSO +.sp +\fBrec_control(1)\fP +\fBsystemctl(1)\fP +.SH AUTHOR +PowerDNS.COM BV +.SH COPYRIGHT +2001-2018, PowerDNS.COM BV +.\" Generated by docutils manpage writer. +. diff --git a/pdns_recursor.cc b/pdns_recursor.cc new file mode 100644 index 0000000..30449b3 --- /dev/null +++ b/pdns_recursor.cc @@ -0,0 +1,3599 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "recpacketcache.hh" +#include "ws-recursor.hh" +#include +#include "utility.hh" +#include "dns_random.hh" +#ifdef HAVE_LIBSODIUM +#include +#endif +#include "opensslsigners.hh" +#include +#include +#include +#include +#include +#include "recursor_cache.hh" +#include "cachecleaner.hh" +#include +#include +#include +#include "misc.hh" +#include "mtasker.hh" +#include +#include "arguments.hh" +#include "syncres.hh" +#include +#include +#include "sortlist.hh" +#include "sstuff.hh" +#include +#include +#include +#include +#include +#ifdef MALLOC_TRACE +#include "malloctrace.hh" +#endif +#include +#include "dnsparser.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" +#include "zoneparser-tng.hh" +#include "rec_channel.hh" +#include "logger.hh" +#include "iputils.hh" +#include "mplexer.hh" +#include "config.h" +#include "lua-recursor4.hh" +#include "version.hh" +#include "responsestats.hh" +#include "secpoll-recursor.hh" +#include "dnsname.hh" +#include "filterpo.hh" +#include "rpzloader.hh" +#include "validate-recursor.hh" +#include "rec-lua-conf.hh" +#include "ednsoptions.hh" +#include "gettime.hh" + +#include "rec-protobuf.hh" +#include "rec-snmp.hh" + +#ifdef HAVE_SYSTEMD +#include +#endif + +#include "namespaces.hh" + +typedef map tcpClientCounts_t; + +static thread_local std::shared_ptr t_pdl; +static thread_local int t_id = -1; +static thread_local std::shared_ptr t_traceRegex; +static thread_local std::unique_ptr t_tcpClientCounts; + +thread_local std::unique_ptr MT; // the big MTasker +thread_local std::unique_ptr t_RC; +thread_local std::unique_ptr t_packetCache; +thread_local FDMultiplexer* t_fdm{nullptr}; +thread_local std::unique_ptr t_remotes, t_servfailremotes, t_largeanswerremotes; +thread_local std::unique_ptr > > t_queryring, t_servfailqueryring; +thread_local std::shared_ptr t_allowFrom; +#ifdef HAVE_PROTOBUF +thread_local std::unique_ptr t_uuidGenerator; +#endif +__thread struct timeval g_now; // timestamp, updated (too) frequently + +// for communicating with our threads +struct ThreadPipeSet +{ + int writeToThread; + int readToThread; + int writeFromThread; + int readFromThread; + int writeQueriesToThread; // this one is non-blocking + int readQueriesToThread; +}; + +/* the TID of the thread handling the web server, carbon, statistics and the control channel */ +static const int s_handlerThreadID = -1; +/* when pdns-distributes-queries is set, the TID of the thread handling, hashing and distributing new queries + to the other threads */ +static const int s_distributorThreadID = 0; + +typedef std::map> tcpListenSockets_t; +typedef map listenSocketsAddresses_t; // is shared across all threads right now + +typedef vector > > deferredAdd_t; + +static const ComboAddress g_local4("0.0.0.0"), g_local6("::"); +static vector g_pipes; // effectively readonly after startup +static tcpListenSockets_t g_tcpListenSockets; // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets +static listenSocketsAddresses_t g_listenSocketsAddresses; // is shared across all threads right now +static std::unordered_map deferredAdds; +static set g_fromtosockets; // listen sockets that use 'sendfromto()' mechanism +static vector g_localQueryAddresses4, g_localQueryAddresses6; +static AtomicCounter counter; +static std::shared_ptr g_initialDomainMap; // new threads needs this to be setup +static std::shared_ptr g_initialAllowFrom; // new thread needs to be setup with this +static size_t g_tcpMaxQueriesPerConn; +static size_t s_maxUDPQueriesPerRound; +static uint64_t g_latencyStatSize; +static uint32_t g_disthashseed; +static unsigned int g_maxTCPPerClient; +static unsigned int g_networkTimeoutMsec; +static unsigned int g_maxMThreads; +static unsigned int g_numWorkerThreads; +static int g_tcpTimeout; +static uint16_t g_udpTruncationThreshold; +static std::atomic statsWanted; +static std::atomic g_quiet; +static bool g_logCommonErrors; +static bool g_anyToTcp; +static bool g_weDistributeQueries; // if true, only 1 thread listens on the incoming query sockets +static bool g_reusePort{false}; +static bool g_useOneSocketPerThread; +static bool g_gettagNeedsEDNSOptions{false}; +static time_t g_statisticsInterval; +static bool g_useIncomingECS; +std::atomic g_maxCacheEntries, g_maxPacketCacheEntries; + +RecursorControlChannel s_rcc; // only active in thread 0 +RecursorStats g_stats; +string s_programname="pdns_recursor"; +string s_pidfname; +bool g_lowercaseOutgoing; +unsigned int g_numThreads; +uint16_t g_outgoingEDNSBufsize; +bool g_logRPZChanges{false}; + +#define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10" +// Bad Nets taken from both: +// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml +// and +// http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml +// where such a network may not be considered a valid destination +#define BAD_NETS "0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32" +#define DONT_QUERY LOCAL_NETS ", " BAD_NETS + +//! used to send information to a newborn mthread +struct DNSComboWriter { + DNSComboWriter(const char* data, uint16_t len, const struct timeval& now) : d_mdp(true, data, len), d_now(now), + d_tcp(false), d_socket(-1) + {} + MOADNSParser d_mdp; + void setRemote(const ComboAddress* sa) + { + d_remote=*sa; + } + + void setLocal(const ComboAddress& sa) + { + d_local=sa; + } + + + void setSocket(int sock) + { + d_socket=sock; + } + + string getRemote() const + { + return d_remote.toString(); + } + + struct timeval d_now; + ComboAddress d_remote, d_local; +#ifdef HAVE_PROTOBUF + boost::uuids::uuid d_uuid; + string d_requestorId; + string d_deviceId; +#endif + EDNSSubnetOpts d_ednssubnet; + bool d_ecsFound{false}; + bool d_ecsParsed{false}; + bool d_tcp; + int d_socket; + unsigned int d_tag{0}; + uint32_t d_qhash{0}; + string d_query; + shared_ptr d_tcpConnection; + vector > d_ednsOpts; + std::vector d_policyTags; + LuaContext::LuaObject d_data; + uint32_t d_ttlCap{std::numeric_limits::max()}; + bool d_variable{false}; +}; + +MT_t* getMT() +{ + return MT ? MT.get() : nullptr; +} + +ArgvMap &arg() +{ + static ArgvMap theArg; + return theArg; +} + +int getRecursorThreadId() +{ + return t_id; +} + +int getMTaskerTID() +{ + return MT->getTid(); +} + +static void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var); + +// -1 is error, 0 is timeout, 1 is success +int asendtcp(const string& data, Socket* sock) +{ + PacketID pident; + pident.sock=sock; + pident.outMSG=data; + + t_fdm->addWriteFD(sock->getHandle(), handleTCPClientWritable, pident); + string packet; + + int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec); + + if(!ret || ret==-1) { // timeout + t_fdm->removeWriteFD(sock->getHandle()); + } + else if(packet.size() !=data.size()) { // main loop tells us what it sent out, or empty in case of an error + return -1; + } + return ret; +} + +static void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var); + +// -1 is error, 0 is timeout, 1 is success +int arecvtcp(string& data, size_t len, Socket* sock, bool incompleteOkay) +{ + data.clear(); + PacketID pident; + pident.sock=sock; + pident.inNeeded=len; + pident.inIncompleteOkay=incompleteOkay; + t_fdm->addReadFD(sock->getHandle(), handleTCPClientReadable, pident); + + int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec); + if(!ret || ret==-1) { // timeout + t_fdm->removeReadFD(sock->getHandle()); + } + else if(data.empty()) {// error, EOF or other + return -1; + } + + return ret; +} + +static void handleGenUDPQueryResponse(int fd, FDMultiplexer::funcparam_t& var) +{ + PacketID pident=*any_cast(&var); + char resp[512]; + ssize_t ret=recv(fd, resp, sizeof(resp), 0); + t_fdm->removeReadFD(fd); + if(ret >= 0) { + string data(resp, (size_t) ret); + MT->sendEvent(pident, &data); + } + else { + string empty; + MT->sendEvent(pident, &empty); + // cerr<<"Had some kind of error: "<addReadFD(s.getHandle(), handleGenUDPQueryResponse, pident); + + string data; + + int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec); + + if(!ret || ret==-1) { // timeout + t_fdm->removeReadFD(s.getHandle()); + } + else if(data.empty()) {// error, EOF or other + // we could special case this + return data; + } + return data; +} + +//! pick a random query local address +ComboAddress getQueryLocalAddress(int family, uint16_t port) +{ + ComboAddress ret; + if(family==AF_INET) { + if(g_localQueryAddresses4.empty()) + ret = g_local4; + else + ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())]; + ret.sin4.sin_port = htons(port); + } + else { + if(g_localQueryAddresses6.empty()) + ret = g_local6; + else + ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())]; + + ret.sin6.sin6_port = htons(port); + } + return ret; +} + +static void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t&); + +static void setSocketBuffer(int fd, int optname, uint32_t size) +{ + uint32_t psize=0; + socklen_t len=sizeof(psize); + + if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) { + L< socks_t; + socks_t d_socks; + + // returning -2 means: temporary OS error (ie, out of files), -1 means error related to remote + int getSocket(const ComboAddress& toaddr, int* fd) + { + *fd=makeClientSocket(toaddr.sin4.sin_family); + if(*fd < 0) // temporary error - receive exception otherwise + return -2; + + if(connect(*fd, (struct sockaddr*)(&toaddr), toaddr.getSocklen()) < 0) { + int err = errno; + // returnSocket(*fd); + try { + closesocket(*fd); + } + catch(const PDNSException& e) { + L<removeReadFD(*i); + } + catch(FDMultiplexerException& e) { + // we sometimes return a socket that has not yet been assigned to t_fdm + } + try { + closesocket(*i); + } + catch(const PDNSException& e) { + L<= 0) + break; + } + if(!tries) + throw PDNSException("Resolver binding to local query client socket on "+sin.toString()+": "+stringerror()); + + setNonBlocking(ret); + return ret; + } +}; + +static thread_local std::unique_ptr t_udpclientsocks; + +/* these two functions are used by LWRes */ +// -2 is OS error, -1 is error that depends on the remote, > 0 is success +int asendto(const char *data, size_t len, int flags, + const ComboAddress& toaddr, uint16_t id, const DNSName& domain, uint16_t qtype, int* fd) +{ + + PacketID pident; + pident.domain = domain; + pident.remote = toaddr; + pident.type = qtype; + + // see if there is an existing outstanding request we can chain on to, using partial equivalence function + pair chain=MT->d_waiters.equal_range(pident, PacketIDBirthdayCompare()); + + for(; chain.first != chain.second; chain.first++) { + if(chain.first->key.fd > -1) { // don't chain onto existing chained waiter! + /* + cerr<<"Orig: "<key.domain<<", "<key.remote.toString()<<", id="<key.id + <<", count="<key.chain.size()<<", origfd: "<key.fd<key.chain.insert(id); // we can chain + *fd=-1; // gets used in waitEvent / sendEvent later on + return 1; + } + } + + int ret=t_udpclientsocks->getSocket(toaddr, fd); + if(ret < 0) + return ret; + + pident.fd=*fd; + pident.id=id; + + t_fdm->addReadFD(*fd, handleUDPServerResponse, pident); + ret = send(*fd, data, len, 0); + + int tmp = errno; + + if(ret < 0) + t_udpclientsocks->returnSocket(*fd); + + errno = tmp; // this is for logging purposes only + return ret; +} + +// -1 is error, 0 is timeout, 1 is success +int arecvfrom(char *data, size_t len, int flags, const ComboAddress& fromaddr, size_t *d_len, + uint16_t id, const DNSName& domain, uint16_t qtype, int fd, struct timeval* now) +{ + static optional nearMissLimit; + if(!nearMissLimit) + nearMissLimit=::arg().asNum("spoof-nearmiss-max"); + + PacketID pident; + pident.fd=fd; + pident.id=id; + pident.domain=domain; + pident.type = qtype; + pident.remote=fromaddr; + + string packet; + int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec, now); + + if(ret > 0) { + if(packet.empty()) // means "error" + return -1; + + *d_len=packet.size(); + memcpy(data,packet.c_str(),min(len,*d_len)); + if(*nearMissLimit && pident.nearMisses > *nearMissLimit) { + L< "<<*nearMissLimit<<") bogus answers for '"<= 0) + t_udpclientsocks->returnSocket(fd); + } + return ret; +} + +static void writePid(void) +{ + if(!::arg().mustDo("write-pid")) + return; + ofstream of(s_pidfname.c_str(), std::ios_base::app); + if(of) + of<< Utility::getpid() <count(d_remote) && !(*t_tcpClientCounts)[d_remote]--) + t_tcpClientCounts->erase(d_remote); + --s_currentConnections; +} + +AtomicCounter TCPConnection::s_currentConnections; + +static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var); + +// the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming. +static void updateResponseStats(int res, const ComboAddress& remote, unsigned int packetsize, const DNSName* query, uint16_t qtype) +{ + if(packetsize > 1000 && t_largeanswerremotes) + t_largeanswerremotes->push_back(remote); + switch(res) { + case RCode::ServFail: + if(t_servfailremotes) { + t_servfailremotes->push_back(remote); + if(query && t_servfailqueryring) // packet cache + t_servfailqueryring->push_back(make_pair(*query, qtype)); + } + g_stats.servFails++; + break; + case RCode::NXDomain: + g_stats.nxDomains++; + break; + case RCode::NoError: + g_stats.noErrors++; + break; + } +} + +static string makeLoginfo(DNSComboWriter* dc) +try +{ + return "("+dc->d_mdp.d_qname.toLogString()+"/"+DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)+" from "+(dc->d_remote.toString())+")"; +} +catch(...) +{ + return "Exception making error message for exception"; +} + +#ifdef HAVE_PROTOBUF +static void protobufLogQuery(const std::shared_ptr& logger, uint8_t maskV4, uint8_t maskV6, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const Netmask& ednssubnet, bool tcp, uint16_t id, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::vector& policyTags, const std::string& requestorId, const std::string& deviceId) +{ + Netmask requestorNM(remote, remote.sin4.sin_family == AF_INET ? maskV4 : maskV6); + const ComboAddress& requestor = requestorNM.getMaskedNetwork(); + RecProtoBufMessage message(DNSProtoBufMessage::Query, uniqueId, &requestor, &local, qname, qtype, qclass, id, tcp, len); + message.setEDNSSubnet(ednssubnet, ednssubnet.isIpv4() ? maskV4 : maskV6); + message.setRequestorId(requestorId); + message.setDeviceId(deviceId); + + if (!policyTags.empty()) { + message.setPolicyTags(policyTags); + } + +// cerr <queueData(str); +} + +static void protobufLogResponse(const std::shared_ptr& logger, const RecProtoBufMessage& message) +{ +// cerr <queueData(str); +} +#endif + +/** + * Chases the CNAME provided by the PolicyCustom RPZ policy. + * + * @param spoofed: The DNSRecord that was created by the policy, should already be added to ret + * @param qtype: The QType of the original query + * @param sr: A SyncRes + * @param res: An integer that will contain the RCODE of the lookup we do + * @param ret: A vector of DNSRecords where the result of the CNAME chase should be appended to + */ +static void handleRPZCustom(const DNSRecord& spoofed, const QType& qtype, SyncRes& sr, int& res, vector& ret) +{ + if (spoofed.d_type == QType::CNAME) { + bool oldWantsRPZ = sr.getWantsRPZ(); + sr.setWantsRPZ(false); + vector ans; + res = sr.beginResolve(DNSName(spoofed.d_content->getZoneRepresentation()), qtype, 1, ans); + for (const auto& rec : ans) { + if(rec.d_place == DNSResourceRecord::ANSWER) { + ret.push_back(rec); + } + } + // Reset the RPZ state of the SyncRes + sr.setWantsRPZ(oldWantsRPZ); + } +} + +static bool addRecordToPacket(DNSPacketWriter& pw, const DNSRecord& rec, uint32_t& minTTL, uint32_t ttlCap, const uint16_t maxAnswerSize) +{ + pw.startRecord(rec.d_name, rec.d_type, (rec.d_ttl > ttlCap ? ttlCap : rec.d_ttl), rec.d_class, rec.d_place); + + if(rec.d_type != QType::OPT) // their TTL ain't real + minTTL = min(minTTL, rec.d_ttl); + + rec.d_content->toPacket(pw); + if(pw.size() > static_cast(maxAnswerSize)) { + pw.rollback(); + if(rec.d_place != DNSResourceRecord::ADDITIONAL) { + pw.getHeader()->tc=1; + pw.truncate(); + } + return false; + } + + return true; +} + +static void startDoResolve(void *p) +{ + DNSComboWriter* dc=(DNSComboWriter *)p; + try { + if (t_queryring) + t_queryring->push_back(make_pair(dc->d_mdp.d_qname, dc->d_mdp.d_qtype)); + + uint16_t maxanswersize = dc->d_tcp ? 65535 : min(static_cast(512), g_udpTruncationThreshold); + EDNSOpts edo; + bool haveEDNS=false; + if(getEDNSOpts(dc->d_mdp, &edo)) { + if(!dc->d_tcp) { + /* rfc6891 6.2.3: + "Values lower than 512 MUST be treated as equal to 512." + */ + maxanswersize = min(static_cast(edo.d_packetsize >= 512 ? edo.d_packetsize : 512), g_udpTruncationThreshold); + } + dc->d_ednsOpts = edo.d_options; + haveEDNS=true; + + if (g_useIncomingECS && !dc->d_ecsParsed) { + for (const auto& o : edo.d_options) { + if (o.first == EDNSOptionCode::ECS) { + dc->d_ecsFound = getEDNSSubnetOptsFromString(o.second, &dc->d_ednssubnet); + break; + } + } + } + } + /* perhaps there was no EDNS or no ECS but by now we looked */ + dc->d_ecsParsed = true; + vector ret; + vector packet; + + auto luaconfsLocal = g_luaconfs.getLocal(); + // Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query + bool wantsRPZ(true); + RecProtoBufMessage pbMessage(RecProtoBufMessage::Response); +#ifdef HAVE_PROTOBUF + if (luaconfsLocal->protobufServer) { + Netmask requestorNM(dc->d_remote, dc->d_remote.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); + const ComboAddress& requestor = requestorNM.getMaskedNetwork(); + pbMessage.update(dc->d_uuid, &requestor, &dc->d_local, dc->d_tcp, dc->d_mdp.d_header.id); + pbMessage.setEDNSSubnet(dc->d_ednssubnet.source, dc->d_ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); + pbMessage.setQuestion(dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass); + } +#endif /* HAVE_PROTOBUF */ + + DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass); + + pw.getHeader()->aa=0; + pw.getHeader()->ra=1; + pw.getHeader()->qr=1; + pw.getHeader()->tc=0; + pw.getHeader()->id=dc->d_mdp.d_header.id; + pw.getHeader()->rd=dc->d_mdp.d_header.rd; + pw.getHeader()->cd=dc->d_mdp.d_header.cd; + + /* This is the lowest TTL seen in the records of the response, + so we can't cache it for longer than this value. + If we have a TTL cap, this value can't be larger than the + cap no matter what. */ + uint32_t minTTL = dc->d_ttlCap; + + SyncRes sr(dc->d_now); + + bool DNSSECOK=false; + if(t_pdl) { + sr.setLuaEngine(t_pdl); + } + sr.d_requestor=dc->d_remote; // ECS needs this too + if(g_dnssecmode != DNSSECMode::Off) { + sr.setDoDNSSEC(true); + + // Does the requestor want DNSSEC records? + if(edo.d_Z & EDNSOpts::DNSSECOK) { + DNSSECOK=true; + g_stats.dnssecQueries++; + } + } else { + // Ignore the client-set CD flag + pw.getHeader()->cd=0; + } + sr.setDNSSECValidationRequested(g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode==DNSSECMode::ValidateForLog || ((dc->d_mdp.d_header.ad || DNSSECOK) && g_dnssecmode==DNSSECMode::Process)); + +#ifdef HAVE_PROTOBUF + sr.setInitialRequestId(dc->d_uuid); +#endif + + if (g_useIncomingECS) { + sr.setIncomingECSFound(dc->d_ecsFound); + if (dc->d_ecsFound) { + sr.setIncomingECS(dc->d_ednssubnet); + } + } + + bool tracedQuery=false; // we could consider letting Lua know about this too + bool variableAnswer = dc->d_variable; + bool shouldNotValidate = false; + + /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */ + int res = RCode::NoError; + DNSFilterEngine::Policy appliedPolicy; + DNSRecord spoofed; + RecursorLua4::DNSQuestion dq(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_tcp, variableAnswer, wantsRPZ); + dq.ednsFlags = &edo.d_Z; + dq.ednsOptions = &dc->d_ednsOpts; + dq.tag = dc->d_tag; + dq.discardedPolicies = &sr.d_discardedPolicies; + dq.policyTags = &dc->d_policyTags; + dq.appliedPolicy = &appliedPolicy; + dq.currentRecords = &ret; + dq.dh = &dc->d_mdp.d_header; + dq.data = dc->d_data; +#ifdef HAVE_PROTOBUF + dq.requestorId = dc->d_requestorId; + dq.deviceId = dc->d_deviceId; +#endif + + if(dc->d_mdp.d_qtype==QType::ANY && !dc->d_tcp && g_anyToTcp) { + pw.getHeader()->tc = 1; + res = 0; + variableAnswer = true; + goto sendit; + } + + if(t_traceRegex && t_traceRegex->match(dc->d_mdp.d_qname.toString())) { + sr.setLogMode(SyncRes::Store); + tracedQuery=true; + } + + + if(!g_quiet || tracedQuery) { + L<getTid()<<"/"<numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<d_mdp.d_qname<<"|" + <d_mdp.d_qtype)<<"' from "<getRemote(); + if(!dc->d_ednssubnet.source.empty()) { + L<<" (ecs "<d_ednssubnet.source.toString()<<")"; + } + L<getTid()); + if(!dc->d_mdp.d_header.rd) + sr.setCacheOnly(); + + if (t_pdl) { + t_pdl->prerpz(dq, res); + } + + // Check if the query has a policy attached to it + if (wantsRPZ) { + appliedPolicy = luaconfsLocal->dfe.getQueryPolicy(dc->d_mdp.d_qname, dc->d_remote, sr.d_discardedPolicies); + } + + // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve + if(!t_pdl || !t_pdl->preresolve(dq, res)) { + + sr.setWantsRPZ(wantsRPZ); + if(wantsRPZ) { + switch(appliedPolicy.d_kind) { + case DNSFilterEngine::PolicyKind::NoAction: + break; + case DNSFilterEngine::PolicyKind::Drop: + g_stats.policyDrops++; + g_stats.policyResults[appliedPolicy.d_kind]++; + delete dc; + dc=0; + return; + case DNSFilterEngine::PolicyKind::NXDOMAIN: + g_stats.policyResults[appliedPolicy.d_kind]++; + res=RCode::NXDomain; + goto haveAnswer; + case DNSFilterEngine::PolicyKind::NODATA: + g_stats.policyResults[appliedPolicy.d_kind]++; + res=RCode::NoError; + goto haveAnswer; + case DNSFilterEngine::PolicyKind::Custom: + g_stats.policyResults[appliedPolicy.d_kind]++; + res=RCode::NoError; + spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname); + ret.push_back(spoofed); + handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret); + goto haveAnswer; + case DNSFilterEngine::PolicyKind::Truncate: + if(!dc->d_tcp) { + g_stats.policyResults[appliedPolicy.d_kind]++; + res=RCode::NoError; + pw.getHeader()->tc=1; + goto haveAnswer; + } + break; + } + } + + // Query got not handled for QNAME Policy reasons, now actually go out to find an answer + try { + res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret); + shouldNotValidate = sr.wasOutOfBand(); + } + catch(ImmediateServFailException &e) { + if(g_logCommonErrors) + L<getRemote()<<" during resolve of '"<d_mdp.d_qname<<"' because: "<d_tcp) { + ret.clear(); + res=RCode::NoError; + pw.getHeader()->tc=1; + goto haveAnswer; + } + break; + + case DNSFilterEngine::PolicyKind::Custom: + ret.clear(); + res=RCode::NoError; + spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname); + ret.push_back(spoofed); + handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret); + goto haveAnswer; + } + } + + if (wantsRPZ) { + appliedPolicy = luaconfsLocal->dfe.getPostPolicy(ret, sr.d_discardedPolicies); + } + + if(t_pdl) { + if(res == RCode::NoError) { + auto i=ret.cbegin(); + for(; i!= ret.cend(); ++i) + if(i->d_type == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER) + break; + if(i == ret.cend() && t_pdl->nodata(dq, res)) + shouldNotValidate = true; + + } + else if(res == RCode::NXDomain && t_pdl->nxdomain(dq, res)) + shouldNotValidate = true; + + if(t_pdl->postresolve(dq, res)) + shouldNotValidate = true; + } + + if (wantsRPZ) { //XXX This block is repeated, see above + g_stats.policyResults[appliedPolicy.d_kind]++; + switch(appliedPolicy.d_kind) { + case DNSFilterEngine::PolicyKind::NoAction: + break; + case DNSFilterEngine::PolicyKind::Drop: + g_stats.policyDrops++; + delete dc; + dc=0; + return; + case DNSFilterEngine::PolicyKind::NXDOMAIN: + ret.clear(); + res=RCode::NXDomain; + goto haveAnswer; + + case DNSFilterEngine::PolicyKind::NODATA: + ret.clear(); + res=RCode::NoError; + goto haveAnswer; + + case DNSFilterEngine::PolicyKind::Truncate: + if(!dc->d_tcp) { + ret.clear(); + res=RCode::NoError; + pw.getHeader()->tc=1; + goto haveAnswer; + } + break; + + case DNSFilterEngine::PolicyKind::Custom: + ret.clear(); + res=RCode::NoError; + spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname); + ret.push_back(spoofed); + handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret); + goto haveAnswer; + } + } + } + haveAnswer:; + if(res == PolicyDecision::DROP) { + g_stats.policyDrops++; + delete dc; + dc=0; + return; + } + if(tracedQuery || res == -1 || res == RCode::ServFail || pw.getHeader()->rcode == RCode::ServFail) + { + string trace(sr.getTrace()); + if(!trace.empty()) { + vector lines; + boost::split(lines, trace, boost::is_any_of("\n")); + for(const string& line : lines) { + if(!line.empty()) + L<rcode=RCode::ServFail; + // no commit here, because no record + g_stats.servFails++; + } + else { + pw.getHeader()->rcode=res; + + // Does the validation mode or query demand validation? + if(!shouldNotValidate && sr.isDNSSECValidationRequested()) { + try { + if(sr.doLog()) { + L<d_mdp.d_qname<<"|"<d_mdp.d_qtype).getName()<<" for "<d_remote.toStringWithPort()<d_mdp.d_qname<<"|"<d_mdp.d_qtype).getName()<<" for "<d_remote.toStringWithPort()<<" validates correctly"<d_mdp.d_header.ad || DNSSECOK) + pw.getHeader()->ad=1; + } + else if(state == Insecure) { + if(sr.doLog()) { + L<d_mdp.d_qname<<"|"<d_mdp.d_qtype).getName()<<" for "<d_remote.toStringWithPort()<<" validates as Insecure"<ad=0; + } + else if(state == Bogus) { + if(g_dnssecLogBogus || sr.doLog() || g_dnssecmode == DNSSECMode::ValidateForLog) { + L<d_mdp.d_qname<<"|"<d_mdp.d_qtype).getName()<<" for "<d_remote.toStringWithPort()<<" validates as Bogus"<cd && (g_dnssecmode == DNSSECMode::ValidateAll || dc->d_mdp.d_header.ad || DNSSECOK)) { + if(sr.doLog()) { + L<d_mdp.d_qname<<"|"<d_mdp.d_qtype).getName()<<" because recursor or query demands it for Bogus results"<rcode=RCode::ServFail; + goto sendit; + } else { + if(sr.doLog()) { + L<d_mdp.d_qname<<"|"<d_mdp.d_qtype).getName()<<" Bogus validation since neither config nor query demands this"<getRemote()<<" during validation of '"<d_mdp.d_qname<<"|"<d_mdp.d_qtype).getName()<<"' because: "<rcode=RCode::ServFail; + goto sendit; + } + } + + if(ret.size()) { + orderAndShuffle(ret); + if(auto sl = luaconfsLocal->sortlist.getOrderCmp(dc->d_remote)) { + stable_sort(ret.begin(), ret.end(), *sl); + variableAnswer=true; + } + } + + bool needCommit = false; + for(auto i=ret.cbegin(); i!=ret.cend(); ++i) { + if( ! DNSSECOK && + ( i->d_type == QType::NSEC3 || + ( + ( i->d_type == QType::RRSIG || i->d_type==QType::NSEC ) && + ( + ( dc->d_mdp.d_qtype != i->d_type && dc->d_mdp.d_qtype != QType::ANY ) || + i->d_place != DNSResourceRecord::ANSWER + ) + ) + ) + ) { + continue; + } + + if (!addRecordToPacket(pw, *i, minTTL, dc->d_ttlCap, maxanswersize)) { + needCommit = false; + break; + } + needCommit = true; + +#ifdef HAVE_PROTOBUF + if(luaconfsLocal->protobufServer && (i->d_type == QType::A || i->d_type == QType::AAAA || i->d_type == QType::CNAME)) { + pbMessage.addRR(*i); + } +#endif + } + if(needCommit) + pw.commit(); + } + sendit:; + + if (haveEDNS) { + /* we try to add the EDNS OPT RR even for truncated answers, + as rfc6891 states: + "The minimal response MUST be the DNS header, question section, and an + OPT record. This MUST also occur when a truncated response (using + the DNS header's TC bit) is returned." + */ + if (addRecordToPacket(pw, makeOpt(edo.d_packetsize, 0, edo.d_Z), minTTL, dc->d_ttlCap, maxanswersize)) { + pw.commit(); + } + } + + g_rs.submitResponse(dc->d_mdp.d_qtype, packet.size(), !dc->d_tcp); + updateResponseStats(res, dc->d_remote, packet.size(), &dc->d_mdp.d_qname, dc->d_mdp.d_qtype); +#ifdef HAVE_PROTOBUF + if (luaconfsLocal->protobufServer && (!luaconfsLocal->protobufTaggedOnly || (appliedPolicy.d_name && !appliedPolicy.d_name->empty()) || !dc->d_policyTags.empty())) { + pbMessage.setBytes(packet.size()); + pbMessage.setResponseCode(pw.getHeader()->rcode); + if (appliedPolicy.d_name) { + pbMessage.setAppliedPolicy(*appliedPolicy.d_name); + pbMessage.setAppliedPolicyType(appliedPolicy.d_type); + } + pbMessage.setPolicyTags(dc->d_policyTags); + pbMessage.setQueryTime(dc->d_now.tv_sec, dc->d_now.tv_usec); + pbMessage.setRequestorId(dq.requestorId); + pbMessage.setDeviceId(dq.deviceId); + protobufLogResponse(luaconfsLocal->protobufServer, pbMessage); + } +#endif + if(!dc->d_tcp) { + struct msghdr msgh; + struct iovec iov; + char cbuf[256]; + fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)&*packet.begin(), packet.size(), &dc->d_remote); + msgh.msg_control=NULL; + + if(g_fromtosockets.count(dc->d_socket)) { + addCMsgSrcAddr(&msgh, cbuf, &dc->d_local, 0); + } + if(sendmsg(dc->d_socket, &msgh, 0) < 0 && g_logCommonErrors) + L<d_remote.toStringWithPort()<<" failed with: "<insertResponsePacket(dc->d_tag, dc->d_qhash, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass, + string((const char*)&*packet.begin(), packet.size()), + g_now.tv_sec, + pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl : + min(minTTL,SyncRes::s_packetcachettl), + &pbMessage); + } + // else cerr<<"Not putting in packet cache: "<d_socket, iov, 2); + bool hadError=true; + + if(wret == 0) + L<getRemote()<getRemote()<<": "<< strerror(errno) <getRemote()<<" for "<d_mdp.d_qname<<" (size="<< (2 + packet.size()) <<", sent "<d_socket = -1; + } + else { + dc->d_tcpConnection->queriesCount++; + if (g_tcpMaxQueriesPerConn && dc->d_tcpConnection->queriesCount >= g_tcpMaxQueriesPerConn) { + dc->d_socket = -1; + } + else { + dc->d_tcpConnection->state=TCPConnection::BYTE0; + Utility::gettimeofday(&g_now, 0); // needs to be updated + t_fdm->addReadFD(dc->d_socket, handleRunningTCPQuestion, dc->d_tcpConnection); + t_fdm->setReadTTD(dc->d_socket, g_now, g_tcpTimeout); + } + } + } + float spent=makeFloat(sr.getNow()-dc->d_now); + if(!g_quiet) { + L<getTid()<<"/"<numProcesses()<<"] answer to "<<(dc->d_mdp.d_header.rd?"":"non-rd ")<<"question '"<d_mdp.d_qname<<"|"<d_mdp.d_qtype); + L<<"': "<ancount)<<" answers, "<arcount)<<" additional, took "< "<d_mdp.d_qname<<"|"<d_mdp.d_qtype)<= 0.0) { + newLat=ourtime*1000; // usec + g_stats.avgLatencyOursUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyOursUsec + (float)newLat/g_latencyStatSize; + } + // cout<d_mdp.d_qname<<"\t"<getUsec()<<"\t"<d_mdp.d_qname<<", "<getMaxStackUsage(), g_stats.maxMThreadStackUsage); +} + +static void makeControlChannelSocket(int processNum=-1) +{ + string sockname=::arg()["socket-dir"]+"/"+s_programname; + if(processNum >= 0) + sockname += "."+std::to_string(processNum); + sockname+=".controlsocket"; + s_rcc.listen(sockname); + + int sockowner = -1; + int sockgroup = -1; + + if (!::arg().isEmpty("socket-group")) + sockgroup=::arg().asGid("socket-group"); + if (!::arg().isEmpty("socket-owner")) + sockowner=::arg().asUid("socket-owner"); + + if (sockgroup > -1 || sockowner > -1) { + if(chown(sockname.c_str(), sockowner, sockgroup) < 0) { + unixDie("Failed to chown control socket"); + } + } + + // do mode change if socket-mode is given + if(!::arg().isEmpty("socket-mode")) { + mode_t sockmode=::arg().asMode("socket-mode"); + if(chmod(sockname.c_str(), sockmode) < 0) { + unixDie("Failed to chmod control socket"); + } + } +} + +static bool getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass, EDNSSubnetOpts* ednssubnet, std::map* options) +{ + bool found = false; + const struct dnsheader* dh = (struct dnsheader*)question.c_str(); + size_t questionLen = question.length(); + unsigned int consumed=0; + *dnsname=DNSName(question.c_str(), questionLen, sizeof(dnsheader), false, qtype, qclass, &consumed); + + size_t pos= sizeof(dnsheader)+consumed+4; + /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2) + = 11 */ + if(ntohs(dh->arcount) == 1 && questionLen > pos + 11) { // this code can extract one (1) EDNS Subnet option + /* OPT root label (1) followed by type (2) */ + if(question.at(pos)==0 && question.at(pos+1)==0 && question.at(pos+2)==QType::OPT) { + if (!options) { + char* ecsStart = nullptr; + size_t ecsLen = 0; + int res = getEDNSOption((char*)question.c_str()+pos+9, questionLen - pos - 9, EDNSOptionCode::ECS, &ecsStart, &ecsLen); + if (res == 0 && ecsLen > 4) { + EDNSSubnetOpts eso; + if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) { + *ednssubnet=eso; + found = true; + } + } + } + else { + int res = getEDNSOptions((char*)question.c_str()+pos+9, questionLen - pos - 9, *options); + if (res == 0) { + const auto& it = options->find(EDNSOptionCode::ECS); + if (it != options->end() && it->second.content != nullptr && it->second.size > 0) { + EDNSSubnetOpts eso; + if(getEDNSSubnetOptsFromString(it->second.content, it->second.size, &eso)) { + *ednssubnet=eso; + found = true; + } + } + } + } + } + } + return found; +} + +static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var) +{ + shared_ptr conn=any_cast >(var); + + if(conn->state==TCPConnection::BYTE0) { + ssize_t bytes=recv(conn->getFD(), conn->data, 2, 0); + if(bytes==1) + conn->state=TCPConnection::BYTE1; + if(bytes==2) { + conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1]; + conn->bytesread=0; + conn->state=TCPConnection::GETQUESTION; + } + if(!bytes || bytes < 0) { + t_fdm->removeReadFD(fd); + return; + } + } + else if(conn->state==TCPConnection::BYTE1) { + ssize_t bytes=recv(conn->getFD(), conn->data+1, 1, 0); + if(bytes==1) { + conn->state=TCPConnection::GETQUESTION; + conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1]; + conn->bytesread=0; + } + if(!bytes || bytes < 0) { + if(g_logCommonErrors) + L<d_remote.toString() <<" disconnected after first byte"<removeReadFD(fd); + return; + } + } + else if(conn->state==TCPConnection::GETQUESTION) { + ssize_t bytes=recv(conn->getFD(), conn->data + conn->bytesread, conn->qlen - conn->bytesread, 0); + if(!bytes || bytes < 0 || bytes > std::numeric_limits::max()) { + L<d_remote.toString() <<" disconnected while reading question body"<removeReadFD(fd); + return; + } + conn->bytesread+=(uint16_t)bytes; + if(conn->bytesread==conn->qlen) { + t_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read + + DNSComboWriter* dc=nullptr; + try { + dc=new DNSComboWriter(conn->data, conn->qlen, g_now); + } + catch(MOADNSException &mde) { + g_stats.clientParseError++; + if(g_logCommonErrors) + L<d_remote.toString() <d_tcpConnection = conn; // carry the torch + dc->setSocket(conn->getFD()); // this is the only time a copy is made of the actual fd + dc->d_tcp=true; + dc->setRemote(&conn->d_remote); + ComboAddress dest; + dest.reset(); + dest.sin4.sin_family = conn->d_remote.sin4.sin_family; + socklen_t len = dest.getSocklen(); + getsockname(conn->getFD(), (sockaddr*)&dest, &len); // if this fails, we're ok with it + dc->setLocal(dest); + DNSName qname; + uint16_t qtype=0; + uint16_t qclass=0; + bool needECS = false; + string requestorId; + string deviceId; +#ifdef HAVE_PROTOBUF + auto luaconfsLocal = g_luaconfs.getLocal(); + if (luaconfsLocal->protobufServer) { + needECS = true; + } +#endif + + if(needECS || (t_pdl && (t_pdl->d_gettag_ffi || t_pdl->d_gettag))) { + + try { + std::map ednsOptions; + dc->d_ecsParsed = true; + dc->d_ecsFound = getQNameAndSubnet(std::string(conn->data, conn->qlen), &qname, &qtype, &qclass, &dc->d_ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr); + + if(t_pdl) { + try { + if (t_pdl->d_gettag_ffi) { + dc->d_tag = t_pdl->gettag_ffi(conn->d_remote, dc->d_ednssubnet.source, dest, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId, dc->d_ttlCap, dc->d_variable); + } + else if (t_pdl->d_gettag) { + dc->d_tag = t_pdl->gettag(conn->d_remote, dc->d_ednssubnet.source, dest, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId); + } + } + catch(const std::exception& e) { + if(g_logCommonErrors) + L<protobufServer || luaconfsLocal->outgoingProtobufServer) { + dc->d_requestorId = requestorId; + dc->d_deviceId = deviceId; + dc->d_uuid = (*t_uuidGenerator)(); + } + + if(luaconfsLocal->protobufServer) { + try { + const struct dnsheader* dh = (const struct dnsheader*) conn->data; + + if (!luaconfsLocal->protobufTaggedOnly) { + protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, dc->d_uuid, conn->d_remote, dest, dc->d_ednssubnet.source, true, dh->id, conn->qlen, qname, qtype, qclass, dc->d_policyTags, dc->d_requestorId, dc->d_deviceId); + } + } + catch(std::exception& e) { + if(g_logCommonErrors) + L<d_mdp.d_header.qr) { + delete dc; + g_stats.ignoredCount++; + L<d_remote.toString() <<" on server socket!"<d_mdp.d_header.opcode) { + delete dc; + g_stats.ignoredCount++; + L<d_remote.toString() <<" on server socket!"<makeThread(startDoResolve, dc); // deletes dc, will set state to BYTE0 again + return; + } + } + } +} + +//! Handle new incoming TCP connection +static void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& ) +{ + ComboAddress addr; + socklen_t addrlen=sizeof(addr); + int newsock=accept(fd, (struct sockaddr*)&addr, &addrlen); + if(newsock>=0) { + if(MT->numProcesses() > g_maxMThreads) { + g_stats.overCapacityDrops++; + try { + closesocket(newsock); + } + catch(const PDNSException& e) { + L<push_back(addr); + if(t_allowFrom && !t_allowFrom->match(&addr)) { + if(!g_quiet) + L<getTid()<<"] dropping TCP query from "<count(addr) && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) { + g_stats.tcpClientOverflow++; + try { + closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet! + } + catch(const PDNSException& e) { + L< tc = std::make_shared(newsock, addr); + tc->state=TCPConnection::BYTE0; + + t_fdm->addReadFD(tc->getFD(), handleRunningTCPQuestion, tc); + + struct timeval now; + Utility::gettimeofday(&now, 0); + t_fdm->setReadTTD(tc->getFD(), now, g_tcpTimeout); + } +} + +static string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd) +{ + gettimeofday(&g_now, 0); + struct timeval diff = g_now - tv; + double delta=(diff.tv_sec*1000 + diff.tv_usec/1000.0); + + if(tv.tv_sec && delta > 1000.0) { + g_stats.tooOldDrops++; + return 0; + } + + ++g_stats.qcounter; + if(fromaddr.sin4.sin_family==AF_INET6) + g_stats.ipv6qcounter++; + + string response; + const struct dnsheader* dh = (struct dnsheader*)question.c_str(); + unsigned int ctag=0; + uint32_t qhash = 0; + bool needECS = false; + std::vector policyTags; + LuaContext::LuaObject data; + string requestorId; + string deviceId; +#ifdef HAVE_PROTOBUF + boost::uuids::uuid uniqueId; + auto luaconfsLocal = g_luaconfs.getLocal(); + if (luaconfsLocal->protobufServer) { + uniqueId = (*t_uuidGenerator)(); + needECS = true; + } else if (luaconfsLocal->outgoingProtobufServer) { + uniqueId = (*t_uuidGenerator)(); + } +#endif + EDNSSubnetOpts ednssubnet; + bool ecsFound = false; + bool ecsParsed = false; + uint32_t ttlCap = std::numeric_limits::max(); + bool variable = false; + try { + DNSName qname; + uint16_t qtype=0; + uint16_t qclass=0; + uint32_t age; + bool qnameParsed=false; +#ifdef MALLOC_TRACE + /* + static uint64_t last=0; + if(!last) + g_mtracer->clearAllocators(); + cout<getAllocs()-last<<" "<getNumOut()<<" -- BEGIN TRACE"<getAllocs(); + cout<topAllocatorsString()<clearAllocators(); + */ +#endif + + if(needECS || (t_pdl && (t_pdl->d_gettag || t_pdl->d_gettag_ffi))) { + try { + std::map ednsOptions; + ecsFound = getQNameAndSubnet(question, &qname, &qtype, &qclass, &ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr); + qnameParsed = true; + ecsParsed = true; + + if(t_pdl) { + try { + if (t_pdl->d_gettag_ffi) { + ctag = t_pdl->gettag_ffi(fromaddr, ednssubnet.source, destaddr, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, ttlCap, variable); + } + else if (t_pdl->d_gettag) { + ctag=t_pdl->gettag(fromaddr, ednssubnet.source, destaddr, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId); + } + } + catch(const std::exception& e) { + if(g_logCommonErrors) + L<protobufServer) { + if (!luaconfsLocal->protobufTaggedOnly || !policyTags.empty()) { + protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, fromaddr, destaddr, ednssubnet.source, false, dh->id, question.size(), qname, qtype, qclass, policyTags, requestorId, deviceId); + } + } +#endif /* HAVE_PROTOBUF */ + + /* It might seem like a good idea to skip the packet cache lookup if we know that the answer is not cacheable, + but it means that the hash would not be computed. If some script decides at a later time to mark back the answer + as cacheable we would cache it with a wrong tag, so better safe than sorry. */ + if (qnameParsed) { + cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &qhash, &pbMessage)); + } + else { + cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, g_now.tv_sec, &response, &age, &qhash, &pbMessage)); + } + + if (cacheHit) { +#ifdef HAVE_PROTOBUF + if(luaconfsLocal->protobufServer && (!luaconfsLocal->protobufTaggedOnly || !pbMessage.getAppliedPolicy().empty() || !pbMessage.getPolicyTags().empty())) { + Netmask requestorNM(fromaddr, fromaddr.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); + const ComboAddress& requestor = requestorNM.getMaskedNetwork(); + pbMessage.update(uniqueId, &requestor, &destaddr, false, dh->id); + pbMessage.setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); + pbMessage.setQueryTime(g_now.tv_sec, g_now.tv_usec); + pbMessage.setRequestorId(requestorId); + pbMessage.setDeviceId(deviceId); + protobufLogResponse(luaconfsLocal->protobufServer, pbMessage); + } +#endif /* HAVE_PROTOBUF */ + if(!g_quiet) + L<(&fromaddr)); + msgh.msg_control=NULL; + + if(g_fromtosockets.count(fd)) { + addCMsgSrcAddr(&msgh, cbuf, &destaddr, 0); + } + if(sendmsg(fd, &msgh, 0) < 0 && g_logCommonErrors) + L<= sizeof(struct dnsheader)) { + struct dnsheader tmpdh; + memcpy(&tmpdh, response.c_str(), sizeof(tmpdh)); + updateResponseStats(tmpdh.rcode, fromaddr, response.length(), 0, 0); + } + g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + 0.0; // we assume 0 usec + g_stats.avgLatencyOursUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyOursUsec + 0.0; // we assume 0 usec + return 0; + } + } + catch(std::exception& e) { + L<ipfilter(fromaddr, destaddr, *dh)) { + if(!g_quiet) + L<getTid()<<"/"<numProcesses()<<"] DROPPED question from "<numProcesses() > g_maxMThreads) { + if(!g_quiet) + L<getTid()<<"/"<numProcesses()<<"] DROPPED question from "<setSocket(fd); + dc->d_tag=ctag; + dc->d_qhash=qhash; + dc->d_query = question; + dc->setRemote(&fromaddr); + dc->setLocal(destaddr); + dc->d_tcp=false; + dc->d_policyTags = policyTags; + dc->d_data = data; + dc->d_ecsFound = ecsFound; + dc->d_ecsParsed = ecsParsed; + dc->d_ednssubnet = ednssubnet; + dc->d_ttlCap = ttlCap; + dc->d_variable = variable; +#ifdef HAVE_PROTOBUF + if (luaconfsLocal->protobufServer || luaconfsLocal->outgoingProtobufServer) { + dc->d_uuid = uniqueId; + } + dc->d_requestorId = requestorId; + dc->d_deviceId = deviceId; +#endif + + MT->makeThread(startDoResolve, (void*) dc); // deletes dc + return 0; +} + + +static void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var) +{ + ssize_t len; + char data[1500]; + ComboAddress fromaddr; + struct msghdr msgh; + struct iovec iov; + char cbuf[256]; + bool firstQuery = true; + + fromaddr.sin6.sin6_family=AF_INET6; // this makes sure fromaddr is big enough + fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), data, sizeof(data), &fromaddr); + + for(size_t counter = 0; counter < s_maxUDPQueriesPerRound; counter++) + if((len=recvmsg(fd, &msgh, 0)) >= 0) { + + firstQuery = false; + + if(t_remotes) + t_remotes->push_back(fromaddr); + + if(t_allowFrom && !t_allowFrom->match(&fromaddr)) { + if(!g_quiet) + L<getTid()<<"] dropping UDP query from "<getTid()<<"] dropping UDP query from "<qr) { + g_stats.ignoredCount++; + if(g_logCommonErrors) + L<opcode) { + g_stats.ignoredCount++; + if(g_logCommonErrors) + L<opcode<<" from "<sin4.sin_port; + } + else { + if(loc) { + dest = *loc; + } + else { + dest.sin4.sin_family = fromaddr.sin4.sin_family; + socklen_t slen = dest.getSocklen(); + getsockname(fd, (sockaddr*)&dest, &slen); // if this fails, we're ok with it + } + } + if(g_weDistributeQueries) + distributeAsyncFunction(question, boost::bind(doProcessUDPQuestion, question, fromaddr, dest, tv, fd)); + else + doProcessUDPQuestion(question, fromaddr, dest, tv, fd); + } + } + catch(MOADNSException& mde) { + g_stats.clientParseError++; + if(g_logCommonErrors) + L<locals; + stringtok(locals,::arg()["local-address"]," ,"); + + if(locals.empty()) + throw PDNSException("No local address specified"); + + for(vector::const_iterator i=locals.begin();i!=locals.end();++i) { + ServiceTuple st; + st.port=::arg().asNum("local-port"); + parseService(*i, st); + + ComboAddress sin; + + sin.reset(); + sin.sin4.sin_family = AF_INET; + if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) { + sin.sin6.sin6_family = AF_INET6; + if(makeIPv6sockaddr(st.host, &sin.sin6) < 0) + throw PDNSException("Unable to resolve local address for TCP server on '"+ st.host +"'"); + } + + fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0); + if(fd<0) + throw PDNSException("Making a TCP server socket for resolver: "+stringerror()); + + setCloseOnExec(fd); + + int tmp=1; + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp)<0) { + L<= 0) { + if(i==locals.begin()) + L< 0) { +#ifdef TCP_FASTOPEN + int fastOpenQueueSize = ::arg().asNum("tcp-fast-open"); + if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) { + L<locals; + stringtok(locals,::arg()["local-address"]," ,"); + + if(locals.empty()) + throw PDNSException("No local address specified"); + + for(vector::const_iterator i=locals.begin();i!=locals.end();++i) { + ServiceTuple st; + st.port=::arg().asNum("local-port"); + parseService(*i, st); + + ComboAddress sin; + + sin.reset(); + sin.sin4.sin_family = AF_INET; + if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) { + sin.sin6.sin6_family = AF_INET6; + if(makeIPv6sockaddr(st.host, &sin.sin6) < 0) + throw PDNSException("Unable to resolve local address for UDP server on '"+ st.host +"'"); + } + + int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0); + if(fd < 0) { + throw PDNSException("Making a UDP server socket for resolver: "+netstringerror()); + } + if (!setSocketTimestamps(fd)) + L<(pleaseGetCacheHits); + uint64_t cacheMisses = broadcastAccFunction(pleaseGetCacheMisses); + + if(g_stats.qcounter && (cacheHits + cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) { + L<(pleaseGetCacheSize)<< " cache entries, "<< + broadcastAccFunction(pleaseGetNegCacheSize)<<" negative entries, "<< + (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<(pleaseGetThrottleSize) <<", ns speeds: " + << broadcastAccFunction(pleaseGetNsSpeedsSize)<(pleaseGetConcurrentQueries)<<" queries running, "<(pleaseGetPacketCacheSize) << + " packet cache entries, "<<(int)(100.0*broadcastAccFunction(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"< (time_t)(5 + t_id)) { + DTime dt; + dt.setTimeval(now); + t_RC->doPrune(g_maxCacheEntries / g_numThreads); // this function is local to a thread, so fine anyhow + t_packetCache->doPruneTo(g_maxPacketCacheEntries / g_numWorkerThreads); + + SyncRes::pruneNegCache(g_maxCacheEntries / (g_numWorkerThreads * 10)); + + if(!((cleanCounter++)%40)) { // this is a full scan! + time_t limit=now.tv_sec-300; + SyncRes::pruneNSSpeeds(limit); + } + last_prune=time(0); + } + + if(now.tv_sec - last_rootupdate > 7200) { + int res = SyncRes::getRootNS(g_now, nullptr); + if (!res) + last_rootupdate=now.tv_sec; + } + + if(t_id == s_distributorThreadID) { + + if(now.tv_sec - last_secpoll >= 3600) { + try { + doSecPoll(&last_secpoll); + } + catch(std::exception& e) + { + L<func = func; + tmsg->wantAnswer = true; + if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { + delete tmsg; + unixDie("write to thread pipe returned wrong size or error"); + } + + string* resp = nullptr; + if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp)) + unixDie("read from thread pipe returned wrong size or error"); + + if(resp) { + delete resp; + resp = nullptr; + } + } +} + +// This function is only called by the distributor thread, when pdns-distributes-queries is set +void distributeAsyncFunction(const string& packet, const pipefunc_t& func) +{ + if (t_id != s_distributorThreadID) { + L<(s_distributorThreadID)) { + L<func = func; + tmsg->wantAnswer = false; + + ssize_t written = write(tps.writeQueriesToThread, &tmsg, sizeof(tmsg)); + if (written > 0) { + if (static_cast(written) != sizeof(tmsg)) { + delete tmsg; + unixDie("write to thread pipe returned wrong size or error"); + } + } + else { + int error = errno; + delete tmsg; + if (error == EAGAIN || error == EWOULDBLOCK) { + g_stats.queryPipeFullDrops++; + } else { + unixDie("write to thread pipe returned wrong size or error:" + std::to_string(error)); + } + } +} + +static void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var) +{ + ThreadMSG* tmsg = nullptr; + + if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread || fd == readQueriesToThread + unixDie("read from thread pipe returned wrong size or error"); + } + + void *resp=0; + try { + resp = tmsg->func(); + } + catch(std::exception& e) { + if(g_logCommonErrors) + L<wantAnswer) { + if(write(g_pipes[t_id].writeFromThread, &resp, sizeof(resp)) != sizeof(resp)) { + delete tmsg; + unixDie("write to thread pipe returned wrong size or error"); + } + } + + delete tmsg; +} + +template void *voider(const boost::function& func) +{ + return func(); +} + +vector& operator+=(vector&a, const vector& b) +{ + a.insert(a.end(), b.begin(), b.end()); + return a; +} + +vector >& operator+=(vector >&a, const vector >& b) +{ + a.insert(a.end(), b.begin(), b.end()); + return a; +} + +vector >& operator+=(vector >&a, const vector >& b) +{ + a.insert(a.end(), b.begin(), b.end()); + return a; +} + + +/* + This function should only be called by the handler to gather metrics, wipe the cache, + reload the Lua script (not the Lua config) or change the current trace regex, + and by the SNMP thread to gather metrics. */ +template T broadcastAccFunction(const boost::function& func) +{ + /* the SNMP thread uses id -1 too */ + if (t_id != s_handlerThreadID) { + L<func = boost::bind(voider, func); + tmsg->wantAnswer = true; + + if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { + delete tmsg; + unixDie("write to thread pipe returned wrong size or error"); + } + + T* resp = nullptr; + if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp)) + unixDie("read from thread pipe returned wrong size or error"); + + if(resp) { + ret += *resp; + delete resp; + resp = nullptr; + } + } + return ret; +} + +template string broadcastAccFunction(const boost::function& fun); // explicit instantiation +template uint64_t broadcastAccFunction(const boost::function& fun); // explicit instantiation +template vector broadcastAccFunction(const boost::function *()>& fun); // explicit instantiation +template vector > broadcastAccFunction(const boost::function > *()>& fun); // explicit instantiation + +static void handleRCC(int fd, FDMultiplexer::funcparam_t& var) +{ + string remote; + string msg=s_rcc.recv(&remote); + RecursorControlParser rcp; + RecursorControlParser::func_t* command; + + string answer=rcp.getAnswer(msg, &command); + + // If we are inside a chroot, we need to strip + if (!arg()["chroot"].empty()) { + size_t len = arg()["chroot"].length(); + remote = remote.substr(len); + } + + try { + s_rcc.send(answer, &remote); + command(); + } + catch(std::exception& e) { + L<(&var); + // cerr<<"handleTCPClientReadable called for fd "<inNeeded: "<inNeeded<<", "<sock->getHandle()< buffer(new char[pident->inNeeded]); + + ssize_t ret=recv(fd, buffer.get(), pident->inNeeded,0); + if(ret > 0) { + pident->inMSG.append(&buffer[0], &buffer[ret]); + pident->inNeeded-=(size_t)ret; + if(!pident->inNeeded || pident->inIncompleteOkay) { + // cerr<<"Got entire load of "<inMSG.size()<<" bytes"<inMSG; + + t_fdm->removeReadFD(fd); + MT->sendEvent(pid, &msg); + } + else { + // cerr<<"Still have "<inNeeded<<" left to go"<removeReadFD(fd); // pident might now be invalid (it isn't, but still) + string empty; + MT->sendEvent(tmp, &empty); // this conveys error status + } +} + +static void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var) +{ + PacketID* pid=any_cast(&var); + ssize_t ret=send(fd, pid->outMSG.c_str() + pid->outPos, pid->outMSG.size() - pid->outPos,0); + if(ret > 0) { + pid->outPos+=(ssize_t)ret; + if(pid->outPos==pid->outMSG.size()) { + PacketID tmp=*pid; + t_fdm->removeWriteFD(fd); + MT->sendEvent(tmp, &tmp.outMSG); // send back what we sent to convey everything is ok + } + } + else { // error or EOF + PacketID tmp(*pid); + t_fdm->removeWriteFD(fd); + string sent; + MT->sendEvent(tmp, &sent); // we convey error status by sending empty string + } +} + +// resend event to everybody chained onto it +static void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content) +{ + if(iter->key.chain.empty()) + return; + // cerr<<"doResends called!\n"; + for(PacketID::chain_t::iterator i=iter->key.chain.begin(); i != iter->key.chain.end() ; ++i) { + resend.fd=-1; + resend.id=*i; + // cerr<<"\tResending "<returnSocket(fd); + string empty; + + MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid); + if(iter != MT->d_waiters.end()) + doResends(iter, pid, empty); + + MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot) + return; + } + + dnsheader dh; + memcpy(&dh, data, sizeof(dh)); + + PacketID pident; + pident.remote=fromaddr; + pident.id=dh.id; + pident.fd=fd; + + if(!dh.qr && g_logCommonErrors) { + L< 12) + pident.domain=DNSName(data, len, 12, false, &pident.type); // don't copy this from above - we need to do the actual read + } + catch(std::exception& e) { + g_stats.serverParseError++; // won't be fed to lwres.cc, so we have to increment + L<d_waiters.find(pident); + if(iter != MT->d_waiters.end()) { + doResends(iter, pident, packet); + } + +retryWithName: + + if(!MT->sendEvent(pident, &packet)) { + // we do a full scan for outstanding queries on unexpected answers. not too bad since we only accept them on the right port number, which is hard enough to guess + for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) { + if(pident.fd==mthread->key.fd && mthread->key.remote==pident.remote && mthread->key.type == pident.type && + pident.domain == mthread->key.domain) { + mthread->key.nearMisses++; + } + + // be a bit paranoid here since we're weakening our matching + if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type && + pident.id == mthread->key.id && mthread->key.remote == pident.remote) { + // cerr<<"Empty response, rest matches though, sending to a waiter"<key.domain; + pident.type = mthread->key.type; + goto retryWithName; // note that this only passes on an error, lwres will still reject the packet + } + } + g_stats.unexpectedCount++; // if we made it here, it really is an unexpected answer + if(g_logCommonErrors) { + L<" : pident.domain.toString())<<", "<d_waiters.size()<<" waiters"<= 0) { + t_udpclientsocks->returnSocket(fd); + } +} + +FDMultiplexer* getMultiplexer() +{ + FDMultiplexer* ret; + for(const auto& i : FDMultiplexer::getMultiplexerMap()) { + try { + ret=i.second(); + return ret; + } + catch(FDMultiplexerException &fe) { + L<(fname); + } + } + catch(std::exception& e) { + L<::const_iterator begin, vector::const_iterator end) +{ + if(begin != end) + ::arg().set("lua-dns-script") = *begin; + + return broadcastAccFunction(doReloadLuaScript); +} + +static string* pleaseUseNewTraceRegex(const std::string& newRegex) +try +{ + if(newRegex.empty()) { + t_traceRegex.reset(); + return new string("unset\n"); + } + else { + t_traceRegex = std::make_shared(newRegex); + return new string("ok\n"); + } +} +catch(PDNSException& ae) +{ + return new string(ae.reason+"\n"); +} + +string doTraceRegex(vector::const_iterator begin, vector::const_iterator end) +{ + return broadcastAccFunction(boost::bind(pleaseUseNewTraceRegex, begin!=end ? *begin : "")); +} + +static void checkLinuxIPv6Limits() +{ +#ifdef __linux__ + string line; + if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line)) { + int lim=std::stoi(line); + if(lim < 16384) { + L< availFDs) { + unsigned int hardlimit= getFilenumLimit(true); + if(hardlimit >= wantFDs) { + setFilenumLimit(wantFDs); + L< ng) +{ + t_allowFrom = ng; + return nullptr; +} + +int g_argc; +char** g_argv; + +void parseACLs() +{ + static bool l_initialized; + + if(l_initialized) { // only reload configuration file on second call + string configname=::arg()["config-dir"]+"/recursor.conf"; + if(::arg()["config-name"]!="") { + configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf"; + } + cleanSlashes(configname); + + if(!::arg().preParseFile(configname.c_str(), "allow-from-file")) + throw runtime_error("Unable to re-parse configuration file '"+configname+"'"); + ::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS); + ::arg().preParseFile(configname.c_str(), "include-dir"); + ::arg().preParse(g_argc, g_argv, "include-dir"); + + // then process includes + std::vector extraConfigs; + ::arg().gatherIncludes(extraConfigs); + + for(const std::string& fn : extraConfigs) { + if(!::arg().preParseFile(fn.c_str(), "allow-from-file", ::arg()["allow-from-file"])) + throw runtime_error("Unable to re-parse configuration file include '"+fn+"'"); + if(!::arg().preParseFile(fn.c_str(), "allow-from", ::arg()["allow-from"])) + throw runtime_error("Unable to re-parse configuration file include '"+fn+"'"); + } + + ::arg().preParse(g_argc, g_argv, "allow-from-file"); + ::arg().preParse(g_argc, g_argv, "allow-from"); + } + + std::shared_ptr oldAllowFrom = t_allowFrom; + std::shared_ptr allowFrom = std::make_shared(); + + if(!::arg()["allow-from-file"].empty()) { + string line; + ifstream ifs(::arg()["allow-from-file"].c_str()); + if(!ifs) { + throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror()); + } + + string::size_type pos; + while(getline(ifs,line)) { + pos=line.find('#'); + if(pos!=string::npos) + line.resize(pos); + trim(line); + if(line.empty()) + continue; + + allowFrom->addMask(line); + } + L<size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"< ips; + stringtok(ips, ::arg()["allow-from"], ", "); + + L<::const_iterator i = ips.begin(); i!= ips.end(); ++i) { + allowFrom->addMask(*i); + if(i!=ips.begin()) + L< parts; + stringtok(parts, ::arg()["delegation-only"], ", \t"); + for(const auto& p : parts) { + SyncRes::addDelegationOnly(DNSName(p)); + } +} + +static std::map > parseCPUMap() +{ + std::map > result; + + const std::string value = ::arg()["cpu-map"]; + + if (!value.empty() && !isSettingThreadCPUAffinitySupported()) { + L< parts; + + stringtok(parts, value, " \t"); + + for(const auto& part : parts) { + if (part.find('=') == string::npos) + continue; + + try { + auto headers = splitField(part, '='); + trim(headers.first); + trim(headers.second); + + unsigned int threadId = pdns_stou(headers.first); + std::vector cpus; + + stringtok(cpus, headers.second, ","); + + for(const auto& cpu : cpus) { + int cpuId = std::stoi(cpu); + + result[threadId].insert(cpuId); + } + } + catch(const std::exception& e) { + L< >& cpusMap, unsigned int n, pthread_t tid) +{ + const auto& cpuMapping = cpusMap.find(n); + if (cpuMapping != cpusMap.cend()) { + int rc = mapThreadToCPUList(tid, cpuMapping->second); + if (rc == 0) { + L<second) { + L<second) { + L<= 0) + theL().setFacility(val); + else + L< addrs; + if(!::arg()["query-local-address6"].empty()) { + SyncRes::s_doIPv6=true; + L< ips; + stringtok(ips, ::arg()["dont-query"], ", "); + ips.push_back("0.0.0.0"); + ips.push_back("::"); + + L<::const_iterator i = ips.begin(); i!= ips.end(); ++i) { + SyncRes::addDontQuery(*i); + if(i!=ips.begin()) + L< SyncRes::s_packetcachettl) ? SyncRes::s_packetcachettl : packetCacheServFailTTL; + SyncRes::s_serverdownmaxfails=::arg().asNum("server-down-max-fails"); + SyncRes::s_serverdownthrottletime=::arg().asNum("server-down-throttle-time"); + SyncRes::s_serverID=::arg()["server-id"]; + SyncRes::s_maxqperq=::arg().asNum("max-qperq"); + SyncRes::s_maxtotusec=1000*::arg().asNum("max-total-msec"); + SyncRes::s_maxdepth=::arg().asNum("max-recursion-depth"); + SyncRes::s_rootNXTrust = ::arg().mustDo( "root-nx-trust"); + if(SyncRes::s_serverID.empty()) { + char tmp[128]; + gethostname(tmp, sizeof(tmp)-1); + SyncRes::s_serverID=tmp; + } + + SyncRes::s_ecsipv4limit = ::arg().asNum("ecs-ipv4-bits"); + SyncRes::s_ecsipv6limit = ::arg().asNum("ecs-ipv6-bits"); + + if (!::arg().isEmpty("ecs-scope-zero-address")) { + ComboAddress scopeZero(::arg()["ecs-scope-zero-address"]); + SyncRes::setECSScopeZeroAddress(Netmask(scopeZero, scopeZero.isIPv4() ? 32 : 128)); + } + else { + bool found = false; + for (const auto& addr : g_localQueryAddresses4) { + if (!IsAnyAddress(addr)) { + SyncRes::setECSScopeZeroAddress(Netmask(addr, 32)); + found = true; + break; + } + } + if (!found) { + for (const auto& addr : g_localQueryAddresses6) { + if (!IsAnyAddress(addr)) { + SyncRes::setECSScopeZeroAddress(Netmask(addr, 128)); + found = true; + break; + } + } + if (!found) { + SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32")); + } + } + } + + g_networkTimeoutMsec = ::arg().asNum("network-timeout"); + + g_initialDomainMap = parseAuthAndForwards(); + + g_latencyStatSize=::arg().asNum("latency-statistic-size"); + + g_logCommonErrors=::arg().mustDo("log-common-errors"); + g_logRPZChanges = ::arg().mustDo("log-rpz-changes"); + + g_anyToTcp = ::arg().mustDo("any-to-tcp"); + g_udpTruncationThreshold = ::arg().asNum("udp-truncation-threshold"); + + g_lowercaseOutgoing = ::arg().mustDo("lowercase-outgoing"); + + g_numWorkerThreads = ::arg().asNum("threads"); + if (g_numWorkerThreads < 1) { + L< 1 ? forks : -1); + + Utility::dropUserPrivs(newuid); + + makeThreadPipes(); + + g_tcpTimeout=::arg().asNum("client-tcp-timeout"); + g_maxTCPPerClient=::arg().asNum("max-tcp-per-client"); + g_tcpMaxQueriesPerConn=::arg().asNum("max-tcp-queries-per-connection"); + s_maxUDPQueriesPerRound=::arg().asNum("max-udp-queries-per-round"); + + if (::arg().mustDo("snmp-agent")) { + g_snmpAgent = std::make_shared("recursor", ::arg()["snmp-master-socket"]); + g_snmpAgent->run(); + } + + /* This thread handles the web server, carbon, statistics and the control channel */ + std::thread handlerThread(recursorThread, s_handlerThreadID, false); + + const auto cpusMap = parseCPUMap(); + + std::vector workers(g_numThreads); + if(g_numThreads == 1) { + L<(new UDPClientSocks()); + t_tcpClientCounts = std::unique_ptr(new tcpClientCounts_t()); + primeHints(); + + t_packetCache = std::unique_ptr(new RecursorPacketCache()); + +#ifdef HAVE_PROTOBUF + t_uuidGenerator = std::unique_ptr(new boost::uuids::random_generator()); +#endif + L<(::arg()["lua-dns-script"]); + L<(new addrringbuf_t()); + if(g_weDistributeQueries) // if so, only 1 thread does recvfrom + t_remotes->set_capacity(::arg().asNum("stats-ringbuffer-entries")); + else + t_remotes->set_capacity(ringsize); + t_servfailremotes = std::unique_ptr(new addrringbuf_t()); + t_servfailremotes->set_capacity(ringsize); + t_largeanswerremotes = std::unique_ptr(new addrringbuf_t()); + t_largeanswerremotes->set_capacity(ringsize); + + t_queryring = std::unique_ptr > >(new boost::circular_buffer >()); + t_queryring->set_capacity(ringsize); + t_servfailqueryring = std::unique_ptr > >(new boost::circular_buffer >()); + t_servfailqueryring->set_capacity(ringsize); + } + + MT=std::unique_ptr >(new MTasker(::arg().asNum("stack-size"))); + + PacketID pident; + + t_fdm=getMultiplexer(); + + if(!worker) { + if(::arg().mustDo("webserver")) { + L<getName() << "' multiplexer"<addReadFD(g_pipes[t_id].readToThread, handlePipeRequest); + t_fdm->addReadFD(g_pipes[t_id].readQueriesToThread, handlePipeRequest); + + if(g_useOneSocketPerThread) { + for(deferredAdd_t::const_iterator i = deferredAdds[t_id].cbegin(); i != deferredAdds[t_id].cend(); ++i) { + t_fdm->addReadFD(i->first, i->second); + } + } + else { + if(!g_weDistributeQueries || t_id == s_distributorThreadID) { // if we distribute queries, only t_id = 0 listens + for(deferredAdd_t::const_iterator i = deferredAdds[0].cbegin(); i != deferredAdds[0].cend(); ++i) { + t_fdm->addReadFD(i->first, i->second); + } + } + } + } + + registerAllStats(); + + if(!worker) { + t_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel + } + + unsigned int maxTcpClients=::arg().asNum("max-tcp-clients"); + + bool listenOnTCP(true); + + time_t last_stat = 0; + time_t last_carbon=0; + time_t carbonInterval=::arg().asNum("carbon-interval"); + counter.store(0); // used to periodically execute certain tasks + for(;;) { + while(MT->schedule(&g_now)); // MTasker letting the mthreads do their thing + + if(!(counter%500)) { + MT->makeThread(houseKeeping, 0); + } + + if(!(counter%55)) { + typedef vector > expired_t; + expired_t expired=t_fdm->getTimeouts(g_now); + + for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) { + shared_ptr conn=any_cast >(i->second); + if(g_logCommonErrors) + L<d_remote.toString() <removeReadFD(i->first); + } + } + + counter++; + + if(!worker) { + if(statsWanted || (g_statisticsInterval > 0 && (g_now.tv_sec - last_stat) >= g_statisticsInterval)) { + doStats(); + last_stat = g_now.tv_sec; + } + + Utility::gettimeofday(&g_now, 0); + + if((g_now.tv_sec - last_carbon) >= carbonInterval) { + MT->makeThread(doCarbonDump, 0); + last_carbon = g_now.tv_sec; + } + } + + t_fdm->run(&g_now); + // 'run' updates g_now for us + + if(worker && (!g_weDistributeQueries || t_id == s_distributorThreadID)) { // if pdns distributes queries, only tid 0 should do this + if(listenOnTCP) { + if(TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections + for(const auto fd : g_tcpListenSockets[t_id]) { + t_fdm->removeReadFD(fd); + } + listenOnTCP=false; + } + } + else { + if(TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable + for(const auto fd : g_tcpListenSockets[t_id]) { + t_fdm->addReadFD(fd, handleNewTCPQuestion); + } + listenOnTCP=true; + } + } + } + } +} +catch(PDNSException &ae) { + L< disabled )")="64"; + ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60"; + ::arg().set("hint-file", "If set, load root hints from this file")=""; + ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000"; + ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600"; + ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400"; + ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600"; + ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000"; + ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60"; + ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname")=""; + ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000"; + ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString(); + ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS; + ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")=""; + ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom"; + ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY; + ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0"; + ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection")="0"; + ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20"; + ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off"; + ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")=""; + ::arg().set("lua-config-file", "More powerful configuration options")=""; + + ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")=""; + ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")=""; + ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")=""; + ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off"; + ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")=""; + ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts"; + ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="yes"; + ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")=""; + ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000"; + ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no"; + ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24"; + ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56"; + ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")=""; + ::arg().set("ecs-scope-zero-address", "Address to send to whitelisted authoritative servers for incoming queries with ECS prefix-length source of 0")=""; + ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="no"; + ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes"; + ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes"; + ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no"; + ::arg().setSwitch( "lowercase-outgoing","Force outgoing questions to lowercase")="no"; + ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook")="no"; + ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680"; + ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size")="1680"; + ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0"; + ::arg().set("max-qperq", "Maximum outgoing queries per query")="50"; + ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000"; + ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40"; + ::arg().set("max-udp-queries-per-round", "Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing")="10000"; + + ::arg().set("include-dir","Include *.conf files from this directory")=""; + ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com."; + + ::arg().setSwitch("reuseport","Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address")="no"; + + ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent")="no"; + ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP master")=""; + + ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0"; + ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record")="2500"; + + ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs")=""; + + ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level")="no"; + + ::arg().setCmd("help","Provide a helpful message"); + ::arg().setCmd("version","Print version string"); + ::arg().setCmd("config","Output blank configuration"); + L.toConsole(Logger::Info); + ::arg().laxParse(argc,argv); // do a lax parse + + string configname=::arg()["config-dir"]+"/recursor.conf"; + if(::arg()["config-name"]!="") { + configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf"; + s_programname+="-"+::arg()["config-name"]; + } + cleanSlashes(configname); + + if(::arg().mustDo("config")) { + cout<<::arg().configstring()< + +#include "namespaces.hh" + +//! Generic Exception thrown +class PDNSException +{ +public: + PDNSException(){reason="Unspecified";}; + PDNSException(string r){reason=r;}; + + string reason; //! Print this to tell the user what went wrong +}; + +class TimeoutException : public PDNSException +{ +public: + TimeoutException() : PDNSException() {} + TimeoutException(string r) : PDNSException(r) {} +}; + +#endif diff --git a/portsmplexer.cc b/portsmplexer.cc new file mode 100644 index 0000000..c6e91e6 --- /dev/null +++ b/portsmplexer.cc @@ -0,0 +1,169 @@ +#if defined(__sun__) && defined(__svr4__) +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#endif +#include +#include "mplexer.hh" +#include "sstuff.hh" +#include + +#include "misc.hh" + +#include "namespaces.hh" + +class PortsFDMultiplexer : public FDMultiplexer +{ +public: + PortsFDMultiplexer(); + virtual ~PortsFDMultiplexer() + { + close(d_portfd); + } + + virtual int run(struct timeval* tv, int timeout=500); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "solaris completion ports"; + } +private: + int d_portfd; + boost::shared_array d_pevents; + static int s_maxevents; // not a hard maximum +}; + + +static FDMultiplexer* makePorts() +{ + return new PortsFDMultiplexer(); +} + +static struct PortsRegisterOurselves +{ + PortsRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makePorts)); // priority 0! + } +} doItPorts; + + +int PortsFDMultiplexer::s_maxevents=1024; +PortsFDMultiplexer::PortsFDMultiplexer() : d_pevents(new port_event_t[s_maxevents]) +{ + d_portfd=port_create(); // not hard max + if(d_portfd < 0) + throw FDMultiplexerException("Setting up port: "+stringerror()); +} + +void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + if(port_associate(d_portfd, PORT_SOURCE_FD, fd, (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT, 0) < 0) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to port set: "+stringerror()); + } +} + +void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); + + if(port_dissociate(d_portfd, PORT_SOURCE_FD, fd) < 0 && errno != ENOENT) // it appears under some circumstances, ENOENT will be returned, without this being an error. Apache has this same "fix" + throw FDMultiplexerException("Removing fd from port set: "+stringerror()); +} + +int PortsFDMultiplexer::run(struct timeval* now, int timeout) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + + struct timespec timeoutspec; + timeoutspec.tv_sec = time / 1000; + timeoutspec.tv_nsec = (time % 1000) * 1000000; + unsigned int numevents=1; + int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec); + + /* port_getn has an unusual API - (ret == -1, errno == ETIME) can + mean partial success; you must check (*numevents) in this case + and process anything in there, otherwise you'll never see any + events from that object again. We don't care about pure timeouts + (ret == -1, errno == ETIME, *numevents == 0) so we don't bother + with that case. */ + if(ret == -1 && errno!=ETIME) { + if(errno!=EINTR) + throw FDMultiplexerException("completion port_getn returned error: "+stringerror()); + // EINTR is not really an error + gettimeofday(now,0); + return 0; + } + gettimeofday(now,0); + if(!numevents) // nothing + return 0; + + d_inrun=true; + + for(unsigned int n=0; n < numevents; ++n) { + d_iter=d_readCallbacks.find(d_pevents[n].portev_object); + + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, + POLLIN, 0) < 0) + throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror()); + continue; // so we don't find ourselves as writable again + } + + d_iter=d_writeCallbacks.find(d_pevents[n].portev_object); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, + POLLOUT, 0) < 0) + throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror()); + } + + } + + d_inrun=false; + return numevents; +} + +#if 0 +void acceptData(int fd, boost::any& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "<set_qname(qname.toString()); + question->set_qtype(qtype); + question->set_qclass(qclass); + } +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setBytes(size_t bytes) +{ +#ifdef HAVE_PROTOBUF + d_message.set_inbytes(bytes); +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setResponseCode(uint8_t rcode) +{ +#ifdef HAVE_PROTOBUF + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (response) { + response->set_rcode(rcode); + } +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setTime(time_t sec, uint32_t usec) +{ +#ifdef HAVE_PROTOBUF + d_message.set_timesec(sec); + d_message.set_timeusec(usec); +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setQueryTime(time_t sec, uint32_t usec) +{ +#ifdef HAVE_PROTOBUF + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (response) { + response->set_querytimesec(sec); + response->set_querytimeusec(usec); + } +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setEDNSSubnet(const Netmask& subnet, uint8_t mask) +{ +#ifdef HAVE_PROTOBUF + if (!subnet.empty()) { + ComboAddress ca(subnet.getNetwork()); + ca.truncate(mask); + if (ca.sin4.sin_family == AF_INET) { + d_message.set_originalrequestorsubnet(&ca.sin4.sin_addr.s_addr, sizeof(ca.sin4.sin_addr.s_addr)); + } + else if (ca.sin4.sin_family == AF_INET6) { + d_message.set_originalrequestorsubnet(&ca.sin6.sin6_addr.s6_addr, sizeof(ca.sin6.sin6_addr.s6_addr)); + } + } +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::addTag(const std::string& strValue) +{ +#ifdef HAVE_PROTOBUF + + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (!response) + return; + + response->add_tags(strValue); + +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::addRR(const DNSName& qname, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob) +{ +#ifdef HAVE_PROTOBUF + + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (!response) + return; + PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs(); + if (rr) { + rr->set_name(qname.toString()); + rr->set_type(uType); + rr->set_class_(uClass); + rr->set_ttl(uTTL); + rr->set_rdata(strBlob.c_str(), strBlob.size()); + } + +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME) +{ +#ifdef HAVE_PROTOBUF + if (len < sizeof(struct dnsheader)) + return; + + const struct dnsheader* dh = (const struct dnsheader*) packet; + + if (ntohs(dh->ancount) == 0) + return; + + if (ntohs(dh->qdcount) == 0) + return; + + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (!response) + return; + + vector content(len - sizeof(dnsheader)); + copy(packet + sizeof(dnsheader), packet + len, content.begin()); + PacketReader pr(content); + + size_t idx = 0; + DNSName rrname; + uint16_t qdcount = ntohs(dh->qdcount); + uint16_t ancount = ntohs(dh->ancount); + uint16_t rrtype; + uint16_t rrclass; + string blob; + struct dnsrecordheader ah; + + rrname = pr.getName(); + rrtype = pr.get16BitInt(); + rrclass = pr.get16BitInt(); + + /* consume remaining qd if any */ + if (qdcount > 1) { + for(idx = 1; idx < qdcount; idx++) { + rrname = pr.getName(); + rrtype = pr.get16BitInt(); + rrclass = pr.get16BitInt(); + (void) rrtype; + (void) rrclass; + } + } + + /* parse AN */ + for (idx = 0; idx < ancount; idx++) { + rrname = pr.getName(); + pr.getDnsrecordheader(ah); + + if (ah.d_type == QType::A || ah.d_type == QType::AAAA) { + pr.xfrBlob(blob); + + PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs(); + if (rr) { + rr->set_name(rrname.toString()); + rr->set_type(ah.d_type); + rr->set_class_(ah.d_class); + rr->set_ttl(ah.d_ttl); + rr->set_rdata(blob.c_str(), blob.length()); + } + } else if (ah.d_type == QType::CNAME && includeCNAME) { + PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs(); + if (rr) { + rr->set_name(rrname.toString()); + rr->set_type(ah.d_type); + rr->set_class_(ah.d_class); + rr->set_ttl(ah.d_ttl); + DNSName target; + pr.xfrName(target, true); + rr->set_rdata(target.toString()); + } + } + else { + pr.xfrBlob(blob); + } + } +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setRequestor(const std::string& requestor) +{ +#ifdef HAVE_PROTOBUF + d_message.set_from(requestor); +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setRequestor(const ComboAddress& requestor) +{ +#ifdef HAVE_PROTOBUF + if (requestor.sin4.sin_family == AF_INET) { + d_message.set_from(&requestor.sin4.sin_addr.s_addr, sizeof(requestor.sin4.sin_addr.s_addr)); + } + else if (requestor.sin4.sin_family == AF_INET6) { + d_message.set_from(&requestor.sin6.sin6_addr.s6_addr, sizeof(requestor.sin6.sin6_addr.s6_addr)); + } +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setRequestorId(const std::string& requestorId) +{ +#ifdef HAVE_PROTOBUF + d_message.set_requestorid(requestorId); +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setDeviceId(const std::string& deviceId) +{ +#ifdef HAVE_PROTOBUF + d_message.set_deviceid(deviceId); +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setResponder(const std::string& responder) +{ +#ifdef HAVE_PROTOBUF + d_message.set_to(responder); +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::setResponder(const ComboAddress& responder) +{ +#ifdef HAVE_PROTOBUF + if (responder.sin4.sin_family == AF_INET) { + d_message.set_to(&responder.sin4.sin_addr.s_addr, sizeof(responder.sin4.sin_addr.s_addr)); + } + else if (responder.sin4.sin_family == AF_INET6) { + d_message.set_to(&responder.sin6.sin6_addr.s6_addr, sizeof(responder.sin6.sin6_addr.s6_addr)); + } +#endif /* HAVE_PROTOBUF */ +} + +void DNSProtoBufMessage::serialize(std::string& data) const +{ +#ifdef HAVE_PROTOBUF + d_message.SerializeToString(&data); +#endif /* HAVE_PROTOBUF */ +} + +std::string DNSProtoBufMessage::toDebugString() const +{ +#ifdef HAVE_PROTOBUF + return d_message.DebugString(); +#else + return std::string(); +#endif /* HAVE_PROTOBUF */ +} + +#ifdef HAVE_PROTOBUF + +void DNSProtoBufMessage::setUUID(const boost::uuids::uuid& uuid) +{ + std::string* messageId = d_message.mutable_messageid(); + messageId->resize(uuid.size()); + std::copy(uuid.begin(), uuid.end(), messageId->begin()); +} + +void DNSProtoBufMessage::setInitialRequestID(const boost::uuids::uuid& uuid) +{ + std::string* messageId = d_message.mutable_initialrequestid(); + messageId->resize(uuid.size()); + std::copy(uuid.begin(), uuid.end(), messageId->begin()); +} + +void DNSProtoBufMessage::update(const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, uint16_t id) +{ + struct timespec ts; + gettime(&ts, true); + setTime(ts.tv_sec, ts.tv_nsec / 1000); + + setUUID(uuid); + d_message.set_id(ntohs(id)); + + if (requestor) { + d_message.set_socketfamily(requestor->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6); + } + else if (responder) { + d_message.set_socketfamily(responder->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6); + } + + d_message.set_socketprotocol(isTCP ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP); + + if (responder) { + setResponder(*responder); + } + if (requestor) { + setRequestor(*requestor); + } +} + + +DNSProtoBufMessage::DNSProtoBufMessage(DNSProtoBufMessageType type, const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, const DNSName& domain, int qtype, uint16_t qclass, uint16_t qid, bool isTCP, size_t bytes) +{ + update(uuid, requestor, responder, isTCP, qid); + + setType(type); + + setBytes(bytes); + setQuestion(domain, qtype, qclass); +} + +#endif /* HAVE_PROTOBUF */ diff --git a/protobuf.hh b/protobuf.hh new file mode 100644 index 0000000..9c37851 --- /dev/null +++ b/protobuf.hh @@ -0,0 +1,86 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +#include +#include + +#include "config.h" + +#ifdef HAVE_PROTOBUF +#include +#include +#include "dnsmessage.pb.h" +#endif /* HAVE_PROTOBUF */ + +#include "dnsname.hh" +#include "iputils.hh" + +class DNSProtoBufMessage +{ +public: + enum DNSProtoBufMessageType { + Query, + Response, + OutgoingQuery, + IncomingResponse + }; + + DNSProtoBufMessage() + { + } + + DNSProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type); + + ~DNSProtoBufMessage() + { + } + + void setType(DNSProtoBufMessage::DNSProtoBufMessageType type); + void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass); + void setEDNSSubnet(const Netmask& subnet, uint8_t mask=128); + void setBytes(size_t bytes); + void setTime(time_t sec, uint32_t usec); + void setQueryTime(time_t sec, uint32_t usec); + void setResponseCode(uint8_t rcode); + void addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME=false); + void serialize(std::string& data) const; + void setRequestor(const std::string& requestor); + void setRequestor(const ComboAddress& requestor); + void setResponder(const std::string& responder); + void setResponder(const ComboAddress& responder); + void setRequestorId(const std::string& requestorId); + void setDeviceId(const std::string& deviceId); + std::string toDebugString() const; + void addTag(const std::string& strValue); + void addRR(const DNSName& qame, uint16_t utype, uint16_t uClass, uint32_t uTTl, const std::string& strBlob); + +#ifdef HAVE_PROTOBUF + DNSProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type, const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, const DNSName& domain, int qtype, uint16_t qclass, uint16_t qid, bool isTCP, size_t bytes); + void update(const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, uint16_t id); + void setUUID(const boost::uuids::uuid& uuid); + void setInitialRequestID(const boost::uuids::uuid& uuid); + +protected: + PBDNSMessage d_message; +#endif /* HAVE_PROTOBUF */ +}; diff --git a/pubsuffix.cc b/pubsuffix.cc new file mode 100644 index 0000000..2a8bf43 --- /dev/null +++ b/pubsuffix.cc @@ -0,0 +1,6733 @@ +const char* g_pubsuffix[]={ +"com.ac", +"edu.ac", +"gov.ac", +"net.ac", +"mil.ac", +"org.ac", +"nom.ad", +"co.ae", +"net.ae", +"org.ae", +"sch.ae", +"ac.ae", +"gov.ae", +"mil.ae", +"accident-investigation.aero", +"accident-prevention.aero", +"aerobatic.aero", +"aeroclub.aero", +"aerodrome.aero", +"agents.aero", +"aircraft.aero", +"airline.aero", +"airport.aero", +"air-surveillance.aero", +"airtraffic.aero", +"air-traffic-control.aero", +"ambulance.aero", +"amusement.aero", +"association.aero", +"author.aero", +"ballooning.aero", +"broker.aero", +"caa.aero", +"cargo.aero", +"catering.aero", +"certification.aero", +"championship.aero", +"charter.aero", +"civilaviation.aero", +"club.aero", +"conference.aero", +"consultant.aero", +"consulting.aero", +"control.aero", +"council.aero", +"crew.aero", +"design.aero", +"dgca.aero", +"educator.aero", +"emergency.aero", +"engine.aero", +"engineer.aero", +"entertainment.aero", +"equipment.aero", +"exchange.aero", +"express.aero", +"federation.aero", +"flight.aero", +"freight.aero", +"fuel.aero", +"gliding.aero", +"government.aero", +"groundhandling.aero", +"group.aero", +"hanggliding.aero", +"homebuilt.aero", +"insurance.aero", +"journal.aero", +"journalist.aero", +"leasing.aero", +"logistics.aero", +"magazine.aero", +"maintenance.aero", +"media.aero", +"microlight.aero", +"modelling.aero", +"navigation.aero", +"parachuting.aero", +"paragliding.aero", +"passenger-association.aero", +"pilot.aero", +"press.aero", +"production.aero", +"recreation.aero", +"repbody.aero", +"res.aero", +"research.aero", +"rotorcraft.aero", +"safety.aero", +"scientist.aero", +"services.aero", +"show.aero", +"skydiving.aero", +"software.aero", +"student.aero", +"trader.aero", +"trading.aero", +"trainer.aero", +"union.aero", +"workinggroup.aero", +"works.aero", +"gov.af", +"com.af", +"org.af", +"net.af", +"edu.af", +"com.ag", +"org.ag", +"net.ag", +"co.ag", +"nom.ag", +"off.ai", +"com.ai", +"net.ai", +"org.ai", +"com.al", +"edu.al", +"gov.al", +"mil.al", +"net.al", +"org.al", +"ed.ao", +"gv.ao", +"og.ao", +"co.ao", +"pb.ao", +"it.ao", +"com.ar", +"edu.ar", +"gob.ar", +"gov.ar", +"int.ar", +"mil.ar", +"musica.ar", +"net.ar", +"org.ar", +"tur.ar", +"e164.arpa", +"in-addr.arpa", +"ip6.arpa", +"iris.arpa", +"uri.arpa", +"urn.arpa", +"gov.as", +"ac.at", +"co.at", +"gv.at", +"or.at", +"com.au", +"net.au", +"org.au", +"edu.au", +"gov.au", +"asn.au", +"id.au", +"info.au", +"conf.au", +"oz.au", +"act.au", +"nsw.au", +"nt.au", +"qld.au", +"sa.au", +"tas.au", +"vic.au", +"wa.au", +"act.edu.au", +"nsw.edu.au", +"nt.edu.au", +"qld.edu.au", +"sa.edu.au", +"tas.edu.au", +"vic.edu.au", +"wa.edu.au", +"qld.gov.au", +"sa.gov.au", +"tas.gov.au", +"vic.gov.au", +"wa.gov.au", +"com.aw", +"com.az", +"net.az", +"int.az", +"gov.az", +"org.az", +"edu.az", +"info.az", +"pp.az", +"mil.az", +"name.az", +"pro.az", +"biz.az", +"com.ba", +"edu.ba", +"gov.ba", +"mil.ba", +"net.ba", +"org.ba", +"biz.bb", +"co.bb", +"com.bb", +"edu.bb", +"gov.bb", +"info.bb", +"net.bb", +"org.bb", +"store.bb", +"tv.bb", +"ac.be", +"gov.bf", +"a.bg", +"b.bg", +"c.bg", +"d.bg", +"e.bg", +"f.bg", +"g.bg", +"h.bg", +"i.bg", +"j.bg", +"k.bg", +"l.bg", +"m.bg", +"n.bg", +"o.bg", +"p.bg", +"q.bg", +"r.bg", +"s.bg", +"t.bg", +"u.bg", +"v.bg", +"w.bg", +"x.bg", +"y.bg", +"z.bg", +"0.bg", +"1.bg", +"2.bg", +"3.bg", +"4.bg", +"5.bg", +"6.bg", +"7.bg", +"8.bg", +"9.bg", +"com.bh", +"edu.bh", +"net.bh", +"org.bh", +"gov.bh", +"co.bi", +"com.bi", +"edu.bi", +"or.bi", +"org.bi", +"asso.bj", +"barreau.bj", +"gouv.bj", +"com.bm", +"edu.bm", +"gov.bm", +"net.bm", +"org.bm", +"com.bn", +"edu.bn", +"gov.bn", +"net.bn", +"org.bn", +"com.bo", +"edu.bo", +"gob.bo", +"int.bo", +"org.bo", +"net.bo", +"mil.bo", +"tv.bo", +"web.bo", +"academia.bo", +"agro.bo", +"arte.bo", +"blog.bo", +"bolivia.bo", +"ciencia.bo", +"cooperativa.bo", +"democracia.bo", +"deporte.bo", +"ecologia.bo", +"economia.bo", +"empresa.bo", +"indigena.bo", +"industria.bo", +"info.bo", +"medicina.bo", +"movimiento.bo", +"musica.bo", +"natural.bo", +"nombre.bo", +"noticias.bo", +"patria.bo", +"politica.bo", +"profesional.bo", +"plurinacional.bo", +"pueblo.bo", +"revista.bo", +"salud.bo", +"tecnologia.bo", +"tksat.bo", +"transporte.bo", +"wiki.bo", +"9guacu.br", +"abc.br", +"adm.br", +"adv.br", +"agr.br", +"aju.br", +"am.br", +"anani.br", +"aparecida.br", +"arq.br", +"art.br", +"ato.br", +"b.br", +"barueri.br", +"belem.br", +"bhz.br", +"bio.br", +"blog.br", +"bmd.br", +"boavista.br", +"bsb.br", +"campinagrande.br", +"campinas.br", +"caxias.br", +"cim.br", +"cng.br", +"cnt.br", +"com.br", +"contagem.br", +"coop.br", +"cri.br", +"cuiaba.br", +"curitiba.br", +"def.br", +"ecn.br", +"eco.br", +"edu.br", +"emp.br", +"eng.br", +"esp.br", +"etc.br", +"eti.br", +"far.br", +"feira.br", +"flog.br", +"floripa.br", +"fm.br", +"fnd.br", +"fortal.br", +"fot.br", +"foz.br", +"fst.br", +"g12.br", +"ggf.br", +"goiania.br", +"gov.br", +"ac.gov.br", +"al.gov.br", +"am.gov.br", +"ap.gov.br", +"ba.gov.br", +"ce.gov.br", +"df.gov.br", +"es.gov.br", +"go.gov.br", +"ma.gov.br", +"mg.gov.br", +"ms.gov.br", +"mt.gov.br", +"pa.gov.br", +"pb.gov.br", +"pe.gov.br", +"pi.gov.br", +"pr.gov.br", +"rj.gov.br", +"rn.gov.br", +"ro.gov.br", +"rr.gov.br", +"rs.gov.br", +"sc.gov.br", +"se.gov.br", +"sp.gov.br", +"to.gov.br", +"gru.br", +"imb.br", +"ind.br", +"inf.br", +"jab.br", +"jampa.br", +"jdf.br", +"joinville.br", +"jor.br", +"jus.br", +"leg.br", +"lel.br", +"londrina.br", +"macapa.br", +"maceio.br", +"manaus.br", +"maringa.br", +"mat.br", +"med.br", +"mil.br", +"morena.br", +"mp.br", +"mus.br", +"natal.br", +"net.br", +"niteroi.br", +"not.br", +"ntr.br", +"odo.br", +"ong.br", +"org.br", +"osasco.br", +"palmas.br", +"poa.br", +"ppg.br", +"pro.br", +"psc.br", +"psi.br", +"pvh.br", +"qsl.br", +"radio.br", +"rec.br", +"recife.br", +"ribeirao.br", +"rio.br", +"riobranco.br", +"riopreto.br", +"salvador.br", +"sampa.br", +"santamaria.br", +"santoandre.br", +"saobernardo.br", +"saogonca.br", +"sjc.br", +"slg.br", +"slz.br", +"sorocaba.br", +"srv.br", +"taxi.br", +"teo.br", +"the.br", +"tmp.br", +"trd.br", +"tur.br", +"tv.br", +"udi.br", +"vet.br", +"vix.br", +"vlog.br", +"wiki.br", +"zlg.br", +"com.bs", +"net.bs", +"org.bs", +"edu.bs", +"gov.bs", +"com.bt", +"edu.bt", +"gov.bt", +"net.bt", +"org.bt", +"co.bw", +"org.bw", +"gov.by", +"mil.by", +"com.by", +"of.by", +"com.bz", +"net.bz", +"org.bz", +"edu.bz", +"gov.bz", +"ab.ca", +"bc.ca", +"mb.ca", +"nb.ca", +"nf.ca", +"nl.ca", +"ns.ca", +"nt.ca", +"nu.ca", +"on.ca", +"pe.ca", +"qc.ca", +"sk.ca", +"yk.ca", +"gc.ca", +"gov.cd", +"org.ci", +"or.ci", +"com.ci", +"co.ci", +"edu.ci", +"ed.ci", +"ac.ci", +"net.ci", +"go.ci", +"asso.ci", +"int.ci", +"presse.ci", +"md.ci", +"gouv.ci", +"gov.cl", +"gob.cl", +"co.cl", +"mil.cl", +"co.cm", +"com.cm", +"gov.cm", +"net.cm", +"ac.cn", +"com.cn", +"edu.cn", +"gov.cn", +"net.cn", +"org.cn", +"mil.cn", +"ah.cn", +"bj.cn", +"cq.cn", +"fj.cn", +"gd.cn", +"gs.cn", +"gz.cn", +"gx.cn", +"ha.cn", +"hb.cn", +"he.cn", +"hi.cn", +"hl.cn", +"hn.cn", +"jl.cn", +"js.cn", +"jx.cn", +"ln.cn", +"nm.cn", +"nx.cn", +"qh.cn", +"sc.cn", +"sd.cn", +"sh.cn", +"sn.cn", +"sx.cn", +"tj.cn", +"xj.cn", +"xz.cn", +"yn.cn", +"zj.cn", +"hk.cn", +"mo.cn", +"tw.cn", +"arts.co", +"com.co", +"edu.co", +"firm.co", +"gov.co", +"info.co", +"int.co", +"mil.co", +"net.co", +"nom.co", +"org.co", +"rec.co", +"web.co", +"ac.cr", +"co.cr", +"ed.cr", +"fi.cr", +"go.cr", +"or.cr", +"sa.cr", +"com.cu", +"edu.cu", +"org.cu", +"net.cu", +"gov.cu", +"inf.cu", +"com.cw", +"edu.cw", +"net.cw", +"org.cw", +"gov.cx", +"ac.cy", +"biz.cy", +"com.cy", +"ekloges.cy", +"gov.cy", +"ltd.cy", +"name.cy", +"net.cy", +"org.cy", +"parliament.cy", +"press.cy", +"pro.cy", +"tm.cy", +"com.dm", +"net.dm", +"org.dm", +"edu.dm", +"gov.dm", +"art.do", +"com.do", +"edu.do", +"gob.do", +"gov.do", +"mil.do", +"net.do", +"org.do", +"sld.do", +"web.do", +"com.dz", +"org.dz", +"net.dz", +"gov.dz", +"edu.dz", +"asso.dz", +"pol.dz", +"art.dz", +"com.ec", +"info.ec", +"net.ec", +"fin.ec", +"k12.ec", +"med.ec", +"pro.ec", +"org.ec", +"edu.ec", +"gov.ec", +"gob.ec", +"mil.ec", +"edu.ee", +"gov.ee", +"riik.ee", +"lib.ee", +"med.ee", +"com.ee", +"pri.ee", +"aip.ee", +"org.ee", +"fie.ee", +"com.eg", +"edu.eg", +"eun.eg", +"gov.eg", +"mil.eg", +"name.eg", +"net.eg", +"org.eg", +"sci.eg", +"com.es", +"nom.es", +"org.es", +"gob.es", +"edu.es", +"com.et", +"gov.et", +"org.et", +"edu.et", +"biz.et", +"name.et", +"info.et", +"net.et", +"aland.fi", +"com.fr", +"asso.fr", +"nom.fr", +"prd.fr", +"presse.fr", +"tm.fr", +"aeroport.fr", +"assedic.fr", +"avocat.fr", +"avoues.fr", +"cci.fr", +"chambagri.fr", +"chirurgiens-dentistes.fr", +"experts-comptables.fr", +"geometre-expert.fr", +"gouv.fr", +"greta.fr", +"huissier-justice.fr", +"medecin.fr", +"notaires.fr", +"pharmacien.fr", +"port.fr", +"veterinaire.fr", +"com.ge", +"edu.ge", +"gov.ge", +"org.ge", +"mil.ge", +"net.ge", +"pvt.ge", +"co.gg", +"net.gg", +"org.gg", +"com.gh", +"edu.gh", +"gov.gh", +"org.gh", +"mil.gh", +"com.gi", +"ltd.gi", +"gov.gi", +"mod.gi", +"edu.gi", +"org.gi", +"co.gl", +"com.gl", +"edu.gl", +"net.gl", +"org.gl", +"ac.gn", +"com.gn", +"edu.gn", +"gov.gn", +"org.gn", +"net.gn", +"com.gp", +"net.gp", +"mobi.gp", +"edu.gp", +"org.gp", +"asso.gp", +"com.gr", +"edu.gr", +"net.gr", +"org.gr", +"gov.gr", +"com.gt", +"edu.gt", +"gob.gt", +"ind.gt", +"mil.gt", +"net.gt", +"org.gt", +"com.gu", +"edu.gu", +"gov.gu", +"guam.gu", +"info.gu", +"net.gu", +"org.gu", +"web.gu", +"co.gy", +"com.gy", +"edu.gy", +"gov.gy", +"net.gy", +"org.gy", +"com.hk", +"edu.hk", +"gov.hk", +"idv.hk", +"net.hk", +"org.hk", +"com.hn", +"edu.hn", +"org.hn", +"net.hn", +"mil.hn", +"gob.hn", +"iz.hr", +"from.hr", +"name.hr", +"com.hr", +"com.ht", +"shop.ht", +"firm.ht", +"info.ht", +"adult.ht", +"net.ht", +"pro.ht", +"org.ht", +"med.ht", +"art.ht", +"coop.ht", +"pol.ht", +"asso.ht", +"edu.ht", +"rel.ht", +"gouv.ht", +"perso.ht", +"co.hu", +"info.hu", +"org.hu", +"priv.hu", +"sport.hu", +"tm.hu", +"2000.hu", +"agrar.hu", +"bolt.hu", +"casino.hu", +"city.hu", +"erotica.hu", +"erotika.hu", +"film.hu", +"forum.hu", +"games.hu", +"hotel.hu", +"ingatlan.hu", +"jogasz.hu", +"konyvelo.hu", +"lakas.hu", +"media.hu", +"news.hu", +"reklam.hu", +"sex.hu", +"shop.hu", +"suli.hu", +"szex.hu", +"tozsde.hu", +"utazas.hu", +"video.hu", +"ac.id", +"biz.id", +"co.id", +"desa.id", +"go.id", +"mil.id", +"my.id", +"net.id", +"or.id", +"ponpes.id", +"sch.id", +"web.id", +"gov.ie", +"ac.il", +"co.il", +"gov.il", +"idf.il", +"k12.il", +"muni.il", +"net.il", +"org.il", +"ac.im", +"co.im", +"com.im", +"ltd.co.im", +"net.im", +"org.im", +"plc.co.im", +"tt.im", +"tv.im", +"co.in", +"firm.in", +"net.in", +"org.in", +"gen.in", +"ind.in", +"nic.in", +"ac.in", +"edu.in", +"res.in", +"gov.in", +"mil.in", +"eu.int", +"com.io", +"gov.iq", +"edu.iq", +"mil.iq", +"com.iq", +"org.iq", +"net.iq", +"ac.ir", +"co.ir", +"gov.ir", +"id.ir", +"net.ir", +"org.ir", +"sch.ir", +"net.is", +"com.is", +"edu.is", +"gov.is", +"org.is", +"int.is", +"gov.it", +"edu.it", +"abr.it", +"abruzzo.it", +"aosta-valley.it", +"aostavalley.it", +"bas.it", +"basilicata.it", +"cal.it", +"calabria.it", +"cam.it", +"campania.it", +"emilia-romagna.it", +"emiliaromagna.it", +"emr.it", +"friuli-v-giulia.it", +"friuli-ve-giulia.it", +"friuli-vegiulia.it", +"friuli-venezia-giulia.it", +"friuli-veneziagiulia.it", +"friuli-vgiulia.it", +"friuliv-giulia.it", +"friulive-giulia.it", +"friulivegiulia.it", +"friulivenezia-giulia.it", +"friuliveneziagiulia.it", +"friulivgiulia.it", +"fvg.it", +"laz.it", +"lazio.it", +"lig.it", +"liguria.it", +"lom.it", +"lombardia.it", +"lombardy.it", +"lucania.it", +"mar.it", +"marche.it", +"mol.it", +"molise.it", +"piedmont.it", +"piemonte.it", +"pmn.it", +"pug.it", +"puglia.it", +"sar.it", +"sardegna.it", +"sardinia.it", +"sic.it", +"sicilia.it", +"sicily.it", +"taa.it", +"tos.it", +"toscana.it", +"trentin-sud-tirol.it", +"trentin-sudtirol.it", +"trentin-sued-tirol.it", +"trentin-suedtirol.it", +"trentino-a-adige.it", +"trentino-aadige.it", +"trentino-alto-adige.it", +"trentino-altoadige.it", +"trentino-s-tirol.it", +"trentino-stirol.it", +"trentino-sud-tirol.it", +"trentino-sudtirol.it", +"trentino-sued-tirol.it", +"trentino-suedtirol.it", +"trentino.it", +"trentinoa-adige.it", +"trentinoaadige.it", +"trentinoalto-adige.it", +"trentinoaltoadige.it", +"trentinos-tirol.it", +"trentinostirol.it", +"trentinosud-tirol.it", +"trentinosudtirol.it", +"trentinosued-tirol.it", +"trentinosuedtirol.it", +"trentinsud-tirol.it", +"trentinsudtirol.it", +"trentinsued-tirol.it", +"trentinsuedtirol.it", +"tuscany.it", +"umb.it", +"umbria.it", +"val-d-aosta.it", +"val-daosta.it", +"vald-aosta.it", +"valdaosta.it", +"valle-aosta.it", +"valle-d-aosta.it", +"valle-daosta.it", +"valleaosta.it", +"valled-aosta.it", +"valledaosta.it", +"vallee-aoste.it", +"vallee-d-aoste.it", +"valleeaoste.it", +"valleedaoste.it", +"vao.it", +"vda.it", +"ven.it", +"veneto.it", +"ag.it", +"agrigento.it", +"al.it", +"alessandria.it", +"alto-adige.it", +"altoadige.it", +"an.it", +"ancona.it", +"andria-barletta-trani.it", +"andria-trani-barletta.it", +"andriabarlettatrani.it", +"andriatranibarletta.it", +"ao.it", +"aosta.it", +"aoste.it", +"ap.it", +"aq.it", +"aquila.it", +"ar.it", +"arezzo.it", +"ascoli-piceno.it", +"ascolipiceno.it", +"asti.it", +"at.it", +"av.it", +"avellino.it", +"ba.it", +"balsan-sudtirol.it", +"balsan-suedtirol.it", +"balsan.it", +"bari.it", +"barletta-trani-andria.it", +"barlettatraniandria.it", +"belluno.it", +"benevento.it", +"bergamo.it", +"bg.it", +"bi.it", +"biella.it", +"bl.it", +"bn.it", +"bo.it", +"bologna.it", +"bolzano-altoadige.it", +"bolzano.it", +"bozen-sudtirol.it", +"bozen-suedtirol.it", +"bozen.it", +"br.it", +"brescia.it", +"brindisi.it", +"bs.it", +"bt.it", +"bulsan-sudtirol.it", +"bulsan-suedtirol.it", +"bulsan.it", +"bz.it", +"ca.it", +"cagliari.it", +"caltanissetta.it", +"campidano-medio.it", +"campidanomedio.it", +"campobasso.it", +"carbonia-iglesias.it", +"carboniaiglesias.it", +"carrara-massa.it", +"carraramassa.it", +"caserta.it", +"catania.it", +"catanzaro.it", +"cb.it", +"ce.it", +"cesena-forli.it", +"cesenaforli.it", +"ch.it", +"chieti.it", +"ci.it", +"cl.it", +"cn.it", +"co.it", +"como.it", +"cosenza.it", +"cr.it", +"cremona.it", +"crotone.it", +"cs.it", +"ct.it", +"cuneo.it", +"cz.it", +"dell-ogliastra.it", +"dellogliastra.it", +"en.it", +"enna.it", +"fc.it", +"fe.it", +"fermo.it", +"ferrara.it", +"fg.it", +"fi.it", +"firenze.it", +"florence.it", +"fm.it", +"foggia.it", +"forli-cesena.it", +"forlicesena.it", +"fr.it", +"frosinone.it", +"ge.it", +"genoa.it", +"genova.it", +"go.it", +"gorizia.it", +"gr.it", +"grosseto.it", +"iglesias-carbonia.it", +"iglesiascarbonia.it", +"im.it", +"imperia.it", +"is.it", +"isernia.it", +"kr.it", +"la-spezia.it", +"laquila.it", +"laspezia.it", +"latina.it", +"lc.it", +"le.it", +"lecce.it", +"lecco.it", +"li.it", +"livorno.it", +"lo.it", +"lodi.it", +"lt.it", +"lu.it", +"lucca.it", +"macerata.it", +"mantova.it", +"massa-carrara.it", +"massacarrara.it", +"matera.it", +"mb.it", +"mc.it", +"me.it", +"medio-campidano.it", +"mediocampidano.it", +"messina.it", +"mi.it", +"milan.it", +"milano.it", +"mn.it", +"mo.it", +"modena.it", +"monza-brianza.it", +"monza-e-della-brianza.it", +"monza.it", +"monzabrianza.it", +"monzaebrianza.it", +"monzaedellabrianza.it", +"ms.it", +"mt.it", +"na.it", +"naples.it", +"napoli.it", +"no.it", +"novara.it", +"nu.it", +"nuoro.it", +"og.it", +"ogliastra.it", +"olbia-tempio.it", +"olbiatempio.it", +"or.it", +"oristano.it", +"ot.it", +"pa.it", +"padova.it", +"padua.it", +"palermo.it", +"parma.it", +"pavia.it", +"pc.it", +"pd.it", +"pe.it", +"perugia.it", +"pesaro-urbino.it", +"pesarourbino.it", +"pescara.it", +"pg.it", +"pi.it", +"piacenza.it", +"pisa.it", +"pistoia.it", +"pn.it", +"po.it", +"pordenone.it", +"potenza.it", +"pr.it", +"prato.it", +"pt.it", +"pu.it", +"pv.it", +"pz.it", +"ra.it", +"ragusa.it", +"ravenna.it", +"rc.it", +"re.it", +"reggio-calabria.it", +"reggio-emilia.it", +"reggiocalabria.it", +"reggioemilia.it", +"rg.it", +"ri.it", +"rieti.it", +"rimini.it", +"rm.it", +"rn.it", +"ro.it", +"roma.it", +"rome.it", +"rovigo.it", +"sa.it", +"salerno.it", +"sassari.it", +"savona.it", +"si.it", +"siena.it", +"siracusa.it", +"so.it", +"sondrio.it", +"sp.it", +"sr.it", +"ss.it", +"suedtirol.it", +"sv.it", +"ta.it", +"taranto.it", +"te.it", +"tempio-olbia.it", +"tempioolbia.it", +"teramo.it", +"terni.it", +"tn.it", +"to.it", +"torino.it", +"tp.it", +"tr.it", +"trani-andria-barletta.it", +"trani-barletta-andria.it", +"traniandriabarletta.it", +"tranibarlettaandria.it", +"trapani.it", +"trento.it", +"treviso.it", +"trieste.it", +"ts.it", +"turin.it", +"tv.it", +"ud.it", +"udine.it", +"urbino-pesaro.it", +"urbinopesaro.it", +"va.it", +"varese.it", +"vb.it", +"vc.it", +"ve.it", +"venezia.it", +"venice.it", +"verbania.it", +"vercelli.it", +"verona.it", +"vi.it", +"vibo-valentia.it", +"vibovalentia.it", +"vicenza.it", +"viterbo.it", +"vr.it", +"vs.it", +"vt.it", +"vv.it", +"co.je", +"net.je", +"org.je", +"com.jo", +"org.jo", +"net.jo", +"edu.jo", +"sch.jo", +"gov.jo", +"mil.jo", +"name.jo", +"ac.jp", +"ad.jp", +"co.jp", +"ed.jp", +"go.jp", +"gr.jp", +"lg.jp", +"ne.jp", +"or.jp", +"aichi.jp", +"akita.jp", +"aomori.jp", +"chiba.jp", +"ehime.jp", +"fukui.jp", +"fukuoka.jp", +"fukushima.jp", +"gifu.jp", +"gunma.jp", +"hiroshima.jp", +"hokkaido.jp", +"hyogo.jp", +"ibaraki.jp", +"ishikawa.jp", +"iwate.jp", +"kagawa.jp", +"kagoshima.jp", +"kanagawa.jp", +"kochi.jp", +"kumamoto.jp", +"kyoto.jp", +"mie.jp", +"miyagi.jp", +"miyazaki.jp", +"nagano.jp", +"nagasaki.jp", +"nara.jp", +"niigata.jp", +"oita.jp", +"okayama.jp", +"okinawa.jp", +"osaka.jp", +"saga.jp", +"saitama.jp", +"shiga.jp", +"shimane.jp", +"shizuoka.jp", +"tochigi.jp", +"tokushima.jp", +"tokyo.jp", +"tottori.jp", +"toyama.jp", +"wakayama.jp", +"yamagata.jp", +"yamaguchi.jp", +"yamanashi.jp", +"aisai.aichi.jp", +"ama.aichi.jp", +"anjo.aichi.jp", +"asuke.aichi.jp", +"chiryu.aichi.jp", +"chita.aichi.jp", +"fuso.aichi.jp", +"gamagori.aichi.jp", +"handa.aichi.jp", +"hazu.aichi.jp", +"hekinan.aichi.jp", +"higashiura.aichi.jp", +"ichinomiya.aichi.jp", +"inazawa.aichi.jp", +"inuyama.aichi.jp", +"isshiki.aichi.jp", +"iwakura.aichi.jp", +"kanie.aichi.jp", +"kariya.aichi.jp", +"kasugai.aichi.jp", +"kira.aichi.jp", +"kiyosu.aichi.jp", +"komaki.aichi.jp", +"konan.aichi.jp", +"kota.aichi.jp", +"mihama.aichi.jp", +"miyoshi.aichi.jp", +"nishio.aichi.jp", +"nisshin.aichi.jp", +"obu.aichi.jp", +"oguchi.aichi.jp", +"oharu.aichi.jp", +"okazaki.aichi.jp", +"owariasahi.aichi.jp", +"seto.aichi.jp", +"shikatsu.aichi.jp", +"shinshiro.aichi.jp", +"shitara.aichi.jp", +"tahara.aichi.jp", +"takahama.aichi.jp", +"tobishima.aichi.jp", +"toei.aichi.jp", +"togo.aichi.jp", +"tokai.aichi.jp", +"tokoname.aichi.jp", +"toyoake.aichi.jp", +"toyohashi.aichi.jp", +"toyokawa.aichi.jp", +"toyone.aichi.jp", +"toyota.aichi.jp", +"tsushima.aichi.jp", +"yatomi.aichi.jp", +"akita.akita.jp", +"daisen.akita.jp", +"fujisato.akita.jp", +"gojome.akita.jp", +"hachirogata.akita.jp", +"happou.akita.jp", +"higashinaruse.akita.jp", +"honjo.akita.jp", +"honjyo.akita.jp", +"ikawa.akita.jp", +"kamikoani.akita.jp", +"kamioka.akita.jp", +"katagami.akita.jp", +"kazuno.akita.jp", +"kitaakita.akita.jp", +"kosaka.akita.jp", +"kyowa.akita.jp", +"misato.akita.jp", +"mitane.akita.jp", +"moriyoshi.akita.jp", +"nikaho.akita.jp", +"noshiro.akita.jp", +"odate.akita.jp", +"oga.akita.jp", +"ogata.akita.jp", +"semboku.akita.jp", +"yokote.akita.jp", +"yurihonjo.akita.jp", +"aomori.aomori.jp", +"gonohe.aomori.jp", +"hachinohe.aomori.jp", +"hashikami.aomori.jp", +"hiranai.aomori.jp", +"hirosaki.aomori.jp", +"itayanagi.aomori.jp", +"kuroishi.aomori.jp", +"misawa.aomori.jp", +"mutsu.aomori.jp", +"nakadomari.aomori.jp", +"noheji.aomori.jp", +"oirase.aomori.jp", +"owani.aomori.jp", +"rokunohe.aomori.jp", +"sannohe.aomori.jp", +"shichinohe.aomori.jp", +"shingo.aomori.jp", +"takko.aomori.jp", +"towada.aomori.jp", +"tsugaru.aomori.jp", +"tsuruta.aomori.jp", +"abiko.chiba.jp", +"asahi.chiba.jp", +"chonan.chiba.jp", +"chosei.chiba.jp", +"choshi.chiba.jp", +"chuo.chiba.jp", +"funabashi.chiba.jp", +"futtsu.chiba.jp", +"hanamigawa.chiba.jp", +"ichihara.chiba.jp", +"ichikawa.chiba.jp", +"ichinomiya.chiba.jp", +"inzai.chiba.jp", +"isumi.chiba.jp", +"kamagaya.chiba.jp", +"kamogawa.chiba.jp", +"kashiwa.chiba.jp", +"katori.chiba.jp", +"katsuura.chiba.jp", +"kimitsu.chiba.jp", +"kisarazu.chiba.jp", +"kozaki.chiba.jp", +"kujukuri.chiba.jp", +"kyonan.chiba.jp", +"matsudo.chiba.jp", +"midori.chiba.jp", +"mihama.chiba.jp", +"minamiboso.chiba.jp", +"mobara.chiba.jp", +"mutsuzawa.chiba.jp", +"nagara.chiba.jp", +"nagareyama.chiba.jp", +"narashino.chiba.jp", +"narita.chiba.jp", +"noda.chiba.jp", +"oamishirasato.chiba.jp", +"omigawa.chiba.jp", +"onjuku.chiba.jp", +"otaki.chiba.jp", +"sakae.chiba.jp", +"sakura.chiba.jp", +"shimofusa.chiba.jp", +"shirako.chiba.jp", +"shiroi.chiba.jp", +"shisui.chiba.jp", +"sodegaura.chiba.jp", +"sosa.chiba.jp", +"tako.chiba.jp", +"tateyama.chiba.jp", +"togane.chiba.jp", +"tohnosho.chiba.jp", +"tomisato.chiba.jp", +"urayasu.chiba.jp", +"yachimata.chiba.jp", +"yachiyo.chiba.jp", +"yokaichiba.chiba.jp", +"yokoshibahikari.chiba.jp", +"yotsukaido.chiba.jp", +"ainan.ehime.jp", +"honai.ehime.jp", +"ikata.ehime.jp", +"imabari.ehime.jp", +"iyo.ehime.jp", +"kamijima.ehime.jp", +"kihoku.ehime.jp", +"kumakogen.ehime.jp", +"masaki.ehime.jp", +"matsuno.ehime.jp", +"matsuyama.ehime.jp", +"namikata.ehime.jp", +"niihama.ehime.jp", +"ozu.ehime.jp", +"saijo.ehime.jp", +"seiyo.ehime.jp", +"shikokuchuo.ehime.jp", +"tobe.ehime.jp", +"toon.ehime.jp", +"uchiko.ehime.jp", +"uwajima.ehime.jp", +"yawatahama.ehime.jp", +"echizen.fukui.jp", +"eiheiji.fukui.jp", +"fukui.fukui.jp", +"ikeda.fukui.jp", +"katsuyama.fukui.jp", +"mihama.fukui.jp", +"minamiechizen.fukui.jp", +"obama.fukui.jp", +"ohi.fukui.jp", +"ono.fukui.jp", +"sabae.fukui.jp", +"sakai.fukui.jp", +"takahama.fukui.jp", +"tsuruga.fukui.jp", +"wakasa.fukui.jp", +"ashiya.fukuoka.jp", +"buzen.fukuoka.jp", +"chikugo.fukuoka.jp", +"chikuho.fukuoka.jp", +"chikujo.fukuoka.jp", +"chikushino.fukuoka.jp", +"chikuzen.fukuoka.jp", +"chuo.fukuoka.jp", +"dazaifu.fukuoka.jp", +"fukuchi.fukuoka.jp", +"hakata.fukuoka.jp", +"higashi.fukuoka.jp", +"hirokawa.fukuoka.jp", +"hisayama.fukuoka.jp", +"iizuka.fukuoka.jp", +"inatsuki.fukuoka.jp", +"kaho.fukuoka.jp", +"kasuga.fukuoka.jp", +"kasuya.fukuoka.jp", +"kawara.fukuoka.jp", +"keisen.fukuoka.jp", +"koga.fukuoka.jp", +"kurate.fukuoka.jp", +"kurogi.fukuoka.jp", +"kurume.fukuoka.jp", +"minami.fukuoka.jp", +"miyako.fukuoka.jp", +"miyama.fukuoka.jp", +"miyawaka.fukuoka.jp", +"mizumaki.fukuoka.jp", +"munakata.fukuoka.jp", +"nakagawa.fukuoka.jp", +"nakama.fukuoka.jp", +"nishi.fukuoka.jp", +"nogata.fukuoka.jp", +"ogori.fukuoka.jp", +"okagaki.fukuoka.jp", +"okawa.fukuoka.jp", +"oki.fukuoka.jp", +"omuta.fukuoka.jp", +"onga.fukuoka.jp", +"onojo.fukuoka.jp", +"oto.fukuoka.jp", +"saigawa.fukuoka.jp", +"sasaguri.fukuoka.jp", +"shingu.fukuoka.jp", +"shinyoshitomi.fukuoka.jp", +"shonai.fukuoka.jp", +"soeda.fukuoka.jp", +"sue.fukuoka.jp", +"tachiarai.fukuoka.jp", +"tagawa.fukuoka.jp", +"takata.fukuoka.jp", +"toho.fukuoka.jp", +"toyotsu.fukuoka.jp", +"tsuiki.fukuoka.jp", +"ukiha.fukuoka.jp", +"umi.fukuoka.jp", +"usui.fukuoka.jp", +"yamada.fukuoka.jp", +"yame.fukuoka.jp", +"yanagawa.fukuoka.jp", +"yukuhashi.fukuoka.jp", +"aizubange.fukushima.jp", +"aizumisato.fukushima.jp", +"aizuwakamatsu.fukushima.jp", +"asakawa.fukushima.jp", +"bandai.fukushima.jp", +"date.fukushima.jp", +"fukushima.fukushima.jp", +"furudono.fukushima.jp", +"futaba.fukushima.jp", +"hanawa.fukushima.jp", +"higashi.fukushima.jp", +"hirata.fukushima.jp", +"hirono.fukushima.jp", +"iitate.fukushima.jp", +"inawashiro.fukushima.jp", +"ishikawa.fukushima.jp", +"iwaki.fukushima.jp", +"izumizaki.fukushima.jp", +"kagamiishi.fukushima.jp", +"kaneyama.fukushima.jp", +"kawamata.fukushima.jp", +"kitakata.fukushima.jp", +"kitashiobara.fukushima.jp", +"koori.fukushima.jp", +"koriyama.fukushima.jp", +"kunimi.fukushima.jp", +"miharu.fukushima.jp", +"mishima.fukushima.jp", +"namie.fukushima.jp", +"nango.fukushima.jp", +"nishiaizu.fukushima.jp", +"nishigo.fukushima.jp", +"okuma.fukushima.jp", +"omotego.fukushima.jp", +"ono.fukushima.jp", +"otama.fukushima.jp", +"samegawa.fukushima.jp", +"shimogo.fukushima.jp", +"shirakawa.fukushima.jp", +"showa.fukushima.jp", +"soma.fukushima.jp", +"sukagawa.fukushima.jp", +"taishin.fukushima.jp", +"tamakawa.fukushima.jp", +"tanagura.fukushima.jp", +"tenei.fukushima.jp", +"yabuki.fukushima.jp", +"yamato.fukushima.jp", +"yamatsuri.fukushima.jp", +"yanaizu.fukushima.jp", +"yugawa.fukushima.jp", +"anpachi.gifu.jp", +"ena.gifu.jp", +"gifu.gifu.jp", +"ginan.gifu.jp", +"godo.gifu.jp", +"gujo.gifu.jp", +"hashima.gifu.jp", +"hichiso.gifu.jp", +"hida.gifu.jp", +"higashishirakawa.gifu.jp", +"ibigawa.gifu.jp", +"ikeda.gifu.jp", +"kakamigahara.gifu.jp", +"kani.gifu.jp", +"kasahara.gifu.jp", +"kasamatsu.gifu.jp", +"kawaue.gifu.jp", +"kitagata.gifu.jp", +"mino.gifu.jp", +"minokamo.gifu.jp", +"mitake.gifu.jp", +"mizunami.gifu.jp", +"motosu.gifu.jp", +"nakatsugawa.gifu.jp", +"ogaki.gifu.jp", +"sakahogi.gifu.jp", +"seki.gifu.jp", +"sekigahara.gifu.jp", +"shirakawa.gifu.jp", +"tajimi.gifu.jp", +"takayama.gifu.jp", +"tarui.gifu.jp", +"toki.gifu.jp", +"tomika.gifu.jp", +"wanouchi.gifu.jp", +"yamagata.gifu.jp", +"yaotsu.gifu.jp", +"yoro.gifu.jp", +"annaka.gunma.jp", +"chiyoda.gunma.jp", +"fujioka.gunma.jp", +"higashiagatsuma.gunma.jp", +"isesaki.gunma.jp", +"itakura.gunma.jp", +"kanna.gunma.jp", +"kanra.gunma.jp", +"katashina.gunma.jp", +"kawaba.gunma.jp", +"kiryu.gunma.jp", +"kusatsu.gunma.jp", +"maebashi.gunma.jp", +"meiwa.gunma.jp", +"midori.gunma.jp", +"minakami.gunma.jp", +"naganohara.gunma.jp", +"nakanojo.gunma.jp", +"nanmoku.gunma.jp", +"numata.gunma.jp", +"oizumi.gunma.jp", +"ora.gunma.jp", +"ota.gunma.jp", +"shibukawa.gunma.jp", +"shimonita.gunma.jp", +"shinto.gunma.jp", +"showa.gunma.jp", +"takasaki.gunma.jp", +"takayama.gunma.jp", +"tamamura.gunma.jp", +"tatebayashi.gunma.jp", +"tomioka.gunma.jp", +"tsukiyono.gunma.jp", +"tsumagoi.gunma.jp", +"ueno.gunma.jp", +"yoshioka.gunma.jp", +"asaminami.hiroshima.jp", +"daiwa.hiroshima.jp", +"etajima.hiroshima.jp", +"fuchu.hiroshima.jp", +"fukuyama.hiroshima.jp", +"hatsukaichi.hiroshima.jp", +"higashihiroshima.hiroshima.jp", +"hongo.hiroshima.jp", +"jinsekikogen.hiroshima.jp", +"kaita.hiroshima.jp", +"kui.hiroshima.jp", +"kumano.hiroshima.jp", +"kure.hiroshima.jp", +"mihara.hiroshima.jp", +"miyoshi.hiroshima.jp", +"naka.hiroshima.jp", +"onomichi.hiroshima.jp", +"osakikamijima.hiroshima.jp", +"otake.hiroshima.jp", +"saka.hiroshima.jp", +"sera.hiroshima.jp", +"seranishi.hiroshima.jp", +"shinichi.hiroshima.jp", +"shobara.hiroshima.jp", +"takehara.hiroshima.jp", +"abashiri.hokkaido.jp", +"abira.hokkaido.jp", +"aibetsu.hokkaido.jp", +"akabira.hokkaido.jp", +"akkeshi.hokkaido.jp", +"asahikawa.hokkaido.jp", +"ashibetsu.hokkaido.jp", +"ashoro.hokkaido.jp", +"assabu.hokkaido.jp", +"atsuma.hokkaido.jp", +"bibai.hokkaido.jp", +"biei.hokkaido.jp", +"bifuka.hokkaido.jp", +"bihoro.hokkaido.jp", +"biratori.hokkaido.jp", +"chippubetsu.hokkaido.jp", +"chitose.hokkaido.jp", +"date.hokkaido.jp", +"ebetsu.hokkaido.jp", +"embetsu.hokkaido.jp", +"eniwa.hokkaido.jp", +"erimo.hokkaido.jp", +"esan.hokkaido.jp", +"esashi.hokkaido.jp", +"fukagawa.hokkaido.jp", +"fukushima.hokkaido.jp", +"furano.hokkaido.jp", +"furubira.hokkaido.jp", +"haboro.hokkaido.jp", +"hakodate.hokkaido.jp", +"hamatonbetsu.hokkaido.jp", +"hidaka.hokkaido.jp", +"higashikagura.hokkaido.jp", +"higashikawa.hokkaido.jp", +"hiroo.hokkaido.jp", +"hokuryu.hokkaido.jp", +"hokuto.hokkaido.jp", +"honbetsu.hokkaido.jp", +"horokanai.hokkaido.jp", +"horonobe.hokkaido.jp", +"ikeda.hokkaido.jp", +"imakane.hokkaido.jp", +"ishikari.hokkaido.jp", +"iwamizawa.hokkaido.jp", +"iwanai.hokkaido.jp", +"kamifurano.hokkaido.jp", +"kamikawa.hokkaido.jp", +"kamishihoro.hokkaido.jp", +"kamisunagawa.hokkaido.jp", +"kamoenai.hokkaido.jp", +"kayabe.hokkaido.jp", +"kembuchi.hokkaido.jp", +"kikonai.hokkaido.jp", +"kimobetsu.hokkaido.jp", +"kitahiroshima.hokkaido.jp", +"kitami.hokkaido.jp", +"kiyosato.hokkaido.jp", +"koshimizu.hokkaido.jp", +"kunneppu.hokkaido.jp", +"kuriyama.hokkaido.jp", +"kuromatsunai.hokkaido.jp", +"kushiro.hokkaido.jp", +"kutchan.hokkaido.jp", +"kyowa.hokkaido.jp", +"mashike.hokkaido.jp", +"matsumae.hokkaido.jp", +"mikasa.hokkaido.jp", +"minamifurano.hokkaido.jp", +"mombetsu.hokkaido.jp", +"moseushi.hokkaido.jp", +"mukawa.hokkaido.jp", +"muroran.hokkaido.jp", +"naie.hokkaido.jp", +"nakagawa.hokkaido.jp", +"nakasatsunai.hokkaido.jp", +"nakatombetsu.hokkaido.jp", +"nanae.hokkaido.jp", +"nanporo.hokkaido.jp", +"nayoro.hokkaido.jp", +"nemuro.hokkaido.jp", +"niikappu.hokkaido.jp", +"niki.hokkaido.jp", +"nishiokoppe.hokkaido.jp", +"noboribetsu.hokkaido.jp", +"numata.hokkaido.jp", +"obihiro.hokkaido.jp", +"obira.hokkaido.jp", +"oketo.hokkaido.jp", +"okoppe.hokkaido.jp", +"otaru.hokkaido.jp", +"otobe.hokkaido.jp", +"otofuke.hokkaido.jp", +"otoineppu.hokkaido.jp", +"oumu.hokkaido.jp", +"ozora.hokkaido.jp", +"pippu.hokkaido.jp", +"rankoshi.hokkaido.jp", +"rebun.hokkaido.jp", +"rikubetsu.hokkaido.jp", +"rishiri.hokkaido.jp", +"rishirifuji.hokkaido.jp", +"saroma.hokkaido.jp", +"sarufutsu.hokkaido.jp", +"shakotan.hokkaido.jp", +"shari.hokkaido.jp", +"shibecha.hokkaido.jp", +"shibetsu.hokkaido.jp", +"shikabe.hokkaido.jp", +"shikaoi.hokkaido.jp", +"shimamaki.hokkaido.jp", +"shimizu.hokkaido.jp", +"shimokawa.hokkaido.jp", +"shinshinotsu.hokkaido.jp", +"shintoku.hokkaido.jp", +"shiranuka.hokkaido.jp", +"shiraoi.hokkaido.jp", +"shiriuchi.hokkaido.jp", +"sobetsu.hokkaido.jp", +"sunagawa.hokkaido.jp", +"taiki.hokkaido.jp", +"takasu.hokkaido.jp", +"takikawa.hokkaido.jp", +"takinoue.hokkaido.jp", +"teshikaga.hokkaido.jp", +"tobetsu.hokkaido.jp", +"tohma.hokkaido.jp", +"tomakomai.hokkaido.jp", +"tomari.hokkaido.jp", +"toya.hokkaido.jp", +"toyako.hokkaido.jp", +"toyotomi.hokkaido.jp", +"toyoura.hokkaido.jp", +"tsubetsu.hokkaido.jp", +"tsukigata.hokkaido.jp", +"urakawa.hokkaido.jp", +"urausu.hokkaido.jp", +"uryu.hokkaido.jp", +"utashinai.hokkaido.jp", +"wakkanai.hokkaido.jp", +"wassamu.hokkaido.jp", +"yakumo.hokkaido.jp", +"yoichi.hokkaido.jp", +"aioi.hyogo.jp", +"akashi.hyogo.jp", +"ako.hyogo.jp", +"amagasaki.hyogo.jp", +"aogaki.hyogo.jp", +"asago.hyogo.jp", +"ashiya.hyogo.jp", +"awaji.hyogo.jp", +"fukusaki.hyogo.jp", +"goshiki.hyogo.jp", +"harima.hyogo.jp", +"himeji.hyogo.jp", +"ichikawa.hyogo.jp", +"inagawa.hyogo.jp", +"itami.hyogo.jp", +"kakogawa.hyogo.jp", +"kamigori.hyogo.jp", +"kamikawa.hyogo.jp", +"kasai.hyogo.jp", +"kasuga.hyogo.jp", +"kawanishi.hyogo.jp", +"miki.hyogo.jp", +"minamiawaji.hyogo.jp", +"nishinomiya.hyogo.jp", +"nishiwaki.hyogo.jp", +"ono.hyogo.jp", +"sanda.hyogo.jp", +"sannan.hyogo.jp", +"sasayama.hyogo.jp", +"sayo.hyogo.jp", +"shingu.hyogo.jp", +"shinonsen.hyogo.jp", +"shiso.hyogo.jp", +"sumoto.hyogo.jp", +"taishi.hyogo.jp", +"taka.hyogo.jp", +"takarazuka.hyogo.jp", +"takasago.hyogo.jp", +"takino.hyogo.jp", +"tamba.hyogo.jp", +"tatsuno.hyogo.jp", +"toyooka.hyogo.jp", +"yabu.hyogo.jp", +"yashiro.hyogo.jp", +"yoka.hyogo.jp", +"yokawa.hyogo.jp", +"ami.ibaraki.jp", +"asahi.ibaraki.jp", +"bando.ibaraki.jp", +"chikusei.ibaraki.jp", +"daigo.ibaraki.jp", +"fujishiro.ibaraki.jp", +"hitachi.ibaraki.jp", +"hitachinaka.ibaraki.jp", +"hitachiomiya.ibaraki.jp", +"hitachiota.ibaraki.jp", +"ibaraki.ibaraki.jp", +"ina.ibaraki.jp", +"inashiki.ibaraki.jp", +"itako.ibaraki.jp", +"iwama.ibaraki.jp", +"joso.ibaraki.jp", +"kamisu.ibaraki.jp", +"kasama.ibaraki.jp", +"kashima.ibaraki.jp", +"kasumigaura.ibaraki.jp", +"koga.ibaraki.jp", +"miho.ibaraki.jp", +"mito.ibaraki.jp", +"moriya.ibaraki.jp", +"naka.ibaraki.jp", +"namegata.ibaraki.jp", +"oarai.ibaraki.jp", +"ogawa.ibaraki.jp", +"omitama.ibaraki.jp", +"ryugasaki.ibaraki.jp", +"sakai.ibaraki.jp", +"sakuragawa.ibaraki.jp", +"shimodate.ibaraki.jp", +"shimotsuma.ibaraki.jp", +"shirosato.ibaraki.jp", +"sowa.ibaraki.jp", +"suifu.ibaraki.jp", +"takahagi.ibaraki.jp", +"tamatsukuri.ibaraki.jp", +"tokai.ibaraki.jp", +"tomobe.ibaraki.jp", +"tone.ibaraki.jp", +"toride.ibaraki.jp", +"tsuchiura.ibaraki.jp", +"tsukuba.ibaraki.jp", +"uchihara.ibaraki.jp", +"ushiku.ibaraki.jp", +"yachiyo.ibaraki.jp", +"yamagata.ibaraki.jp", +"yawara.ibaraki.jp", +"yuki.ibaraki.jp", +"anamizu.ishikawa.jp", +"hakui.ishikawa.jp", +"hakusan.ishikawa.jp", +"kaga.ishikawa.jp", +"kahoku.ishikawa.jp", +"kanazawa.ishikawa.jp", +"kawakita.ishikawa.jp", +"komatsu.ishikawa.jp", +"nakanoto.ishikawa.jp", +"nanao.ishikawa.jp", +"nomi.ishikawa.jp", +"nonoichi.ishikawa.jp", +"noto.ishikawa.jp", +"shika.ishikawa.jp", +"suzu.ishikawa.jp", +"tsubata.ishikawa.jp", +"tsurugi.ishikawa.jp", +"uchinada.ishikawa.jp", +"wajima.ishikawa.jp", +"fudai.iwate.jp", +"fujisawa.iwate.jp", +"hanamaki.iwate.jp", +"hiraizumi.iwate.jp", +"hirono.iwate.jp", +"ichinohe.iwate.jp", +"ichinoseki.iwate.jp", +"iwaizumi.iwate.jp", +"iwate.iwate.jp", +"joboji.iwate.jp", +"kamaishi.iwate.jp", +"kanegasaki.iwate.jp", +"karumai.iwate.jp", +"kawai.iwate.jp", +"kitakami.iwate.jp", +"kuji.iwate.jp", +"kunohe.iwate.jp", +"kuzumaki.iwate.jp", +"miyako.iwate.jp", +"mizusawa.iwate.jp", +"morioka.iwate.jp", +"ninohe.iwate.jp", +"noda.iwate.jp", +"ofunato.iwate.jp", +"oshu.iwate.jp", +"otsuchi.iwate.jp", +"rikuzentakata.iwate.jp", +"shiwa.iwate.jp", +"shizukuishi.iwate.jp", +"sumita.iwate.jp", +"tanohata.iwate.jp", +"tono.iwate.jp", +"yahaba.iwate.jp", +"yamada.iwate.jp", +"ayagawa.kagawa.jp", +"higashikagawa.kagawa.jp", +"kanonji.kagawa.jp", +"kotohira.kagawa.jp", +"manno.kagawa.jp", +"marugame.kagawa.jp", +"mitoyo.kagawa.jp", +"naoshima.kagawa.jp", +"sanuki.kagawa.jp", +"tadotsu.kagawa.jp", +"takamatsu.kagawa.jp", +"tonosho.kagawa.jp", +"uchinomi.kagawa.jp", +"utazu.kagawa.jp", +"zentsuji.kagawa.jp", +"akune.kagoshima.jp", +"amami.kagoshima.jp", +"hioki.kagoshima.jp", +"isa.kagoshima.jp", +"isen.kagoshima.jp", +"izumi.kagoshima.jp", +"kagoshima.kagoshima.jp", +"kanoya.kagoshima.jp", +"kawanabe.kagoshima.jp", +"kinko.kagoshima.jp", +"kouyama.kagoshima.jp", +"makurazaki.kagoshima.jp", +"matsumoto.kagoshima.jp", +"minamitane.kagoshima.jp", +"nakatane.kagoshima.jp", +"nishinoomote.kagoshima.jp", +"satsumasendai.kagoshima.jp", +"soo.kagoshima.jp", +"tarumizu.kagoshima.jp", +"yusui.kagoshima.jp", +"aikawa.kanagawa.jp", +"atsugi.kanagawa.jp", +"ayase.kanagawa.jp", +"chigasaki.kanagawa.jp", +"ebina.kanagawa.jp", +"fujisawa.kanagawa.jp", +"hadano.kanagawa.jp", +"hakone.kanagawa.jp", +"hiratsuka.kanagawa.jp", +"isehara.kanagawa.jp", +"kaisei.kanagawa.jp", +"kamakura.kanagawa.jp", +"kiyokawa.kanagawa.jp", +"matsuda.kanagawa.jp", +"minamiashigara.kanagawa.jp", +"miura.kanagawa.jp", +"nakai.kanagawa.jp", +"ninomiya.kanagawa.jp", +"odawara.kanagawa.jp", +"oi.kanagawa.jp", +"oiso.kanagawa.jp", +"sagamihara.kanagawa.jp", +"samukawa.kanagawa.jp", +"tsukui.kanagawa.jp", +"yamakita.kanagawa.jp", +"yamato.kanagawa.jp", +"yokosuka.kanagawa.jp", +"yugawara.kanagawa.jp", +"zama.kanagawa.jp", +"zushi.kanagawa.jp", +"aki.kochi.jp", +"geisei.kochi.jp", +"hidaka.kochi.jp", +"higashitsuno.kochi.jp", +"ino.kochi.jp", +"kagami.kochi.jp", +"kami.kochi.jp", +"kitagawa.kochi.jp", +"kochi.kochi.jp", +"mihara.kochi.jp", +"motoyama.kochi.jp", +"muroto.kochi.jp", +"nahari.kochi.jp", +"nakamura.kochi.jp", +"nankoku.kochi.jp", +"nishitosa.kochi.jp", +"niyodogawa.kochi.jp", +"ochi.kochi.jp", +"okawa.kochi.jp", +"otoyo.kochi.jp", +"otsuki.kochi.jp", +"sakawa.kochi.jp", +"sukumo.kochi.jp", +"susaki.kochi.jp", +"tosa.kochi.jp", +"tosashimizu.kochi.jp", +"toyo.kochi.jp", +"tsuno.kochi.jp", +"umaji.kochi.jp", +"yasuda.kochi.jp", +"yusuhara.kochi.jp", +"amakusa.kumamoto.jp", +"arao.kumamoto.jp", +"aso.kumamoto.jp", +"choyo.kumamoto.jp", +"gyokuto.kumamoto.jp", +"kamiamakusa.kumamoto.jp", +"kikuchi.kumamoto.jp", +"kumamoto.kumamoto.jp", +"mashiki.kumamoto.jp", +"mifune.kumamoto.jp", +"minamata.kumamoto.jp", +"minamioguni.kumamoto.jp", +"nagasu.kumamoto.jp", +"nishihara.kumamoto.jp", +"oguni.kumamoto.jp", +"ozu.kumamoto.jp", +"sumoto.kumamoto.jp", +"takamori.kumamoto.jp", +"uki.kumamoto.jp", +"uto.kumamoto.jp", +"yamaga.kumamoto.jp", +"yamato.kumamoto.jp", +"yatsushiro.kumamoto.jp", +"ayabe.kyoto.jp", +"fukuchiyama.kyoto.jp", +"higashiyama.kyoto.jp", +"ide.kyoto.jp", +"ine.kyoto.jp", +"joyo.kyoto.jp", +"kameoka.kyoto.jp", +"kamo.kyoto.jp", +"kita.kyoto.jp", +"kizu.kyoto.jp", +"kumiyama.kyoto.jp", +"kyotamba.kyoto.jp", +"kyotanabe.kyoto.jp", +"kyotango.kyoto.jp", +"maizuru.kyoto.jp", +"minami.kyoto.jp", +"minamiyamashiro.kyoto.jp", +"miyazu.kyoto.jp", +"muko.kyoto.jp", +"nagaokakyo.kyoto.jp", +"nakagyo.kyoto.jp", +"nantan.kyoto.jp", +"oyamazaki.kyoto.jp", +"sakyo.kyoto.jp", +"seika.kyoto.jp", +"tanabe.kyoto.jp", +"uji.kyoto.jp", +"ujitawara.kyoto.jp", +"wazuka.kyoto.jp", +"yamashina.kyoto.jp", +"yawata.kyoto.jp", +"asahi.mie.jp", +"inabe.mie.jp", +"ise.mie.jp", +"kameyama.mie.jp", +"kawagoe.mie.jp", +"kiho.mie.jp", +"kisosaki.mie.jp", +"kiwa.mie.jp", +"komono.mie.jp", +"kumano.mie.jp", +"kuwana.mie.jp", +"matsusaka.mie.jp", +"meiwa.mie.jp", +"mihama.mie.jp", +"minamiise.mie.jp", +"misugi.mie.jp", +"miyama.mie.jp", +"nabari.mie.jp", +"shima.mie.jp", +"suzuka.mie.jp", +"tado.mie.jp", +"taiki.mie.jp", +"taki.mie.jp", +"tamaki.mie.jp", +"toba.mie.jp", +"tsu.mie.jp", +"udono.mie.jp", +"ureshino.mie.jp", +"watarai.mie.jp", +"yokkaichi.mie.jp", +"furukawa.miyagi.jp", +"higashimatsushima.miyagi.jp", +"ishinomaki.miyagi.jp", +"iwanuma.miyagi.jp", +"kakuda.miyagi.jp", +"kami.miyagi.jp", +"kawasaki.miyagi.jp", +"marumori.miyagi.jp", +"matsushima.miyagi.jp", +"minamisanriku.miyagi.jp", +"misato.miyagi.jp", +"murata.miyagi.jp", +"natori.miyagi.jp", +"ogawara.miyagi.jp", +"ohira.miyagi.jp", +"onagawa.miyagi.jp", +"osaki.miyagi.jp", +"rifu.miyagi.jp", +"semine.miyagi.jp", +"shibata.miyagi.jp", +"shichikashuku.miyagi.jp", +"shikama.miyagi.jp", +"shiogama.miyagi.jp", +"shiroishi.miyagi.jp", +"tagajo.miyagi.jp", +"taiwa.miyagi.jp", +"tome.miyagi.jp", +"tomiya.miyagi.jp", +"wakuya.miyagi.jp", +"watari.miyagi.jp", +"yamamoto.miyagi.jp", +"zao.miyagi.jp", +"aya.miyazaki.jp", +"ebino.miyazaki.jp", +"gokase.miyazaki.jp", +"hyuga.miyazaki.jp", +"kadogawa.miyazaki.jp", +"kawaminami.miyazaki.jp", +"kijo.miyazaki.jp", +"kitagawa.miyazaki.jp", +"kitakata.miyazaki.jp", +"kitaura.miyazaki.jp", +"kobayashi.miyazaki.jp", +"kunitomi.miyazaki.jp", +"kushima.miyazaki.jp", +"mimata.miyazaki.jp", +"miyakonojo.miyazaki.jp", +"miyazaki.miyazaki.jp", +"morotsuka.miyazaki.jp", +"nichinan.miyazaki.jp", +"nishimera.miyazaki.jp", +"nobeoka.miyazaki.jp", +"saito.miyazaki.jp", +"shiiba.miyazaki.jp", +"shintomi.miyazaki.jp", +"takaharu.miyazaki.jp", +"takanabe.miyazaki.jp", +"takazaki.miyazaki.jp", +"tsuno.miyazaki.jp", +"achi.nagano.jp", +"agematsu.nagano.jp", +"anan.nagano.jp", +"aoki.nagano.jp", +"asahi.nagano.jp", +"azumino.nagano.jp", +"chikuhoku.nagano.jp", +"chikuma.nagano.jp", +"chino.nagano.jp", +"fujimi.nagano.jp", +"hakuba.nagano.jp", +"hara.nagano.jp", +"hiraya.nagano.jp", +"iida.nagano.jp", +"iijima.nagano.jp", +"iiyama.nagano.jp", +"iizuna.nagano.jp", +"ikeda.nagano.jp", +"ikusaka.nagano.jp", +"ina.nagano.jp", +"karuizawa.nagano.jp", +"kawakami.nagano.jp", +"kiso.nagano.jp", +"kisofukushima.nagano.jp", +"kitaaiki.nagano.jp", +"komagane.nagano.jp", +"komoro.nagano.jp", +"matsukawa.nagano.jp", +"matsumoto.nagano.jp", +"miasa.nagano.jp", +"minamiaiki.nagano.jp", +"minamimaki.nagano.jp", +"minamiminowa.nagano.jp", +"minowa.nagano.jp", +"miyada.nagano.jp", +"miyota.nagano.jp", +"mochizuki.nagano.jp", +"nagano.nagano.jp", +"nagawa.nagano.jp", +"nagiso.nagano.jp", +"nakagawa.nagano.jp", +"nakano.nagano.jp", +"nozawaonsen.nagano.jp", +"obuse.nagano.jp", +"ogawa.nagano.jp", +"okaya.nagano.jp", +"omachi.nagano.jp", +"omi.nagano.jp", +"ookuwa.nagano.jp", +"ooshika.nagano.jp", +"otaki.nagano.jp", +"otari.nagano.jp", +"sakae.nagano.jp", +"sakaki.nagano.jp", +"saku.nagano.jp", +"sakuho.nagano.jp", +"shimosuwa.nagano.jp", +"shinanomachi.nagano.jp", +"shiojiri.nagano.jp", +"suwa.nagano.jp", +"suzaka.nagano.jp", +"takagi.nagano.jp", +"takamori.nagano.jp", +"takayama.nagano.jp", +"tateshina.nagano.jp", +"tatsuno.nagano.jp", +"togakushi.nagano.jp", +"togura.nagano.jp", +"tomi.nagano.jp", +"ueda.nagano.jp", +"wada.nagano.jp", +"yamagata.nagano.jp", +"yamanouchi.nagano.jp", +"yasaka.nagano.jp", +"yasuoka.nagano.jp", +"chijiwa.nagasaki.jp", +"futsu.nagasaki.jp", +"goto.nagasaki.jp", +"hasami.nagasaki.jp", +"hirado.nagasaki.jp", +"iki.nagasaki.jp", +"isahaya.nagasaki.jp", +"kawatana.nagasaki.jp", +"kuchinotsu.nagasaki.jp", +"matsuura.nagasaki.jp", +"nagasaki.nagasaki.jp", +"obama.nagasaki.jp", +"omura.nagasaki.jp", +"oseto.nagasaki.jp", +"saikai.nagasaki.jp", +"sasebo.nagasaki.jp", +"seihi.nagasaki.jp", +"shimabara.nagasaki.jp", +"shinkamigoto.nagasaki.jp", +"togitsu.nagasaki.jp", +"tsushima.nagasaki.jp", +"unzen.nagasaki.jp", +"ando.nara.jp", +"gose.nara.jp", +"heguri.nara.jp", +"higashiyoshino.nara.jp", +"ikaruga.nara.jp", +"ikoma.nara.jp", +"kamikitayama.nara.jp", +"kanmaki.nara.jp", +"kashiba.nara.jp", +"kashihara.nara.jp", +"katsuragi.nara.jp", +"kawai.nara.jp", +"kawakami.nara.jp", +"kawanishi.nara.jp", +"koryo.nara.jp", +"kurotaki.nara.jp", +"mitsue.nara.jp", +"miyake.nara.jp", +"nara.nara.jp", +"nosegawa.nara.jp", +"oji.nara.jp", +"ouda.nara.jp", +"oyodo.nara.jp", +"sakurai.nara.jp", +"sango.nara.jp", +"shimoichi.nara.jp", +"shimokitayama.nara.jp", +"shinjo.nara.jp", +"soni.nara.jp", +"takatori.nara.jp", +"tawaramoto.nara.jp", +"tenkawa.nara.jp", +"tenri.nara.jp", +"uda.nara.jp", +"yamatokoriyama.nara.jp", +"yamatotakada.nara.jp", +"yamazoe.nara.jp", +"yoshino.nara.jp", +"aga.niigata.jp", +"agano.niigata.jp", +"gosen.niigata.jp", +"itoigawa.niigata.jp", +"izumozaki.niigata.jp", +"joetsu.niigata.jp", +"kamo.niigata.jp", +"kariwa.niigata.jp", +"kashiwazaki.niigata.jp", +"minamiuonuma.niigata.jp", +"mitsuke.niigata.jp", +"muika.niigata.jp", +"murakami.niigata.jp", +"myoko.niigata.jp", +"nagaoka.niigata.jp", +"niigata.niigata.jp", +"ojiya.niigata.jp", +"omi.niigata.jp", +"sado.niigata.jp", +"sanjo.niigata.jp", +"seiro.niigata.jp", +"seirou.niigata.jp", +"sekikawa.niigata.jp", +"shibata.niigata.jp", +"tagami.niigata.jp", +"tainai.niigata.jp", +"tochio.niigata.jp", +"tokamachi.niigata.jp", +"tsubame.niigata.jp", +"tsunan.niigata.jp", +"uonuma.niigata.jp", +"yahiko.niigata.jp", +"yoita.niigata.jp", +"yuzawa.niigata.jp", +"beppu.oita.jp", +"bungoono.oita.jp", +"bungotakada.oita.jp", +"hasama.oita.jp", +"hiji.oita.jp", +"himeshima.oita.jp", +"hita.oita.jp", +"kamitsue.oita.jp", +"kokonoe.oita.jp", +"kuju.oita.jp", +"kunisaki.oita.jp", +"kusu.oita.jp", +"oita.oita.jp", +"saiki.oita.jp", +"taketa.oita.jp", +"tsukumi.oita.jp", +"usa.oita.jp", +"usuki.oita.jp", +"yufu.oita.jp", +"akaiwa.okayama.jp", +"asakuchi.okayama.jp", +"bizen.okayama.jp", +"hayashima.okayama.jp", +"ibara.okayama.jp", +"kagamino.okayama.jp", +"kasaoka.okayama.jp", +"kibichuo.okayama.jp", +"kumenan.okayama.jp", +"kurashiki.okayama.jp", +"maniwa.okayama.jp", +"misaki.okayama.jp", +"nagi.okayama.jp", +"niimi.okayama.jp", +"nishiawakura.okayama.jp", +"okayama.okayama.jp", +"satosho.okayama.jp", +"setouchi.okayama.jp", +"shinjo.okayama.jp", +"shoo.okayama.jp", +"soja.okayama.jp", +"takahashi.okayama.jp", +"tamano.okayama.jp", +"tsuyama.okayama.jp", +"wake.okayama.jp", +"yakage.okayama.jp", +"aguni.okinawa.jp", +"ginowan.okinawa.jp", +"ginoza.okinawa.jp", +"gushikami.okinawa.jp", +"haebaru.okinawa.jp", +"higashi.okinawa.jp", +"hirara.okinawa.jp", +"iheya.okinawa.jp", +"ishigaki.okinawa.jp", +"ishikawa.okinawa.jp", +"itoman.okinawa.jp", +"izena.okinawa.jp", +"kadena.okinawa.jp", +"kin.okinawa.jp", +"kitadaito.okinawa.jp", +"kitanakagusuku.okinawa.jp", +"kumejima.okinawa.jp", +"kunigami.okinawa.jp", +"minamidaito.okinawa.jp", +"motobu.okinawa.jp", +"nago.okinawa.jp", +"naha.okinawa.jp", +"nakagusuku.okinawa.jp", +"nakijin.okinawa.jp", +"nanjo.okinawa.jp", +"nishihara.okinawa.jp", +"ogimi.okinawa.jp", +"okinawa.okinawa.jp", +"onna.okinawa.jp", +"shimoji.okinawa.jp", +"taketomi.okinawa.jp", +"tarama.okinawa.jp", +"tokashiki.okinawa.jp", +"tomigusuku.okinawa.jp", +"tonaki.okinawa.jp", +"urasoe.okinawa.jp", +"uruma.okinawa.jp", +"yaese.okinawa.jp", +"yomitan.okinawa.jp", +"yonabaru.okinawa.jp", +"yonaguni.okinawa.jp", +"zamami.okinawa.jp", +"abeno.osaka.jp", +"chihayaakasaka.osaka.jp", +"chuo.osaka.jp", +"daito.osaka.jp", +"fujiidera.osaka.jp", +"habikino.osaka.jp", +"hannan.osaka.jp", +"higashiosaka.osaka.jp", +"higashisumiyoshi.osaka.jp", +"higashiyodogawa.osaka.jp", +"hirakata.osaka.jp", +"ibaraki.osaka.jp", +"ikeda.osaka.jp", +"izumi.osaka.jp", +"izumiotsu.osaka.jp", +"izumisano.osaka.jp", +"kadoma.osaka.jp", +"kaizuka.osaka.jp", +"kanan.osaka.jp", +"kashiwara.osaka.jp", +"katano.osaka.jp", +"kawachinagano.osaka.jp", +"kishiwada.osaka.jp", +"kita.osaka.jp", +"kumatori.osaka.jp", +"matsubara.osaka.jp", +"minato.osaka.jp", +"minoh.osaka.jp", +"misaki.osaka.jp", +"moriguchi.osaka.jp", +"neyagawa.osaka.jp", +"nishi.osaka.jp", +"nose.osaka.jp", +"osakasayama.osaka.jp", +"sakai.osaka.jp", +"sayama.osaka.jp", +"sennan.osaka.jp", +"settsu.osaka.jp", +"shijonawate.osaka.jp", +"shimamoto.osaka.jp", +"suita.osaka.jp", +"tadaoka.osaka.jp", +"taishi.osaka.jp", +"tajiri.osaka.jp", +"takaishi.osaka.jp", +"takatsuki.osaka.jp", +"tondabayashi.osaka.jp", +"toyonaka.osaka.jp", +"toyono.osaka.jp", +"yao.osaka.jp", +"ariake.saga.jp", +"arita.saga.jp", +"fukudomi.saga.jp", +"genkai.saga.jp", +"hamatama.saga.jp", +"hizen.saga.jp", +"imari.saga.jp", +"kamimine.saga.jp", +"kanzaki.saga.jp", +"karatsu.saga.jp", +"kashima.saga.jp", +"kitagata.saga.jp", +"kitahata.saga.jp", +"kiyama.saga.jp", +"kouhoku.saga.jp", +"kyuragi.saga.jp", +"nishiarita.saga.jp", +"ogi.saga.jp", +"omachi.saga.jp", +"ouchi.saga.jp", +"saga.saga.jp", +"shiroishi.saga.jp", +"taku.saga.jp", +"tara.saga.jp", +"tosu.saga.jp", +"yoshinogari.saga.jp", +"arakawa.saitama.jp", +"asaka.saitama.jp", +"chichibu.saitama.jp", +"fujimi.saitama.jp", +"fujimino.saitama.jp", +"fukaya.saitama.jp", +"hanno.saitama.jp", +"hanyu.saitama.jp", +"hasuda.saitama.jp", +"hatogaya.saitama.jp", +"hatoyama.saitama.jp", +"hidaka.saitama.jp", +"higashichichibu.saitama.jp", +"higashimatsuyama.saitama.jp", +"honjo.saitama.jp", +"ina.saitama.jp", +"iruma.saitama.jp", +"iwatsuki.saitama.jp", +"kamiizumi.saitama.jp", +"kamikawa.saitama.jp", +"kamisato.saitama.jp", +"kasukabe.saitama.jp", +"kawagoe.saitama.jp", +"kawaguchi.saitama.jp", +"kawajima.saitama.jp", +"kazo.saitama.jp", +"kitamoto.saitama.jp", +"koshigaya.saitama.jp", +"kounosu.saitama.jp", +"kuki.saitama.jp", +"kumagaya.saitama.jp", +"matsubushi.saitama.jp", +"minano.saitama.jp", +"misato.saitama.jp", +"miyashiro.saitama.jp", +"miyoshi.saitama.jp", +"moroyama.saitama.jp", +"nagatoro.saitama.jp", +"namegawa.saitama.jp", +"niiza.saitama.jp", +"ogano.saitama.jp", +"ogawa.saitama.jp", +"ogose.saitama.jp", +"okegawa.saitama.jp", +"omiya.saitama.jp", +"otaki.saitama.jp", +"ranzan.saitama.jp", +"ryokami.saitama.jp", +"saitama.saitama.jp", +"sakado.saitama.jp", +"satte.saitama.jp", +"sayama.saitama.jp", +"shiki.saitama.jp", +"shiraoka.saitama.jp", +"soka.saitama.jp", +"sugito.saitama.jp", +"toda.saitama.jp", +"tokigawa.saitama.jp", +"tokorozawa.saitama.jp", +"tsurugashima.saitama.jp", +"urawa.saitama.jp", +"warabi.saitama.jp", +"yashio.saitama.jp", +"yokoze.saitama.jp", +"yono.saitama.jp", +"yorii.saitama.jp", +"yoshida.saitama.jp", +"yoshikawa.saitama.jp", +"yoshimi.saitama.jp", +"aisho.shiga.jp", +"gamo.shiga.jp", +"higashiomi.shiga.jp", +"hikone.shiga.jp", +"koka.shiga.jp", +"konan.shiga.jp", +"kosei.shiga.jp", +"koto.shiga.jp", +"kusatsu.shiga.jp", +"maibara.shiga.jp", +"moriyama.shiga.jp", +"nagahama.shiga.jp", +"nishiazai.shiga.jp", +"notogawa.shiga.jp", +"omihachiman.shiga.jp", +"otsu.shiga.jp", +"ritto.shiga.jp", +"ryuoh.shiga.jp", +"takashima.shiga.jp", +"takatsuki.shiga.jp", +"torahime.shiga.jp", +"toyosato.shiga.jp", +"yasu.shiga.jp", +"akagi.shimane.jp", +"ama.shimane.jp", +"gotsu.shimane.jp", +"hamada.shimane.jp", +"higashiizumo.shimane.jp", +"hikawa.shimane.jp", +"hikimi.shimane.jp", +"izumo.shimane.jp", +"kakinoki.shimane.jp", +"masuda.shimane.jp", +"matsue.shimane.jp", +"misato.shimane.jp", +"nishinoshima.shimane.jp", +"ohda.shimane.jp", +"okinoshima.shimane.jp", +"okuizumo.shimane.jp", +"shimane.shimane.jp", +"tamayu.shimane.jp", +"tsuwano.shimane.jp", +"unnan.shimane.jp", +"yakumo.shimane.jp", +"yasugi.shimane.jp", +"yatsuka.shimane.jp", +"arai.shizuoka.jp", +"atami.shizuoka.jp", +"fuji.shizuoka.jp", +"fujieda.shizuoka.jp", +"fujikawa.shizuoka.jp", +"fujinomiya.shizuoka.jp", +"fukuroi.shizuoka.jp", +"gotemba.shizuoka.jp", +"haibara.shizuoka.jp", +"hamamatsu.shizuoka.jp", +"higashiizu.shizuoka.jp", +"ito.shizuoka.jp", +"iwata.shizuoka.jp", +"izu.shizuoka.jp", +"izunokuni.shizuoka.jp", +"kakegawa.shizuoka.jp", +"kannami.shizuoka.jp", +"kawanehon.shizuoka.jp", +"kawazu.shizuoka.jp", +"kikugawa.shizuoka.jp", +"kosai.shizuoka.jp", +"makinohara.shizuoka.jp", +"matsuzaki.shizuoka.jp", +"minamiizu.shizuoka.jp", +"mishima.shizuoka.jp", +"morimachi.shizuoka.jp", +"nishiizu.shizuoka.jp", +"numazu.shizuoka.jp", +"omaezaki.shizuoka.jp", +"shimada.shizuoka.jp", +"shimizu.shizuoka.jp", +"shimoda.shizuoka.jp", +"shizuoka.shizuoka.jp", +"susono.shizuoka.jp", +"yaizu.shizuoka.jp", +"yoshida.shizuoka.jp", +"ashikaga.tochigi.jp", +"bato.tochigi.jp", +"haga.tochigi.jp", +"ichikai.tochigi.jp", +"iwafune.tochigi.jp", +"kaminokawa.tochigi.jp", +"kanuma.tochigi.jp", +"karasuyama.tochigi.jp", +"kuroiso.tochigi.jp", +"mashiko.tochigi.jp", +"mibu.tochigi.jp", +"moka.tochigi.jp", +"motegi.tochigi.jp", +"nasu.tochigi.jp", +"nasushiobara.tochigi.jp", +"nikko.tochigi.jp", +"nishikata.tochigi.jp", +"nogi.tochigi.jp", +"ohira.tochigi.jp", +"ohtawara.tochigi.jp", +"oyama.tochigi.jp", +"sakura.tochigi.jp", +"sano.tochigi.jp", +"shimotsuke.tochigi.jp", +"shioya.tochigi.jp", +"takanezawa.tochigi.jp", +"tochigi.tochigi.jp", +"tsuga.tochigi.jp", +"ujiie.tochigi.jp", +"utsunomiya.tochigi.jp", +"yaita.tochigi.jp", +"aizumi.tokushima.jp", +"anan.tokushima.jp", +"ichiba.tokushima.jp", +"itano.tokushima.jp", +"kainan.tokushima.jp", +"komatsushima.tokushima.jp", +"matsushige.tokushima.jp", +"mima.tokushima.jp", +"minami.tokushima.jp", +"miyoshi.tokushima.jp", +"mugi.tokushima.jp", +"nakagawa.tokushima.jp", +"naruto.tokushima.jp", +"sanagochi.tokushima.jp", +"shishikui.tokushima.jp", +"tokushima.tokushima.jp", +"wajiki.tokushima.jp", +"adachi.tokyo.jp", +"akiruno.tokyo.jp", +"akishima.tokyo.jp", +"aogashima.tokyo.jp", +"arakawa.tokyo.jp", +"bunkyo.tokyo.jp", +"chiyoda.tokyo.jp", +"chofu.tokyo.jp", +"chuo.tokyo.jp", +"edogawa.tokyo.jp", +"fuchu.tokyo.jp", +"fussa.tokyo.jp", +"hachijo.tokyo.jp", +"hachioji.tokyo.jp", +"hamura.tokyo.jp", +"higashikurume.tokyo.jp", +"higashimurayama.tokyo.jp", +"higashiyamato.tokyo.jp", +"hino.tokyo.jp", +"hinode.tokyo.jp", +"hinohara.tokyo.jp", +"inagi.tokyo.jp", +"itabashi.tokyo.jp", +"katsushika.tokyo.jp", +"kita.tokyo.jp", +"kiyose.tokyo.jp", +"kodaira.tokyo.jp", +"koganei.tokyo.jp", +"kokubunji.tokyo.jp", +"komae.tokyo.jp", +"koto.tokyo.jp", +"kouzushima.tokyo.jp", +"kunitachi.tokyo.jp", +"machida.tokyo.jp", +"meguro.tokyo.jp", +"minato.tokyo.jp", +"mitaka.tokyo.jp", +"mizuho.tokyo.jp", +"musashimurayama.tokyo.jp", +"musashino.tokyo.jp", +"nakano.tokyo.jp", +"nerima.tokyo.jp", +"ogasawara.tokyo.jp", +"okutama.tokyo.jp", +"ome.tokyo.jp", +"oshima.tokyo.jp", +"ota.tokyo.jp", +"setagaya.tokyo.jp", +"shibuya.tokyo.jp", +"shinagawa.tokyo.jp", +"shinjuku.tokyo.jp", +"suginami.tokyo.jp", +"sumida.tokyo.jp", +"tachikawa.tokyo.jp", +"taito.tokyo.jp", +"tama.tokyo.jp", +"toshima.tokyo.jp", +"chizu.tottori.jp", +"hino.tottori.jp", +"kawahara.tottori.jp", +"koge.tottori.jp", +"kotoura.tottori.jp", +"misasa.tottori.jp", +"nanbu.tottori.jp", +"nichinan.tottori.jp", +"sakaiminato.tottori.jp", +"tottori.tottori.jp", +"wakasa.tottori.jp", +"yazu.tottori.jp", +"yonago.tottori.jp", +"asahi.toyama.jp", +"fuchu.toyama.jp", +"fukumitsu.toyama.jp", +"funahashi.toyama.jp", +"himi.toyama.jp", +"imizu.toyama.jp", +"inami.toyama.jp", +"johana.toyama.jp", +"kamiichi.toyama.jp", +"kurobe.toyama.jp", +"nakaniikawa.toyama.jp", +"namerikawa.toyama.jp", +"nanto.toyama.jp", +"nyuzen.toyama.jp", +"oyabe.toyama.jp", +"taira.toyama.jp", +"takaoka.toyama.jp", +"tateyama.toyama.jp", +"toga.toyama.jp", +"tonami.toyama.jp", +"toyama.toyama.jp", +"unazuki.toyama.jp", +"uozu.toyama.jp", +"yamada.toyama.jp", +"arida.wakayama.jp", +"aridagawa.wakayama.jp", +"gobo.wakayama.jp", +"hashimoto.wakayama.jp", +"hidaka.wakayama.jp", +"hirogawa.wakayama.jp", +"inami.wakayama.jp", +"iwade.wakayama.jp", +"kainan.wakayama.jp", +"kamitonda.wakayama.jp", +"katsuragi.wakayama.jp", +"kimino.wakayama.jp", +"kinokawa.wakayama.jp", +"kitayama.wakayama.jp", +"koya.wakayama.jp", +"koza.wakayama.jp", +"kozagawa.wakayama.jp", +"kudoyama.wakayama.jp", +"kushimoto.wakayama.jp", +"mihama.wakayama.jp", +"misato.wakayama.jp", +"nachikatsuura.wakayama.jp", +"shingu.wakayama.jp", +"shirahama.wakayama.jp", +"taiji.wakayama.jp", +"tanabe.wakayama.jp", +"wakayama.wakayama.jp", +"yuasa.wakayama.jp", +"yura.wakayama.jp", +"asahi.yamagata.jp", +"funagata.yamagata.jp", +"higashine.yamagata.jp", +"iide.yamagata.jp", +"kahoku.yamagata.jp", +"kaminoyama.yamagata.jp", +"kaneyama.yamagata.jp", +"kawanishi.yamagata.jp", +"mamurogawa.yamagata.jp", +"mikawa.yamagata.jp", +"murayama.yamagata.jp", +"nagai.yamagata.jp", +"nakayama.yamagata.jp", +"nanyo.yamagata.jp", +"nishikawa.yamagata.jp", +"obanazawa.yamagata.jp", +"oe.yamagata.jp", +"oguni.yamagata.jp", +"ohkura.yamagata.jp", +"oishida.yamagata.jp", +"sagae.yamagata.jp", +"sakata.yamagata.jp", +"sakegawa.yamagata.jp", +"shinjo.yamagata.jp", +"shirataka.yamagata.jp", +"shonai.yamagata.jp", +"takahata.yamagata.jp", +"tendo.yamagata.jp", +"tozawa.yamagata.jp", +"tsuruoka.yamagata.jp", +"yamagata.yamagata.jp", +"yamanobe.yamagata.jp", +"yonezawa.yamagata.jp", +"yuza.yamagata.jp", +"abu.yamaguchi.jp", +"hagi.yamaguchi.jp", +"hikari.yamaguchi.jp", +"hofu.yamaguchi.jp", +"iwakuni.yamaguchi.jp", +"kudamatsu.yamaguchi.jp", +"mitou.yamaguchi.jp", +"nagato.yamaguchi.jp", +"oshima.yamaguchi.jp", +"shimonoseki.yamaguchi.jp", +"shunan.yamaguchi.jp", +"tabuse.yamaguchi.jp", +"tokuyama.yamaguchi.jp", +"toyota.yamaguchi.jp", +"ube.yamaguchi.jp", +"yuu.yamaguchi.jp", +"chuo.yamanashi.jp", +"doshi.yamanashi.jp", +"fuefuki.yamanashi.jp", +"fujikawa.yamanashi.jp", +"fujikawaguchiko.yamanashi.jp", +"fujiyoshida.yamanashi.jp", +"hayakawa.yamanashi.jp", +"hokuto.yamanashi.jp", +"ichikawamisato.yamanashi.jp", +"kai.yamanashi.jp", +"kofu.yamanashi.jp", +"koshu.yamanashi.jp", +"kosuge.yamanashi.jp", +"minami-alps.yamanashi.jp", +"minobu.yamanashi.jp", +"nakamichi.yamanashi.jp", +"nanbu.yamanashi.jp", +"narusawa.yamanashi.jp", +"nirasaki.yamanashi.jp", +"nishikatsura.yamanashi.jp", +"oshino.yamanashi.jp", +"otsuki.yamanashi.jp", +"showa.yamanashi.jp", +"tabayama.yamanashi.jp", +"tsuru.yamanashi.jp", +"uenohara.yamanashi.jp", +"yamanakako.yamanashi.jp", +"yamanashi.yamanashi.jp", +"ac.ke", +"co.ke", +"go.ke", +"info.ke", +"me.ke", +"mobi.ke", +"ne.ke", +"or.ke", +"sc.ke", +"org.kg", +"net.kg", +"com.kg", +"edu.kg", +"gov.kg", +"mil.kg", +"edu.ki", +"biz.ki", +"net.ki", +"org.ki", +"gov.ki", +"info.ki", +"com.ki", +"org.km", +"nom.km", +"gov.km", +"prd.km", +"tm.km", +"edu.km", +"mil.km", +"ass.km", +"com.km", +"coop.km", +"asso.km", +"presse.km", +"medecin.km", +"notaires.km", +"pharmaciens.km", +"veterinaire.km", +"gouv.km", +"net.kn", +"org.kn", +"edu.kn", +"gov.kn", +"com.kp", +"edu.kp", +"gov.kp", +"org.kp", +"rep.kp", +"tra.kp", +"ac.kr", +"co.kr", +"es.kr", +"go.kr", +"hs.kr", +"kg.kr", +"mil.kr", +"ms.kr", +"ne.kr", +"or.kr", +"pe.kr", +"re.kr", +"sc.kr", +"busan.kr", +"chungbuk.kr", +"chungnam.kr", +"daegu.kr", +"daejeon.kr", +"gangwon.kr", +"gwangju.kr", +"gyeongbuk.kr", +"gyeonggi.kr", +"gyeongnam.kr", +"incheon.kr", +"jeju.kr", +"jeonbuk.kr", +"jeonnam.kr", +"seoul.kr", +"ulsan.kr", +"com.kw", +"edu.kw", +"emb.kw", +"gov.kw", +"ind.kw", +"net.kw", +"org.kw", +"edu.ky", +"gov.ky", +"com.ky", +"org.ky", +"net.ky", +"org.kz", +"edu.kz", +"net.kz", +"gov.kz", +"mil.kz", +"com.kz", +"int.la", +"net.la", +"info.la", +"edu.la", +"gov.la", +"per.la", +"com.la", +"org.la", +"com.lb", +"edu.lb", +"gov.lb", +"net.lb", +"org.lb", +"com.lc", +"net.lc", +"co.lc", +"org.lc", +"edu.lc", +"gov.lc", +"gov.lk", +"sch.lk", +"net.lk", +"int.lk", +"com.lk", +"org.lk", +"edu.lk", +"ngo.lk", +"soc.lk", +"web.lk", +"ltd.lk", +"assn.lk", +"grp.lk", +"hotel.lk", +"ac.lk", +"com.lr", +"edu.lr", +"gov.lr", +"org.lr", +"net.lr", +"co.ls", +"org.ls", +"gov.lt", +"com.lv", +"edu.lv", +"gov.lv", +"org.lv", +"mil.lv", +"id.lv", +"net.lv", +"asn.lv", +"conf.lv", +"com.ly", +"net.ly", +"gov.ly", +"plc.ly", +"edu.ly", +"sch.ly", +"med.ly", +"org.ly", +"id.ly", +"co.ma", +"net.ma", +"gov.ma", +"org.ma", +"ac.ma", +"press.ma", +"tm.mc", +"asso.mc", +"co.me", +"net.me", +"org.me", +"edu.me", +"ac.me", +"gov.me", +"its.me", +"priv.me", +"org.mg", +"nom.mg", +"gov.mg", +"prd.mg", +"tm.mg", +"edu.mg", +"mil.mg", +"com.mg", +"co.mg", +"com.mk", +"org.mk", +"net.mk", +"edu.mk", +"gov.mk", +"inf.mk", +"name.mk", +"com.ml", +"edu.ml", +"gouv.ml", +"gov.ml", +"net.ml", +"org.ml", +"presse.ml", +"gov.mn", +"edu.mn", +"org.mn", +"com.mo", +"net.mo", +"org.mo", +"edu.mo", +"gov.mo", +"gov.mr", +"com.ms", +"edu.ms", +"gov.ms", +"net.ms", +"org.ms", +"com.mt", +"edu.mt", +"net.mt", +"org.mt", +"com.mu", +"net.mu", +"org.mu", +"gov.mu", +"ac.mu", +"co.mu", +"or.mu", +"academy.museum", +"agriculture.museum", +"air.museum", +"airguard.museum", +"alabama.museum", +"alaska.museum", +"amber.museum", +"ambulance.museum", +"american.museum", +"americana.museum", +"americanantiques.museum", +"americanart.museum", +"amsterdam.museum", +"and.museum", +"annefrank.museum", +"anthro.museum", +"anthropology.museum", +"antiques.museum", +"aquarium.museum", +"arboretum.museum", +"archaeological.museum", +"archaeology.museum", +"architecture.museum", +"art.museum", +"artanddesign.museum", +"artcenter.museum", +"artdeco.museum", +"arteducation.museum", +"artgallery.museum", +"arts.museum", +"artsandcrafts.museum", +"asmatart.museum", +"assassination.museum", +"assisi.museum", +"association.museum", +"astronomy.museum", +"atlanta.museum", +"austin.museum", +"australia.museum", +"automotive.museum", +"aviation.museum", +"axis.museum", +"badajoz.museum", +"baghdad.museum", +"bahn.museum", +"bale.museum", +"baltimore.museum", +"barcelona.museum", +"baseball.museum", +"basel.museum", +"baths.museum", +"bauern.museum", +"beauxarts.museum", +"beeldengeluid.museum", +"bellevue.museum", +"bergbau.museum", +"berkeley.museum", +"berlin.museum", +"bern.museum", +"bible.museum", +"bilbao.museum", +"bill.museum", +"birdart.museum", +"birthplace.museum", +"bonn.museum", +"boston.museum", +"botanical.museum", +"botanicalgarden.museum", +"botanicgarden.museum", +"botany.museum", +"brandywinevalley.museum", +"brasil.museum", +"bristol.museum", +"british.museum", +"britishcolumbia.museum", +"broadcast.museum", +"brunel.museum", +"brussel.museum", +"brussels.museum", +"bruxelles.museum", +"building.museum", +"burghof.museum", +"bus.museum", +"bushey.museum", +"cadaques.museum", +"california.museum", +"cambridge.museum", +"can.museum", +"canada.museum", +"capebreton.museum", +"carrier.museum", +"cartoonart.museum", +"casadelamoneda.museum", +"castle.museum", +"castres.museum", +"celtic.museum", +"center.museum", +"chattanooga.museum", +"cheltenham.museum", +"chesapeakebay.museum", +"chicago.museum", +"children.museum", +"childrens.museum", +"childrensgarden.museum", +"chiropractic.museum", +"chocolate.museum", +"christiansburg.museum", +"cincinnati.museum", +"cinema.museum", +"circus.museum", +"civilisation.museum", +"civilization.museum", +"civilwar.museum", +"clinton.museum", +"clock.museum", +"coal.museum", +"coastaldefence.museum", +"cody.museum", +"coldwar.museum", +"collection.museum", +"colonialwilliamsburg.museum", +"coloradoplateau.museum", +"columbia.museum", +"columbus.museum", +"communication.museum", +"communications.museum", +"community.museum", +"computer.museum", +"computerhistory.museum", +"contemporary.museum", +"contemporaryart.museum", +"convent.museum", +"copenhagen.museum", +"corporation.museum", +"corvette.museum", +"costume.museum", +"countryestate.museum", +"county.museum", +"crafts.museum", +"cranbrook.museum", +"creation.museum", +"cultural.museum", +"culturalcenter.museum", +"culture.museum", +"cyber.museum", +"cymru.museum", +"dali.museum", +"dallas.museum", +"database.museum", +"ddr.museum", +"decorativearts.museum", +"delaware.museum", +"delmenhorst.museum", +"denmark.museum", +"depot.museum", +"design.museum", +"detroit.museum", +"dinosaur.museum", +"discovery.museum", +"dolls.museum", +"donostia.museum", +"durham.museum", +"eastafrica.museum", +"eastcoast.museum", +"education.museum", +"educational.museum", +"egyptian.museum", +"eisenbahn.museum", +"elburg.museum", +"elvendrell.museum", +"embroidery.museum", +"encyclopedic.museum", +"england.museum", +"entomology.museum", +"environment.museum", +"environmentalconservation.museum", +"epilepsy.museum", +"essex.museum", +"estate.museum", +"ethnology.museum", +"exeter.museum", +"exhibition.museum", +"family.museum", +"farm.museum", +"farmequipment.museum", +"farmers.museum", +"farmstead.museum", +"field.museum", +"figueres.museum", +"filatelia.museum", +"film.museum", +"fineart.museum", +"finearts.museum", +"finland.museum", +"flanders.museum", +"florida.museum", +"force.museum", +"fortmissoula.museum", +"fortworth.museum", +"foundation.museum", +"francaise.museum", +"frankfurt.museum", +"franziskaner.museum", +"freemasonry.museum", +"freiburg.museum", +"fribourg.museum", +"frog.museum", +"fundacio.museum", +"furniture.museum", +"gallery.museum", +"garden.museum", +"gateway.museum", +"geelvinck.museum", +"gemological.museum", +"geology.museum", +"georgia.museum", +"giessen.museum", +"glas.museum", +"glass.museum", +"gorge.museum", +"grandrapids.museum", +"graz.museum", +"guernsey.museum", +"halloffame.museum", +"hamburg.museum", +"handson.museum", +"harvestcelebration.museum", +"hawaii.museum", +"health.museum", +"heimatunduhren.museum", +"hellas.museum", +"helsinki.museum", +"hembygdsforbund.museum", +"heritage.museum", +"histoire.museum", +"historical.museum", +"historicalsociety.museum", +"historichouses.museum", +"historisch.museum", +"historisches.museum", +"history.museum", +"historyofscience.museum", +"horology.museum", +"house.museum", +"humanities.museum", +"illustration.museum", +"imageandsound.museum", +"indian.museum", +"indiana.museum", +"indianapolis.museum", +"indianmarket.museum", +"intelligence.museum", +"interactive.museum", +"iraq.museum", +"iron.museum", +"isleofman.museum", +"jamison.museum", +"jefferson.museum", +"jerusalem.museum", +"jewelry.museum", +"jewish.museum", +"jewishart.museum", +"jfk.museum", +"journalism.museum", +"judaica.museum", +"judygarland.museum", +"juedisches.museum", +"juif.museum", +"karate.museum", +"karikatur.museum", +"kids.museum", +"koebenhavn.museum", +"koeln.museum", +"kunst.museum", +"kunstsammlung.museum", +"kunstunddesign.museum", +"labor.museum", +"labour.museum", +"lajolla.museum", +"lancashire.museum", +"landes.museum", +"lans.museum", +"larsson.museum", +"lewismiller.museum", +"lincoln.museum", +"linz.museum", +"living.museum", +"livinghistory.museum", +"localhistory.museum", +"london.museum", +"losangeles.museum", +"louvre.museum", +"loyalist.museum", +"lucerne.museum", +"luxembourg.museum", +"luzern.museum", +"mad.museum", +"madrid.museum", +"mallorca.museum", +"manchester.museum", +"mansion.museum", +"mansions.museum", +"manx.museum", +"marburg.museum", +"maritime.museum", +"maritimo.museum", +"maryland.museum", +"marylhurst.museum", +"media.museum", +"medical.museum", +"medizinhistorisches.museum", +"meeres.museum", +"memorial.museum", +"mesaverde.museum", +"michigan.museum", +"midatlantic.museum", +"military.museum", +"mill.museum", +"miners.museum", +"mining.museum", +"minnesota.museum", +"missile.museum", +"missoula.museum", +"modern.museum", +"moma.museum", +"money.museum", +"monmouth.museum", +"monticello.museum", +"montreal.museum", +"moscow.museum", +"motorcycle.museum", +"muenchen.museum", +"muenster.museum", +"mulhouse.museum", +"muncie.museum", +"museet.museum", +"museumcenter.museum", +"museumvereniging.museum", +"music.museum", +"national.museum", +"nationalfirearms.museum", +"nationalheritage.museum", +"nativeamerican.museum", +"naturalhistory.museum", +"naturalhistorymuseum.museum", +"naturalsciences.museum", +"nature.museum", +"naturhistorisches.museum", +"natuurwetenschappen.museum", +"naumburg.museum", +"naval.museum", +"nebraska.museum", +"neues.museum", +"newhampshire.museum", +"newjersey.museum", +"newmexico.museum", +"newport.museum", +"newspaper.museum", +"newyork.museum", +"niepce.museum", +"norfolk.museum", +"north.museum", +"nrw.museum", +"nuernberg.museum", +"nuremberg.museum", +"nyc.museum", +"nyny.museum", +"oceanographic.museum", +"oceanographique.museum", +"omaha.museum", +"online.museum", +"ontario.museum", +"openair.museum", +"oregon.museum", +"oregontrail.museum", +"otago.museum", +"oxford.museum", +"pacific.museum", +"paderborn.museum", +"palace.museum", +"paleo.museum", +"palmsprings.museum", +"panama.museum", +"paris.museum", +"pasadena.museum", +"pharmacy.museum", +"philadelphia.museum", +"philadelphiaarea.museum", +"philately.museum", +"phoenix.museum", +"photography.museum", +"pilots.museum", +"pittsburgh.museum", +"planetarium.museum", +"plantation.museum", +"plants.museum", +"plaza.museum", +"portal.museum", +"portland.museum", +"portlligat.museum", +"posts-and-telecommunications.museum", +"preservation.museum", +"presidio.museum", +"press.museum", +"project.museum", +"public.museum", +"pubol.museum", +"quebec.museum", +"railroad.museum", +"railway.museum", +"research.museum", +"resistance.museum", +"riodejaneiro.museum", +"rochester.museum", +"rockart.museum", +"roma.museum", +"russia.museum", +"saintlouis.museum", +"salem.museum", +"salvadordali.museum", +"salzburg.museum", +"sandiego.museum", +"sanfrancisco.museum", +"santabarbara.museum", +"santacruz.museum", +"santafe.museum", +"saskatchewan.museum", +"satx.museum", +"savannahga.museum", +"schlesisches.museum", +"schoenbrunn.museum", +"schokoladen.museum", +"school.museum", +"schweiz.museum", +"science.museum", +"scienceandhistory.museum", +"scienceandindustry.museum", +"sciencecenter.museum", +"sciencecenters.museum", +"science-fiction.museum", +"sciencehistory.museum", +"sciences.museum", +"sciencesnaturelles.museum", +"scotland.museum", +"seaport.museum", +"settlement.museum", +"settlers.museum", +"shell.museum", +"sherbrooke.museum", +"sibenik.museum", +"silk.museum", +"ski.museum", +"skole.museum", +"society.museum", +"sologne.museum", +"soundandvision.museum", +"southcarolina.museum", +"southwest.museum", +"space.museum", +"spy.museum", +"square.museum", +"stadt.museum", +"stalbans.museum", +"starnberg.museum", +"state.museum", +"stateofdelaware.museum", +"station.museum", +"steam.museum", +"steiermark.museum", +"stjohn.museum", +"stockholm.museum", +"stpetersburg.museum", +"stuttgart.museum", +"suisse.museum", +"surgeonshall.museum", +"surrey.museum", +"svizzera.museum", +"sweden.museum", +"sydney.museum", +"tank.museum", +"tcm.museum", +"technology.museum", +"telekommunikation.museum", +"television.museum", +"texas.museum", +"textile.museum", +"theater.museum", +"time.museum", +"timekeeping.museum", +"topology.museum", +"torino.museum", +"touch.museum", +"town.museum", +"transport.museum", +"tree.museum", +"trolley.museum", +"trust.museum", +"trustee.museum", +"uhren.museum", +"ulm.museum", +"undersea.museum", +"university.museum", +"usa.museum", +"usantiques.museum", +"usarts.museum", +"uscountryestate.museum", +"usculture.museum", +"usdecorativearts.museum", +"usgarden.museum", +"ushistory.museum", +"ushuaia.museum", +"uslivinghistory.museum", +"utah.museum", +"uvic.museum", +"valley.museum", +"vantaa.museum", +"versailles.museum", +"viking.museum", +"village.museum", +"virginia.museum", +"virtual.museum", +"virtuel.museum", +"vlaanderen.museum", +"volkenkunde.museum", +"wales.museum", +"wallonie.museum", +"war.museum", +"washingtondc.museum", +"watchandclock.museum", +"watch-and-clock.museum", +"western.museum", +"westfalen.museum", +"whaling.museum", +"wildlife.museum", +"williamsburg.museum", +"windmill.museum", +"workshop.museum", +"york.museum", +"yorkshire.museum", +"yosemite.museum", +"youth.museum", +"zoological.museum", +"zoology.museum", +"aero.mv", +"biz.mv", +"com.mv", +"coop.mv", +"edu.mv", +"gov.mv", +"info.mv", +"int.mv", +"mil.mv", +"museum.mv", +"name.mv", +"net.mv", +"org.mv", +"pro.mv", +"ac.mw", +"biz.mw", +"co.mw", +"com.mw", +"coop.mw", +"edu.mw", +"gov.mw", +"int.mw", +"museum.mw", +"net.mw", +"org.mw", +"com.mx", +"org.mx", +"gob.mx", +"edu.mx", +"net.mx", +"com.my", +"net.my", +"org.my", +"gov.my", +"edu.my", +"mil.my", +"name.my", +"ac.mz", +"adv.mz", +"co.mz", +"edu.mz", +"gov.mz", +"mil.mz", +"net.mz", +"org.mz", +"info.na", +"pro.na", +"name.na", +"school.na", +"or.na", +"dr.na", +"us.na", +"mx.na", +"ca.na", +"in.na", +"cc.na", +"tv.na", +"ws.na", +"mobi.na", +"co.na", +"com.na", +"org.na", +"asso.nc", +"nom.nc", +"com.nf", +"net.nf", +"per.nf", +"rec.nf", +"web.nf", +"arts.nf", +"firm.nf", +"info.nf", +"other.nf", +"store.nf", +"com.ng", +"edu.ng", +"gov.ng", +"i.ng", +"mil.ng", +"mobi.ng", +"name.ng", +"net.ng", +"org.ng", +"sch.ng", +"ac.ni", +"biz.ni", +"co.ni", +"com.ni", +"edu.ni", +"gob.ni", +"in.ni", +"info.ni", +"int.ni", +"mil.ni", +"net.ni", +"nom.ni", +"org.ni", +"web.ni", +"bv.nl", +"fhs.no", +"vgs.no", +"fylkesbibl.no", +"folkebibl.no", +"museum.no", +"idrett.no", +"priv.no", +"mil.no", +"stat.no", +"dep.no", +"kommune.no", +"herad.no", +"aa.no", +"ah.no", +"bu.no", +"fm.no", +"hl.no", +"hm.no", +"jan-mayen.no", +"mr.no", +"nl.no", +"nt.no", +"of.no", +"ol.no", +"oslo.no", +"rl.no", +"sf.no", +"st.no", +"svalbard.no", +"tm.no", +"tr.no", +"va.no", +"vf.no", +"gs.aa.no", +"gs.ah.no", +"gs.bu.no", +"gs.fm.no", +"gs.hl.no", +"gs.hm.no", +"gs.jan-mayen.no", +"gs.mr.no", +"gs.nl.no", +"gs.nt.no", +"gs.of.no", +"gs.ol.no", +"gs.oslo.no", +"gs.rl.no", +"gs.sf.no", +"gs.st.no", +"gs.svalbard.no", +"gs.tm.no", +"gs.tr.no", +"gs.va.no", +"gs.vf.no", +"akrehamn.no", +"algard.no", +"arna.no", +"brumunddal.no", +"bryne.no", +"bronnoysund.no", +"drobak.no", +"egersund.no", +"fetsund.no", +"floro.no", +"fredrikstad.no", +"hokksund.no", +"honefoss.no", +"jessheim.no", +"jorpeland.no", +"kirkenes.no", +"kopervik.no", +"krokstadelva.no", +"langevag.no", +"leirvik.no", +"mjondalen.no", +"mo-i-rana.no", +"mosjoen.no", +"nesoddtangen.no", +"orkanger.no", +"osoyro.no", +"raholt.no", +"sandnessjoen.no", +"skedsmokorset.no", +"slattum.no", +"spjelkavik.no", +"stathelle.no", +"stavern.no", +"stjordalshalsen.no", +"tananger.no", +"tranby.no", +"vossevangen.no", +"afjord.no", +"agdenes.no", +"al.no", +"alesund.no", +"alstahaug.no", +"alta.no", +"alaheadju.no", +"alvdal.no", +"amli.no", +"amot.no", +"andebu.no", +"andoy.no", +"andasuolo.no", +"ardal.no", +"aremark.no", +"arendal.no", +"aseral.no", +"asker.no", +"askim.no", +"askvoll.no", +"askoy.no", +"asnes.no", +"audnedaln.no", +"aukra.no", +"aure.no", +"aurland.no", +"aurskog-holand.no", +"austevoll.no", +"austrheim.no", +"averoy.no", +"balestrand.no", +"ballangen.no", +"balat.no", +"balsfjord.no", +"bahccavuotna.no", +"bamble.no", +"bardu.no", +"beardu.no", +"beiarn.no", +"bajddar.no", +"baidar.no", +"berg.no", +"bergen.no", +"berlevag.no", +"bearalvahki.no", +"bindal.no", +"birkenes.no", +"bjarkoy.no", +"bjerkreim.no", +"bjugn.no", +"bodo.no", +"badaddja.no", +"budejju.no", +"bokn.no", +"bremanger.no", +"bronnoy.no", +"bygland.no", +"bykle.no", +"barum.no", +"bo.telemark.no", +"bo.nordland.no", +"bievat.no", +"bomlo.no", +"batsfjord.no", +"bahcavuotna.no", +"dovre.no", +"drammen.no", +"drangedal.no", +"dyroy.no", +"donna.no", +"eid.no", +"eidfjord.no", +"eidsberg.no", +"eidskog.no", +"eidsvoll.no", +"eigersund.no", +"elverum.no", +"enebakk.no", +"engerdal.no", +"etne.no", +"etnedal.no", +"evenes.no", +"evenassi.no", +"evje-og-hornnes.no", +"farsund.no", +"fauske.no", +"fuossko.no", +"fuoisku.no", +"fedje.no", +"fet.no", +"finnoy.no", +"fitjar.no", +"fjaler.no", +"fjell.no", +"flakstad.no", +"flatanger.no", +"flekkefjord.no", +"flesberg.no", +"flora.no", +"fla.no", +"folldal.no", +"forsand.no", +"fosnes.no", +"frei.no", +"frogn.no", +"froland.no", +"frosta.no", +"frana.no", +"froya.no", +"fusa.no", +"fyresdal.no", +"forde.no", +"gamvik.no", +"gangaviika.no", +"gaular.no", +"gausdal.no", +"gildeskal.no", +"giske.no", +"gjemnes.no", +"gjerdrum.no", +"gjerstad.no", +"gjesdal.no", +"gjovik.no", +"gloppen.no", +"gol.no", +"gran.no", +"grane.no", +"granvin.no", +"gratangen.no", +"grimstad.no", +"grong.no", +"kraanghke.no", +"grue.no", +"gulen.no", +"hadsel.no", +"halden.no", +"halsa.no", +"hamar.no", +"hamaroy.no", +"habmer.no", +"hapmir.no", +"hammerfest.no", +"hammarfeasta.no", +"haram.no", +"hareid.no", +"harstad.no", +"hasvik.no", +"aknoluokta.no", +"hattfjelldal.no", +"aarborte.no", +"haugesund.no", +"hemne.no", +"hemnes.no", +"hemsedal.no", +"heroy.more-og-romsdal.no", +"heroy.nordland.no", +"hitra.no", +"hjartdal.no", +"hjelmeland.no", +"hobol.no", +"hof.no", +"hol.no", +"hole.no", +"holmestrand.no", +"holtalen.no", +"hornindal.no", +"horten.no", +"hurdal.no", +"hurum.no", +"hvaler.no", +"hyllestad.no", +"hagebostad.no", +"hoyanger.no", +"hoylandet.no", +"ha.no", +"ibestad.no", +"inderoy.no", +"iveland.no", +"jevnaker.no", +"jondal.no", +"jolster.no", +"karasjok.no", +"karasjohka.no", +"karlsoy.no", +"galsa.no", +"karmoy.no", +"kautokeino.no", +"guovdageaidnu.no", +"klepp.no", +"klabu.no", +"kongsberg.no", +"kongsvinger.no", +"kragero.no", +"kristiansand.no", +"kristiansund.no", +"krodsherad.no", +"kvalsund.no", +"rahkkeravju.no", +"kvam.no", +"kvinesdal.no", +"kvinnherad.no", +"kviteseid.no", +"kvitsoy.no", +"kvafjord.no", +"giehtavuoatna.no", +"kvanangen.no", +"navuotna.no", +"kafjord.no", +"gaivuotna.no", +"larvik.no", +"lavangen.no", +"lavagis.no", +"loabat.no", +"lebesby.no", +"davvesiida.no", +"leikanger.no", +"leirfjord.no", +"leka.no", +"leksvik.no", +"lenvik.no", +"leangaviika.no", +"lesja.no", +"levanger.no", +"lier.no", +"lierne.no", +"lillehammer.no", +"lillesand.no", +"lindesnes.no", +"lindas.no", +"lom.no", +"loppa.no", +"lahppi.no", +"lund.no", +"lunner.no", +"luroy.no", +"luster.no", +"lyngdal.no", +"lyngen.no", +"ivgu.no", +"lardal.no", +"lerdal.no", +"lodingen.no", +"lorenskog.no", +"loten.no", +"malvik.no", +"masoy.no", +"muosat.no", +"mandal.no", +"marker.no", +"marnardal.no", +"masfjorden.no", +"meland.no", +"meldal.no", +"melhus.no", +"meloy.no", +"meraker.no", +"moareke.no", +"midsund.no", +"midtre-gauldal.no", +"modalen.no", +"modum.no", +"molde.no", +"moskenes.no", +"moss.no", +"mosvik.no", +"malselv.no", +"malatvuopmi.no", +"namdalseid.no", +"aejrie.no", +"namsos.no", +"namsskogan.no", +"naamesjevuemie.no", +"laakesvuemie.no", +"nannestad.no", +"narvik.no", +"narviika.no", +"naustdal.no", +"nedre-eiker.no", +"nes.akershus.no", +"nes.buskerud.no", +"nesna.no", +"nesodden.no", +"nesseby.no", +"unjarga.no", +"nesset.no", +"nissedal.no", +"nittedal.no", +"nord-aurdal.no", +"nord-fron.no", +"nord-odal.no", +"norddal.no", +"nordkapp.no", +"davvenjarga.no", +"nordre-land.no", +"nordreisa.no", +"raisa.no", +"nore-og-uvdal.no", +"notodden.no", +"naroy.no", +"notteroy.no", +"odda.no", +"oksnes.no", +"oppdal.no", +"oppegard.no", +"orkdal.no", +"orland.no", +"orskog.no", +"orsta.no", +"os.hedmark.no", +"os.hordaland.no", +"osen.no", +"osteroy.no", +"ostre-toten.no", +"overhalla.no", +"ovre-eiker.no", +"oyer.no", +"oygarden.no", +"oystre-slidre.no", +"porsanger.no", +"porsangu.no", +"porsgrunn.no", +"radoy.no", +"rakkestad.no", +"rana.no", +"ruovat.no", +"randaberg.no", +"rauma.no", +"rendalen.no", +"rennebu.no", +"rennesoy.no", +"rindal.no", +"ringebu.no", +"ringerike.no", +"ringsaker.no", +"rissa.no", +"risor.no", +"roan.no", +"rollag.no", +"rygge.no", +"ralingen.no", +"rodoy.no", +"romskog.no", +"roros.no", +"rost.no", +"royken.no", +"royrvik.no", +"rade.no", +"salangen.no", +"siellak.no", +"saltdal.no", +"salat.no", +"samnanger.no", +"sande.more-og-romsdal.no", +"sande.vestfold.no", +"sandefjord.no", +"sandnes.no", +"sandoy.no", +"sarpsborg.no", +"sauda.no", +"sauherad.no", +"sel.no", +"selbu.no", +"selje.no", +"seljord.no", +"sigdal.no", +"siljan.no", +"sirdal.no", +"skaun.no", +"skedsmo.no", +"ski.no", +"skien.no", +"skiptvet.no", +"skjervoy.no", +"skierva.no", +"skjak.no", +"skodje.no", +"skanland.no", +"skanit.no", +"smola.no", +"snillfjord.no", +"snasa.no", +"snoasa.no", +"snaase.no", +"sogndal.no", +"sokndal.no", +"sola.no", +"solund.no", +"songdalen.no", +"sortland.no", +"spydeberg.no", +"stange.no", +"stavanger.no", +"steigen.no", +"steinkjer.no", +"stjordal.no", +"stokke.no", +"stor-elvdal.no", +"stord.no", +"stordal.no", +"storfjord.no", +"omasvuotna.no", +"strand.no", +"stranda.no", +"stryn.no", +"sula.no", +"suldal.no", +"sund.no", +"sunndal.no", +"surnadal.no", +"sveio.no", +"svelvik.no", +"sykkylven.no", +"sogne.no", +"somna.no", +"sondre-land.no", +"sor-aurdal.no", +"sor-fron.no", +"sor-odal.no", +"sor-varanger.no", +"matta-varjjat.no", +"sorfold.no", +"sorreisa.no", +"sorum.no", +"tana.no", +"deatnu.no", +"time.no", +"tingvoll.no", +"tinn.no", +"tjeldsund.no", +"dielddanuorri.no", +"tjome.no", +"tokke.no", +"tolga.no", +"torsken.no", +"tranoy.no", +"tromso.no", +"tromsa.no", +"romsa.no", +"trondheim.no", +"troandin.no", +"trysil.no", +"trana.no", +"trogstad.no", +"tvedestrand.no", +"tydal.no", +"tynset.no", +"tysfjord.no", +"divtasvuodna.no", +"divttasvuotna.no", +"tysnes.no", +"tysvar.no", +"tonsberg.no", +"ullensaker.no", +"ullensvang.no", +"ulvik.no", +"utsira.no", +"vadso.no", +"cahcesuolo.no", +"vaksdal.no", +"valle.no", +"vang.no", +"vanylven.no", +"vardo.no", +"varggat.no", +"vefsn.no", +"vaapste.no", +"vega.no", +"vegarshei.no", +"vennesla.no", +"verdal.no", +"verran.no", +"vestby.no", +"vestnes.no", +"vestre-slidre.no", +"vestre-toten.no", +"vestvagoy.no", +"vevelstad.no", +"vik.no", +"vikna.no", +"vindafjord.no", +"volda.no", +"voss.no", +"varoy.no", +"vagan.no", +"voagat.no", +"vagsoy.no", +"vaga.no", +"valer.ostfold.no", +"valer.hedmark.no", +"biz.nr", +"info.nr", +"gov.nr", +"edu.nr", +"org.nr", +"net.nr", +"com.nr", +"ac.nz", +"co.nz", +"cri.nz", +"geek.nz", +"gen.nz", +"govt.nz", +"health.nz", +"iwi.nz", +"kiwi.nz", +"maori.nz", +"mil.nz", +"net.nz", +"org.nz", +"parliament.nz", +"school.nz", +"co.om", +"com.om", +"edu.om", +"gov.om", +"med.om", +"museum.om", +"net.om", +"org.om", +"pro.om", +"ac.pa", +"gob.pa", +"com.pa", +"org.pa", +"sld.pa", +"edu.pa", +"net.pa", +"ing.pa", +"abo.pa", +"med.pa", +"nom.pa", +"edu.pe", +"gob.pe", +"nom.pe", +"mil.pe", +"org.pe", +"com.pe", +"net.pe", +"com.pf", +"org.pf", +"edu.pf", +"com.ph", +"net.ph", +"org.ph", +"gov.ph", +"edu.ph", +"ngo.ph", +"mil.ph", +"i.ph", +"com.pk", +"net.pk", +"edu.pk", +"org.pk", +"fam.pk", +"biz.pk", +"web.pk", +"gov.pk", +"gob.pk", +"gok.pk", +"gon.pk", +"gop.pk", +"gos.pk", +"info.pk", +"com.pl", +"net.pl", +"org.pl", +"aid.pl", +"agro.pl", +"atm.pl", +"auto.pl", +"biz.pl", +"edu.pl", +"gmina.pl", +"gsm.pl", +"info.pl", +"mail.pl", +"miasta.pl", +"media.pl", +"mil.pl", +"nieruchomosci.pl", +"nom.pl", +"pc.pl", +"powiat.pl", +"priv.pl", +"realestate.pl", +"rel.pl", +"sex.pl", +"shop.pl", +"sklep.pl", +"sos.pl", +"szkola.pl", +"targi.pl", +"tm.pl", +"tourism.pl", +"travel.pl", +"turystyka.pl", +"gov.pl", +"ap.gov.pl", +"ic.gov.pl", +"is.gov.pl", +"us.gov.pl", +"kmpsp.gov.pl", +"kppsp.gov.pl", +"kwpsp.gov.pl", +"psp.gov.pl", +"wskr.gov.pl", +"kwp.gov.pl", +"mw.gov.pl", +"ug.gov.pl", +"um.gov.pl", +"umig.gov.pl", +"ugim.gov.pl", +"upow.gov.pl", +"uw.gov.pl", +"starostwo.gov.pl", +"pa.gov.pl", +"po.gov.pl", +"psse.gov.pl", +"pup.gov.pl", +"rzgw.gov.pl", +"sa.gov.pl", +"so.gov.pl", +"sr.gov.pl", +"wsa.gov.pl", +"sko.gov.pl", +"uzs.gov.pl", +"wiih.gov.pl", +"winb.gov.pl", +"pinb.gov.pl", +"wios.gov.pl", +"witd.gov.pl", +"wzmiuw.gov.pl", +"piw.gov.pl", +"wiw.gov.pl", +"griw.gov.pl", +"wif.gov.pl", +"oum.gov.pl", +"sdn.gov.pl", +"zp.gov.pl", +"uppo.gov.pl", +"mup.gov.pl", +"wuoz.gov.pl", +"konsulat.gov.pl", +"oirm.gov.pl", +"augustow.pl", +"babia-gora.pl", +"bedzin.pl", +"beskidy.pl", +"bialowieza.pl", +"bialystok.pl", +"bielawa.pl", +"bieszczady.pl", +"boleslawiec.pl", +"bydgoszcz.pl", +"bytom.pl", +"cieszyn.pl", +"czeladz.pl", +"czest.pl", +"dlugoleka.pl", +"elblag.pl", +"elk.pl", +"glogow.pl", +"gniezno.pl", +"gorlice.pl", +"grajewo.pl", +"ilawa.pl", +"jaworzno.pl", +"jelenia-gora.pl", +"jgora.pl", +"kalisz.pl", +"kazimierz-dolny.pl", +"karpacz.pl", +"kartuzy.pl", +"kaszuby.pl", +"katowice.pl", +"kepno.pl", +"ketrzyn.pl", +"klodzko.pl", +"kobierzyce.pl", +"kolobrzeg.pl", +"konin.pl", +"konskowola.pl", +"kutno.pl", +"lapy.pl", +"lebork.pl", +"legnica.pl", +"lezajsk.pl", +"limanowa.pl", +"lomza.pl", +"lowicz.pl", +"lubin.pl", +"lukow.pl", +"malbork.pl", +"malopolska.pl", +"mazowsze.pl", +"mazury.pl", +"mielec.pl", +"mielno.pl", +"mragowo.pl", +"naklo.pl", +"nowaruda.pl", +"nysa.pl", +"olawa.pl", +"olecko.pl", +"olkusz.pl", +"olsztyn.pl", +"opoczno.pl", +"opole.pl", +"ostroda.pl", +"ostroleka.pl", +"ostrowiec.pl", +"ostrowwlkp.pl", +"pila.pl", +"pisz.pl", +"podhale.pl", +"podlasie.pl", +"polkowice.pl", +"pomorze.pl", +"pomorskie.pl", +"prochowice.pl", +"pruszkow.pl", +"przeworsk.pl", +"pulawy.pl", +"radom.pl", +"rawa-maz.pl", +"rybnik.pl", +"rzeszow.pl", +"sanok.pl", +"sejny.pl", +"slask.pl", +"slupsk.pl", +"sosnowiec.pl", +"stalowa-wola.pl", +"skoczow.pl", +"starachowice.pl", +"stargard.pl", +"suwalki.pl", +"swidnica.pl", +"swiebodzin.pl", +"swinoujscie.pl", +"szczecin.pl", +"szczytno.pl", +"tarnobrzeg.pl", +"tgory.pl", +"turek.pl", +"tychy.pl", +"ustka.pl", +"walbrzych.pl", +"warmia.pl", +"warszawa.pl", +"waw.pl", +"wegrow.pl", +"wielun.pl", +"wlocl.pl", +"wloclawek.pl", +"wodzislaw.pl", +"wolomin.pl", +"wroclaw.pl", +"zachpomor.pl", +"zagan.pl", +"zarow.pl", +"zgora.pl", +"zgorzelec.pl", +"gov.pn", +"co.pn", +"org.pn", +"edu.pn", +"net.pn", +"com.pr", +"net.pr", +"org.pr", +"gov.pr", +"edu.pr", +"isla.pr", +"pro.pr", +"biz.pr", +"info.pr", +"name.pr", +"est.pr", +"prof.pr", +"ac.pr", +"aaa.pro", +"aca.pro", +"acct.pro", +"avocat.pro", +"bar.pro", +"cpa.pro", +"eng.pro", +"jur.pro", +"law.pro", +"med.pro", +"recht.pro", +"edu.ps", +"gov.ps", +"sec.ps", +"plo.ps", +"com.ps", +"org.ps", +"net.ps", +"net.pt", +"gov.pt", +"org.pt", +"edu.pt", +"int.pt", +"publ.pt", +"com.pt", +"nome.pt", +"co.pw", +"ne.pw", +"or.pw", +"ed.pw", +"go.pw", +"belau.pw", +"com.py", +"coop.py", +"edu.py", +"gov.py", +"mil.py", +"net.py", +"org.py", +"com.qa", +"edu.qa", +"gov.qa", +"mil.qa", +"name.qa", +"net.qa", +"org.qa", +"sch.qa", +"asso.re", +"com.re", +"nom.re", +"arts.ro", +"com.ro", +"firm.ro", +"info.ro", +"nom.ro", +"nt.ro", +"org.ro", +"rec.ro", +"store.ro", +"tm.ro", +"www.ro", +"ac.rs", +"co.rs", +"edu.rs", +"gov.rs", +"in.rs", +"org.rs", +"ac.ru", +"edu.ru", +"gov.ru", +"int.ru", +"mil.ru", +"test.ru", +"gov.rw", +"net.rw", +"edu.rw", +"ac.rw", +"com.rw", +"co.rw", +"int.rw", +"mil.rw", +"gouv.rw", +"com.sa", +"net.sa", +"org.sa", +"gov.sa", +"med.sa", +"pub.sa", +"edu.sa", +"sch.sa", +"com.sb", +"edu.sb", +"gov.sb", +"net.sb", +"org.sb", +"com.sc", +"gov.sc", +"net.sc", +"org.sc", +"edu.sc", +"com.sd", +"net.sd", +"org.sd", +"edu.sd", +"med.sd", +"tv.sd", +"gov.sd", +"info.sd", +"a.se", +"ac.se", +"b.se", +"bd.se", +"brand.se", +"c.se", +"d.se", +"e.se", +"f.se", +"fh.se", +"fhsk.se", +"fhv.se", +"g.se", +"h.se", +"i.se", +"k.se", +"komforb.se", +"kommunalforbund.se", +"komvux.se", +"l.se", +"lanbib.se", +"m.se", +"n.se", +"naturbruksgymn.se", +"o.se", +"org.se", +"p.se", +"parti.se", +"pp.se", +"press.se", +"r.se", +"s.se", +"t.se", +"tm.se", +"u.se", +"w.se", +"x.se", +"y.se", +"z.se", +"com.sg", +"net.sg", +"org.sg", +"gov.sg", +"edu.sg", +"per.sg", +"com.sh", +"net.sh", +"gov.sh", +"org.sh", +"mil.sh", +"com.sl", +"net.sl", +"edu.sl", +"gov.sl", +"org.sl", +"art.sn", +"com.sn", +"edu.sn", +"gouv.sn", +"org.sn", +"perso.sn", +"univ.sn", +"com.so", +"net.so", +"org.so", +"co.st", +"com.st", +"consulado.st", +"edu.st", +"embaixada.st", +"gov.st", +"mil.st", +"net.st", +"org.st", +"principe.st", +"saotome.st", +"store.st", +"com.sv", +"edu.sv", +"gob.sv", +"org.sv", +"red.sv", +"gov.sx", +"edu.sy", +"gov.sy", +"net.sy", +"mil.sy", +"com.sy", +"org.sy", +"co.sz", +"ac.sz", +"org.sz", +"ac.th", +"co.th", +"go.th", +"in.th", +"mi.th", +"net.th", +"or.th", +"ac.tj", +"biz.tj", +"co.tj", +"com.tj", +"edu.tj", +"go.tj", +"gov.tj", +"int.tj", +"mil.tj", +"name.tj", +"net.tj", +"nic.tj", +"org.tj", +"test.tj", +"web.tj", +"gov.tl", +"com.tm", +"co.tm", +"org.tm", +"net.tm", +"nom.tm", +"gov.tm", +"mil.tm", +"edu.tm", +"com.tn", +"ens.tn", +"fin.tn", +"gov.tn", +"ind.tn", +"intl.tn", +"nat.tn", +"net.tn", +"org.tn", +"info.tn", +"perso.tn", +"tourism.tn", +"edunet.tn", +"rnrt.tn", +"rns.tn", +"rnu.tn", +"mincom.tn", +"agrinet.tn", +"defense.tn", +"turen.tn", +"com.to", +"gov.to", +"net.to", +"org.to", +"edu.to", +"mil.to", +"com.tr", +"info.tr", +"biz.tr", +"net.tr", +"org.tr", +"web.tr", +"gen.tr", +"tv.tr", +"av.tr", +"dr.tr", +"bbs.tr", +"name.tr", +"tel.tr", +"gov.tr", +"bel.tr", +"pol.tr", +"mil.tr", +"k12.tr", +"edu.tr", +"kep.tr", +"nc.tr", +"gov.nc.tr", +"co.tt", +"com.tt", +"org.tt", +"net.tt", +"biz.tt", +"info.tt", +"pro.tt", +"int.tt", +"coop.tt", +"jobs.tt", +"mobi.tt", +"travel.tt", +"museum.tt", +"aero.tt", +"name.tt", +"gov.tt", +"edu.tt", +"edu.tw", +"gov.tw", +"mil.tw", +"com.tw", +"net.tw", +"org.tw", +"idv.tw", +"game.tw", +"ebiz.tw", +"club.tw", +"ac.tz", +"co.tz", +"go.tz", +"hotel.tz", +"info.tz", +"me.tz", +"mil.tz", +"mobi.tz", +"ne.tz", +"or.tz", +"sc.tz", +"tv.tz", +"com.ua", +"edu.ua", +"gov.ua", +"in.ua", +"net.ua", +"org.ua", +"cherkassy.ua", +"cherkasy.ua", +"chernigov.ua", +"chernihiv.ua", +"chernivtsi.ua", +"chernovtsy.ua", +"ck.ua", +"cn.ua", +"cr.ua", +"crimea.ua", +"cv.ua", +"dn.ua", +"dnepropetrovsk.ua", +"dnipropetrovsk.ua", +"dominic.ua", +"donetsk.ua", +"dp.ua", +"if.ua", +"ivano-frankivsk.ua", +"kh.ua", +"kharkiv.ua", +"kharkov.ua", +"kherson.ua", +"khmelnitskiy.ua", +"khmelnytskyi.ua", +"kiev.ua", +"kirovograd.ua", +"km.ua", +"kr.ua", +"krym.ua", +"ks.ua", +"kv.ua", +"kyiv.ua", +"lg.ua", +"lt.ua", +"lugansk.ua", +"lutsk.ua", +"lv.ua", +"lviv.ua", +"mk.ua", +"mykolaiv.ua", +"nikolaev.ua", +"od.ua", +"odesa.ua", +"odessa.ua", +"pl.ua", +"poltava.ua", +"rivne.ua", +"rovno.ua", +"rv.ua", +"sb.ua", +"sebastopol.ua", +"sevastopol.ua", +"sm.ua", +"sumy.ua", +"te.ua", +"ternopil.ua", +"uz.ua", +"uzhgorod.ua", +"vinnica.ua", +"vinnytsia.ua", +"vn.ua", +"volyn.ua", +"yalta.ua", +"zaporizhzhe.ua", +"zaporizhzhia.ua", +"zhitomir.ua", +"zhytomyr.ua", +"zp.ua", +"zt.ua", +"co.ug", +"or.ug", +"ac.ug", +"sc.ug", +"go.ug", +"ne.ug", +"com.ug", +"org.ug", +"ac.uk", +"co.uk", +"gov.uk", +"ltd.uk", +"me.uk", +"net.uk", +"nhs.uk", +"org.uk", +"plc.uk", +"police.uk", +"dni.us", +"fed.us", +"isa.us", +"kids.us", +"nsn.us", +"ak.us", +"al.us", +"ar.us", +"as.us", +"az.us", +"ca.us", +"co.us", +"ct.us", +"dc.us", +"de.us", +"fl.us", +"ga.us", +"gu.us", +"hi.us", +"ia.us", +"id.us", +"il.us", +"in.us", +"ks.us", +"ky.us", +"la.us", +"ma.us", +"md.us", +"me.us", +"mi.us", +"mn.us", +"mo.us", +"ms.us", +"mt.us", +"nc.us", +"nd.us", +"ne.us", +"nh.us", +"nj.us", +"nm.us", +"nv.us", +"ny.us", +"oh.us", +"ok.us", +"or.us", +"pa.us", +"pr.us", +"ri.us", +"sc.us", +"sd.us", +"tn.us", +"tx.us", +"ut.us", +"vi.us", +"vt.us", +"va.us", +"wa.us", +"wi.us", +"wv.us", +"wy.us", +"k12.ak.us", +"k12.al.us", +"k12.ar.us", +"k12.as.us", +"k12.az.us", +"k12.ca.us", +"k12.co.us", +"k12.ct.us", +"k12.dc.us", +"k12.de.us", +"k12.fl.us", +"k12.ga.us", +"k12.gu.us", +"k12.ia.us", +"k12.id.us", +"k12.il.us", +"k12.in.us", +"k12.ks.us", +"k12.ky.us", +"k12.la.us", +"k12.ma.us", +"k12.md.us", +"k12.me.us", +"k12.mi.us", +"k12.mn.us", +"k12.mo.us", +"k12.ms.us", +"k12.mt.us", +"k12.nc.us", +"k12.ne.us", +"k12.nh.us", +"k12.nj.us", +"k12.nm.us", +"k12.nv.us", +"k12.ny.us", +"k12.oh.us", +"k12.ok.us", +"k12.or.us", +"k12.pa.us", +"k12.pr.us", +"k12.ri.us", +"k12.sc.us", +"k12.tn.us", +"k12.tx.us", +"k12.ut.us", +"k12.vi.us", +"k12.vt.us", +"k12.va.us", +"k12.wa.us", +"k12.wi.us", +"k12.wy.us", +"cc.ak.us", +"cc.al.us", +"cc.ar.us", +"cc.as.us", +"cc.az.us", +"cc.ca.us", +"cc.co.us", +"cc.ct.us", +"cc.dc.us", +"cc.de.us", +"cc.fl.us", +"cc.ga.us", +"cc.gu.us", +"cc.hi.us", +"cc.ia.us", +"cc.id.us", +"cc.il.us", +"cc.in.us", +"cc.ks.us", +"cc.ky.us", +"cc.la.us", +"cc.ma.us", +"cc.md.us", +"cc.me.us", +"cc.mi.us", +"cc.mn.us", +"cc.mo.us", +"cc.ms.us", +"cc.mt.us", +"cc.nc.us", +"cc.nd.us", +"cc.ne.us", +"cc.nh.us", +"cc.nj.us", +"cc.nm.us", +"cc.nv.us", +"cc.ny.us", +"cc.oh.us", +"cc.ok.us", +"cc.or.us", +"cc.pa.us", +"cc.pr.us", +"cc.ri.us", +"cc.sc.us", +"cc.sd.us", +"cc.tn.us", +"cc.tx.us", +"cc.ut.us", +"cc.vi.us", +"cc.vt.us", +"cc.va.us", +"cc.wa.us", +"cc.wi.us", +"cc.wv.us", +"cc.wy.us", +"lib.ak.us", +"lib.al.us", +"lib.ar.us", +"lib.as.us", +"lib.az.us", +"lib.ca.us", +"lib.co.us", +"lib.ct.us", +"lib.dc.us", +"lib.fl.us", +"lib.ga.us", +"lib.gu.us", +"lib.hi.us", +"lib.ia.us", +"lib.id.us", +"lib.il.us", +"lib.in.us", +"lib.ks.us", +"lib.ky.us", +"lib.la.us", +"lib.ma.us", +"lib.md.us", +"lib.me.us", +"lib.mi.us", +"lib.mn.us", +"lib.mo.us", +"lib.ms.us", +"lib.mt.us", +"lib.nc.us", +"lib.nd.us", +"lib.ne.us", +"lib.nh.us", +"lib.nj.us", +"lib.nm.us", +"lib.nv.us", +"lib.ny.us", +"lib.oh.us", +"lib.ok.us", +"lib.or.us", +"lib.pa.us", +"lib.pr.us", +"lib.ri.us", +"lib.sc.us", +"lib.sd.us", +"lib.tn.us", +"lib.tx.us", +"lib.ut.us", +"lib.vi.us", +"lib.vt.us", +"lib.va.us", +"lib.wa.us", +"lib.wi.us", +"lib.wy.us", +"pvt.k12.ma.us", +"chtr.k12.ma.us", +"paroch.k12.ma.us", +"ann-arbor.mi.us", +"cog.mi.us", +"dst.mi.us", +"eaton.mi.us", +"gen.mi.us", +"mus.mi.us", +"tec.mi.us", +"washtenaw.mi.us", +"com.uy", +"edu.uy", +"gub.uy", +"mil.uy", +"net.uy", +"org.uy", +"co.uz", +"com.uz", +"net.uz", +"org.uz", +"com.vc", +"net.vc", +"org.vc", +"gov.vc", +"mil.vc", +"edu.vc", +"arts.ve", +"co.ve", +"com.ve", +"e12.ve", +"edu.ve", +"firm.ve", +"gob.ve", +"gov.ve", +"info.ve", +"int.ve", +"mil.ve", +"net.ve", +"org.ve", +"rec.ve", +"store.ve", +"tec.ve", +"web.ve", +"co.vi", +"com.vi", +"k12.vi", +"net.vi", +"org.vi", +"com.vn", +"net.vn", +"org.vn", +"edu.vn", +"gov.vn", +"int.vn", +"ac.vn", +"biz.vn", +"info.vn", +"name.vn", +"pro.vn", +"health.vn", +"com.vu", +"edu.vu", +"net.vu", +"org.vu", +"com.ws", +"net.ws", +"org.ws", +"gov.ws", +"edu.ws", +"ac.za", +"agric.za", +"alt.za", +"co.za", +"edu.za", +"gov.za", +"grondar.za", +"law.za", +"mil.za", +"net.za", +"ngo.za", +"nis.za", +"nom.za", +"org.za", +"school.za", +"tm.za", +"web.za", +"ac.zm", +"biz.zm", +"co.zm", +"com.zm", +"edu.zm", +"gov.zm", +"info.zm", +"mil.zm", +"net.zm", +"org.zm", +"sch.zm", +"ac.zw", +"co.zw", +"gov.zw", +"mil.zw", +"org.zw", +"cc.ua", +"inf.ua", +"ltd.ua", +"beep.pl", +"alwaysdata.net", +"cloudfront.net", +"us-east-1.amazonaws.com", +"cn-north-1.eb.amazonaws.com.cn", +"cn-northwest-1.eb.amazonaws.com.cn", +"elasticbeanstalk.com", +"ap-northeast-1.elasticbeanstalk.com", +"ap-northeast-2.elasticbeanstalk.com", +"ap-northeast-3.elasticbeanstalk.com", +"ap-south-1.elasticbeanstalk.com", +"ap-southeast-1.elasticbeanstalk.com", +"ap-southeast-2.elasticbeanstalk.com", +"ca-central-1.elasticbeanstalk.com", +"eu-central-1.elasticbeanstalk.com", +"eu-west-1.elasticbeanstalk.com", +"eu-west-2.elasticbeanstalk.com", +"eu-west-3.elasticbeanstalk.com", +"sa-east-1.elasticbeanstalk.com", +"us-east-1.elasticbeanstalk.com", +"us-east-2.elasticbeanstalk.com", +"us-gov-west-1.elasticbeanstalk.com", +"us-west-1.elasticbeanstalk.com", +"us-west-2.elasticbeanstalk.com", +"s3.amazonaws.com", +"s3-ap-northeast-1.amazonaws.com", +"s3-ap-northeast-2.amazonaws.com", +"s3-ap-south-1.amazonaws.com", +"s3-ap-southeast-1.amazonaws.com", +"s3-ap-southeast-2.amazonaws.com", +"s3-ca-central-1.amazonaws.com", +"s3-eu-central-1.amazonaws.com", +"s3-eu-west-1.amazonaws.com", +"s3-eu-west-2.amazonaws.com", +"s3-eu-west-3.amazonaws.com", +"s3-external-1.amazonaws.com", +"s3-fips-us-gov-west-1.amazonaws.com", +"s3-sa-east-1.amazonaws.com", +"s3-us-gov-west-1.amazonaws.com", +"s3-us-east-2.amazonaws.com", +"s3-us-west-1.amazonaws.com", +"s3-us-west-2.amazonaws.com", +"s3.ap-northeast-2.amazonaws.com", +"s3.ap-south-1.amazonaws.com", +"s3.cn-north-1.amazonaws.com.cn", +"s3.ca-central-1.amazonaws.com", +"s3.eu-central-1.amazonaws.com", +"s3.eu-west-2.amazonaws.com", +"s3.eu-west-3.amazonaws.com", +"s3.us-east-2.amazonaws.com", +"s3.dualstack.ap-northeast-1.amazonaws.com", +"s3.dualstack.ap-northeast-2.amazonaws.com", +"s3.dualstack.ap-south-1.amazonaws.com", +"s3.dualstack.ap-southeast-1.amazonaws.com", +"s3.dualstack.ap-southeast-2.amazonaws.com", +"s3.dualstack.ca-central-1.amazonaws.com", +"s3.dualstack.eu-central-1.amazonaws.com", +"s3.dualstack.eu-west-1.amazonaws.com", +"s3.dualstack.eu-west-2.amazonaws.com", +"s3.dualstack.eu-west-3.amazonaws.com", +"s3.dualstack.sa-east-1.amazonaws.com", +"s3.dualstack.us-east-1.amazonaws.com", +"s3.dualstack.us-east-2.amazonaws.com", +"s3-website-us-east-1.amazonaws.com", +"s3-website-us-west-1.amazonaws.com", +"s3-website-us-west-2.amazonaws.com", +"s3-website-ap-northeast-1.amazonaws.com", +"s3-website-ap-southeast-1.amazonaws.com", +"s3-website-ap-southeast-2.amazonaws.com", +"s3-website-eu-west-1.amazonaws.com", +"s3-website-sa-east-1.amazonaws.com", +"s3-website.ap-northeast-2.amazonaws.com", +"s3-website.ap-south-1.amazonaws.com", +"s3-website.ca-central-1.amazonaws.com", +"s3-website.eu-central-1.amazonaws.com", +"s3-website.eu-west-2.amazonaws.com", +"s3-website.eu-west-3.amazonaws.com", +"s3-website.us-east-2.amazonaws.com", +"t3l3p0rt.net", +"tele.amune.org", +"on-aptible.com", +"user.party.eus", +"pimienta.org", +"poivron.org", +"potager.org", +"sweetpepper.org", +"myasustor.com", +"myfritz.net", +"backplaneapp.io", +"betainabox.com", +"bnr.la", +"blackbaudcdn.net", +"boomla.net", +"boxfuse.io", +"square7.ch", +"bplaced.com", +"bplaced.de", +"square7.de", +"bplaced.net", +"square7.net", +"browsersafetymark.io", +"mycd.eu", +"ae.org", +"ar.com", +"br.com", +"cn.com", +"com.de", +"com.se", +"de.com", +"eu.com", +"gb.com", +"gb.net", +"hu.com", +"hu.net", +"jp.net", +"jpn.com", +"kr.com", +"mex.com", +"no.com", +"qc.com", +"ru.com", +"sa.com", +"se.net", +"uk.com", +"uk.net", +"us.com", +"uy.com", +"za.bz", +"za.com", +"africa.com", +"gr.com", +"in.net", +"us.org", +"co.com", +"c.la", +"certmgr.org", +"xenapponazure.com", +"virtueeldomein.nl", +"cleverapps.io", +"c66.me", +"cloud66.ws", +"jdevcloud.com", +"wpdevcloud.com", +"cloudaccess.host", +"freesite.host", +"cloudaccess.net", +"cloudcontrolled.com", +"cloudcontrolapp.com", +"co.ca", +"co.cz", +"c.cdn77.org", +"cdn77-ssl.net", +"r.cdn77.net", +"rsc.cdn77.org", +"ssl.origin.cdn77-secure.org", +"cloudns.asia", +"cloudns.biz", +"cloudns.club", +"cloudns.cc", +"cloudns.eu", +"cloudns.in", +"cloudns.info", +"cloudns.org", +"cloudns.pro", +"cloudns.pw", +"cloudns.us", +"cloudeity.net", +"cnpy.gdn", +"co.nl", +"co.no", +"webhosting.be", +"hosting-cluster.nl", +"dyn.cosidns.de", +"dynamisches-dns.de", +"dnsupdater.de", +"internet-dns.de", +"l-o-g-i-n.de", +"dynamic-dns.info", +"feste-ip.net", +"knx-server.net", +"static-access.net", +"realm.cz", +"cupcake.is", +"cyon.link", +"cyon.site", +"daplie.me", +"localhost.daplie.me", +"dattolocal.com", +"dattorelay.com", +"dattoweb.com", +"mydatto.com", +"dattolocal.net", +"mydatto.net", +"biz.dk", +"co.dk", +"firm.dk", +"reg.dk", +"store.dk", +"debian.net", +"dedyn.io", +"dnshome.de", +"drayddns.com", +"dreamhosters.com", +"mydrobo.com", +"drud.io", +"drud.us", +"duckdns.org", +"dy.fi", +"tunk.org", +"dyndns-at-home.com", +"dyndns-at-work.com", +"dyndns-blog.com", +"dyndns-free.com", +"dyndns-home.com", +"dyndns-ip.com", +"dyndns-mail.com", +"dyndns-office.com", +"dyndns-pics.com", +"dyndns-remote.com", +"dyndns-server.com", +"dyndns-web.com", +"dyndns-wiki.com", +"dyndns-work.com", +"dyndns.biz", +"dyndns.info", +"dyndns.org", +"dyndns.tv", +"at-band-camp.net", +"ath.cx", +"barrel-of-knowledge.info", +"barrell-of-knowledge.info", +"better-than.tv", +"blogdns.com", +"blogdns.net", +"blogdns.org", +"blogsite.org", +"boldlygoingnowhere.org", +"broke-it.net", +"buyshouses.net", +"cechire.com", +"dnsalias.com", +"dnsalias.net", +"dnsalias.org", +"dnsdojo.com", +"dnsdojo.net", +"dnsdojo.org", +"does-it.net", +"doesntexist.com", +"doesntexist.org", +"dontexist.com", +"dontexist.net", +"dontexist.org", +"doomdns.com", +"doomdns.org", +"dvrdns.org", +"dyn-o-saur.com", +"dynalias.com", +"dynalias.net", +"dynalias.org", +"dynathome.net", +"dyndns.ws", +"endofinternet.net", +"endofinternet.org", +"endoftheinternet.org", +"est-a-la-maison.com", +"est-a-la-masion.com", +"est-le-patron.com", +"est-mon-blogueur.com", +"for-better.biz", +"for-more.biz", +"for-our.info", +"for-some.biz", +"for-the.biz", +"forgot.her.name", +"forgot.his.name", +"from-ak.com", +"from-al.com", +"from-ar.com", +"from-az.net", +"from-ca.com", +"from-co.net", +"from-ct.com", +"from-dc.com", +"from-de.com", +"from-fl.com", +"from-ga.com", +"from-hi.com", +"from-ia.com", +"from-id.com", +"from-il.com", +"from-in.com", +"from-ks.com", +"from-ky.com", +"from-la.net", +"from-ma.com", +"from-md.com", +"from-me.org", +"from-mi.com", +"from-mn.com", +"from-mo.com", +"from-ms.com", +"from-mt.com", +"from-nc.com", +"from-nd.com", +"from-ne.com", +"from-nh.com", +"from-nj.com", +"from-nm.com", +"from-nv.com", +"from-ny.net", +"from-oh.com", +"from-ok.com", +"from-or.com", +"from-pa.com", +"from-pr.com", +"from-ri.com", +"from-sc.com", +"from-sd.com", +"from-tn.com", +"from-tx.com", +"from-ut.com", +"from-va.com", +"from-vt.com", +"from-wa.com", +"from-wi.com", +"from-wv.com", +"from-wy.com", +"ftpaccess.cc", +"fuettertdasnetz.de", +"game-host.org", +"game-server.cc", +"getmyip.com", +"gets-it.net", +"go.dyndns.org", +"gotdns.com", +"gotdns.org", +"groks-the.info", +"groks-this.info", +"ham-radio-op.net", +"here-for-more.info", +"hobby-site.com", +"hobby-site.org", +"home.dyndns.org", +"homedns.org", +"homeftp.net", +"homeftp.org", +"homeip.net", +"homelinux.com", +"homelinux.net", +"homelinux.org", +"homeunix.com", +"homeunix.net", +"homeunix.org", +"iamallama.com", +"in-the-band.net", +"is-a-anarchist.com", +"is-a-blogger.com", +"is-a-bookkeeper.com", +"is-a-bruinsfan.org", +"is-a-bulls-fan.com", +"is-a-candidate.org", +"is-a-caterer.com", +"is-a-celticsfan.org", +"is-a-chef.com", +"is-a-chef.net", +"is-a-chef.org", +"is-a-conservative.com", +"is-a-cpa.com", +"is-a-cubicle-slave.com", +"is-a-democrat.com", +"is-a-designer.com", +"is-a-doctor.com", +"is-a-financialadvisor.com", +"is-a-geek.com", +"is-a-geek.net", +"is-a-geek.org", +"is-a-green.com", +"is-a-guru.com", +"is-a-hard-worker.com", +"is-a-hunter.com", +"is-a-knight.org", +"is-a-landscaper.com", +"is-a-lawyer.com", +"is-a-liberal.com", +"is-a-libertarian.com", +"is-a-linux-user.org", +"is-a-llama.com", +"is-a-musician.com", +"is-a-nascarfan.com", +"is-a-nurse.com", +"is-a-painter.com", +"is-a-patsfan.org", +"is-a-personaltrainer.com", +"is-a-photographer.com", +"is-a-player.com", +"is-a-republican.com", +"is-a-rockstar.com", +"is-a-socialist.com", +"is-a-soxfan.org", +"is-a-student.com", +"is-a-teacher.com", +"is-a-techie.com", +"is-a-therapist.com", +"is-an-accountant.com", +"is-an-actor.com", +"is-an-actress.com", +"is-an-anarchist.com", +"is-an-artist.com", +"is-an-engineer.com", +"is-an-entertainer.com", +"is-by.us", +"is-certified.com", +"is-found.org", +"is-gone.com", +"is-into-anime.com", +"is-into-cars.com", +"is-into-cartoons.com", +"is-into-games.com", +"is-leet.com", +"is-lost.org", +"is-not-certified.com", +"is-saved.org", +"is-slick.com", +"is-uberleet.com", +"is-very-bad.org", +"is-very-evil.org", +"is-very-good.org", +"is-very-nice.org", +"is-very-sweet.org", +"is-with-theband.com", +"isa-geek.com", +"isa-geek.net", +"isa-geek.org", +"isa-hockeynut.com", +"issmarterthanyou.com", +"isteingeek.de", +"istmein.de", +"kicks-ass.net", +"kicks-ass.org", +"knowsitall.info", +"land-4-sale.us", +"lebtimnetz.de", +"leitungsen.de", +"likes-pie.com", +"likescandy.com", +"merseine.nu", +"mine.nu", +"misconfused.org", +"mypets.ws", +"myphotos.cc", +"neat-url.com", +"office-on-the.net", +"on-the-web.tv", +"podzone.net", +"podzone.org", +"readmyblog.org", +"saves-the-whales.com", +"scrapper-site.net", +"scrapping.cc", +"selfip.biz", +"selfip.com", +"selfip.info", +"selfip.net", +"selfip.org", +"sells-for-less.com", +"sells-for-u.com", +"sells-it.net", +"sellsyourhome.org", +"servebbs.com", +"servebbs.net", +"servebbs.org", +"serveftp.net", +"serveftp.org", +"servegame.org", +"shacknet.nu", +"simple-url.com", +"space-to-rent.com", +"stuff-4-sale.org", +"stuff-4-sale.us", +"teaches-yoga.com", +"thruhere.net", +"traeumtgerade.de", +"webhop.biz", +"webhop.info", +"webhop.net", +"webhop.org", +"worse-than.tv", +"writesthisblog.com", +"ddnss.de", +"dyn.ddnss.de", +"dyndns.ddnss.de", +"dyndns1.de", +"dyn-ip24.de", +"home-webserver.de", +"dyn.home-webserver.de", +"myhome-server.de", +"ddnss.org", +"definima.net", +"definima.io", +"bci.dnstrace.pro", +"ddnsfree.com", +"ddnsgeek.com", +"giize.com", +"gleeze.com", +"kozow.com", +"loseyourip.com", +"ooguy.com", +"theworkpc.com", +"casacam.net", +"dynu.net", +"accesscam.org", +"camdvr.org", +"freeddns.org", +"mywire.org", +"webredirect.org", +"myddns.rocks", +"blogsite.xyz", +"dynv6.net", +"e4.cz", +"mytuleap.com", +"enonic.io", +"customer.enonic.io", +"eu.org", +"al.eu.org", +"asso.eu.org", +"at.eu.org", +"au.eu.org", +"be.eu.org", +"bg.eu.org", +"ca.eu.org", +"cd.eu.org", +"ch.eu.org", +"cn.eu.org", +"cy.eu.org", +"cz.eu.org", +"de.eu.org", +"dk.eu.org", +"edu.eu.org", +"ee.eu.org", +"es.eu.org", +"fi.eu.org", +"fr.eu.org", +"gr.eu.org", +"hr.eu.org", +"hu.eu.org", +"ie.eu.org", +"il.eu.org", +"in.eu.org", +"int.eu.org", +"is.eu.org", +"it.eu.org", +"jp.eu.org", +"kr.eu.org", +"lt.eu.org", +"lu.eu.org", +"lv.eu.org", +"mc.eu.org", +"me.eu.org", +"mk.eu.org", +"mt.eu.org", +"my.eu.org", +"net.eu.org", +"ng.eu.org", +"nl.eu.org", +"no.eu.org", +"nz.eu.org", +"paris.eu.org", +"pl.eu.org", +"pt.eu.org", +"q-a.eu.org", +"ro.eu.org", +"ru.eu.org", +"se.eu.org", +"si.eu.org", +"sk.eu.org", +"tr.eu.org", +"uk.eu.org", +"us.eu.org", +"eu-1.evennode.com", +"eu-2.evennode.com", +"eu-3.evennode.com", +"eu-4.evennode.com", +"us-1.evennode.com", +"us-2.evennode.com", +"us-3.evennode.com", +"us-4.evennode.com", +"twmail.cc", +"twmail.net", +"twmail.org", +"mymailer.com.tw", +"url.tw", +"apps.fbsbx.com", +"ru.net", +"adygeya.ru", +"bashkiria.ru", +"bir.ru", +"cbg.ru", +"com.ru", +"dagestan.ru", +"grozny.ru", +"kalmykia.ru", +"kustanai.ru", +"marine.ru", +"mordovia.ru", +"msk.ru", +"mytis.ru", +"nalchik.ru", +"nov.ru", +"pyatigorsk.ru", +"spb.ru", +"vladikavkaz.ru", +"vladimir.ru", +"abkhazia.su", +"adygeya.su", +"aktyubinsk.su", +"arkhangelsk.su", +"armenia.su", +"ashgabad.su", +"azerbaijan.su", +"balashov.su", +"bashkiria.su", +"bryansk.su", +"bukhara.su", +"chimkent.su", +"dagestan.su", +"east-kazakhstan.su", +"exnet.su", +"georgia.su", +"grozny.su", +"ivanovo.su", +"jambyl.su", +"kalmykia.su", +"kaluga.su", +"karacol.su", +"karaganda.su", +"karelia.su", +"khakassia.su", +"krasnodar.su", +"kurgan.su", +"kustanai.su", +"lenug.su", +"mangyshlak.su", +"mordovia.su", +"msk.su", +"murmansk.su", +"nalchik.su", +"navoi.su", +"north-kazakhstan.su", +"nov.su", +"obninsk.su", +"penza.su", +"pokrovsk.su", +"sochi.su", +"spb.su", +"tashkent.su", +"termez.su", +"togliatti.su", +"troitsk.su", +"tselinograd.su", +"tula.su", +"tuva.su", +"vladikavkaz.su", +"vladimir.su", +"vologda.su", +"channelsdvr.net", +"fastlylb.net", +"map.fastlylb.net", +"freetls.fastly.net", +"map.fastly.net", +"a.prod.fastly.net", +"global.prod.fastly.net", +"a.ssl.fastly.net", +"b.ssl.fastly.net", +"global.ssl.fastly.net", +"fastpanel.direct", +"fastvps-server.com", +"fhapp.xyz", +"fedorainfracloud.org", +"fedorapeople.org", +"cloud.fedoraproject.org", +"app.os.fedoraproject.org", +"app.os.stg.fedoraproject.org", +"filegear.me", +"firebaseapp.com", +"flynnhub.com", +"flynnhosting.net", +"freebox-os.com", +"freeboxos.com", +"fbx-os.fr", +"fbxos.fr", +"freebox-os.fr", +"freeboxos.fr", +"freedesktop.org", +"futurehosting.at", +"futuremailing.at", +"service.gov.uk", +"github.io", +"githubusercontent.com", +"gitlab.io", +"homeoffice.gov.uk", +"ro.im", +"shop.ro", +"goip.de", +"appspot.com", +"blogspot.ae", +"blogspot.al", +"blogspot.am", +"blogspot.ba", +"blogspot.be", +"blogspot.bg", +"blogspot.bj", +"blogspot.ca", +"blogspot.cf", +"blogspot.ch", +"blogspot.cl", +"blogspot.co.at", +"blogspot.co.id", +"blogspot.co.il", +"blogspot.co.ke", +"blogspot.co.nz", +"blogspot.co.uk", +"blogspot.co.za", +"blogspot.com", +"blogspot.com.ar", +"blogspot.com.au", +"blogspot.com.br", +"blogspot.com.by", +"blogspot.com.co", +"blogspot.com.cy", +"blogspot.com.ee", +"blogspot.com.eg", +"blogspot.com.es", +"blogspot.com.mt", +"blogspot.com.ng", +"blogspot.com.tr", +"blogspot.com.uy", +"blogspot.cv", +"blogspot.cz", +"blogspot.de", +"blogspot.dk", +"blogspot.fi", +"blogspot.fr", +"blogspot.gr", +"blogspot.hk", +"blogspot.hr", +"blogspot.hu", +"blogspot.ie", +"blogspot.in", +"blogspot.is", +"blogspot.it", +"blogspot.jp", +"blogspot.kr", +"blogspot.li", +"blogspot.lt", +"blogspot.lu", +"blogspot.md", +"blogspot.mk", +"blogspot.mr", +"blogspot.mx", +"blogspot.my", +"blogspot.nl", +"blogspot.no", +"blogspot.pe", +"blogspot.pt", +"blogspot.qa", +"blogspot.re", +"blogspot.ro", +"blogspot.rs", +"blogspot.ru", +"blogspot.se", +"blogspot.sg", +"blogspot.si", +"blogspot.sk", +"blogspot.sn", +"blogspot.td", +"blogspot.tw", +"blogspot.ug", +"blogspot.vn", +"cloudfunctions.net", +"cloud.goog", +"codespot.com", +"googleapis.com", +"googlecode.com", +"pagespeedmobilizer.com", +"publishproxy.com", +"withgoogle.com", +"withyoutube.com", +"hashbang.sh", +"hasura.app", +"hasura-app.io", +"hepforge.org", +"herokuapp.com", +"herokussl.com", +"myravendb.com", +"ravendb.community", +"ravendb.me", +"development.run", +"ravendb.run", +"moonscale.net", +"iki.fi", +"biz.at", +"info.at", +"info.cx", +"ac.leg.br", +"al.leg.br", +"am.leg.br", +"ap.leg.br", +"ba.leg.br", +"ce.leg.br", +"df.leg.br", +"es.leg.br", +"go.leg.br", +"ma.leg.br", +"mg.leg.br", +"ms.leg.br", +"mt.leg.br", +"pa.leg.br", +"pb.leg.br", +"pe.leg.br", +"pi.leg.br", +"pr.leg.br", +"rj.leg.br", +"rn.leg.br", +"ro.leg.br", +"rr.leg.br", +"rs.leg.br", +"sc.leg.br", +"se.leg.br", +"sp.leg.br", +"to.leg.br", +"pixolino.com", +"ipifony.net", +"mein-iserv.de", +"test-iserv.de", +"myjino.ru", +"js.org", +"keymachine.de", +"knightpoint.systems", +"co.krd", +"edu.krd", +"git-repos.de", +"lcube-server.de", +"svn-repos.de", +"app.lmpm.com", +"linkitools.space", +"linkyard.cloud", +"linkyard-cloud.ch", +"we.bs", +"uklugs.org", +"glug.org.uk", +"lug.org.uk", +"lugs.org.uk", +"barsy.bg", +"barsy.co.uk", +"barsyonline.co.uk", +"barsycenter.com", +"barsyonline.com", +"barsy.club", +"barsy.de", +"barsy.eu", +"barsy.in", +"barsy.info", +"barsy.io", +"barsy.me", +"barsy.menu", +"barsy.mobi", +"barsy.net", +"barsy.online", +"barsy.org", +"barsy.pro", +"barsy.pub", +"barsy.shop", +"barsy.site", +"barsy.support", +"barsy.uk", +"mayfirst.info", +"mayfirst.org", +"hb.cldmail.ru", +"miniserver.com", +"memset.net", +"cloud.metacentrum.cz", +"custom.metacentrum.cz", +"flt.cloud.muni.cz", +"usr.cloud.muni.cz", +"meteorapp.com", +"eu.meteorapp.com", +"co.pl", +"azurecontainer.io", +"azurewebsites.net", +"azure-mobile.net", +"cloudapp.net", +"mozilla-iot.org", +"bmoattachments.org", +"net.ru", +"org.ru", +"pp.ru", +"bitballoon.com", +"netlify.com", +"4u.com", +"ngrok.io", +"nh-serv.co.uk", +"nfshost.com", +"dnsking.ch", +"mypi.co", +"n4t.co", +"001www.com", +"ddnslive.com", +"myiphost.com", +"forumz.info", +"16-b.it", +"32-b.it", +"64-b.it", +"soundcast.me", +"tcp4.me", +"dnsup.net", +"hicam.net", +"now-dns.net", +"ownip.net", +"vpndns.net", +"dynserv.org", +"now-dns.org", +"x443.pw", +"now-dns.top", +"ntdll.top", +"freeddns.us", +"crafting.xyz", +"zapto.xyz", +"nsupdate.info", +"nerdpol.ovh", +"blogsyte.com", +"brasilia.me", +"cable-modem.org", +"ciscofreak.com", +"collegefan.org", +"couchpotatofries.org", +"damnserver.com", +"ddns.me", +"ditchyourip.com", +"dnsfor.me", +"dnsiskinky.com", +"dvrcam.info", +"dynns.com", +"eating-organic.net", +"fantasyleague.cc", +"geekgalaxy.com", +"golffan.us", +"health-carereform.com", +"homesecuritymac.com", +"homesecuritypc.com", +"hopto.me", +"ilovecollege.info", +"loginto.me", +"mlbfan.org", +"mmafan.biz", +"myactivedirectory.com", +"mydissent.net", +"myeffect.net", +"mymediapc.net", +"mypsx.net", +"mysecuritycamera.com", +"mysecuritycamera.net", +"mysecuritycamera.org", +"net-freaks.com", +"nflfan.org", +"nhlfan.net", +"no-ip.ca", +"no-ip.co.uk", +"no-ip.net", +"noip.us", +"onthewifi.com", +"pgafan.net", +"point2this.com", +"pointto.us", +"privatizehealthinsurance.net", +"quicksytes.com", +"read-books.org", +"securitytactics.com", +"serveexchange.com", +"servehumour.com", +"servep2p.com", +"servesarcasm.com", +"stufftoread.com", +"ufcfan.org", +"unusualperson.com", +"workisboring.com", +"3utilities.com", +"bounceme.net", +"ddns.net", +"ddnsking.com", +"gotdns.ch", +"hopto.org", +"myftp.biz", +"myftp.org", +"myvnc.com", +"no-ip.biz", +"no-ip.info", +"no-ip.org", +"noip.me", +"redirectme.net", +"servebeer.com", +"serveblog.net", +"servecounterstrike.com", +"serveftp.com", +"servegame.com", +"servehalflife.com", +"servehttp.com", +"serveirc.com", +"serveminecraft.net", +"servemp3.com", +"servepics.com", +"servequake.com", +"sytes.net", +"webhop.me", +"zapto.org", +"stage.nodeart.io", +"nodum.co", +"nodum.io", +"pcloud.host", +"nyc.mn", +"nom.ae", +"nom.af", +"nom.ai", +"nom.al", +"nym.by", +"nym.bz", +"nom.cl", +"nom.gd", +"nom.ge", +"nom.gl", +"nym.gr", +"nom.gt", +"nym.gy", +"nom.hn", +"nym.ie", +"nom.im", +"nom.ke", +"nym.kz", +"nym.la", +"nym.lc", +"nom.li", +"nym.li", +"nym.lt", +"nym.lu", +"nym.me", +"nom.mk", +"nym.mn", +"nym.mx", +"nom.nu", +"nym.nz", +"nym.pe", +"nym.pt", +"nom.pw", +"nom.qa", +"nym.ro", +"nom.rs", +"nom.si", +"nym.sk", +"nom.st", +"nym.su", +"nym.sx", +"nom.tj", +"nym.tw", +"nom.ug", +"nom.uy", +"nom.vc", +"nom.vg", +"cya.gg", +"cloudycluster.net", +"nid.io", +"opencraft.hosting", +"operaunite.com", +"outsystemscloud.com", +"ownprovider.com", +"own.pm", +"ox.rs", +"oy.lc", +"pgfog.com", +"pagefrontapp.com", +"art.pl", +"gliwice.pl", +"krakow.pl", +"poznan.pl", +"wroc.pl", +"zakopane.pl", +"pantheonsite.io", +"gotpantheon.com", +"mypep.link", +"on-web.fr", +"xen.prgmr.com", +"priv.at", +"protonet.io", +"chirurgiens-dentistes-en-france.fr", +"byen.site", +"ras.ru", +"qa2.com", +"dev-myqnapcloud.com", +"alpha-myqnapcloud.com", +"myqnapcloud.com", +"vapor.cloud", +"vaporcloud.io", +"rackmaze.com", +"rackmaze.net", +"rhcloud.com", +"resindevice.io", +"devices.resinstaging.io", +"hzc.io", +"wellbeingzone.eu", +"ptplus.fit", +"wellbeingzone.co.uk", +"sandcats.io", +"logoip.de", +"logoip.com", +"schokokeks.net", +"scrysec.com", +"firewall-gateway.com", +"firewall-gateway.de", +"my-gateway.de", +"my-router.de", +"spdns.de", +"spdns.eu", +"firewall-gateway.net", +"my-firewall.org", +"myfirewall.org", +"spdns.org", +"biz.ua", +"co.ua", +"pp.ua", +"shiftedit.io", +"myshopblocks.com", +"1kapp.com", +"appchizi.com", +"applinzi.com", +"sinaapp.com", +"vipsinaapp.com", +"bounty-full.com", +"alpha.bounty-full.com", +"beta.bounty-full.com", +"static.land", +"dev.static.land", +"sites.static.land", +"apps.lair.io", +"spacekit.io", +"customer.speedpartner.de", +"storj.farm", +"utwente.io", +"temp-dns.com", +"diskstation.me", +"dscloud.biz", +"dscloud.me", +"dscloud.mobi", +"dsmynas.com", +"dsmynas.net", +"dsmynas.org", +"familyds.com", +"familyds.net", +"familyds.org", +"i234.me", +"myds.me", +"synology.me", +"vpnplus.to", +"taifun-dns.de", +"gda.pl", +"gdansk.pl", +"gdynia.pl", +"med.pl", +"sopot.pl", +"gwiddle.co.uk", +"cust.dev.thingdust.io", +"cust.disrec.thingdust.io", +"cust.prod.thingdust.io", +"cust.testing.thingdust.io", +"bloxcms.com", +"townnews-staging.com", +"12hp.at", +"2ix.at", +"4lima.at", +"lima-city.at", +"12hp.ch", +"2ix.ch", +"4lima.ch", +"lima-city.ch", +"trafficplex.cloud", +"de.cool", +"12hp.de", +"2ix.de", +"4lima.de", +"lima-city.de", +"1337.pictures", +"clan.rip", +"lima-city.rocks", +"webspace.rocks", +"lima.zone", +"tuxfamily.org", +"dd-dns.de", +"diskstation.eu", +"diskstation.org", +"dray-dns.de", +"draydns.de", +"dyn-vpn.de", +"dynvpn.de", +"mein-vigor.de", +"my-vigor.de", +"my-wan.de", +"syno-ds.de", +"synology-diskstation.de", +"synology-ds.de", +"uber.space", +"hk.com", +"hk.org", +"ltd.hk", +"inc.hk", +"virtualuser.de", +"virtual-user.de", +"lib.de.us", +"2038.io", +"router.management", +"v-info.info", +"wedeploy.io", +"wedeploy.me", +"wedeploy.sh", +"remotewd.com", +"wmflabs.org", +"half.host", +"xnbay.com", +"u2.xnbay.com", +"u2-local.xnbay.com", +"cistron.nl", +"demon.nl", +"xs4all.space", +"official.academy", +"yolasite.com", +"ybo.faith", +"yombo.me", +"homelink.one", +"ybo.party", +"ybo.review", +"ybo.science", +"ybo.trade", +"nohost.me", +"noho.st", +"za.net", +"za.org", +"now.sh", +"zone.id", +0}; diff --git a/pubsuffix.hh b/pubsuffix.hh new file mode 100644 index 0000000..721200d --- /dev/null +++ b/pubsuffix.hh @@ -0,0 +1,24 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_PUBSUFFIX_HH +extern const char* g_pubsuffix[]; +#endif diff --git a/qtype.cc b/qtype.cc new file mode 100644 index 0000000..31f3831 --- /dev/null +++ b/qtype.cc @@ -0,0 +1,116 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#include "dns.hh" +#include +#include +#include +#include +#include +#include "qtype.hh" +#include "misc.hh" + +static_assert(sizeof(QType) == 2, "QType is not 2 bytes in size, something is wrong!"); + +vector QType::names; +// XXX FIXME we need to do something with initializer order here! +QType::init QType::initializer; + +QType::QType() +{ + code = 0; +} + +bool QType::isSupportedType() { + for(vector::iterator pos=names.begin();possecond==code) + return true; + return false; +} + +bool QType::isMetadataType() { + if (code == QType::AXFR || + code == QType::MAILA || + code == QType::MAILB || + code == QType::TSIG || + code == QType::IXFR) + return true; + + return false; +} + +uint16_t QType::getCode() const +{ + return code; +} + +const string QType::getName() const +{ + vector::iterator pos; + for(pos=names.begin();possecond==code) + return pos->first; + + return "TYPE"+itoa(code); +} + +QType &QType::operator=(uint16_t n) +{ + code=n; + return *this; +} + +int QType::chartocode(const char *p) +{ + string P = toUpper(p); + vector::iterator pos; + + for(pos=names.begin(); pos < names.end(); ++pos) + if(pos->first == P) + return pos->second; + + if(*p=='#') { + return atoi(p+1); + } + + if(boost::starts_with(P, "TYPE")) + return atoi(p+4); + + return 0; +} + +QType &QType::operator=(const char *p) +{ + code=chartocode(p); + return *this; +} + +QType &QType::operator=(const string &s) +{ + code=chartocode(s.c_str()); + return *this; +} + + +QType::QType(uint16_t n): QType() +{ + code=n; +} diff --git a/qtype.hh b/qtype.hh new file mode 100644 index 0000000..5d3577f --- /dev/null +++ b/qtype.hh @@ -0,0 +1,230 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 QTYPE_HH +#define QTYPE_HH +// $Id$ +#include +#include +#include "namespaces.hh" + +/** The QType class is meant to deal easily with the different kind of resource types, like 'A', 'NS', + * 'CNAME' etcetera. These types have both a name and a number. This class can seamlessly move between + * them. Use it like this: + +\code + QType t; + t="CNAME"; + cout< namenum; + static vector names; + + inline bool operator==(const QType &comp) const { + return(comp.code==code); + } + + inline bool operator!=(const QType &comp) const { + return(comp.code!=code); + } + + inline bool operator==(QType::typeenum comp) const { + return(comp==code); + } + + inline bool operator!=(QType::typeenum comp) const { + return(comp!=code); + } + + inline bool operator==(uint16_t comp) const { + return(comp==code); + } + + inline bool operator!=(uint16_t comp) const { + return(comp!=code); + } + +private: + static class init { + public: + void qtype_insert(const char* a, uint16_t num) + { + names.push_back(make_pair(string(a), num)); + } + + init() + { + qtype_insert("A", 1); + qtype_insert("NS", 2); + qtype_insert("CNAME", 5); + qtype_insert("SOA", 6); + qtype_insert("MR", 9); + qtype_insert("PTR", 12); + qtype_insert("HINFO", 13); + qtype_insert("MINFO", 14); + qtype_insert("MX", 15); + qtype_insert("TXT", 16); + qtype_insert("RP", 17); + qtype_insert("AFSDB", 18); + qtype_insert("SIG", 24); + qtype_insert("KEY", 25); + qtype_insert("AAAA", 28); + qtype_insert("LOC", 29); + qtype_insert("SRV", 33); + qtype_insert("NAPTR", 35); + qtype_insert("KX", 36); + qtype_insert("CERT", 37); + qtype_insert("A6", 38); + qtype_insert("DNAME", 39); + qtype_insert("OPT", 41); + qtype_insert("DS", 43); + qtype_insert("SSHFP", 44); + qtype_insert("IPSECKEY", 45); + qtype_insert("RRSIG", 46); + qtype_insert("NSEC", 47); + qtype_insert("DNSKEY", 48); + qtype_insert("DHCID", 49); + qtype_insert("NSEC3", 50); + qtype_insert("NSEC3PARAM", 51); + qtype_insert("TLSA", 52); + qtype_insert("RKEY", 57); + qtype_insert("CDS", 59); + qtype_insert("CDNSKEY", 60); + qtype_insert("OPENPGPKEY", 61); + qtype_insert("SPF", 99); + qtype_insert("EUI48", 108); + qtype_insert("EUI64", 109); + qtype_insert("TKEY", 249); +// qtype_insert("TSIG", 250); + qtype_insert("IXFR", 251); + qtype_insert("AXFR", 252); + qtype_insert("MAILB", 253); + qtype_insert("MAILA", 254); + qtype_insert("ANY", 255); + qtype_insert("URI", 256); + qtype_insert("CAA", 257); + qtype_insert("DLV", 32769); + qtype_insert("ADDR", 65400); + qtype_insert("ALIAS", 65401); + } + } initializer; + + uint16_t code; +}; + +struct QClass +{ + enum QClassEnum {IN=1, CHAOS=3, NONE=254, ANY=255}; +}; +#endif diff --git a/randomhelper.cc b/randomhelper.cc new file mode 100644 index 0000000..8d8b2db --- /dev/null +++ b/randomhelper.cc @@ -0,0 +1,40 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "misc.hh" +#include "logger.hh" +#include +#include +#include +#include +#include "dns_random.hh" + +void seedRandom(const string& source) +{ + L< +#include +#include "base32.hh" +#include "base64.hh" +#include "namespaces.hh" + +RecordTextReader::RecordTextReader(const string& str, const string& zone) : d_string(str), d_zone(zone), d_pos(0), d_end(str.size()) +{ +} + +void RecordTextReader::xfr48BitInt(uint64_t &val) +{ + xfr64BitInt(val); + if (val > 281474976710655LL) + throw RecordTextException("Overflow reading 48 bit integer from record content"); // fixme improve +} + +void RecordTextReader::xfr64BitInt(uint64_t &val) +{ + skipSpaces(); + + if(!isdigit(d_string.at(d_pos))) + throw RecordTextException("expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); + + size_t pos; + val=std::stoull(d_string.substr(d_pos), &pos); + + d_pos += pos; +} + + +void RecordTextReader::xfr32BitInt(uint32_t &val) +{ + skipSpaces(); + + if(!isdigit(d_string.at(d_pos))) + throw RecordTextException("expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); + + size_t pos; + val=pdns_stou(d_string.c_str()+d_pos, &pos); + + d_pos += pos; +} + +void RecordTextReader::xfrTime(uint32_t &val) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + + uint64_t itmp; + xfr64BitInt(itmp); + + ostringstream tmp; + + tmp< 3) + break; + } + else if(isdigit(d_string.at(d_pos))) { + octet*=10; + octet+=d_string.at(d_pos) - '0'; + if(octet > 255) + throw RecordTextException("unable to parse IP address"); + } + else if(dns_isspace(d_string.at(d_pos))) + break; + else { + throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos)); + } + d_pos++; + if(d_pos == d_string.length()) + break; + } + if(count<=3) { + val<<=8; + val+=octet; + } + val=ntohl(val); +} + + +void RecordTextReader::xfrIP6(std::string &val) +{ + struct in6_addr tmpbuf; + + skipSpaces(); + + size_t len; + // lookup end of value - think of ::ffff encoding too, has dots in it! + for(len=0; + d_pos+len < d_string.length() && (isxdigit(d_string.at(d_pos+len)) || d_string.at(d_pos+len) == ':' || d_string.at(d_pos+len)=='.'); + len++); + + if(!len) + throw RecordTextException("while parsing IPv6 address, expected xdigits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); + + // end of value is here, try parse as IPv6 + string address=d_string.substr(d_pos, len); + + if (inet_pton(AF_INET6, address.c_str(), &tmpbuf) != 1) { + throw RecordTextException("while parsing IPv6 address: '" + address + "' is invalid"); + } + + val = std::string((char*)tmpbuf.s6_addr, 16); + + d_pos += len; +} + +bool RecordTextReader::eof() +{ + return d_pos==d_end; +} + +void RecordTextReader::xfr16BitInt(uint16_t &val) +{ + uint32_t tmp; + xfr32BitInt(tmp); + val=tmp; + if(val!=tmp) + throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve +} + +void RecordTextReader::xfr8BitInt(uint8_t &val) +{ + uint32_t tmp; + xfr32BitInt(tmp); + val=tmp; + if(val!=tmp) + throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve +} + +// this code should leave all the escapes around +void RecordTextReader::xfrName(DNSName& val, bool, bool) +{ + skipSpaces(); + string sval; + sval.reserve(d_end - d_pos); + + const char* strptr=d_string.c_str(); + string::size_type begin_pos = d_pos; + while(d_pos < d_end) { + if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos])) + break; + + d_pos++; + } + sval.append(strptr+begin_pos, strptr+d_pos); + + if(sval.empty()) + sval=d_zone; + else if(!d_zone.empty()) { + char last=sval[sval.size()-1]; + + if(last =='.') + sval.resize(sval.size()-1); + else if(last != '.' && !isdigit(last)) // don't add zone to IP address + sval+="."+d_zone; + } + val = DNSName(sval); +} + +static bool isbase64(char c, bool acceptspace) +{ + if(dns_isspace(c)) + return acceptspace; + if(c >= '0' && c <= '9') + return true; + if(c >= 'a' && c <= 'z') + return true; + if(c >= 'A' && c <= 'Z') + return true; + if(c=='+' || c=='/' || c=='=') + return true; + return false; +} + +void RecordTextReader::xfrBlobNoSpaces(string& val, int len) { + skipSpaces(); + int pos=(int)d_pos; + const char* strptr=d_string.c_str(); + while(d_pos < d_end && isbase64(strptr[d_pos], false)) + d_pos++; + + string tmp; + tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); + boost::erase_all(tmp," "); + val.clear(); + B64Decode(tmp, val); + + if (len>-1 && val.size() != static_cast(len)) + throw RecordTextException("Record length "+std::to_string(val.size()) + " does not match expected length '"+std::to_string(len)); +} + +void RecordTextReader::xfrBlob(string& val, int) +{ + skipSpaces(); + int pos=(int)d_pos; + const char* strptr=d_string.c_str(); + while(d_pos < d_end && isbase64(strptr[d_pos], true)) + d_pos++; + + string tmp; + tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); + boost::erase_all(tmp," "); + val.clear(); + B64Decode(tmp, val); +} + + +static inline uint8_t hextodec(uint8_t val) +{ + if(val >= '0' && val<='9') + return val-'0'; + else if(val >= 'A' && val<='F') + return 10+(val-'A'); + else if(val >= 'a' && val<='f') + return 10+(val-'a'); + else + throw RecordTextException("Unknown hexadecimal character '"+std::to_string(val)+"'"); +} + + +void HEXDecode(const char* begin, const char* end, string& out) +{ + if(end - begin == 1 && *begin=='-') { + out.clear(); + return; + } + out.clear(); + out.reserve((end-begin)/2); + uint8_t mode=0, val=0; + for(; begin != end; ++begin) { + if(!isalnum(*begin)) + continue; + if(mode==0) { + val = 16*hextodec(*begin); + mode=1; + } else { + val += hextodec(*begin); + out.append(1, (char) val); + mode = 0; + val = 0; + } + } + if(mode) + out.append(1, (char) val); + +} + +void RecordTextReader::xfrHexBlob(string& val, bool keepReading) +{ + skipSpaces(); + int pos=(int)d_pos; + while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos]))) + d_pos++; + + HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val); +} + +void RecordTextReader::xfrBase32HexBlob(string& val) +{ + skipSpaces(); + int pos=(int)d_pos; + while(d_pos < d_end && !dns_isspace(d_string[d_pos])) + d_pos++; + + val=fromBase32Hex(string(d_string.c_str()+pos, d_pos-pos)); +} + + +void RecordTextWriter::xfrBase32HexBlob(const string& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + d_string.append(toUpper(toBase32Hex(val))); +} + + +void RecordTextReader::xfrText(string& val, bool multi, bool lenField) +{ + val.clear(); + val.reserve(d_end - d_pos); + + while(d_pos != d_end) { + if(!val.empty()) + val.append(1, ' '); + + skipSpaces(); + if(d_string[d_pos]!='"') { // special case 'plenus' - without quotes + string::size_type pos = d_pos; + while(pos != d_end && isalnum(d_string[pos])) + pos++; + if(pos == d_end) { + val.append(1, '"'); + val.append(d_string.c_str() + d_pos, d_end - d_pos); + val.append(1, '"'); + d_pos = d_end; + break; + } + throw RecordTextException("Data field in DNS should start with quote (\") at position "+std::to_string(d_pos)+" of '"+d_string+"'"); + } + val.append(1, '"'); + while(++d_pos < d_end && d_string[d_pos]!='"') { + if(d_string[d_pos]=='\\' && d_pos+1!=d_end) { + val.append(1, d_string[d_pos++]); + } + val.append(1, d_string[d_pos]); + } + val.append(1,'"'); + if(d_pos == d_end) + throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); + d_pos++; + if(!multi) + break; + } +} + +void RecordTextReader::xfrUnquotedText(string& val, bool lenField) +{ + val.clear(); + val.reserve(d_end - d_pos); + + if(!val.empty()) + val.append(1, ' '); + + skipSpaces(); + val.append(1, d_string[d_pos]); + while(++d_pos < d_end && d_string[d_pos] != ' '){ + val.append(1, d_string[d_pos]); + } +} + +void RecordTextReader::xfrType(uint16_t& val) +{ + skipSpaces(); + int pos=(int)d_pos; + while(d_pos < d_end && !dns_isspace(d_string[d_pos])) + d_pos++; + + string tmp; + tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); + + val=DNSRecordContent::TypeToNumber(tmp); +} + + +void RecordTextReader::skipSpaces() +{ + const char* strptr = d_string.c_str(); + while(d_pos < d_end && dns_isspace(strptr[d_pos])) + d_pos++; + if(d_pos == d_end) + throw RecordTextException("missing field at the end of record content '"+d_string+"'"); +} + + +RecordTextWriter::RecordTextWriter(string& str, bool noDot) : d_string(str) +{ + d_string.clear(); + d_nodot=noDot; +} + +void RecordTextWriter::xfr48BitInt(const uint64_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + d_string+=std::to_string(val); +} + + +void RecordTextWriter::xfr32BitInt(const uint32_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + d_string+=std::to_string(val); +} + +void RecordTextWriter::xfrType(const uint16_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + d_string+=DNSRecordContent::NumberToType(val); +} + +// this function is on the fast path for the pdns_recursor +void RecordTextWriter::xfrIP(const uint32_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + char tmp[17]; + uint32_t ip=val; + uint8_t vals[4]; + + memcpy(&vals[0], &ip, sizeof(ip)); + + char *pos=tmp; + + for(int n=0; n < 4; ++n) { + if(vals[n]<10) { + *(pos++)=vals[n]+'0'; + } else if(vals[n] < 100) { + *(pos++)=(vals[n]/10) +'0'; + *(pos++)=(vals[n]%10) +'0'; + } else { + *(pos++)=(vals[n]/100) +'0'; + vals[n]%=100; + *(pos++)=(vals[n]/10) +'0'; + *(pos++)=(vals[n]%10) +'0'; + } + if(n!=3) + *(pos++)='.'; + } + *pos=0; + d_string.append(tmp, pos); +} + +void RecordTextWriter::xfrIP6(const std::string& val) +{ + char tmpbuf[16]; + char addrbuf[40]; + + if(!d_string.empty()) + d_string.append(1,' '); + + val.copy(tmpbuf,16); + + if (inet_ntop(AF_INET6, tmpbuf, addrbuf, sizeof addrbuf) == NULL) + throw RecordTextException("Unable to convert to ipv6 address"); + + d_string += std::string(addrbuf); +} + +void RecordTextWriter::xfrTime(const uint32_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + struct tm tm; + time_t time=val; // Y2038 bug! + gmtime_r(&time, &tm); + + char tmp[16]; + snprintf(tmp,sizeof(tmp)-1, "%04d%02d%02d" "%02d%02d%02d", + tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + d_string += tmp; +} + + +void RecordTextWriter::xfr16BitInt(const uint16_t& val) +{ + xfr32BitInt(val); +} + +void RecordTextWriter::xfr8BitInt(const uint8_t& val) +{ + xfr32BitInt(val); +} + +// should not mess with the escapes +void RecordTextWriter::xfrName(const DNSName& val, bool, bool noDot) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + if(d_nodot) { + d_string+=val.toStringRootDot(); + } + else + { + d_string+=val.toString(); + } +} + +void RecordTextWriter::xfrBlobNoSpaces(const string& val, int size) +{ + xfrBlob(val, size); +} + +void RecordTextWriter::xfrBlob(const string& val, int) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + d_string+=Base64Encode(val); +} + +void RecordTextWriter::xfrHexBlob(const string& val, bool) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + if(val.empty()) { + d_string.append(1,'-'); + return; + } + + string::size_type limit=val.size(); + char tmp[5]; + for(string::size_type n = 0; n < limit; ++n) { + snprintf(tmp, sizeof(tmp)-1, "%02x", (unsigned char)val[n]); + d_string+=tmp; + } +} + +void RecordTextWriter::xfrText(const string& val, bool multi, bool lenField) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + d_string.append(val); +} + +void RecordTextWriter::xfrUnquotedText(const string& val, bool lenField) +{ + if(!d_string.empty()) + d_string.append(1,' '); + d_string.append(val); +} + +#ifdef TESTING + +int main(int argc, char**argv) +try +{ + RecordTextReader rtr(argv[1], argv[2]); + + unsigned int order, pref; + string flags, services, regexp, replacement; + string mx; + + rtr.xfrInt(order); + rtr.xfrInt(pref); + rtr.xfrText(flags); + rtr.xfrText(services); + rtr.xfrText(regexp); + rtr.xfrName(replacement); + + cout<<"order: "< +#include +#include + +#include "namespaces.hh" +#include "dnsname.hh" + +class RecordTextException : public runtime_error +{ +public: + RecordTextException(const string& str) : runtime_error(str) + {} +}; + +class RecordTextReader +{ +public: + RecordTextReader(const string& str, const string& zone=""); + void xfr64BitInt(uint64_t& val); + void xfr48BitInt(uint64_t& val); + void xfr32BitInt(uint32_t& val); + void xfr16BitInt(uint16_t& val); + void xfr8BitInt(uint8_t& val); + + void xfrType(uint16_t& val); + void xfrIP(uint32_t& val); + void xfrIP6(std::string& val); + void xfrTime(uint32_t& val); + + void xfrName(DNSName& val, bool compress=false, bool noDot=false); + void xfrText(string& val, bool multi=false, bool lenField=true); + void xfrUnquotedText(string& val, bool lenField=true); + void xfrHexBlob(string& val, bool keepReading=false); + void xfrBase32HexBlob(string& val); + + void xfrBlobNoSpaces(string& val, int len=-1); + void xfrBlob(string& val, int len=-1); + + bool eof(); +private: + string d_string; + string d_zone; + string::size_type d_pos; + string::size_type d_end; + void skipSpaces(); +}; + +class RecordTextWriter +{ +public: + RecordTextWriter(string& str, bool noDot=false); + void xfr48BitInt(const uint64_t& val); + void xfr32BitInt(const uint32_t& val); + void xfr16BitInt(const uint16_t& val); + void xfr8BitInt(const uint8_t& val); + void xfrIP(const uint32_t& val); + void xfrIP6(const std::string& val); + void xfrTime(const uint32_t& val); + void xfrBase32HexBlob(const string& val); + + void xfrType(const uint16_t& val); + void xfrName(const DNSName& val, bool compress=false, bool noDot=false); + void xfrText(const string& val, bool multi=false, bool lenField=true); + void xfrUnquotedText(const string& val, bool lenField=true); + void xfrBlobNoSpaces(const string& val, int len=-1); + void xfrBlob(const string& val, int len=-1); + void xfrHexBlob(const string& val, bool keepReading=false); + bool eof() { return true; }; +private: + string& d_string; + bool d_nodot; +}; +#endif diff --git a/rec-carbon.cc b/rec-carbon.cc new file mode 100644 index 0000000..f8098ed --- /dev/null +++ b/rec-carbon.cc @@ -0,0 +1,79 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "syncres.hh" +#include "mtasker.hh" +#include "rec_channel.hh" +#include "iputils.hh" +#include "logger.hh" +#include "arguments.hh" +#include "lock.hh" + + +void doCarbonDump(void*) +try +{ + string hostname; + vector carbonServers; + + { + Lock l(&g_carbon_config_lock); + stringtok(carbonServers, arg()["carbon-server"], ", "); + hostname=arg()["carbon-ourname"]; + } + + if(carbonServers.empty()) + return; + + if(hostname.empty()) { + char tmp[80]; + memset(tmp, 0, sizeof(tmp)); + gethostname(tmp, sizeof(tmp)); + char *p = strchr(tmp, '.'); + if(p) *p=0; + + hostname=tmp; + boost::replace_all(hostname, ".", "_"); + } + + registerAllStats(); + string msg; + for(const auto& carbonServer: carbonServers) { + ComboAddress remote(carbonServer, 2003); + Socket s(remote.sin4.sin_family, SOCK_STREAM); + + s.setNonBlocking(); + s.connect(remote); // we do the connect so the first attempt happens while we gather stats + + if(msg.empty()) { + typedef map all_t; + all_t all=getAllStatsMap(); + + ostringstream str; + time_t now=time(0); + + for(const all_t::value_type& val : all) { + str<<"pdns."< +#include +#include "namespaces.hh" +#include "syncres.hh" +#include "logger.hh" +#include "rec-lua-conf.hh" +#include "sortlist.hh" +#include "filterpo.hh" +#include "rpzloader.hh" +#include "base64.hh" +#include "remote_logger.hh" +#include "validate.hh" +#include "validate-recursor.hh" +#include "root-dnssec.hh" + +GlobalStateHolder g_luaconfs; + +/* SO HOW DOES THIS WORK! AND PLEASE PAY ATTENTION! + This function can be called at any time. It is expected to overwrite all the contents + of LuaConfigItems, which is held in a GlobalStateHolder for RCU properties. + + This function can be called again at a later date, so you must make sure that anything you + allow to be configured from here lives in g_luaconfs AND NOWHERE ELSE. + + If someone loads an empty Lua file, the default LuaConfigItems struct MUST MAKE SENSE. + + To make this easy on you, here is a LuaConfigItems constructor where you + can set sane defaults: +*/ + +LuaConfigItems::LuaConfigItems() +{ + DNSName root("."); // don't use g_rootdnsname here, it might not exist yet + for (const auto &dsRecord : rootDSs) { + auto ds=unique_ptr(dynamic_cast(DSRecordContent::make(dsRecord))); + dsAnchors[root].insert(*ds); + } +} + +/* DID YOU READ THE STORY ABOVE? */ + +template +typename C::value_type::second_type constGet(const C& c, const std::string& name) +{ + auto iter = c.find(name); + if(iter == c.end()) + return 0; + return iter->second; +} + + +static void parseRPZParameters(const std::unordered_map >& have, std::string& polName, boost::optional& defpol, uint32_t& maxTTL, size_t& zoneSizeHint) +{ + if(have.count("policyName")) { + polName = boost::get(constGet(have, "policyName")); + } + if(have.count("defpol")) { + defpol=DNSFilterEngine::Policy(); + defpol->d_kind = (DNSFilterEngine::PolicyKind)boost::get(constGet(have, "defpol")); + defpol->d_name = std::make_shared(polName); + if(defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) { + defpol->d_custom= + DNSRecordContent::mastermake(QType::CNAME, 1, + boost::get(constGet(have,"defcontent")) + ); + + if(have.count("defttl")) + defpol->d_ttl = static_cast(boost::get(constGet(have, "defttl"))); + else + defpol->d_ttl = -1; // get it from the zone + } + } + if(have.count("maxTTL")) { + maxTTL = boost::get(constGet(have, "maxTTL")); + } + if(have.count("zoneSizeHint")) { + zoneSizeHint = static_cast(boost::get(constGet(have, "zoneSizeHint"))); + } +} + +void loadRecursorLuaConfig(const std::string& fname, bool checkOnly) +{ + LuaConfigItems lci; + + LuaContext Lua; + if(fname.empty()) + return; + ifstream ifs(fname); + if(!ifs) + throw PDNSException("Cannot open file '"+fname+"': "+strerror(errno)); + + std::vector, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t> > rpzMasterThreads; + + auto luaconfsLocal = g_luaconfs.getLocal(); + + Lua.writeFunction("clearSortlist", [&lci]() { lci.sortlist.clear(); }); + + /* we can get: "1.2.3.4" + {"1.2.3.4", "4.5.6.7"} + {"1.2.3.4", {"4.5.6.7", "8.9.10.11"}} + */ + + map pmap{ + {"NoAction", DNSFilterEngine::PolicyKind::NoAction}, + {"Drop", DNSFilterEngine::PolicyKind::Drop}, + {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN}, + {"NODATA", DNSFilterEngine::PolicyKind::NODATA}, + {"Truncate", DNSFilterEngine::PolicyKind::Truncate}, + {"Custom", DNSFilterEngine::PolicyKind::Custom} + }; + Lua.writeVariable("Policy", pmap); + + Lua.writeFunction("rpzFile", [&lci](const string& filename, const boost::optional>>& options) { + try { + boost::optional defpol; + std::string polName("rpzFile"); + std::shared_ptr zone = std::make_shared(); + uint32_t maxTTL = std::numeric_limits::max(); + if(options) { + auto& have = *options; + size_t zoneSizeHint = 0; + parseRPZParameters(have, polName, defpol, maxTTL, zoneSizeHint); + if (zoneSizeHint > 0) { + zone->reserve(zoneSizeHint); + } + } + theL()<setName(polName); + loadRPZFromFile(filename, zone, defpol, maxTTL); + lci.dfe.addZone(zone); + theL()<>>& options) { + + boost::optional defpol; + std::shared_ptr zone = std::make_shared(); + TSIGTriplet tt; + uint32_t refresh=0; + size_t maxReceivedXFRMBytes = 0; + uint16_t axfrTimeout = 20; + uint32_t maxTTL = std::numeric_limits::max(); + ComboAddress localAddress; + ComboAddress master(master_, 53); + size_t zoneIdx; + + try { + std::string polName(zoneName); + if(options) { + auto& have = *options; + size_t zoneSizeHint = 0; + parseRPZParameters(have, polName, defpol, maxTTL, zoneSizeHint); + if (zoneSizeHint > 0) { + zone->reserve(zoneSizeHint); + } + if(have.count("tsigname")) { + tt.name=DNSName(toLower(boost::get(constGet(have, "tsigname")))); + tt.algo=DNSName(toLower(boost::get(constGet(have, "tsigalgo")))); + if(B64Decode(boost::get(constGet(have, "tsigsecret")), tt.secret)) + throw std::runtime_error("TSIG secret is not valid Base-64 encoded"); + } + if(have.count("refresh")) { + refresh = boost::get(constGet(have,"refresh")); + } + if(have.count("maxReceivedMBytes")) { + maxReceivedXFRMBytes = static_cast(boost::get(constGet(have,"maxReceivedMBytes"))); + } + if(have.count("localAddress")) { + localAddress = ComboAddress(boost::get(constGet(have,"localAddress"))); + } + if(have.count("axfrTimeout")) { + axfrTimeout = static_cast(boost::get(constGet(have, "axfrTimeout"))); + } + } + if (localAddress != ComboAddress() && localAddress.sin4.sin_family != master.sin4.sin_family) { + // We were passed a localAddress, check if its AF matches the master's + throw PDNSException("Master address("+master.toString()+") is not of the same Address Family as the local address ("+localAddress.toString()+")."); + } + + zone->setDomain(DNSName(zoneName)); + zone->setName(polName); + zone->setRefresh(refresh); + zoneIdx = lci.dfe.addZone(zone); + } + catch(const std::exception& e) { + theL()< > > > > argvec_t; + Lua.writeFunction("addSortList", + [&lci](const std::string& formask_, + const boost::variant& masks, + boost::optional order_) + { + try { + Netmask formask(formask_); + int order = order_ ? (*order_) : lci.sortlist.getMaxOrder(formask)+1; + if(auto str = boost::get(&masks)) + lci.sortlist.addEntry(formask, Netmask(*str), order); + else { + + auto vec = boost::get(&masks); + for(const auto& e : *vec) { + if(auto s = boost::get(&e.second)) { + lci.sortlist.addEntry(formask, Netmask(*s), order); + } + else { + const auto& v =boost::get > >(e.second); + for(const auto& entry : v) + lci.sortlist.addEntry(formask, Netmask(entry.second), order); + } + ++order; + } + } + } + catch(std::exception& e) { + theL()<(dynamic_cast(DSRecordContent::make(what))); + lci.dsAnchors[zone].insert(*ds); + }); + + Lua.writeFunction("clearDS", [&lci](boost::optional who) { + warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearDS), but dnssec is set to 'off'!"); + if(who) + lci.dsAnchors.erase(DNSName(*who)); + else + lci.dsAnchors.clear(); + }); + + Lua.writeFunction("addNTA", [&lci](const std::string& who, const boost::optional why) { + warnIfDNSSECDisabled("Warning: adding Negative Trust Anchor for DNSSEC (addNTA), but dnssec is set to 'off'!"); + if(why) + lci.negAnchors[DNSName(who)] = static_cast(*why); + else + lci.negAnchors[DNSName(who)] = ""; + }); + + Lua.writeFunction("clearNTA", [&lci](boost::optional who) { + warnIfDNSSECDisabled("Warning: removing Negative Trust Anchor for DNSSEC (clearNTA), but dnssec is set to 'off'!"); + if(who) + lci.negAnchors.erase(DNSName(*who)); + else + lci.negAnchors.clear(); + }); + +#if HAVE_PROTOBUF + Lua.writeFunction("protobufServer", [&lci, checkOnly](const string& server_, const boost::optional timeout, const boost::optional maxQueuedEntries, const boost::optional reconnectWaitTime, const boost::optional maskV4, boost::optional maskV6, boost::optional asyncConnect, boost::optional taggedOnly) { + try { + ComboAddress server(server_); + if (!lci.protobufServer) { + if (!checkOnly) { + lci.protobufServer = std::make_shared(server, timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1, asyncConnect ? *asyncConnect : false); + } + + if (maskV4) { + lci.protobufMaskV4 = *maskV4; + } + if (maskV6) { + lci.protobufMaskV6 = *maskV6; + } + if (taggedOnly) { + lci.protobufTaggedOnly = *taggedOnly; + } + } + else { + theL()<toString()< timeout, const boost::optional maxQueuedEntries, const boost::optional reconnectWaitTime, boost::optional asyncConnect) { + try { + ComboAddress server(server_); + if (!lci.outgoingProtobufServer) { + if (!checkOnly) { + lci.outgoingProtobufServer = std::make_shared(server, timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1, asyncConnect ? *asyncConnect : false); + } + } + else { + theL()<toString()<(rpzMaster), std::get<1>(rpzMaster), std::get<2>(rpzMaster), std::get<3>(rpzMaster), std::get<4>(rpzMaster), std::get<5>(rpzMaster) * 1024 * 1024, std::get<6>(rpzMaster), std::get<7>(rpzMaster)); + t.detach(); + } + catch(const std::exception& e) { + L< dsAnchors; + map negAnchors; + std::shared_ptr protobufServer{nullptr}; + std::shared_ptr outgoingProtobufServer{nullptr}; + uint8_t protobufMaskV4{32}; + uint8_t protobufMaskV6{128}; + bool protobufTaggedOnly{false}; +}; + +extern GlobalStateHolder g_luaconfs; +void loadRecursorLuaConfig(const std::string& fname, bool checkOnly); + diff --git a/rec-protobuf.cc b/rec-protobuf.cc new file mode 100644 index 0000000..b0c2393 --- /dev/null +++ b/rec-protobuf.cc @@ -0,0 +1,128 @@ + +#include "config.h" +#include "rec-protobuf.hh" + +void RecProtoBufMessage::addRR(const DNSRecord& record) +{ +#ifdef HAVE_PROTOBUF + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (!response) { + return; + } + + if (record.d_place != DNSResourceRecord::ANSWER || + record.d_class != QClass::IN || + (record.d_type != QType::A && + record.d_type != QType::AAAA && + record.d_type != QType::CNAME)) { + return; + } + + PBDNSMessage_DNSResponse_DNSRR* pbRR = response->add_rrs(); + if (!pbRR) { + return; + } + + pbRR->set_name(record.d_name.toString()); + pbRR->set_type(record.d_type); + pbRR->set_class_(record.d_class); + pbRR->set_ttl(record.d_ttl); + if (record.d_type == QType::A) { + const ARecordContent& arc = dynamic_cast(*(record.d_content)); + ComboAddress data = arc.getCA(); + pbRR->set_rdata(&data.sin4.sin_addr.s_addr, sizeof(data.sin4.sin_addr.s_addr)); + } + else if (record.d_type == QType::AAAA) { + const AAAARecordContent& arc = dynamic_cast(*(record.d_content)); + ComboAddress data = arc.getCA(); + pbRR->set_rdata(&data.sin6.sin6_addr.s6_addr, sizeof(data.sin6.sin6_addr.s6_addr)); + } else if (record.d_type == QType::CNAME) { + const CNAMERecordContent& crc = dynamic_cast(*(record.d_content)); + DNSName data = crc.getTarget(); + pbRR->set_rdata(data.toString()); + } +#endif /* HAVE_PROTOBUF */ +} + +void RecProtoBufMessage::addRRs(const std::vector& records) +{ + for (const auto& record : records) { + addRR(record); + } +} + +void RecProtoBufMessage::setAppliedPolicy(const std::string& policy) +{ +#ifdef HAVE_PROTOBUF + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (response && !policy.empty()) { + response->set_appliedpolicy(policy); + } +#endif /* HAVE_PROTOBUF */ +} + +void RecProtoBufMessage::setAppliedPolicyType(const DNSFilterEngine::PolicyType& type) +{ +#ifdef HAVE_PROTOBUF + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (response) { + switch(type) { + case DNSFilterEngine::PolicyType::None: + response->set_appliedpolicytype(PBDNSMessage_PolicyType_UNKNOWN); + break; + case DNSFilterEngine::PolicyType::QName: + response->set_appliedpolicytype(PBDNSMessage_PolicyType_QNAME); + break; + case DNSFilterEngine::PolicyType::ClientIP: + response->set_appliedpolicytype(PBDNSMessage_PolicyType_CLIENTIP); + break; + case DNSFilterEngine::PolicyType::ResponseIP: + response->set_appliedpolicytype(PBDNSMessage_PolicyType_RESPONSEIP); + break; + case DNSFilterEngine::PolicyType::NSDName: + response->set_appliedpolicytype(PBDNSMessage_PolicyType_NSDNAME); + break; + case DNSFilterEngine::PolicyType::NSIP: + response->set_appliedpolicytype(PBDNSMessage_PolicyType_NSIP); + break; + default: + throw std::runtime_error("Unsupported protobuf policy type"); + } + } +#endif /* HAVE_PROTOBUF */ +} + +void RecProtoBufMessage::setPolicyTags(const std::vector& policyTags) +{ +#ifdef HAVE_PROTOBUF + PBDNSMessage_DNSResponse* response = d_message.mutable_response(); + if (response) { + for (const auto& tag : policyTags) { + response->add_tags(tag); + } + } +#endif /* HAVE_PROTOBUF */ +} + +std::string RecProtoBufMessage::getAppliedPolicy() const +{ + std::string result; +#ifdef HAVE_PROTOBUF + const PBDNSMessage_DNSResponse& response = d_message.response(); + result = response.appliedpolicy(); +#endif /* HAVE_PROTOBUF */ + return result; +} + +std::vector RecProtoBufMessage::getPolicyTags() const +{ + std::vector result; +#ifdef HAVE_PROTOBUF + const PBDNSMessage_DNSResponse& response = d_message.response(); + const int count = response.tags_size(); + for (int idx = 0; idx < count; idx++) { + result.push_back(response.tags(idx)); + } +#endif /* HAVE_PROTOBUF */ + return result; +} diff --git a/rec-protobuf.hh b/rec-protobuf.hh new file mode 100644 index 0000000..cebdbcb --- /dev/null +++ b/rec-protobuf.hh @@ -0,0 +1,52 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +#include "protobuf.hh" +#include "filterpo.hh" +#include "dnsrecords.hh" + +class RecProtoBufMessage: public DNSProtoBufMessage +{ +public: + RecProtoBufMessage(): DNSProtoBufMessage() + { + } + + RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type): DNSProtoBufMessage(type) + { + } + +#ifdef HAVE_PROTOBUF + RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type, const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, const DNSName& domain, int qtype, uint16_t qclass, uint16_t qid, bool isTCP, size_t bytes): DNSProtoBufMessage(type, uuid, requestor, responder, domain, qtype, qclass, qid, isTCP, bytes) + { + } +#endif /* HAVE_PROTOBUF */ + + void addRRs(const std::vector& records); + void addRR(const DNSRecord& record); + void setAppliedPolicy(const std::string& policy); + void setAppliedPolicyType(const DNSFilterEngine::PolicyType& policyType); + void setPolicyTags(const std::vector& policyTags); + std::string getAppliedPolicy() const; + std::vector getPolicyTags() const; +}; diff --git a/rec-snmp.cc b/rec-snmp.cc new file mode 100644 index 0000000..4669755 --- /dev/null +++ b/rec-snmp.cc @@ -0,0 +1,297 @@ + +#include + +#include "rec-snmp.hh" +#include "rec_channel.hh" + +#include "logger.hh" + +#ifdef HAVE_NET_SNMP + +#define RECURSOR_OID 1, 3, 6, 1, 4, 1, 43315, 2 +#define RECURSOR_STATS_OID RECURSOR_OID, 1 +#define RECURSOR_TRAPS_OID RECURSOR_OID, 10, 0 +#define RECURSOR_TRAP_OBJECTS_OID RECURSOR_OID, 11 + +static const oid trapReasonOID[] = { RECURSOR_TRAP_OBJECTS_OID, 1, 0 }; +static const oid customTrapOID[] = { RECURSOR_TRAPS_OID, 1 }; + +static const oid questionsOID[] = { RECURSOR_STATS_OID, 1 }; +static const oid ipv6QuestionsOID[] = { RECURSOR_STATS_OID, 2 }; +static const oid tcpQuestionsOID[] = { RECURSOR_STATS_OID, 3 }; +static const oid cacheHitsOID[] = { RECURSOR_STATS_OID, 4 }; +static const oid cacheMissesOID[] = { RECURSOR_STATS_OID, 5 }; +static const oid cacheEntriesOID[] = { RECURSOR_STATS_OID, 6 }; +static const oid cacheBytesOID[] = { RECURSOR_STATS_OID, 7 }; +static const oid packetcacheHitsOID[] = { RECURSOR_STATS_OID, 8 }; +static const oid packetcacheMissesOID[] = { RECURSOR_STATS_OID, 9 }; +static const oid packetcacheEntriesOID[] = { RECURSOR_STATS_OID, 10 }; +static const oid packetcacheBytesOID[] = { RECURSOR_STATS_OID, 11 }; +static const oid mallocBytesOID[] = { RECURSOR_STATS_OID, 12 }; +static const oid servfailAnswersOID[] = { RECURSOR_STATS_OID, 13 }; +static const oid nxdomainAnswersOID[] = { RECURSOR_STATS_OID, 14 }; +static const oid noerrorAnswersOID[] = { RECURSOR_STATS_OID, 15 }; +static const oid unauthorizedUdpOID[] = { RECURSOR_STATS_OID, 16 }; +static const oid unauthorizedTcpOID[] = { RECURSOR_STATS_OID, 17 }; +static const oid tcpClientOverflowOID[] = { RECURSOR_STATS_OID, 18 }; +static const oid clientParseErrorsOID[] = { RECURSOR_STATS_OID, 19 }; +static const oid serverParseErrorsOID[] = { RECURSOR_STATS_OID, 20 }; +static const oid tooOldDropsOID[] = { RECURSOR_STATS_OID, 21 }; +static const oid answers01OID[] = { RECURSOR_STATS_OID, 22 }; +static const oid answers110OID[] = { RECURSOR_STATS_OID, 23 }; +static const oid answers10100OID[] = { RECURSOR_STATS_OID, 24 }; +static const oid answers1001000OID[] = { RECURSOR_STATS_OID, 25 }; +static const oid answersSlowOID[] = { RECURSOR_STATS_OID, 26 }; +static const oid auth4Answers01OID[] = { RECURSOR_STATS_OID, 27 }; +static const oid auth4Answers110OID[] = { RECURSOR_STATS_OID, 28 }; +static const oid auth4Answers10100OID[] = { RECURSOR_STATS_OID, 29 }; +static const oid auth4Answers1001000OID[] = { RECURSOR_STATS_OID, 30 }; +static const oid auth4AnswersslowOID[] = { RECURSOR_STATS_OID, 31 }; +static const oid auth6Answers01OID[] = { RECURSOR_STATS_OID, 32 }; +static const oid auth6Answers110OID[] = { RECURSOR_STATS_OID, 33 }; +static const oid auth6Answers10100OID[] = { RECURSOR_STATS_OID, 34 }; +static const oid auth6Answers1001000OID[] = { RECURSOR_STATS_OID, 35 }; +static const oid auth6AnswersSlowOID[] = { RECURSOR_STATS_OID, 36 }; +static const oid qaLatencyOID[] = { RECURSOR_STATS_OID, 37 }; +static const oid unexpectedPacketsOID[] = { RECURSOR_STATS_OID, 38 }; +static const oid caseMismatchesOID[] = { RECURSOR_STATS_OID, 39 }; +static const oid spoofPreventsOID[] = { RECURSOR_STATS_OID, 40 }; +static const oid nssetInvalidationsOID[] = { RECURSOR_STATS_OID, 41 }; +static const oid resourceLimitsOID[] = { RECURSOR_STATS_OID, 42 }; +static const oid overCapacityDropsOID[] = { RECURSOR_STATS_OID, 43 }; +static const oid policyDropsOID[] = { RECURSOR_STATS_OID, 44 }; +static const oid noPacketErrorOID[] = { RECURSOR_STATS_OID, 45 }; +static const oid dlgOnlyDropsOID[] = { RECURSOR_STATS_OID, 46 }; +static const oid ignoredPacketsOID[] = { RECURSOR_STATS_OID, 47 }; +static const oid maxMthreadStackOID[] = { RECURSOR_STATS_OID, 48 }; +static const oid negcacheEntriesOID[] = { RECURSOR_STATS_OID, 49 }; +static const oid throttleEntriesOID[] = { RECURSOR_STATS_OID, 50 }; +static const oid nsspeedsEntriesOID[] = { RECURSOR_STATS_OID, 51 }; +static const oid failedHostEntriesOID[] = { RECURSOR_STATS_OID, 52 }; +static const oid concurrentQueriesOID[] = { RECURSOR_STATS_OID, 53 }; +static const oid securityStatusOID[] = { RECURSOR_STATS_OID, 54 }; +static const oid outgoingTimeoutsOID[] = { RECURSOR_STATS_OID, 55 }; +static const oid outgoing4TimeoutsOID[] = { RECURSOR_STATS_OID, 56 }; +static const oid outgoing6TimeoutsOID[] = { RECURSOR_STATS_OID, 57 }; +static const oid tcpOutqueriesOID[] = { RECURSOR_STATS_OID, 58 }; +static const oid allOutqueriesOID[] = { RECURSOR_STATS_OID, 59 }; +static const oid ipv6OutqueriesOID[] = { RECURSOR_STATS_OID, 60 }; +static const oid throttledOutqueriesOID[] = { RECURSOR_STATS_OID, 61 }; +static const oid dontOutqueriesOID[] = { RECURSOR_STATS_OID, 62 }; +static const oid unreachablesOID[] = { RECURSOR_STATS_OID, 63 }; +static const oid chainResendsOID[] = { RECURSOR_STATS_OID, 64 }; +static const oid tcpClientsOID[] = { RECURSOR_STATS_OID, 65 }; +static const oid udpRecvbufErrorsOID[] = { RECURSOR_STATS_OID, 66 }; +static const oid udpSndbufErrorsOID[] = { RECURSOR_STATS_OID, 67 }; +static const oid udpNoportErrorsOID[] = { RECURSOR_STATS_OID, 68 }; +static const oid udpinErrorsOID[] = { RECURSOR_STATS_OID, 69 }; +static const oid ednsPingMatchesOID[] = { RECURSOR_STATS_OID, 70 }; +static const oid ednsPingMismatchesOID[] = { RECURSOR_STATS_OID, 71 }; +static const oid dnssecQueriesOID[] = { RECURSOR_STATS_OID, 72 }; +static const oid nopingOutqueriesOID[] = { RECURSOR_STATS_OID, 73 }; +static const oid noednsOutqueriesOID[] = { RECURSOR_STATS_OID, 74 }; +static const oid uptimeOID[] = { RECURSOR_STATS_OID, 75 }; +static const oid realMemoryUsageOID[] = { RECURSOR_STATS_OID, 76 }; +static const oid fdUsageOID[] = { RECURSOR_STATS_OID, 77 }; +static const oid userMsecOID[] = { RECURSOR_STATS_OID, 78 }; +static const oid sysMsecOID[] = { RECURSOR_STATS_OID, 79 }; +static const oid dnssecValidationsOID[] = { RECURSOR_STATS_OID, 80 }; +static const oid dnssecResultInsecureOID[] = { RECURSOR_STATS_OID, 81 }; +static const oid dnssecResultSecureOID[] = { RECURSOR_STATS_OID, 82 }; +static const oid dnssecResultBogusOID[] = { RECURSOR_STATS_OID, 83 }; +static const oid dnssecResultIndeterminateOID[] = { RECURSOR_STATS_OID, 84 }; +static const oid dnssecResultNtaOID[] = { RECURSOR_STATS_OID, 85 }; +static const oid policyResultNoactionOID[] = { RECURSOR_STATS_OID, 86 }; +static const oid policyResultDropOID[] = { RECURSOR_STATS_OID, 87 }; +static const oid policyResultNxdomainOID[] = { RECURSOR_STATS_OID, 88 }; +static const oid policyResultNodataOID[] = { RECURSOR_STATS_OID, 89 }; +static const oid policyResultTruncateOID[] = { RECURSOR_STATS_OID, 90 }; +static const oid policyResultCustomOID[] = { RECURSOR_STATS_OID, 91 }; +static const oid queryPipeFullDropsOID[] = { RECURSOR_STATS_OID, 92 }; + +static std::unordered_map s_statsMap; + +/* We are never called for a GETNEXT if it's registered as a + "instance", as it's "magically" handled for us. */ +/* a instance handler also only hands us one request at a time, so + we don't need to loop over a list of requests; we'll only get one. */ + +static int handleCounter64Stats(netsnmp_mib_handler* handler, + netsnmp_handler_registration* reginfo, + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* requests) +{ + if (reqinfo->mode != MODE_GET) { + return SNMP_ERR_GENERR; + } + + if (reginfo->rootoid_len != OID_LENGTH(questionsOID) + 1) { + return SNMP_ERR_GENERR; + } + + const auto& it = s_statsMap.find(reginfo->rootoid[reginfo->rootoid_len - 2]); + if (it == s_statsMap.end()) { + return SNMP_ERR_GENERR; + } + + optional value = getStatByName(it->second); + if (value) { + return RecursorSNMPAgent::setCounter64Value(requests, *value); + } else { + return RecursorSNMPAgent::setCounter64Value(requests, 0); + } +} + +static void registerCounter64Stat(const char* name, const oid statOID[], size_t statOIDLength) +{ + if (statOIDLength != OID_LENGTH(questionsOID)) { + L< g_snmpAgent{nullptr}; + +bool RecursorSNMPAgent::sendCustomTrap(const std::string& reason) +{ +#ifdef HAVE_NET_SNMP + netsnmp_variable_list* varList = nullptr; + + snmp_varlist_add_variable(&varList, + snmpTrapOID, + snmpTrapOIDLen, + ASN_OBJECT_ID, + customTrapOID, + OID_LENGTH(customTrapOID) * sizeof(oid)); + + snmp_varlist_add_variable(&varList, + trapReasonOID, + OID_LENGTH(trapReasonOID), + ASN_OCTET_STR, + reason.c_str(), + reason.size()); + + return sendTrap(d_trapPipe[1], varList); +#endif /* HAVE_NET_SNMP */ + return true; +} + + +RecursorSNMPAgent::RecursorSNMPAgent(const std::string& name, const std::string& masterSocket): SNMPAgent(name, masterSocket) +{ +#ifdef HAVE_NET_SNMP + /* This is done so that the statistics maps are + initialized. */ + registerAllStats(); + + registerCounter64Stat("questions", questionsOID, OID_LENGTH(questionsOID)); + registerCounter64Stat("ipv6-questions", ipv6QuestionsOID, OID_LENGTH(ipv6QuestionsOID)); + registerCounter64Stat("tcp-questions", tcpQuestionsOID, OID_LENGTH(tcpQuestionsOID)); + registerCounter64Stat("cache-hits", cacheHitsOID, OID_LENGTH(cacheHitsOID)); + registerCounter64Stat("cache-misses", cacheMissesOID, OID_LENGTH(cacheMissesOID)); + registerCounter64Stat("cache-entries", cacheEntriesOID, OID_LENGTH(cacheEntriesOID)); + registerCounter64Stat("cache-bytes", cacheBytesOID, OID_LENGTH(cacheBytesOID)); + registerCounter64Stat("packetcache-hits", packetcacheHitsOID, OID_LENGTH(packetcacheHitsOID)); + registerCounter64Stat("packetcache-misses", packetcacheMissesOID, OID_LENGTH(packetcacheMissesOID)); + registerCounter64Stat("packetcache-entries", packetcacheEntriesOID, OID_LENGTH(packetcacheEntriesOID)); + registerCounter64Stat("packetcache-bytes", packetcacheBytesOID, OID_LENGTH(packetcacheBytesOID)); + registerCounter64Stat("malloc-bytes", mallocBytesOID, OID_LENGTH(mallocBytesOID)); + registerCounter64Stat("servfail-answers", servfailAnswersOID, OID_LENGTH(servfailAnswersOID)); + registerCounter64Stat("nxdomain-answers", nxdomainAnswersOID, OID_LENGTH(nxdomainAnswersOID)); + registerCounter64Stat("noerror-answers", noerrorAnswersOID, OID_LENGTH(noerrorAnswersOID)); + registerCounter64Stat("unauthorized-udp", unauthorizedUdpOID, OID_LENGTH(unauthorizedUdpOID)); + registerCounter64Stat("unauthorized-tcp", unauthorizedTcpOID, OID_LENGTH(unauthorizedTcpOID)); + registerCounter64Stat("tcp-client-overflow", tcpClientOverflowOID, OID_LENGTH(tcpClientOverflowOID)); + registerCounter64Stat("client-parse-errors", clientParseErrorsOID, OID_LENGTH(clientParseErrorsOID)); + registerCounter64Stat("server-parse-errors", serverParseErrorsOID, OID_LENGTH(serverParseErrorsOID)); + registerCounter64Stat("too-old-drops", tooOldDropsOID, OID_LENGTH(tooOldDropsOID)); + registerCounter64Stat("query-pipe-full-drops", queryPipeFullDropsOID, OID_LENGTH(queryPipeFullDropsOID)); + registerCounter64Stat("answers0-1", answers01OID, OID_LENGTH(answers01OID)); + registerCounter64Stat("answers1-10", answers110OID, OID_LENGTH(answers110OID)); + registerCounter64Stat("answers10-100", answers10100OID, OID_LENGTH(answers10100OID)); + registerCounter64Stat("answers100-1000", answers1001000OID, OID_LENGTH(answers1001000OID)); + registerCounter64Stat("answers-slow", answersSlowOID, OID_LENGTH(answersSlowOID)); + registerCounter64Stat("auth4-answers0-1", auth4Answers01OID, OID_LENGTH(auth4Answers01OID)); + registerCounter64Stat("auth4-answers1-10", auth4Answers110OID, OID_LENGTH(auth4Answers110OID)); + registerCounter64Stat("auth4-answers10-100", auth4Answers10100OID, OID_LENGTH(auth4Answers10100OID)); + registerCounter64Stat("auth4-answers100-1000", auth4Answers1001000OID, OID_LENGTH(auth4Answers1001000OID)); + registerCounter64Stat("auth4-answers-slow", auth4AnswersslowOID, OID_LENGTH(auth4AnswersslowOID)); + registerCounter64Stat("auth6-answers0-1", auth6Answers01OID, OID_LENGTH(auth6Answers01OID)); + registerCounter64Stat("auth6-answers1-10", auth6Answers110OID, OID_LENGTH(auth6Answers110OID)); + registerCounter64Stat("auth6-answers10-100", auth6Answers10100OID, OID_LENGTH(auth6Answers10100OID)); + registerCounter64Stat("auth6-answers100-1000", auth6Answers1001000OID, OID_LENGTH(auth6Answers1001000OID)); + registerCounter64Stat("auth6-answers-slow", auth6AnswersSlowOID, OID_LENGTH(auth6AnswersSlowOID)); + registerCounter64Stat("qa-latency", qaLatencyOID, OID_LENGTH(qaLatencyOID)); + registerCounter64Stat("unexpected-packets", unexpectedPacketsOID, OID_LENGTH(unexpectedPacketsOID)); + registerCounter64Stat("case-mismatches", caseMismatchesOID, OID_LENGTH(caseMismatchesOID)); + registerCounter64Stat("spoof-prevents", spoofPreventsOID, OID_LENGTH(spoofPreventsOID)); + registerCounter64Stat("nsset-invalidations", nssetInvalidationsOID, OID_LENGTH(nssetInvalidationsOID)); + registerCounter64Stat("resource-limits", resourceLimitsOID, OID_LENGTH(resourceLimitsOID)); + registerCounter64Stat("over-capacity-drops", overCapacityDropsOID, OID_LENGTH(overCapacityDropsOID)); + registerCounter64Stat("policy-drops", policyDropsOID, OID_LENGTH(policyDropsOID)); + registerCounter64Stat("no-packet-error", noPacketErrorOID, OID_LENGTH(noPacketErrorOID)); + registerCounter64Stat("dlg-only-drops", dlgOnlyDropsOID, OID_LENGTH(dlgOnlyDropsOID)); + registerCounter64Stat("ignored-packets", ignoredPacketsOID, OID_LENGTH(ignoredPacketsOID)); + registerCounter64Stat("max-mthread-stack", maxMthreadStackOID, OID_LENGTH(maxMthreadStackOID)); + registerCounter64Stat("negcache-entries", negcacheEntriesOID, OID_LENGTH(negcacheEntriesOID)); + registerCounter64Stat("throttle-entries", throttleEntriesOID, OID_LENGTH(throttleEntriesOID)); + registerCounter64Stat("nsspeeds-entries", nsspeedsEntriesOID, OID_LENGTH(nsspeedsEntriesOID)); + registerCounter64Stat("failed-host-entries", failedHostEntriesOID, OID_LENGTH(failedHostEntriesOID)); + registerCounter64Stat("concurrent-queries", concurrentQueriesOID, OID_LENGTH(concurrentQueriesOID)); + registerCounter64Stat("security-status", securityStatusOID, OID_LENGTH(securityStatusOID)); + registerCounter64Stat("outgoing-timeouts", outgoingTimeoutsOID, OID_LENGTH(outgoingTimeoutsOID)); + registerCounter64Stat("outgoing4-timeouts", outgoing4TimeoutsOID, OID_LENGTH(outgoing4TimeoutsOID)); + registerCounter64Stat("outgoing6-timeouts", outgoing6TimeoutsOID, OID_LENGTH(outgoing6TimeoutsOID)); + registerCounter64Stat("tcp-outqueries", tcpOutqueriesOID, OID_LENGTH(tcpOutqueriesOID)); + registerCounter64Stat("all-outqueries", allOutqueriesOID, OID_LENGTH(allOutqueriesOID)); + registerCounter64Stat("ipv6-outqueries", ipv6OutqueriesOID, OID_LENGTH(ipv6OutqueriesOID)); + registerCounter64Stat("throttled-outqueries", throttledOutqueriesOID, OID_LENGTH(throttledOutqueriesOID)); + registerCounter64Stat("dont-outqueries", dontOutqueriesOID, OID_LENGTH(dontOutqueriesOID)); + registerCounter64Stat("unreachables", unreachablesOID, OID_LENGTH(unreachablesOID)); + registerCounter64Stat("chain-resends", chainResendsOID, OID_LENGTH(chainResendsOID)); + registerCounter64Stat("tcp-clients", tcpClientsOID, OID_LENGTH(tcpClientsOID)); +#ifdef __linux__ + registerCounter64Stat("udp-recvbuf-errors", udpRecvbufErrorsOID, OID_LENGTH(udpRecvbufErrorsOID)); + registerCounter64Stat("udp-sndbuf-errors", udpSndbufErrorsOID, OID_LENGTH(udpSndbufErrorsOID)); + registerCounter64Stat("udp-noport-errors", udpNoportErrorsOID, OID_LENGTH(udpNoportErrorsOID)); + registerCounter64Stat("udp-in-errors", udpinErrorsOID, OID_LENGTH(udpinErrorsOID)); +#endif /* __linux__ */ + registerCounter64Stat("edns-ping-matches", ednsPingMatchesOID, OID_LENGTH(ednsPingMatchesOID)); + registerCounter64Stat("edns-ping-mismatches", ednsPingMismatchesOID, OID_LENGTH(ednsPingMismatchesOID)); + registerCounter64Stat("dnssec-queries", dnssecQueriesOID, OID_LENGTH(dnssecQueriesOID)); + registerCounter64Stat("noping-outqueries", nopingOutqueriesOID, OID_LENGTH(nopingOutqueriesOID)); + registerCounter64Stat("noedns-outqueries", noednsOutqueriesOID, OID_LENGTH(noednsOutqueriesOID)); + registerCounter64Stat("uptime", uptimeOID, OID_LENGTH(uptimeOID)); + registerCounter64Stat("real-memory-usage", realMemoryUsageOID, OID_LENGTH(realMemoryUsageOID)); + registerCounter64Stat("fd-usage", fdUsageOID, OID_LENGTH(fdUsageOID)); + registerCounter64Stat("user-msec", userMsecOID, OID_LENGTH(userMsecOID)); + registerCounter64Stat("sys-msec", sysMsecOID, OID_LENGTH(sysMsecOID)); + registerCounter64Stat("dnssec-validations", dnssecValidationsOID, OID_LENGTH(dnssecValidationsOID)); + registerCounter64Stat("dnssec-result-insecure", dnssecResultInsecureOID, OID_LENGTH(dnssecResultInsecureOID)); + registerCounter64Stat("dnssec-result-secure", dnssecResultSecureOID, OID_LENGTH(dnssecResultSecureOID)); + registerCounter64Stat("dnssec-result-bogus", dnssecResultBogusOID, OID_LENGTH(dnssecResultBogusOID)); + registerCounter64Stat("dnssec-result-indeterminate", dnssecResultIndeterminateOID, OID_LENGTH(dnssecResultIndeterminateOID)); + registerCounter64Stat("dnssec-result-nta", dnssecResultNtaOID, OID_LENGTH(dnssecResultNtaOID)); + registerCounter64Stat("policy-result-noaction", policyResultNoactionOID, OID_LENGTH(policyResultNoactionOID)); + registerCounter64Stat("policy-result-drop", policyResultDropOID, OID_LENGTH(policyResultDropOID)); + registerCounter64Stat("policy-result-nxdomain", policyResultNxdomainOID, OID_LENGTH(policyResultNxdomainOID)); + registerCounter64Stat("policy-result-nodata", policyResultNodataOID, OID_LENGTH(policyResultNodataOID)); + registerCounter64Stat("policy-result-truncate", policyResultTruncateOID, OID_LENGTH(policyResultTruncateOID)); + registerCounter64Stat("policy-result-custom", policyResultCustomOID, OID_LENGTH(policyResultCustomOID)); + +#endif /* HAVE_NET_SNMP */ +} diff --git a/rec-snmp.hh b/rec-snmp.hh new file mode 100644 index 0000000..3ccc73f --- /dev/null +++ b/rec-snmp.hh @@ -0,0 +1,19 @@ +#ifndef REC_SNMP_HH +#define REC_SNMP_HH + +#pragma once + +#include "snmp-agent.hh" + +class RecursorSNMPAgent; + +class RecursorSNMPAgent: public SNMPAgent +{ +public: + RecursorSNMPAgent(const std::string& name, const std::string& masterSocket); + bool sendCustomTrap(const std::string& reason); +}; + +extern std::shared_ptr g_snmpAgent; + +#endif /* REC_SNMP_HH */ diff --git a/rec_channel.cc b/rec_channel.cc new file mode 100644 index 0000000..3c0fb6d --- /dev/null +++ b/rec_channel.cc @@ -0,0 +1,147 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "rec_channel.hh" +#include "utility.hh" +#include +#include +#include "misc.hh" +#include +#include +#include +#include +#include +#include + +#include "pdnsexception.hh" + +#include "namespaces.hh" + +RecursorControlChannel::RecursorControlChannel() +{ + d_fd=-1; + *d_local.sun_path=0; + d_local.sun_family=0; +} + +RecursorControlChannel::~RecursorControlChannel() +{ + if(d_fd > 0) + close(d_fd); + if(*d_local.sun_path) + unlink(d_local.sun_path); +} + +int RecursorControlChannel::listen(const string& fname) +{ + d_fd=socket(AF_UNIX,SOCK_DGRAM,0); + setCloseOnExec(d_fd); + + if(d_fd < 0) + throw PDNSException("Creating UNIX domain socket: "+stringerror()); + + int tmp=1; + if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) + throw PDNSException("Setsockopt failed: "+stringerror()); + + int err=unlink(fname.c_str()); + if(err < 0 && errno!=ENOENT) + throw PDNSException("Can't remove (previous) controlsocket '"+fname+"': "+stringerror() + " (try --socket-dir)"); + + if(makeUNsockaddr(fname, &d_local)) + throw PDNSException("Unable to bind to controlsocket, path '"+fname+"' is not a valid UNIX socket path."); + + if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0) + throw PDNSException("Unable to bind to controlsocket '"+fname+"': "+stringerror()); + + return d_fd; +} + +void RecursorControlChannel::connect(const string& path, const string& fname) +{ + struct sockaddr_un remote; + + d_fd=socket(AF_UNIX,SOCK_DGRAM,0); + setCloseOnExec(d_fd); + + if(d_fd < 0) + throw PDNSException("Creating UNIX domain socket: "+string(strerror(errno))); + + try { + int tmp=1; + if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) + throw PDNSException("Setsockopt failed: "+stringerror()); + + string localname=path+"/lsockXXXXXX"; + *d_local.sun_path=0; + if (makeUNsockaddr(localname, &d_local)) + throw PDNSException("Unable to bind to local temporary file, path '"+localname+"' is not a valid UNIX socket path."); + + if(mkstemp(d_local.sun_path) < 0) + throw PDNSException("Unable to generate local temporary file in directory '"+path+"': "+stringerror()); + + int err=unlink(d_local.sun_path); + if(err < 0 && errno!=ENOENT) + throw PDNSException("Unable to remove local controlsocket: "+stringerror()); + + if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0) + throw PDNSException("Unable to bind to local temporary file: "+stringerror()); + + if(chmod(d_local.sun_path,0666)<0) // make sure that pdns can reply! + throw PDNSException("Unable to chmod local temporary socket: "+stringerror()); + + string remotename=path+"/"+fname; + if (makeUNsockaddr(remotename, &remote)) + throw PDNSException("Unable to connect to controlsocket, path '"+remotename+"' is not a valid UNIX socket path."); + + if(::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) { + if(*d_local.sun_path) + unlink(d_local.sun_path); + throw PDNSException("Unable to connect to remote '"+string(remote.sun_path)+"': "+stringerror()); + } + + } catch (...) { + close(d_fd); + d_fd=-1; + d_local.sun_path[0]=0; + throw; + } +} + +void RecursorControlChannel::send(const std::string& msg, const std::string* remote) +{ + if(remote) { + struct sockaddr_un remoteaddr; + memset(&remoteaddr, 0, sizeof(remoteaddr)); + + remoteaddr.sun_family=AF_UNIX; + strncpy(remoteaddr.sun_path, remote->c_str(), sizeof(remoteaddr.sun_path)); + remoteaddr.sun_path[sizeof(remoteaddr.sun_path)-1] = '\0'; + + if(::sendto(d_fd, msg.c_str(), msg.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0) + throw PDNSException("Unable to send message over control channel '"+string(remoteaddr.sun_path)+"': "+string(strerror(errno))); + } + else if(::send(d_fd, msg.c_str(), msg.length(), 0) < 0) + throw PDNSException("Unable to send message over control channel: "+string(strerror(errno))); +} + +string RecursorControlChannel::recv(std::string* remote, unsigned int timeout) +{ + char buffer[16384]; + ssize_t len; + struct sockaddr_un remoteaddr; + socklen_t addrlen=sizeof(remoteaddr); + + int ret=waitForData(d_fd, timeout, 0); + if(ret==0) + throw PDNSException("Timeout waiting for answer from control channel"); + + if( ret < 0 || (len=::recvfrom(d_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteaddr, &addrlen)) < 0) + throw PDNSException("Unable to receive message over control channel: "+string(strerror(errno))); + + if(remote) + *remote=remoteaddr.sun_path; + + return string(buffer, buffer+len); +} + diff --git a/rec_channel.hh b/rec_channel.hh new file mode 100644 index 0000000..4e2ce45 --- /dev/null +++ b/rec_channel.hh @@ -0,0 +1,78 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_REC_CHANNEL +#define PDNS_REC_CHANNEL +#include +#include +#include +#include +#include +#include +#include "iputils.hh" +#include "dnsname.hh" +#include + +/** this class is used both to send and answer channel commands to the PowerDNS Recursor */ +class RecursorControlChannel +{ +public: + RecursorControlChannel(); + + ~RecursorControlChannel(); + + int listen(const std::string& filename); + void connect(const std::string& path, const std::string& filename); + + uint64_t getStat(const std::string& name); + + void send(const std::string& msg, const std::string* remote=0); + std::string recv(std::string* remote=0, unsigned int timeout=5); + + int d_fd; +private: + struct sockaddr_un d_local; +}; + +class RecursorControlParser +{ +public: + RecursorControlParser() + { + } + static void nop(void){} + typedef void func_t(void); + std::string getAnswer(const std::string& question, func_t** func); +}; + +std::map getAllStatsMap(); +extern pthread_mutex_t g_carbon_config_lock; +void sortPublicSuffixList(); +std::vector >* pleaseGetQueryRing(); +std::vector >* pleaseGetServfailQueryRing(); +std::vector* pleaseGetRemotes(); +std::vector* pleaseGetServfailRemotes(); +std::vector* pleaseGetLargeAnswerRemotes(); +DNSName getRegisteredName(const DNSName& dom); +std::atomic* getDynMetric(const std::string& str); +optional getStatByName(const std::string& name); +void registerAllStats(); +#endif diff --git a/rec_channel_rec.cc b/rec_channel_rec.cc new file mode 100644 index 0000000..17dddd0 --- /dev/null +++ b/rec_channel_rec.cc @@ -0,0 +1,1435 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "syncres.hh" +#include "utility.hh" +#include "rec_channel.hh" +#include +#include +#ifdef MALLOC_TRACE +#include "malloctrace.hh" +#endif +#include "misc.hh" +#include "recursor_cache.hh" +#include "negcache.hh" +#include +#include +#include +#include +#include + +#include "version.hh" +#include +#include +#include +#include "logger.hh" +#include "dnsparser.hh" +#include "arguments.hh" +#include +#include +#include "lock.hh" +#include "responsestats.hh" +#include "rec-lua-conf.hh" + +#include "validate-recursor.hh" +#include "filterpo.hh" + +#include "secpoll-recursor.hh" +#include "pubsuffix.hh" +#include "namespaces.hh" +pthread_mutex_t g_carbon_config_lock=PTHREAD_MUTEX_INITIALIZER; + +static map d_get32bitpointers; +static map d_get64bitpointers; +static map*> d_getatomics; +static map > d_get64bitmembers; +static pthread_mutex_t d_dynmetricslock = PTHREAD_MUTEX_INITIALIZER; +static map* > d_dynmetrics; + +static void addGetStat(const string& name, const uint32_t* place) +{ + d_get32bitpointers[name]=place; +} + +static void addGetStat(const string& name, const std::atomic* place) +{ + d_getatomics[name]=place; +} + +static void addGetStat(const string& name, function f ) +{ + d_get64bitmembers[name]=f; +} + +std::atomic* getDynMetric(const std::string& str) +{ + Lock l(&d_dynmetricslock); + auto f = d_dynmetrics.find(str); + if(f != d_dynmetrics.end()) + return f->second; + + auto ret = new std::atomic(); + d_dynmetrics[str]= ret; + return ret; +} + +static optional get(const string& name) +{ + optional ret; + + if(d_get32bitpointers.count(name)) + return *d_get32bitpointers.find(name)->second; + if(d_get64bitpointers.count(name)) + return *d_get64bitpointers.find(name)->second; + if(d_getatomics.count(name)) + return d_getatomics.find(name)->second->load(); + if(d_get64bitmembers.count(name)) + return d_get64bitmembers.find(name)->second(); + + Lock l(&d_dynmetricslock); + auto f =rplookup(d_dynmetrics, name); + if(f) + return (*f)->load(); + + return ret; +} + +optional getStatByName(const std::string& name) +{ + return get(name); +} + +map getAllStatsMap() +{ + map ret; + + for(const auto& the32bits : d_get32bitpointers) { + ret.insert(make_pair(the32bits.first, std::to_string(*the32bits.second))); + } + for(const auto& the64bits : d_get64bitpointers) { + ret.insert(make_pair(the64bits.first, std::to_string(*the64bits.second))); + } + for(const auto& atomic : d_getatomics) { + ret.insert(make_pair(atomic.first, std::to_string(atomic.second->load()))); + } + + for(const auto& the64bitmembers : d_get64bitmembers) { + if(the64bitmembers.first == "cache-bytes" || the64bitmembers.first=="packetcache-bytes") + continue; // too slow for 'get-all' + ret.insert(make_pair(the64bitmembers.first, std::to_string(the64bitmembers.second()))); + } + Lock l(&d_dynmetricslock); + for(const auto& a : d_dynmetrics) + ret.insert({a.first, std::to_string(*a.second)}); + return ret; +} + +string getAllStats() +{ + typedef map varmap_t; + varmap_t varmap = getAllStatsMap(); + string ret; + for(varmap_t::value_type& tup : varmap) { + ret += tup.first + "\t" + tup.second +"\n"; + } + return ret; +} + +template +string doGet(T begin, T end) +{ + string ret; + + for(T i=begin; i != end; ++i) { + optional num=get(*i); + if(num) + ret+=std::to_string(*num)+"\n"; + else + ret+="UNKNOWN\n"; + } + return ret; +} + +template +string doGetParameter(T begin, T end) +{ + string ret; + string parm; + using boost::replace_all; + for(T i=begin; i != end; ++i) { + if(::arg().parmIsset(*i)) { + parm=::arg()[*i]; + replace_all(parm, "\\", "\\\\"); + replace_all(parm, "\"", "\\\""); + replace_all(parm, "\n", "\\n"); + ret += *i +"=\""+ parm +"\"\n"; + } + else + ret += *i +" not known\n"; + } + return ret; +} + + +static uint64_t dumpNegCache(NegCache& negcache, int fd) +{ + FILE* fp=fdopen(dup(fd), "w"); + if(!fp) { // dup probably failed + return 0; + } + uint64_t ret; + fprintf(fp, "; negcache dump from thread follows\n;\n"); + ret = negcache.dumpToFile(fp); + fclose(fp); + return ret; +} + +static uint64_t* pleaseDump(int fd) +{ + return new uint64_t(t_RC->doDump(fd) + dumpNegCache(SyncRes::t_sstorage.negcache, fd) + t_packetCache->doDump(fd)); +} + +static uint64_t* pleaseDumpNSSpeeds(int fd) +{ + return new uint64_t(SyncRes::doDumpNSSpeeds(fd)); +} + +template +string doDumpNSSpeeds(T begin, T end) +{ + T i=begin; + string fname; + + if(i!=end) + fname=*i; + + int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + if(fd < 0) + return "Error opening dump file for writing: "+string(strerror(errno))+"\n"; + uint64_t total = 0; + try { + total = broadcastAccFunction(boost::bind(pleaseDumpNSSpeeds, fd)); + } + catch(std::exception& e) + { + close(fd); + return "error dumping NS speeds: "+string(e.what())+"\n"; + } + catch(PDNSException& e) + { + close(fd); + return "error dumping NS speeds: "+e.reason+"\n"; + } + + close(fd); + return "dumped "+std::to_string(total)+" records\n"; +} + +template +string doDumpCache(T begin, T end) +{ + T i=begin; + string fname; + + if(i!=end) + fname=*i; + + int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + if(fd < 0) + return "Error opening dump file for writing: "+string(strerror(errno))+"\n"; + uint64_t total = 0; + try { + total = broadcastAccFunction(boost::bind(pleaseDump, fd)); + } + catch(...){} + + close(fd); + return "dumped "+std::to_string(total)+" records\n"; +} + +template +string doDumpEDNSStatus(T begin, T end) +{ + T i=begin; + string fname; + + if(i!=end) + fname=*i; + + int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + if(fd < 0) + return "Error opening dump file for writing: "+string(strerror(errno))+"\n"; + + SyncRes::doEDNSDumpAndClose(fd); + + return "done\n"; +} + +template +string doDumpRPZ(T begin, T end) +{ + T i=begin; + + if (i == end) { + return "No zone name specified\n"; + } + string zoneName = *i; + i++; + + if (i == end) { + return "No file name specified\n"; + } + string fname = *i; + + auto luaconf = g_luaconfs.getLocal(); + const auto zone = luaconf->dfe.getZone(zoneName); + if (!zone) { + return "No RPZ zone named "+zoneName+"\n"; + } + + int fd = open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + + if(fd < 0) { + return "Error opening dump file for writing: "+string(strerror(errno))+"\n"; + } + + FILE* fp = fdopen(fd, "w"); + if (!fp) { + close(fd); + return "Error converting file descriptor: "+string(strerror(errno))+"\n"; + } + + zone->dump(fp); + fclose(fp); + + return "done\n"; +} + +uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree) +{ + return new uint64_t(t_RC->doWipeCache(canon, subtree)); +} + +uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree) +{ + return new uint64_t(t_packetCache->doWipePacketCache(canon,0xffff, subtree)); +} + + +uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree) +{ + uint64_t ret = SyncRes::wipeNegCache(canon, subtree); + return new uint64_t(ret); +} + + +template +string doWipeCache(T begin, T end) +{ + vector > toWipe; + for(T i=begin; i != end; ++i) { + DNSName canon; + bool subtree=false; + + try { + if(boost::ends_with(*i, "$")) { + canon=DNSName(i->substr(0, i->size()-1)); + subtree=true; + } else { + canon=DNSName(*i); + } + } catch (std::exception &e) { + return "Error: " + std::string(e.what()) + ", nothing wiped\n"; + } + toWipe.push_back({canon, subtree}); + } + + int count=0, pcount=0, countNeg=0; + for (auto wipe : toWipe) { + count+= broadcastAccFunction(boost::bind(pleaseWipeCache, wipe.first, wipe.second)); + pcount+= broadcastAccFunction(boost::bind(pleaseWipePacketCache, wipe.first, wipe.second)); + countNeg+=broadcastAccFunction(boost::bind(pleaseWipeAndCountNegCache, wipe.first, wipe.second)); + } + + return "wiped "+std::to_string(count)+" records, "+std::to_string(countNeg)+" negative records, "+std::to_string(pcount)+" packets\n"; +} + +template +string doSetCarbonServer(T begin, T end) +{ + Lock l(&g_carbon_config_lock); + if(begin==end) { + ::arg().set("carbon-server").clear(); + return "cleared carbon-server setting\n"; + } + string ret; + ::arg().set("carbon-server")=*begin; + ret="set carbon-server to '"+::arg()["carbon-server"]+"'\n"; + ++begin; + if(begin != end) { + ::arg().set("carbon-ourname")=*begin; + ret+="set carbon-ourname to '"+*begin+"'\n"; + } + return ret; +} + +template +string doSetDnssecLogBogus(T begin, T end) +{ + if(checkDNSSECDisabled()) + return "DNSSEC is disabled in the configuration, not changing the Bogus logging setting\n"; + + if (begin == end) + return "No DNSSEC Bogus logging setting specified\n"; + + if (pdns_iequals(*begin, "on") || pdns_iequals(*begin, "yes")) { + if (!g_dnssecLogBogus) { + L< +string doAddNTA(T begin, T end) +{ + if(checkDNSSECDisabled()) + return "DNSSEC is disabled in the configuration, not adding a Negative Trust Anchor\n"; + + if(begin == end) + return "No NTA specified, doing nothing\n"; + + DNSName who; + try { + who = DNSName(*begin); + } + catch(std::exception &e) { + string ret("Can't add Negative Trust Anchor: "); + ret += e.what(); + ret += "\n"; + return ret; + } + begin++; + + string why(""); + while (begin != end) { + why += *begin; + begin++; + if (begin != end) + why += " "; + } + L<(boost::bind(pleaseWipePacketCache, who, true)); + return "Added Negative Trust Anchor for " + who.toLogString() + " with reason '" + why + "'\n"; +} + +template +string doClearNTA(T begin, T end) +{ + if(checkDNSSECDisabled()) + return "DNSSEC is disabled in the configuration, not removing a Negative Trust Anchor\n"; + + if(begin == end) + return "No Negative Trust Anchor specified, doing nothing.\n"; + + if (begin + 1 == end && *begin == "*"){ + L< toRemove; + DNSName who; + while (begin != end) { + if (*begin == "*") + return "Don't mix all Negative Trust Anchor removal with multiple Negative Trust Anchor removal. Nothing removed\n"; + try { + who = DNSName(*begin); + } + catch(std::exception &e) { + string ret("Error: "); + ret += e.what(); + ret += ". No Negative Anchors removed\n"; + return ret; + } + toRemove.push_back(who); + begin++; + } + + string removed(""); + bool first(true); + for (auto const &entry : toRemove) { + L<(boost::bind(pleaseWipePacketCache, entry, true)); + if (!first) { + first = false; + removed += ","; + } + removed += " " + entry.toStringRootDot(); + } + return "Removed Negative Trust Anchors for " + removed + "\n"; +} + +static string getNTAs() +{ + if(checkDNSSECDisabled()) + return "DNSSEC is disabled in the configuration\n"; + + string ret("Configured Negative Trust Anchors:\n"); + auto luaconf = g_luaconfs.getLocal(); + for (auto negAnchor : luaconf->negAnchors) + ret += negAnchor.first.toLogString() + "\t" + negAnchor.second + "\n"; + return ret; +} + +template +string doAddTA(T begin, T end) +{ + if(checkDNSSECDisabled()) + return "DNSSEC is disabled in the configuration, not adding a Trust Anchor\n"; + + if(begin == end) + return "No TA specified, doing nothing\n"; + + DNSName who; + try { + who = DNSName(*begin); + } + catch(std::exception &e) { + string ret("Can't add Trust Anchor: "); + ret += e.what(); + ret += "\n"; + return ret; + } + begin++; + + string what(""); + while (begin != end) { + what += *begin + " "; + begin++; + } + + try { + L<(dynamic_cast(DSRecordContent::make(what))); + lci.dsAnchors[who].insert(*ds); + }); + broadcastAccFunction(boost::bind(pleaseWipePacketCache, who, true)); + L< +string doClearTA(T begin, T end) +{ + if(checkDNSSECDisabled()) + return "DNSSEC is disabled in the configuration, not removing a Trust Anchor\n"; + + if(begin == end) + return "No Trust Anchor to clear\n"; + + vector toRemove; + DNSName who; + while (begin != end) { + try { + who = DNSName(*begin); + } + catch(std::exception &e) { + string ret("Error: "); + ret += e.what(); + ret += ". No Anchors removed\n"; + return ret; + } + if (who.isRoot()) + return "Refusing to remove root Trust Anchor, no Anchors removed\n"; + toRemove.push_back(who); + begin++; + } + + string removed(""); + bool first(true); + for (auto const &entry : toRemove) { + L<(boost::bind(pleaseWipePacketCache, entry, true)); + if (!first) { + first = false; + removed += ","; + } + removed += " " + entry.toStringRootDot(); + } + return "Removed Trust Anchor(s) for" + removed + "\n"; +} + +static string getTAs() +{ + if(checkDNSSECDisabled()) + return "DNSSEC is disabled in the configuration\n"; + + string ret("Configured Trust Anchors:\n"); + auto luaconf = g_luaconfs.getLocal(); + for (auto anchor : luaconf->dsAnchors) { + ret += anchor.first.toLogString() + "\n"; + for (auto e : anchor.second) { + ret+="\t\t"+e.getZoneRepresentation() + "\n"; + } + } + + return ret; +} + +template +string setMinimumTTL(T begin, T end) +{ + if(end-begin != 1) + return "Need to supply new minimum TTL number\n"; + SyncRes::s_minimumTTL = pdns_stou(*begin); + return "New minimum TTL: " + std::to_string(SyncRes::s_minimumTTL) + "\n"; +} + +template +string setMaxCacheEntries(T begin, T end) +{ + if(end-begin != 1) + return "Need to supply new cache size\n"; + g_maxCacheEntries = pdns_stou(*begin); + return "New max cache entries: " + std::to_string(g_maxCacheEntries) + "\n"; +} + +template +string setMaxPacketCacheEntries(T begin, T end) +{ + if(end-begin != 1) + return "Need to supply new packet cache size\n"; + g_maxPacketCacheEntries = pdns_stou(*begin); + return "New max packetcache entries: " + std::to_string(g_maxPacketCacheEntries) + "\n"; +} + + +static uint64_t getSysTimeMsec() +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000); +} + +static uint64_t getUserTimeMsec() +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000); +} + +static uint64_t calculateUptime() +{ + return time(0) - g_stats.startupTime; +} + +static string* pleaseGetCurrentQueries() +{ + ostringstream ostr; + + ostr << getMT()->d_waiters.size() <<" currently outstanding questions\n"; + + boost::format fmt("%1% %|40t|%2% %|47t|%3% %|63t|%4% %|68t|%5%\n"); + + ostr << (fmt % "qname" % "qtype" % "remote" % "tcp" % "chained"); + unsigned int n=0; + for(const auto& mthread : getMT()->d_waiters) { + const PacketID& pident = mthread.key; + ostr << (fmt + % pident.domain.toLogString() /* ?? */ % DNSRecordContent::NumberToType(pident.type) + % pident.remote.toString() % (pident.sock ? 'Y' : 'n') + % (pident.fd == -1 ? 'Y' : 'n') + ); + ++n; + if (n >= 100) + break; + } + ostr <<" - done\n"; + return new string(ostr.str()); +} + +static string doCurrentQueries() +{ + return broadcastAccFunction(pleaseGetCurrentQueries); +} + +uint64_t* pleaseGetThrottleSize() +{ + return new uint64_t(SyncRes::getThrottledServersSize()); +} + +static uint64_t getThrottleSize() +{ + return broadcastAccFunction(pleaseGetThrottleSize); +} + +uint64_t* pleaseGetNegCacheSize() +{ + uint64_t tmp=(SyncRes::getNegCacheSize()); + return new uint64_t(tmp); +} + +uint64_t getNegCacheSize() +{ + return broadcastAccFunction(pleaseGetNegCacheSize); +} + +uint64_t* pleaseGetFailedHostsSize() +{ + uint64_t tmp=(SyncRes::getThrottledServersSize()); + return new uint64_t(tmp); +} +uint64_t getFailedHostsSize() +{ + return broadcastAccFunction(pleaseGetFailedHostsSize); +} + +uint64_t* pleaseGetNsSpeedsSize() +{ + return new uint64_t(SyncRes::getNSSpeedsSize()); +} + +uint64_t getNsSpeedsSize() +{ + return broadcastAccFunction(pleaseGetNsSpeedsSize); +} + +uint64_t* pleaseGetConcurrentQueries() +{ + return new uint64_t(getMT() ? getMT()->numProcesses() : 0); +} + +static uint64_t getConcurrentQueries() +{ + return broadcastAccFunction(pleaseGetConcurrentQueries); +} + +uint64_t* pleaseGetCacheSize() +{ + return new uint64_t(t_RC ? t_RC->size() : 0); +} + +uint64_t* pleaseGetCacheBytes() +{ + return new uint64_t(t_RC ? t_RC->bytes() : 0); +} + + +uint64_t doGetCacheSize() +{ + return broadcastAccFunction(pleaseGetCacheSize); +} + +uint64_t doGetAvgLatencyUsec() +{ + return (uint64_t) g_stats.avgLatencyUsec; +} + + +uint64_t doGetCacheBytes() +{ + return broadcastAccFunction(pleaseGetCacheBytes); +} + +uint64_t* pleaseGetCacheHits() +{ + return new uint64_t(t_RC ? t_RC->cacheHits : 0); +} + +uint64_t doGetCacheHits() +{ + return broadcastAccFunction(pleaseGetCacheHits); +} + +uint64_t* pleaseGetCacheMisses() +{ + return new uint64_t(t_RC ? t_RC->cacheMisses : 0); +} + +uint64_t doGetCacheMisses() +{ + return broadcastAccFunction(pleaseGetCacheMisses); +} + + +uint64_t* pleaseGetPacketCacheSize() +{ + return new uint64_t(t_packetCache ? t_packetCache->size() : 0); +} + +uint64_t* pleaseGetPacketCacheBytes() +{ + return new uint64_t(t_packetCache ? t_packetCache->bytes() : 0); +} + + +uint64_t doGetPacketCacheSize() +{ + return broadcastAccFunction(pleaseGetPacketCacheSize); +} + +uint64_t doGetPacketCacheBytes() +{ + return broadcastAccFunction(pleaseGetPacketCacheBytes); +} + + +uint64_t* pleaseGetPacketCacheHits() +{ + return new uint64_t(t_packetCache ? t_packetCache->d_hits : 0); +} + +uint64_t doGetPacketCacheHits() +{ + return broadcastAccFunction(pleaseGetPacketCacheHits); +} + +uint64_t* pleaseGetPacketCacheMisses() +{ + return new uint64_t(t_packetCache ? t_packetCache->d_misses : 0); +} + +uint64_t doGetPacketCacheMisses() +{ + return broadcastAccFunction(pleaseGetPacketCacheMisses); +} + +uint64_t doGetMallocated() +{ + // this turned out to be broken +/* struct mallinfo mi = mallinfo(); + return mi.uordblks; */ + return 0; +} + +extern ResponseStats g_rs; + +void registerAllStats() +{ + static std::atomic_flag s_init = ATOMIC_FLAG_INIT; + if(s_init.test_and_set()) + return; + + addGetStat("questions", &g_stats.qcounter); + addGetStat("ipv6-questions", &g_stats.ipv6qcounter); + addGetStat("tcp-questions", &g_stats.tcpqcounter); + + addGetStat("cache-hits", doGetCacheHits); + addGetStat("cache-misses", doGetCacheMisses); + addGetStat("cache-entries", doGetCacheSize); + addGetStat("max-cache-entries", []() { return g_maxCacheEntries.load(); }); + addGetStat("max-packetcache-entries", []() { return g_maxPacketCacheEntries.load();}); + addGetStat("cache-bytes", doGetCacheBytes); + + addGetStat("packetcache-hits", doGetPacketCacheHits); + addGetStat("packetcache-misses", doGetPacketCacheMisses); + addGetStat("packetcache-entries", doGetPacketCacheSize); + addGetStat("packetcache-bytes", doGetPacketCacheBytes); + + addGetStat("malloc-bytes", doGetMallocated); + + addGetStat("servfail-answers", &g_stats.servFails); + addGetStat("nxdomain-answers", &g_stats.nxDomains); + addGetStat("noerror-answers", &g_stats.noErrors); + + addGetStat("unauthorized-udp", &g_stats.unauthorizedUDP); + addGetStat("unauthorized-tcp", &g_stats.unauthorizedTCP); + addGetStat("tcp-client-overflow", &g_stats.tcpClientOverflow); + + addGetStat("client-parse-errors", &g_stats.clientParseError); + addGetStat("server-parse-errors", &g_stats.serverParseError); + addGetStat("too-old-drops", &g_stats.tooOldDrops); + addGetStat("query-pipe-full-drops", &g_stats.queryPipeFullDrops); + + addGetStat("answers0-1", &g_stats.answers0_1); + addGetStat("answers1-10", &g_stats.answers1_10); + addGetStat("answers10-100", &g_stats.answers10_100); + addGetStat("answers100-1000", &g_stats.answers100_1000); + addGetStat("answers-slow", &g_stats.answersSlow); + + addGetStat("x-ourtime0-1", &g_stats.ourtime0_1); + addGetStat("x-ourtime1-2", &g_stats.ourtime1_2); + addGetStat("x-ourtime2-4", &g_stats.ourtime2_4); + addGetStat("x-ourtime4-8", &g_stats.ourtime4_8); + addGetStat("x-ourtime8-16", &g_stats.ourtime8_16); + addGetStat("x-ourtime16-32", &g_stats.ourtime16_32); + addGetStat("x-ourtime-slow", &g_stats.ourtimeSlow); + + addGetStat("auth4-answers0-1", &g_stats.auth4Answers0_1); + addGetStat("auth4-answers1-10", &g_stats.auth4Answers1_10); + addGetStat("auth4-answers10-100", &g_stats.auth4Answers10_100); + addGetStat("auth4-answers100-1000", &g_stats.auth4Answers100_1000); + addGetStat("auth4-answers-slow", &g_stats.auth4AnswersSlow); + + addGetStat("auth6-answers0-1", &g_stats.auth6Answers0_1); + addGetStat("auth6-answers1-10", &g_stats.auth6Answers1_10); + addGetStat("auth6-answers10-100", &g_stats.auth6Answers10_100); + addGetStat("auth6-answers100-1000", &g_stats.auth6Answers100_1000); + addGetStat("auth6-answers-slow", &g_stats.auth6AnswersSlow); + + + addGetStat("qa-latency", doGetAvgLatencyUsec); + addGetStat("x-our-latency", []() { return g_stats.avgLatencyOursUsec; }); + addGetStat("unexpected-packets", &g_stats.unexpectedCount); + addGetStat("case-mismatches", &g_stats.caseMismatchCount); + addGetStat("spoof-prevents", &g_stats.spoofCount); + + addGetStat("nsset-invalidations", &g_stats.nsSetInvalidations); + + addGetStat("resource-limits", &g_stats.resourceLimits); + addGetStat("over-capacity-drops", &g_stats.overCapacityDrops); + addGetStat("policy-drops", &g_stats.policyDrops); + addGetStat("no-packet-error", &g_stats.noPacketError); + addGetStat("dlg-only-drops", &SyncRes::s_nodelegated); + addGetStat("ignored-packets", &g_stats.ignoredCount); + addGetStat("max-mthread-stack", &g_stats.maxMThreadStackUsage); + + addGetStat("negcache-entries", boost::bind(getNegCacheSize)); + addGetStat("throttle-entries", boost::bind(getThrottleSize)); + + addGetStat("nsspeeds-entries", boost::bind(getNsSpeedsSize)); + addGetStat("failed-host-entries", boost::bind(getFailedHostsSize)); + + addGetStat("concurrent-queries", boost::bind(getConcurrentQueries)); + addGetStat("security-status", &g_security_status); + addGetStat("outgoing-timeouts", &SyncRes::s_outgoingtimeouts); + addGetStat("outgoing4-timeouts", &SyncRes::s_outgoing4timeouts); + addGetStat("outgoing6-timeouts", &SyncRes::s_outgoing6timeouts); + addGetStat("auth-zone-queries", &SyncRes::s_authzonequeries); + addGetStat("tcp-outqueries", &SyncRes::s_tcpoutqueries); + addGetStat("all-outqueries", &SyncRes::s_outqueries); + addGetStat("ipv6-outqueries", &g_stats.ipv6queries); + addGetStat("throttled-outqueries", &SyncRes::s_throttledqueries); + addGetStat("dont-outqueries", &SyncRes::s_dontqueries); + addGetStat("throttled-out", &SyncRes::s_throttledqueries); + addGetStat("unreachables", &SyncRes::s_unreachables); + addGetStat("ecs-queries", &SyncRes::s_ecsqueries); + addGetStat("ecs-responses", &SyncRes::s_ecsresponses); + addGetStat("chain-resends", &g_stats.chainResends); + addGetStat("tcp-clients", boost::bind(TCPConnection::getCurrentConnections)); + +#ifdef __linux__ + addGetStat("udp-recvbuf-errors", boost::bind(udpErrorStats, "udp-recvbuf-errors")); + addGetStat("udp-sndbuf-errors", boost::bind(udpErrorStats, "udp-sndbuf-errors")); + addGetStat("udp-noport-errors", boost::bind(udpErrorStats, "udp-noport-errors")); + addGetStat("udp-in-errors", boost::bind(udpErrorStats, "udp-in-errors")); +#endif + + addGetStat("edns-ping-matches", &g_stats.ednsPingMatches); + addGetStat("edns-ping-mismatches", &g_stats.ednsPingMismatches); + addGetStat("dnssec-queries", &g_stats.dnssecQueries); + + addGetStat("noping-outqueries", &g_stats.noPingOutQueries); + addGetStat("noedns-outqueries", &g_stats.noEdnsOutQueries); + + addGetStat("uptime", calculateUptime); + addGetStat("real-memory-usage", boost::bind(getRealMemoryUsage, string())); + addGetStat("fd-usage", boost::bind(getOpenFileDescriptors, string())); + + // addGetStat("query-rate", getQueryRate); + addGetStat("user-msec", getUserTimeMsec); + addGetStat("sys-msec", getSysTimeMsec); + +#ifdef MALLOC_TRACE + addGetStat("memory-allocs", boost::bind(&MallocTracer::getAllocs, g_mtracer, string())); + addGetStat("memory-alloc-flux", boost::bind(&MallocTracer::getAllocFlux, g_mtracer, string())); + addGetStat("memory-allocated", boost::bind(&MallocTracer::getTotAllocated, g_mtracer, string())); +#endif + + addGetStat("dnssec-validations", &g_stats.dnssecValidations); + addGetStat("dnssec-result-insecure", &g_stats.dnssecResults[Insecure]); + addGetStat("dnssec-result-secure", &g_stats.dnssecResults[Secure]); + addGetStat("dnssec-result-bogus", &g_stats.dnssecResults[Bogus]); + addGetStat("dnssec-result-indeterminate", &g_stats.dnssecResults[Indeterminate]); + addGetStat("dnssec-result-nta", &g_stats.dnssecResults[NTA]); + + addGetStat("policy-result-noaction", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NoAction]); + addGetStat("policy-result-drop", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Drop]); + addGetStat("policy-result-nxdomain", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NXDOMAIN]); + addGetStat("policy-result-nodata", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NODATA]); + addGetStat("policy-result-truncate", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Truncate]); + addGetStat("policy-result-custom", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Custom]); +} + +static void doExitGeneric(bool nicely) +{ + L< >* pleaseGetQueryRing() +{ + typedef pair query_t; + vector* ret = new vector(); + if(!t_queryring) + return ret; + ret->reserve(t_queryring->size()); + + for(const query_t& q : *t_queryring) { + ret->push_back(q); + } + return ret; +} +vector >* pleaseGetServfailQueryRing() +{ + typedef pair query_t; + vector* ret = new vector(); + if(!t_servfailqueryring) + return ret; + ret->reserve(t_servfailqueryring->size()); + for(const query_t& q : *t_servfailqueryring) { + ret->push_back(q); + } + return ret; +} + + + +typedef boost::function*()> pleaseremotefunc_t; +typedef boost::function >*()> pleasequeryfunc_t; + +vector* pleaseGetRemotes() +{ + vector* ret = new vector(); + if(!t_remotes) + return ret; + + ret->reserve(t_remotes->size()); + for(const ComboAddress& ca : *t_remotes) { + ret->push_back(ca); + } + return ret; +} + +vector* pleaseGetServfailRemotes() +{ + vector* ret = new vector(); + if(!t_servfailremotes) + return ret; + ret->reserve(t_servfailremotes->size()); + for(const ComboAddress& ca : *t_servfailremotes) { + ret->push_back(ca); + } + return ret; +} + +vector* pleaseGetLargeAnswerRemotes() +{ + vector* ret = new vector(); + if(!t_largeanswerremotes) + return ret; + ret->reserve(t_largeanswerremotes->size()); + for(const ComboAddress& ca : *t_largeanswerremotes) { + ret->push_back(ca); + } + return ret; +} + +string doGenericTopRemotes(pleaseremotefunc_t func) +{ + typedef map counts_t; + counts_t counts; + + vector remotes=broadcastAccFunction >(func); + + unsigned int total=0; + for(const ComboAddress& ca : remotes) { + total++; + counts[ca]++; + } + + typedef std::multimap rcounts_t; + rcounts_t rcounts; + + for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i) + rcounts.insert(make_pair(-i->second, i->first)); + + ostringstream ret; + ret<<"Over last "<first/total) % i->second.toString(); + accounted+= -i->first; + } + ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest"; + } + return ret.str(); +} + +namespace { + typedef vector > pubs_t; + pubs_t g_pubs; +} + +void sortPublicSuffixList() +{ + for(const char** p=g_pubsuffix; *p; ++p) { + string low=toLower(*p); + + vector parts; + stringtok(parts, low, "."); + reverse(parts.begin(), parts.end()); + g_pubs.push_back(parts); + } + sort(g_pubs.begin(), g_pubs.end()); +} + +// XXX DNSName Pain - this function should benefit from native DNSName methods +DNSName getRegisteredName(const DNSName& dom) +{ + auto parts=dom.getRawLabels(); + if(parts.size()<=2) + return dom; + reverse(parts.begin(), parts.end()); + for(string& str : parts) { str=toLower(str); }; + + // uk co migweb + string last; + while(!parts.empty()) { + if(parts.size()==1 || binary_search(g_pubs.begin(), g_pubs.end(), parts)) { + + string ret=last; + if(!ret.empty()) + ret+="."; + + for(auto p = parts.crbegin(); p != parts.crend(); ++p) { + ret+=(*p)+"."; + } + return DNSName(ret); + } + + last=parts[parts.size()-1]; + parts.resize(parts.size()-1); + } + return DNSName("??"); +} + +static DNSName nopFilter(const DNSName& name) +{ + return name; +} + +string doGenericTopQueries(pleasequeryfunc_t func, boost::function filter=nopFilter) +{ + typedef pair query_t; + typedef map counts_t; + counts_t counts; + vector queries=broadcastAccFunction >(func); + + unsigned int total=0; + for(const query_t& q : queries) { + total++; + counts[make_pair(filter(q.first),q.second)]++; + } + + typedef std::multimap rcounts_t; + rcounts_t rcounts; + + for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i) + rcounts.insert(make_pair(-i->second, i->first)); + + ostringstream ret; + ret<<"Over last "<first/total) % (i->second.first.toString()+"|"+DNSRecordContent::NumberToType(i->second.second)); + accounted+= -i->first; + } + ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest"; + } + + + return ret.str(); +} + +static string* nopFunction() +{ + return new string("pong\n"); +} + +string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command) +{ + *command=nop; + vector words; + stringtok(words, question); + + if(words.empty()) + return "invalid command\n"; + + string cmd=toLower(words[0]); + vector::const_iterator begin=words.begin()+1, end=words.end(); + + // should probably have a smart dispatcher here, like auth has + if(cmd=="help") + return +"add-nta DOMAIN [REASON] add a Negative Trust Anchor for DOMAIN with the comment REASON\n" +"add-ta DOMAIN DSRECORD add a Trust Anchor for DOMAIN with data DSRECORD\n" +"current-queries show currently active queries\n" +"clear-nta [DOMAIN]... Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n" +"clear-ta [DOMAIN]... Clear the Trust Anchor for DOMAINs\n" +"dump-cache dump cache contents to the named file\n" +"dump-edns [status] dump EDNS status to the named file\n" +"dump-nsspeeds dump nsspeeds statistics to the named file\n" +"dump-rpz dump the content of a RPZ zone to the named file\n" +"get [key1] [key2] .. get specific statistics\n" +"get-all get all statistics\n" +"get-ntas get all configured Negative Trust Anchors\n" +"get-tas get all configured Trust Anchors\n" +"get-parameter [key1] [key2] .. get configuration parameters\n" +"get-qtypelist get QType statistics\n" +" notice: queries from cache aren't being counted yet\n" +"help get this list\n" +"ping check that all threads are alive\n" +"quit stop the recursor daemon\n" +"quit-nicely stop the recursor daemon nicely\n" +"reload-acls reload ACLS\n" +"reload-lua-script [filename] (re)load Lua script\n" +"reload-lua-config [filename] (re)load Lua configuration file\n" +"reload-zones reload all auth and forward zones\n" +"set-max-cache-entries value set new maximum cache size\n" +"set-max-packetcache-entries val set new maximum packet cache size\n" +"set-minimum-ttl value set minimum-ttl-override\n" +"set-carbon-server set a carbon server for telemetry\n" +"set-dnssec-log-bogus SETTING enable (SETTING=yes) or disable (SETTING=no) logging of DNSSEC validation failures\n" +"trace-regex [regex] emit resolution trace for matching queries (empty regex to clear trace)\n" +"top-largeanswer-remotes show top remotes receiving large answers\n" +"top-queries show top queries\n" +"top-pub-queries show top queries grouped by public suffix list\n" +"top-remotes show top remotes\n" +"top-servfail-queries show top queries receiving servfail answers\n" +"top-pub-servfail-queries show top queries receiving servfail answers grouped by public suffix list\n" +"top-servfail-remotes show top remotes receiving servfail answers\n" +"unload-lua-script unload Lua script\n" +"version return Recursor version number\n" +"wipe-cache domain0 [domain1] .. wipe domain data from cache\n"; + + if(cmd=="get-all") + return getAllStats(); + + if(cmd=="get") + return doGet(begin, end); + + if(cmd=="get-parameter") + return doGetParameter(begin, end); + + if(cmd=="quit") { + *command=&doExit; + return "bye\n"; + } + + if(cmd=="version") { + return getPDNSVersion()+"\n"; + } + + if(cmd=="quit-nicely") { + *command=&doExitNicely; + return "bye nicely\n"; + } + + if(cmd=="dump-cache") + return doDumpCache(begin, end); + + if(cmd=="dump-ednsstatus" || cmd=="dump-edns") + return doDumpEDNSStatus(begin, end); + + if(cmd=="dump-nsspeeds") + return doDumpNSSpeeds(begin, end); + + if(cmd=="dump-rpz") { + return doDumpRPZ(begin, end); + } + + if(cmd=="wipe-cache" || cmd=="flushname") + return doWipeCache(begin, end); + + if(cmd=="reload-lua-script") + return doQueueReloadLuaScript(begin, end); + + if(cmd=="reload-lua-config") { + if(begin != end) + ::arg().set("lua-config-file") = *begin; + + try { + loadRecursorLuaConfig(::arg()["lua-config-file"], false); + L< empty; + empty.push_back(string()); + return doQueueReloadLuaScript(empty.begin(), empty.end()); + } + + if(cmd=="reload-acls") { + if(!::arg()["chroot"].empty()) { + L<(nopFunction); + } + + if(cmd=="reload-zones") { + if(!::arg()["chroot"].empty()) { + L< +Directory where the recursor.conf lives. +.TP +.BI \-\-config\-name\fB= +Name of the virtual configuration. +.TP +.BI \-\-socket\-dir\fB= +Where the controlsocket will live, please +use \fB\-\-config\-dir\fP instead. +.TP +.BI \-\-socket\-pid\fB= +When running in SMP mode, pid of \fBpdns_recursor\fP to +control. +.TP +.BI \-\-timeout\fB= +Number of seconds to wait for the remote PowerDNS +Recursor to respond. Set to 0 for infinite. +.UNINDENT +.SH COMMANDS +.INDENT 0.0 +.TP +.B add\-nta \fIDOMAIN\fP [\fIREASON\fP] +Add a Negative Trust Anchor for \fIDOMAIN\fP, suffixed optionally with +\fIREASON\fP\&. +.TP +.B add\-ta \fIDOMAIN\fP \fIDSRECORD\fP +Add a Trust Anchor for \fIDOMAIN\fP with DS record data \fIDSRECORD\fP\&. This adds +the new Trust Anchor to the existing set of Trust Anchors for \fIDOMAIN\fP\&. +.TP +.B current\-queries +Shows the currently active queries. +.TP +.B clear\-nta \fIDOMAIN\fP\&... +Remove Negative Trust Anchor for one or more \fIDOMAIN\fPs. Set domain to +\(aq*\(aq to remove all NTA\(aqs. +.TP +.B clear\-ta [\fIDOMAIN\fP]... +Remove Trust Anchor for one or more \fIDOMAIN\fPs. Note that removing the +root trust anchor is not possible. +.TP +.B dump\-cache \fIFILENAME\fP +Dumps the entire cache to \fIFILENAME\fP\&. This file should not exist already, +PowerDNS will refuse to overwrite it. While dumping, the recursor will not +answer questions. +.sp +Typical PowerDNS Recursors run multiple threads, therefore you\(aqll see +duplicate, different entries for the same domains. The negative cache is +also dumped to the same file. The per\-thread positive and negative cache +dumps are separated with an appropriate comment. +.TP +.B dump\-edns \fIFILENAME\fP +Dumps the EDNS status to the filename mentioned. This file should not exist +already, PowerDNS will refuse to overwrite it. While dumping, the recursor +will not answer questions. +.TP +.B dump\-nsspeeds \fIFILENAME\fP +Dumps the nameserver speed statistics to the \fIFILENAME\fP mentioned. This +file should not exist already, PowerDNS will refuse to overwrite it. While +dumping, the recursor will not answer questions. Statistics are kept per +thread, and the dumps end up in the same file. +.TP +.B dump\-rpz \fIZONE NAME\fP \fIFILE NAME\fP +Dumps the content of the RPZ zone named \fIZONE NAME\fP to the \fIFILENAME\fP +mentioned. This file should not exist already, PowerDNS will refuse to +overwrite it otherwise. While dumping, the recursor will not answer +questions. +.TP +.B get \fISTATISTIC\fP [\fISTATISTIC\fP]... +Retrieve a statistic. For items that can be queried, see +\&../metrics +.TP +.B get\-all +Retrieve all known statistics. +.TP +.B get\-ntas +Get a list of the currently configured Negative Trust Anchors. +.TP +.B get\-tas +Get a list of the currently configured Trust Anchors. +.TP +.B get\-parameter \fIKEY\fP [\fIKEY\fP]... +Retrieves the specified configuration parameter(s). +.TP +.B get\-qtypelist +Retrieves QType statistics. Queries from cache aren\(aqt being counted yet. +.TP +.B help +Shows a list of supported commands understood by the running +\fBpdns_recursor\fP +.TP +.B ping +Check if server is alive. +.TP +.B quit +Request shutdown of the recursor. +.TP +.B quit\-nicely +Request nice shutdown of the recursor. +.TP +.B reload\-acls +Reloads ACLs. +.TP +.B reload\-lua\-script [\fIFILENAME\fP] +(Re)loads Lua script \fIFILENAME\fP\&. If \fIFILENAME\fP is empty, attempt to reload +the currently loaded script. This replaces the script currently loaded. +.TP +.B reload\-lua\-config [\fIFILENAME\fP] +(Re)loads Lua configuration \fIFILENAME\fP\&. If \fIFILENAME\fP is empty, attempt +to reload the currently loaded file. Note that \fIFILENAME\fP will be fully +executed, any settings changed at runtime that are not modified in this +file, will still be active. Reloading RPZ, especially by AXFR, can take +some time; during which the recursor will not answer questions. +.TP +.B reload\-zones +Reload authoritative and forward zones. Retains current configuration in +case of errors. +.TP +.B set\-carbon\-server \fICARBON SERVER\fP [\fICARBON OURNAME\fP] +Set the carbon\-server setting to \fICARBON SERVER\fP\&. If \fICARBON OURNAME\fP is +not empty, also set the carbon\-ourname setting to \fICARBON OURNAME\fP\&. +.TP +.B set\-dnssec\-log\-bogus \fISETTING\fP +Set dnssec\-log\-bogus setting to \fISETTING\fP\&. Set to \(aqon\(aq or \(aqyes\(aq to log +DNSSEC validation failures and to \(aqno\(aq or \(aqoff\(aq to disable logging these +failures. +.TP +.B set\-max\-cache\-entries \fINUM\fP +Change the maximum number of entries in the DNS cache. If reduced, the +cache size will start shrinking to this number as part of the normal +cache purging process, which might take a while. +.TP +.B set\-max\-packetcache\-entries \fINUM\fP +Change the maximum number of entries in the packet cache. If reduced, the +cache size will start shrinking to this number as part of the normal +cache purging process, which might take a while. +.TP +.B set\-minimum\-ttl \fINUM\fP +Set minimum\-ttl\-override to \fINUM\fP\&. +.TP +.B top\-queries +Shows the top\-20 queries. Statistics are over the last +\(aqstats\-ringbuffer\-entries\(aq queries. +.TP +.B top\-pub\-queries +Shows the top\-20 queries grouped by public suffix list. Statistics are over +the last \(aqstats\-ringbuffer\-entries\(aq queries. +.TP +.B top\-largeanswer\-remotes +Shows the top\-20 remote hosts causing large answers. Statistics are over +the last \(aqstats\-ringbuffer\-entries\(aq queries. +.TP +.B top\-remotes +Shows the top\-20 most active remote hosts. Statistics are over the last +\(aqstats\-ringbuffer\-entries\(aq queries. +.TP +.B top\-servfail\-queries +Shows the top\-20 queries causing servfail responses. Statistics are over +the last \(aqstats\-ringbuffer\-entries\(aq queries. +.TP +.B top\-pub\-servfail\-queries +Shows the top\-20 queries causing servfail responses grouped by public +suffix list. Statistics are over the last \(aqstats\-ringbuffer\-entries\(aq +queries. +.TP +.B top\-servfail\-remotes +Shows the top\-20 most active remote hosts causing servfail responses. +Statistics are over the last \(aqstats\-ringbuffer\-entries\(aq queries. +.TP +.B trace\-regex \fIREGEX\fP +Emit resolution trace for matching queries. Empty regex to disable trace. +.sp +Queries matching this regular expression will generate voluminous tracing +output. Be aware that matches from the packet cache will still not generate +tracing. To unset the regex, pass \fBtrace\-regex\fP without a new regex. +.sp +The regular expression is matched against domain queries terminated with a +\(aq.\(aq. For example the regex \(aqpowerdns.com$\(aq will not match a query for +\(aqwww.powerdns.com\(aq, since the attempted match will be with +\(aqwww.powerdns.com.\(aq. +.sp +In addition, since this is a regular expression, to exclusively match +queries for \(aqwww.powerdns.com\(aq, one should escape the dots: +\(aq^www.powerdns.com.$\(aq. +.sp +Multiple matches can be chained with the \(aq|\(aq operator. For example, to +match all queries for Dutch (.nl) and German (.de) domain names, use: +\(aq.nl.$|.de.$\(aq. +.TP +.B unload\-lua\-script +Unloads Lua script if one was loaded. +.TP +.B version +Report running version. +.TP +.B wipe\-cache \fIDOMAIN\fP [\fIDOMAIN\fP] [...] +Wipe entries for \fIDOMAIN\fP (exact name match) from the cache. This is useful +if, for example, an important server has a new IP address, but the TTL has +not yet expired. Multiple domain names can be passed. +\fIDOMAIN\fP can be suffixed with a \(aq$\(aq. to delete the whole tree from the +cache. i.e. \(aqpowerdns.com$\(aq will remove all cached entries under and +including the powerdns.com name. +.sp +\fBNote\fP: this command also wipes the negative cache. +.sp +\fBWarning\fP: Don\(aqt just wipe "www.somedomain.com", its NS records or CNAME +target may still be undesired, so wipe "somedomain.com" as well. +.UNINDENT +.SH SEE ALSO +.sp +\fBpdns_recursor(1)\fP +.SH AUTHOR +PowerDNS.COM BV +.SH COPYRIGHT +2001-2018, PowerDNS.COM BV +.\" Generated by docutils manpage writer. +. diff --git a/rec_control.cc b/rec_control.cc new file mode 100644 index 0000000..90f6fd1 --- /dev/null +++ b/rec_control.cc @@ -0,0 +1,120 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "rec_channel.hh" +#include +#include "pdnsexception.hh" +#include "arguments.hh" + +#include "namespaces.hh" + +ArgvMap &arg() +{ + static ArgvMap arg; + return arg; +} + +static void initArguments(int argc, char** argv) +{ + arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR; + + arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR+" when unset and not chrooted" )=""; + arg().set("chroot","switch to chroot jail")=""; + arg().set("process","When controlling multiple recursors, the target process number")=""; + arg().set("timeout", "Number of seconds to wait for the recursor to respond")="5"; + arg().set("config-name","Name of this virtual configuration - will rename the binary image")=""; + arg().setCmd("help","Provide this helpful message"); + arg().setCmd("version","Show the version of this program"); + + arg().laxParse(argc,argv); + if(arg().mustDo("help") || arg().getCommands().empty()) { + cout<<"syntax: rec_control [options] command, options as below: "<&commands=arg().getCommands(); + string command; + for(unsigned int i=0; i< commands.size(); ++i) { + if(i>0) + command+=" "; + command+=commands[i]; + } + rccS.send(command); + string receive=rccS.recv(0, arg().asNum("timeout")); + if(receive.compare(0, 7, "Unknown") == 0) { + cerr< +#include + +#include "recpacketcache.hh" +#include "cachecleaner.hh" +#include "dns.hh" +#include "dnsparser.hh" +#include "namespaces.hh" +#include "lock.hh" +#include "dnswriter.hh" +#include "ednsoptions.hh" + +RecursorPacketCache::RecursorPacketCache() +{ + d_hits = d_misses = 0; +} + +int RecursorPacketCache::doWipePacketCache(const DNSName& name, uint16_t qtype, bool subtree) +{ + int count=0; + auto& idx = d_packetCache.get(); + for(auto iter = idx.lower_bound(name); iter != idx.end(); ) { + if(subtree) { + if(!iter->d_name.isPartOf(name)) { // this is case insensitive + break; + } + } + else { + if(iter->d_name != name) + break; + } + + if(qtype==0xffff || iter->d_type == qtype) { + iter=idx.erase(iter); + count++; + } + else + ++iter; + } + return count; +} + +static bool qrMatch(const DNSName& qname, uint16_t qtype, uint16_t qclass, const DNSName& rname, uint16_t rtype, uint16_t rclass) +{ + // this ignores checking on the EDNS subnet flags! + return qname==rname && rtype == qtype && rclass == qclass; +} + +bool RecursorPacketCache::checkResponseMatches(std::pair::type::iterator, packetCache_t::index::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage) +{ + for(auto iter = range.first ; iter != range.second ; ++ iter) { + // the possibility is VERY real that we get hits that are not right - birthday paradox + if(!qrMatch(qname, qtype, qclass, iter->d_name, iter->d_type, iter->d_class)) + continue; + if(now < iter->d_ttd) { // it is right, it is fresh! + *age = static_cast(now - iter->d_creation); + *responsePacket = iter->d_packet; + responsePacket->replace(0, 2, queryPacket.c_str(), 2); + + string::size_type i=sizeof(dnsheader); + + for(;;) { + unsigned int labellen = (unsigned char)queryPacket[i]; + if(!labellen || i + labellen > responsePacket->size()) break; + i++; + responsePacket->replace(i, labellen, queryPacket, i, labellen); + i = i + labellen; + } + + d_hits++; + moveCacheItemToBack(d_packetCache, iter); +#ifdef HAVE_PROTOBUF + if (protobufMessage) { + *protobufMessage = iter->d_protobufMessage; + } +#endif + + return true; + } + else { + moveCacheItemToFront(d_packetCache, iter); + d_misses++; + break; + } + } + + return false; +} + +bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, + std::string* responsePacket, uint32_t* age, uint32_t* qhash) +{ + return getResponsePacket(tag, queryPacket, now, responsePacket, age, qhash, nullptr); +} + +bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, + std::string* responsePacket, uint32_t* age, uint32_t* qhash) +{ + return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, qhash, nullptr); +} + +bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, + std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage) +{ + *qhash = canHashPacket(queryPacket, true); + const auto& idx = d_packetCache.get(); + auto range = idx.equal_range(tie(tag,*qhash)); + + if(range.first == range.second) { + d_misses++; + return false; + } + + return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage); +} + +bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, + std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage) +{ + *qhash = canHashPacket(queryPacket, true); + const auto& idx = d_packetCache.get(); + auto range = idx.equal_range(tie(tag,*qhash)); + + if(range.first == range.second) { + d_misses++; + return false; + } + + uint16_t qtype, qclass; + DNSName qname(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, &qtype, &qclass, 0); + + return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage); +} + + +void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl) +{ + insertResponsePacket(tag, qhash, qname, qtype, qclass, responsePacket, now, ttl, nullptr); +} + +void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage) +{ + auto& idx = d_packetCache.get(); + auto range = idx.equal_range(tie(tag,qhash)); + auto iter = range.first; + + for( ; iter != range.second ; ++iter) { + if(iter->d_type != qtype || iter->d_class != qclass || iter->d_name != qname) + continue; + + moveCacheItemToBack(d_packetCache, iter); + iter->d_packet = responsePacket; + iter->d_ttd = now + ttl; + iter->d_creation = now; +#ifdef HAVE_PROTOBUF + if (protobufMessage) { + iter->d_protobufMessage = *protobufMessage; + } +#endif + + break; + } + + if(iter == range.second) { // nothing to refresh + struct Entry e; + e.d_packet = responsePacket; + e.d_name = qname; + e.d_qhash = qhash; + e.d_type = qtype; + e.d_class = qclass; + e.d_ttd = now+ttl; + e.d_creation = now; + e.d_tag = tag; +#ifdef HAVE_PROTOBUF + if (protobufMessage) { + e.d_protobufMessage = *protobufMessage; + } +#endif + d_packetCache.insert(e); + } +} + +uint64_t RecursorPacketCache::size() +{ + return d_packetCache.size(); +} + +uint64_t RecursorPacketCache::bytes() +{ + uint64_t sum=0; + for(const auto& e : d_packetCache) { + sum += sizeof(e) + e.d_packet.length() + 4; + } + return sum; +} + +void RecursorPacketCache::doPruneTo(unsigned int maxCached) +{ + pruneCollection(*this, d_packetCache, maxCached); +} + +uint64_t RecursorPacketCache::doDump(int fd) +{ + FILE* fp=fdopen(dup(fd), "w"); + if(!fp) { // dup probably failed + return 0; + } + fprintf(fp, "; main packet cache dump from thread follows\n;\n"); + const auto& sidx=d_packetCache.get<1>(); + + uint64_t count=0; + time_t now=time(0); + for(auto i=sidx.cbegin(); i != sidx.cend(); ++i) { + count++; + try { + fprintf(fp, "%s %" PRId64 " %s ; tag %d\n", i->d_name.toString().c_str(), static_cast(i->d_ttd - now), DNSRecordContent::NumberToType(i->d_type).c_str(), i->d_tag); + } + catch(...) { + fprintf(fp, "; error printing '%s'\n", i->d_name.empty() ? "EMPTY" : i->d_name.toString().c_str()); + } + } + fclose(fp); + return count; + +} diff --git a/recpacketcache.hh b/recpacketcache.hh new file mode 100644 index 0000000..8263c73 --- /dev/null +++ b/recpacketcache.hh @@ -0,0 +1,115 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_RECPACKETCACHE_HH +#define PDNS_RECPACKETCACHE_HH + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "rec-protobuf.hh" + +#include +#include +#include +#include "dns.hh" +#include "namespaces.hh" +#include +#include +#include +#include +#include +#include + +#include "packetcache.hh" + + + +using namespace ::boost::multi_index; + +//! Stores whole packets, ready for lobbing back at the client. Not threadsafe. +/* Note: we store answers as value AND KEY, and with careful work, we make sure that + you can use a query as a key too. But query and answer must compare as identical! + + This precludes doing anything smart with EDNS directly from the packet */ +class RecursorPacketCache: public PacketCache +{ +public: + RecursorPacketCache(); + bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash); + bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage); + bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash); + bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage); + void insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl); + void insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage); + void doPruneTo(unsigned int maxSize=250000); + uint64_t doDump(int fd); + int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false); + + void prune(); + uint64_t d_hits, d_misses; + uint64_t size(); + uint64_t bytes(); + +private: + struct HashTag {}; + struct NameTag {}; + struct Entry + { + mutable time_t d_ttd; + mutable time_t d_creation; // so we can 'age' our packets + DNSName d_name; + uint16_t d_type; + uint16_t d_class; + mutable std::string d_packet; // "I know what I am doing" +#ifdef HAVE_PROTOBUF + mutable RecProtoBufMessage d_protobufMessage; +#endif + uint32_t d_qhash; + uint32_t d_tag; + inline bool operator<(const struct Entry& rhs) const; + + time_t getTTD() const + { + return d_ttd; + } + }; + + typedef multi_index_container< + Entry, + indexed_by < + hashed_non_unique, composite_key, member > >, + sequenced<> , + ordered_non_unique, member, CanonDNSNameCompare > + > + > packetCache_t; + + packetCache_t d_packetCache; + + bool checkResponseMatches(std::pair::type::iterator, packetCache_t::index::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage); + +public: + void preRemoval(const Entry& entry) + { + } +}; + +#endif diff --git a/recursor_cache.cc b/recursor_cache.cc new file mode 100644 index 0000000..9ccecf8 --- /dev/null +++ b/recursor_cache.cc @@ -0,0 +1,485 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "syncres.hh" +#include "recursor_cache.hh" +#include "misc.hh" +#include +#include "dnsrecords.hh" +#include "arguments.hh" +#include "recursor_cache.hh" +#include "cachecleaner.hh" +#include "namespaces.hh" + +unsigned int MemRecursorCache::size() const +{ + return (unsigned int)d_cache.size(); +} + +size_t MemRecursorCache::ecsIndexSize() const +{ + return d_ecsIndex.size(); +} + +// this function is too slow to poll! +unsigned int MemRecursorCache::bytes() const +{ + unsigned int ret=0; + + for(cache_t::const_iterator i=d_cache.begin(); i!=d_cache.end(); ++i) { + ret+=sizeof(struct CacheEntry); + ret+=(unsigned int)i->d_qname.toString().length(); + for(auto j=i->d_records.begin(); j!= i->d_records.end(); ++j) + ret+= sizeof(*j); // XXX WRONG we don't know the stored size! j->size(); + } + return ret; +} + +int32_t MemRecursorCache::handleHit(cache_t::iterator entry, const DNSName& qname, const ComboAddress& who, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, vState* state, bool* wasAuth) +{ + int32_t ttd = entry->d_ttd; + + if(variable && !entry->d_netmask.empty()) { + *variable = true; + } + + // cerr<<"Looking at "<d_records.size()<<" records for this name"<d_records) { + DNSRecord dr; + dr.d_name = qname; + dr.d_type = entry->d_qtype; + dr.d_class = QClass::IN; + dr.d_content = k; + dr.d_ttl = static_cast(entry->d_ttd); + dr.d_place = DNSResourceRecord::ANSWER; + res->push_back(dr); + } + } + + if(signatures) { // if you do an ANY lookup you are hosed XXXX + *signatures = entry->d_signatures; + } + + if(authorityRecs) { + *authorityRecs = entry->d_authorityRecs; + } + + if (state) { + *state = entry->d_state; + } + + if (wasAuth) { + *wasAuth = entry->d_auth; + } + + moveCacheItemToBack(d_cache, entry); + + return ttd; +} + +MemRecursorCache::cache_t::const_iterator MemRecursorCache::getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who) +{ + auto ecsIndexKey = tie(qname, qtype); + auto ecsIndex = d_ecsIndex.find(ecsIndexKey); + if (ecsIndex != d_ecsIndex.end() && !ecsIndex->isEmpty()) { + /* we have netmask-specific entries, let's see if we match one */ + while (true) { + const Netmask best = ecsIndex->lookupBestMatch(who); + if (best.empty()) { + /* we have nothing more specific for you */ + break; + } + auto key = boost::make_tuple(qname, qtype, best); + auto entry = d_cache.find(key); + if (entry == d_cache.end()) { + /* ecsIndex is not up-to-date */ + ecsIndex->removeNetmask(best); + if (ecsIndex->isEmpty()) { + d_ecsIndex.erase(ecsIndex); + break; + } + continue; + } + + if (entry->d_ttd > now) { + if (!requireAuth || entry->d_auth) { + return entry; + } + /* we need auth data and the best match is not authoritative */ + return d_cache.end(); + } + else { + /* this netmask-specific entry has expired */ + moveCacheItemToFront(d_cache, entry); + ecsIndex->removeNetmask(best); + if (ecsIndex->isEmpty()) { + d_ecsIndex.erase(ecsIndex); + break; + } + } + } + } + + /* we have nothing specific, let's see if we have a generic one */ + auto key = boost::make_tuple(qname, qtype, Netmask()); + auto entry = d_cache.find(key); + if (entry != d_cache.end()) { + if (entry->d_ttd > now) { + if (!requireAuth || entry->d_auth) { + return entry; + } + } + else { + moveCacheItemToFront(d_cache, entry); + } + } + + /* nothing for you, sorry */ + return d_cache.end(); +} + +// returns -1 for no hits +std::pair MemRecursorCache::getEntries(const DNSName &qname, const QType& qt) +{ + // cerr<<"looking up "<< qname<<"|"+qt.getName()<<"\n"; + if(!d_cachecachevalid || d_cachedqname!= qname) { + // cerr<<"had cache cache miss"<d_auth) + return false; + + return ((entry->d_qtype == qt || qt == QType::ANY || + (qt == QType::ADDR && (entry->d_qtype == QType::A || entry->d_qtype == QType::AAAA))) + && (entry->d_netmask.empty() || entry->d_netmask.match(who))); +} + +// returns -1 for no hits +int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, bool requireAuth, vector* res, const ComboAddress& who, vector>* signatures, std::vector>* authorityRecs, bool* variable, vState* state, bool* wasAuth) +{ + time_t ttd=0; + // cerr<<"looking up "<< qname<<"|"+qt.getName()<<"\n"; + if(res) { + res->clear(); + } + + const uint16_t qtype = qt.getCode(); + /* If we don't have any netmask-specific entries at all, let's just skip this + to be able to use the nice d_cachecache hack. */ + if (qtype != QType::ANY && !d_ecsIndex.empty()) { + if (qtype == QType::ADDR) { + int32_t ret = -1; + + auto entryA = getEntryUsingECSIndex(now, qname, QType::A, requireAuth, who); + if (entryA != d_cache.end()) { + ret = handleHit(entryA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth); + } + auto entryAAAA = getEntryUsingECSIndex(now, qname, QType::AAAA, requireAuth, who); + if (entryAAAA != d_cache.end()) { + int32_t ttdAAAA = handleHit(entryAAAA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth); + if (ret > 0) { + ret = std::min(ret, ttdAAAA); + } else { + ret = ttdAAAA; + } + } + return ret > 0 ? static_cast(ret-now) : ret; + } + else { + auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who); + if (entry != d_cache.end()) { + return static_cast(handleHit(entry, qname, who, res, signatures, authorityRecs, variable, state, wasAuth) - now); + } + return -1; + } + } + + auto entries = getEntries(qname, qt); + + if(entries.first!=entries.second) { + for(cache_t::const_iterator i=entries.first; i != entries.second; ++i) { + + if (i->d_ttd <= now) { + moveCacheItemToFront(d_cache, i); + continue; + } + + if (!entryMatches(i, qtype, requireAuth, who)) + continue; + + ttd = handleHit(i, qname, who, res, signatures, authorityRecs, variable, state, wasAuth); + + if(qt.getCode()!=QType::ANY && qt.getCode()!=QType::ADDR) // normally if we have a hit, we are done + break; + } + + // cerr<<"time left : "<size() : 0) <<"\n"; + return static_cast(ttd-now); + } + return -1; +} + +bool MemRecursorCache::attemptToRefreshNSTTL(const QType& qt, const vector& content, const CacheEntry& stored) +{ + if(!stored.d_auth) { + //~ cerr<<"feel free to scribble non-auth data!"< content.begin()->d_ttl) { + //~ cerr<<"attempt to LOWER TTL - fine by us"<& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, boost::optional ednsmask, vState state) +{ + d_cachecachevalid = false; + // cerr<<"Replacing "<toString() : "everyone") << endl; + auto key = boost::make_tuple(qname, qt.getCode(), ednsmask ? *ednsmask : Netmask()); + bool isNew = false; + cache_t::iterator stored = d_cache.find(key); + if (stored == d_cache.end()) { + stored = d_cache.insert(CacheEntry(key, CacheEntry::records_t(), auth)).first; + isNew = true; + } + + /* don't bother building an ecsIndex if we don't have any netmask-specific entries */ + if (ednsmask && !ednsmask->empty()) { + auto ecsIndexKey = boost::make_tuple(qname, qt.getCode()); + auto ecsIndex = d_ecsIndex.find(ecsIndexKey); + if (ecsIndex == d_ecsIndex.end()) { + ecsIndex = d_ecsIndex.insert(ECSIndexEntry(qname, qt.getCode())).first; + } + ecsIndex->addMask(*ednsmask); + } + + time_t maxTTD=std::numeric_limits::max(); + CacheEntry ce=*stored; // this is a COPY + ce.d_qtype=qt.getCode(); + ce.d_signatures=signatures; + ce.d_authorityRecs=authorityRecs; + ce.d_state=state; + + // cerr<<"asked to store "<< (qname.empty() ? "EMPTY" : qname.toString()) <<"|"+qt.getName()<<" -> '"; + // cerr<<(content.empty() ? string("EMPTY CONTENT") : content.begin()->d_content->getZoneRepresentation())<<"', auth="<toString() : "none") < now) { // we still have valid data, ignore unauth data + // cerr<<"\tStill hold valid auth data, and the new data is unauth, return\n"; + return; + } + else { + ce.d_auth = false; // new data won't be auth + } + } + ce.d_records.clear(); + + // limit TTL of auth->auth NSset update if needed, except for root + if(ce.d_auth && auth && qt.getCode()==QType::NS && !isNew && !qname.isRoot()) { + // cerr<<"\tLimiting TTL of auth->auth NS set replace to "<(i.d_ttl)); // XXX this does weird things if TTLs differ in the set + // cerr<<"To store: "<getZoneRepresentation()<<" with ttl/ttd "< range; + + if(!sub) { + pair ecsIndexRange; + if(qtype==0xffff) { + range = d_cache.equal_range(tie(name)); + ecsIndexRange = d_ecsIndex.equal_range(tie(name)); + } + else { + range=d_cache.equal_range(tie(name, qtype)); + ecsIndexRange = d_ecsIndex.equal_range(tie(name, qtype)); + } + for(cache_t::const_iterator i=range.first; i != range.second; ) { + count++; + d_cache.erase(i++); + } + for(auto i = ecsIndexRange.first; i != ecsIndexRange.second; ) { + d_ecsIndex.erase(i++); + } + } + else { + for(auto iter = d_cache.lower_bound(tie(name)); iter != d_cache.end(); ) { + if(!iter->d_qname.isPartOf(name)) + break; + if(iter->d_qtype == qtype || qtype == 0xffff) { + count++; + d_cache.erase(iter++); + } + else + iter++; + } + for(auto iter = d_ecsIndex.lower_bound(tie(name)); iter != d_ecsIndex.end(); ) { + if(!iter->d_qname.isPartOf(name)) + break; + if(iter->d_qtype == qtype || qtype == 0xffff) { + d_ecsIndex.erase(iter++); + } + else { + iter++; + } + } + } + return count; +} + +bool MemRecursorCache::doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL) +{ + cache_t::iterator iter = d_cache.find(tie(name, qtype)); + if(iter == d_cache.end()) { + return false; + } + + CacheEntry ce = *iter; + if(ce.d_ttd < now) + return false; // would be dead anyhow + + uint32_t maxTTL = static_cast(ce.d_ttd - now); + if(maxTTL > newTTL) { + d_cachecachevalid=false; + + time_t newTTD = now + newTTL; + + + if(ce.d_ttd > newTTD) // do never renew expired or older TTLs + ce.d_ttd = newTTD; + + + d_cache.replace(iter, ce); + return true; + } + return false; +} + +bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState) +{ + bool updated = false; + uint16_t qtype = qt.getCode(); + if (qtype != QType::ANY && qtype != QType::ADDR && !d_ecsIndex.empty()) { + auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who); + if (entry == d_cache.end()) { + return false; + } + + entry->d_state = newState; + return true; + } + + auto entries = getEntries(qname, qt); + + for(auto i = entries.first; i != entries.second; ++i) { + if (!entryMatches(i, qtype, requireAuth, who)) + continue; + + i->d_state = newState; + updated = true; + + if(qtype != QType::ANY && qtype != QType::ADDR) // normally if we have a hit, we are done + break; + } + + return updated; +} + +uint64_t MemRecursorCache::doDump(int fd) +{ + FILE* fp=fdopen(dup(fd), "w"); + if(!fp) { // dup probably failed + return 0; + } + fprintf(fp, "; main record cache dump from thread follows\n;\n"); + const auto& sidx=d_cache.get<1>(); + + uint64_t count=0; + time_t now=time(0); + for(const auto i : sidx) { + for(const auto j : i.d_records) { + count++; + try { + fprintf(fp, "%s %" PRId64 " IN %s %s ; (%s) auth=%i %s\n", i.d_qname.toString().c_str(), static_cast(i.d_ttd - now), DNSRecordContent::NumberToType(i.d_qtype).c_str(), j->getZoneRepresentation().c_str(), vStates[i.d_state], i.d_auth, i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str()); + } + catch(...) { + fprintf(fp, "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str()); + } + } + for(const auto &sig : i.d_signatures) { + count++; + try { + fprintf(fp, "%s %" PRId64 " IN RRSIG %s ; %s\n", i.d_qname.toString().c_str(), static_cast(i.d_ttd - now), sig->getZoneRepresentation().c_str(), i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str()); + } + catch(...) { + fprintf(fp, "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str()); + } + } + } + fclose(fp); + return count; +} + +void MemRecursorCache::doPrune(unsigned int keep) +{ + d_cachecachevalid=false; + + pruneCollection(*this, d_cache, keep); +} + diff --git a/recursor_cache.hh b/recursor_cache.hh new file mode 100644 index 0000000..2e40d4b --- /dev/null +++ b/recursor_cache.hh @@ -0,0 +1,205 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 RECURSOR_CACHE_HH +#define RECURSOR_CACHE_HH +#include +#include +#include "dns.hh" +#include "qtype.hh" +#include "misc.hh" +#include "dnsname.hh" +#include +#include "dnsrecords.hh" +#include +#undef L +#include +#include +#include +#include +#include +#include +#include +#include "iputils.hh" +#include "validate.hh" +#undef max + +#define L theL() +#include "namespaces.hh" +using namespace ::boost::multi_index; + +class MemRecursorCache : public boost::noncopyable // : public RecursorCache +{ +public: + MemRecursorCache() : d_cachecachevalid(false) + { + cacheHits = cacheMisses = 0; + } + unsigned int size() const; + unsigned int bytes() const; + size_t ecsIndexSize() const; + + int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector* res, const ComboAddress& who, vector>* signatures=nullptr, std::vector>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr); + + void replace(time_t, const DNSName &qname, const QType& qt, const vector& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, boost::optional ednsmask=boost::none, vState state=Indeterminate); + + void doPrune(unsigned int keep); + uint64_t doDump(int fd); + + int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff); + bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL); + bool updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState); + + uint64_t cacheHits, cacheMisses; + +private: + + struct CacheEntry + { + CacheEntry(const boost::tuple& key, const vector>& records, bool auth) : + d_records(records), d_qname(key.get<0>()), d_netmask(key.get<2>()), d_state(Indeterminate), d_ttd(0), d_qtype(key.get<1>()), d_auth(auth) + {} + + typedef vector> records_t; + time_t getTTD() const + { + return d_ttd; + } + + records_t d_records; + std::vector> d_signatures; + std::vector> d_authorityRecs; + DNSName d_qname; + Netmask d_netmask; + mutable vState d_state; + time_t d_ttd; + uint16_t d_qtype; + bool d_auth; + }; + + /* The ECS Index (d_ecsIndex) keeps track of whether there is any ECS-specific + entry for a given (qname,qtype) entry in the cache (d_cache), and if so + provides a NetmaskTree of those ECS entries. + This allows figuring out quickly if we should look for an entry + specific to the requestor IP, and if so which entry is the most + specific one. + Keeping the entries in the regular cache is currently necessary + because of the way we manage expired entries (moving them to the + front of the expunge queue to be deleted at a regular interval). + */ + class ECSIndexEntry + { + public: + ECSIndexEntry(const DNSName& qname, uint16_t qtype): d_qname(qname), d_qtype(qtype) + { + } + + Netmask lookupBestMatch(const ComboAddress& addr) const + { + Netmask result = Netmask(); + + const auto best = d_nmt.lookup(addr); + if (best != nullptr) { + result = best->first; + } + + return result; + } + + void addMask(const Netmask& nm) const + { + d_nmt.insert(nm).second = true; + } + + void removeNetmask(const Netmask& nm) const + { + d_nmt.erase(nm); + } + + bool isEmpty() const + { + return d_nmt.empty(); + } + + mutable NetmaskTree d_nmt; + DNSName d_qname; + uint16_t d_qtype; + }; + + typedef multi_index_container< + CacheEntry, + indexed_by < + ordered_unique< + composite_key< + CacheEntry, + member, + member, + member + >, + composite_key_compare, std::less > + >, + sequenced<> + > + > cache_t; + typedef multi_index_container< + ECSIndexEntry, + indexed_by < + ordered_unique < + composite_key< + ECSIndexEntry, + member, + member + >, + composite_key_compare > + > + > + > ecsIndex_t; + + cache_t d_cache; + ecsIndex_t d_ecsIndex; + pair d_cachecache; + DNSName d_cachedqname; + bool d_cachecachevalid; + + bool attemptToRefreshNSTTL(const QType& qt, const vector& content, const CacheEntry& stored); + bool entryMatches(cache_t::const_iterator& entry, uint16_t qt, bool requireAuth, const ComboAddress& who); + std::pair getEntries(const DNSName &qname, const QType& qt); + cache_t::const_iterator getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who); + int32_t handleHit(cache_t::iterator entry, const DNSName& qname, const ComboAddress& who, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, vState* state, bool* wasAuth); + +public: + void preRemoval(const CacheEntry& entry) + { + if (entry.d_netmask.empty()) { + return; + } + + auto key = tie(entry.d_qname, entry.d_qtype); + auto ecsIndexEntry = d_ecsIndex.find(key); + if (ecsIndexEntry != d_ecsIndex.end()) { + ecsIndexEntry->removeNetmask(entry.d_netmask); + if (ecsIndexEntry->isEmpty()) { + d_ecsIndex.erase(ecsIndexEntry); + } + } + } +}; +#endif diff --git a/reczones.cc b/reczones.cc new file mode 100644 index 0000000..ab6a4e1 --- /dev/null +++ b/reczones.cc @@ -0,0 +1,485 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "syncres.hh" +#include "arguments.hh" +#include "zoneparser-tng.hh" +#include "logger.hh" +#include "dnsrecords.hh" +#include "root-addresses.hh" + +extern int g_argc; +extern char** g_argv; + +void primeHints(void) +{ + // prime root cache + const vState validationState = Insecure; + vector nsset; + if(!t_RC) + t_RC = std::unique_ptr(new MemRecursorCache()); + + if(::arg()["hint-file"].empty()) { + DNSRecord arr, aaaarr, nsrr; + nsrr.d_name=g_rootdnsname; + arr.d_type=QType::A; + aaaarr.d_type=QType::AAAA; + nsrr.d_type=QType::NS; + arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(0)+3600000; + + for(char c='a';c<='m';++c) { + char templ[40]; + strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1); + templ[sizeof(templ)-1] = '\0'; + *templ=c; + aaaarr.d_name=arr.d_name=DNSName(templ); + nsrr.d_content=std::make_shared(DNSName(templ)); + arr.d_content=std::make_shared(ComboAddress(rootIps4[c-'a'])); + vector aset; + aset.push_back(arr); + t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector>(), vector>(), true, boost::none, validationState); // auth, nuke it all + if (rootIps6[c-'a'] != NULL) { + aaaarr.d_content=std::make_shared(ComboAddress(rootIps6[c-'a'])); + + vector aaaaset; + aaaaset.push_back(aaaarr); + t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector>(), vector>(), true, boost::none, validationState); + } + + nsset.push_back(nsrr); + } + } + else { + ZoneParserTNG zpt(::arg()["hint-file"]); + DNSResourceRecord rr; + + while(zpt.get(rr)) { + rr.ttl+=time(0); + if(rr.qtype.getCode()==QType::A) { + vector aset; + aset.push_back(DNSRecord(rr)); + t_RC->replace(time(0), rr.qname, QType(QType::A), aset, vector>(), vector>(), true, boost::none, validationState); // auth, etc see above + } else if(rr.qtype.getCode()==QType::AAAA) { + vector aaaaset; + aaaaset.push_back(DNSRecord(rr)); + t_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector>(), vector>(), true, boost::none, validationState); + } else if(rr.qtype.getCode()==QType::NS) { + rr.content=toLower(rr.content); + nsset.push_back(DNSRecord(rr)); + } + } + } + t_RC->doWipeCache(g_rootdnsname, false, QType::NS); + t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector>(), vector>(), false, boost::none, validationState); // and stuff in the cache +} + +static void makeNameToIPZone(std::shared_ptr newMap, const DNSName& hostname, const string& ip) +{ + SyncRes::AuthDomain ad; + ad.d_rdForward=false; + + DNSRecord dr; + dr.d_name=hostname; + dr.d_place=DNSResourceRecord::ANSWER; + dr.d_ttl=86400; + dr.d_type=QType::SOA; + dr.d_class = 1; + dr.d_content = DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800"); + + ad.d_records.insert(dr); + + dr.d_type=QType::NS; + dr.d_content=std::make_shared("localhost."); + + ad.d_records.insert(dr); + + dr.d_type=QType::A; + dr.d_content = DNSRecordContent::mastermake(QType::A, 1, ip); + ad.d_records.insert(dr); + + if(newMap->count(dr.d_name)) { + L< newMap, const vector& parts) +{ + string address=parts[0]; + vector ipparts; + stringtok(ipparts, address,"."); + + SyncRes::AuthDomain ad; + ad.d_rdForward=false; + + DNSRecord dr; + for(int n=ipparts.size()-1; n>=0 ; --n) { + dr.d_name.appendRawLabel(ipparts[n]); + } + dr.d_name.appendRawLabel("in-addr"); + dr.d_name.appendRawLabel("arpa"); + dr.d_class = 1; + dr.d_place=DNSResourceRecord::ANSWER; + dr.d_ttl=86400; + dr.d_type=QType::SOA; + dr.d_content=DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800"); + + ad.d_records.insert(dr); + + dr.d_type=QType::NS; + dr.d_content=std::make_shared(DNSName("localhost.")); + + ad.d_records.insert(dr); + dr.d_type=QType::PTR; + + if(ipparts.size()==4) // otherwise this is a partial zone + for(unsigned int n=1; n < parts.size(); ++n) { + dr.d_content=DNSRecordContent::mastermake(QType::PTR, 1, DNSName(parts[n]).toString()); // XXX FIXME DNSNAME PAIN CAN THIS BE RIGHT? + ad.d_records.insert(dr); + } + + if(newMap->count(dr.d_name)) { + L< both; + + try { // case 2 + both=splitField(input,':'); + uint16_t newport=static_cast(pdns_stou(both.second)); + return ComboAddress(both.first, newport); + } + catch(...){} + + if(input[0]=='[') { // case 4 + both=splitField(input.substr(1),']'); + return ComboAddress(both.first, both.second.empty() ? port : static_cast(pdns_stou(both.second.substr(1)))); + } + + return ComboAddress(input, port); // case 3 +} + + +void convertServersForAD(const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, bool verbose=true) +{ + vector servers; + stringtok(servers, input, sepa); + ad.d_servers.clear(); + + for(vector::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) { + if(verbose && iter != servers.begin()) + L<<", "; + + ComboAddress addr=parseIPAndPort(*iter, 53); + if(verbose) + L< newmap) +{ + SyncRes::setDomainMap(newmap); + return 0; +} + +string reloadAuthAndForwards() +{ + std::shared_ptr original=SyncRes::getDomainMap(); + + try { + L< extraConfigs; + ::arg().gatherIncludes(extraConfigs); + + for(const std::string& fn : extraConfigs) { + if(!::arg().preParseFile(fn.c_str(), "forward-zones", ::arg()["forward-zones"])) + throw runtime_error("Unable to re-parse configuration file include '"+fn+"'"); + ::arg().preParseFile(fn.c_str(), "forward-zones-file", ::arg()["forward-zones-file"]); + ::arg().preParseFile(fn.c_str(), "forward-zones-recurse", ::arg()["forward-zones-recurse"]); + ::arg().preParseFile(fn.c_str(), "auth-zones",::arg()["auth-zones"]); + ::arg().preParseFile(fn.c_str(), "export-etc-hosts",::arg()["export-etc-hosts"]); + ::arg().preParseFile(fn.c_str(), "serve-rfc1918",::arg()["serve-rfc1918"]); + } + + ::arg().preParse(g_argc, g_argv, "forward-zones"); + ::arg().preParse(g_argc, g_argv, "forward-zones-file"); + ::arg().preParse(g_argc, g_argv, "forward-zones-recurse"); + ::arg().preParse(g_argc, g_argv, "auth-zones"); + ::arg().preParse(g_argc, g_argv, "export-etc-hosts"); + ::arg().preParse(g_argc, g_argv, "serve-rfc1918"); + + std::shared_ptr newDomainMap = parseAuthAndForwards(); + + // purge both original and new names + std::set oldAndNewDomains; + for(const auto& i : *newDomainMap) { + oldAndNewDomains.insert(i.first); + } + + if(original) { + for(const auto& i : *original) { + oldAndNewDomains.insert(i.first); + } + } + + for(const auto i : oldAndNewDomains) { + broadcastAccFunction(boost::bind(pleaseWipeCache, i, true)); + broadcastAccFunction(boost::bind(pleaseWipePacketCache, i, true)); + broadcastAccFunction(boost::bind(pleaseWipeAndCountNegCache, i, true)); + } + + broadcastFunction(boost::bind(pleaseUseNewSDomainsMap, newDomainMap)); + return "ok\n"; + } + catch(std::exception& e) { + L< parseAuthAndForwards() +{ + TXTRecordContent::report(); + OPTRecordContent::report(); + + auto newMap = std::make_shared(); + + typedef vector parts_t; + parts_t parts; + const char *option_names[3]={"auth-zones", "forward-zones", "forward-zones-recurse"}; + for(int n=0; n < 3 ; ++n ) { + parts.clear(); + stringtok(parts, ::arg()[option_names[n]], " ,\t\n\r"); + for(parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) { + SyncRes::AuthDomain ad; + if ((*iter).find('=') == string::npos) + throw PDNSException("Error parsing '" + *iter + "', missing ="); + pair headers=splitField(*iter, '='); + trim(headers.first); + trim(headers.second); + // headers.first=toCanonic("", headers.first); + if(n==0) { + ad.d_rdForward = false; + L< fp=shared_ptr(rfp, fclose); + + string line; + int linenum=0; + uint64_t before = newMap->size(); + while(linenum++, stringfgets(fp.get(), line)) { + trim(line); + if (line[0] == '#') // Comment line, skip to the next line + continue; + string domain, instructions; + tie(domain, instructions)=splitField(line, '='); + instructions = splitField(instructions, '#').first; // Remove EOL comments + trim(domain); + trim(instructions); + if(domain.empty() && instructions.empty()) { // empty line + continue; + } + if(boost::starts_with(domain,"+")) { + domain=domain.c_str()+1; + ad.d_rdForward = true; + } + else + ad.d_rdForward = false; + if(domain.empty()) { + throw PDNSException("Error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]); + } + + try { + convertServersForAD(instructions, ad, ",; ", false); + } + catch(...) { + throw PDNSException("Conversion error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]); + } + + ad.d_name = DNSName(domain); + (*newMap)[ad.d_name]=ad; + } + L<size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"< +#include "remote_logger.hh" +#include "config.h" +#ifdef PDNS_CONFIG_ARGS +#include "logger.hh" +#define WE_ARE_RECURSOR +#else +#include "dolog.hh" +#endif + +bool RemoteLogger::reconnect() +{ + if (d_socket >= 0) { + close(d_socket); + d_socket = -1; + } + try { + d_socket = SSocket(d_remote.sin4.sin_family, SOCK_STREAM, 0); + setNonBlocking(d_socket); + SConnectWithTimeout(d_socket, d_remote, d_timeout); + } + catch(const std::exception& e) { +#ifdef WE_ARE_RECURSOR + L< lock(d_writeMutex); + d_queueCond.wait(lock, [this]{return (!d_writeQueue.empty()) || d_exiting;}); + if (d_exiting) { + return; + } + data = d_writeQueue.front(); + d_writeQueue.pop(); + } + + try { + uint16_t len = static_cast(data.length()); + sendSizeAndMsgWithTimeout(d_socket, len, data.c_str(), static_cast(d_timeout), nullptr, nullptr, 0, 0, 0); + } + catch(const std::runtime_error& e) { +#ifdef WE_ARE_RECURSOR + L< lock(d_writeMutex); + if (d_writeQueue.size() >= d_maxQueuedEntries) { + d_writeQueue.pop(); + } + d_writeQueue.push(data); + } + d_queueCond.notify_one(); +} + +RemoteLogger::RemoteLogger(const ComboAddress& remote, uint16_t timeout, uint64_t maxQueuedEntries, uint8_t reconnectWaitTime, bool asyncConnect): d_remote(remote), d_maxQueuedEntries(maxQueuedEntries), d_timeout(timeout), d_reconnectWaitTime(reconnectWaitTime), d_asyncConnect(asyncConnect), d_thread(&RemoteLogger::worker, this) +{ + if (!d_asyncConnect) { + reconnect(); + } +} + +RemoteLogger::~RemoteLogger() +{ + d_exiting = true; + if (d_socket >= 0) { + close(d_socket); + d_socket = -1; + } + d_queueCond.notify_one(); + d_thread.join(); +} diff --git a/remote_logger.hh b/remote_logger.hh new file mode 100644 index 0000000..33f0bba --- /dev/null +++ b/remote_logger.hh @@ -0,0 +1,59 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "iputils.hh" + +class RemoteLogger +{ +public: + RemoteLogger(const ComboAddress& remote, uint16_t timeout=2, uint64_t maxQueuedEntries=100, uint8_t reconnectWaitTime=1, bool asyncConnect=false); + ~RemoteLogger(); + void queueData(const std::string& data); + std::string toString() + { + return d_remote.toStringWithPort(); + } +private: + bool reconnect(); + void worker(); + + std::queue d_writeQueue; + std::mutex d_writeMutex; + std::condition_variable d_queueCond; + ComboAddress d_remote; + uint64_t d_maxQueuedEntries; + int d_socket{-1}; + uint16_t d_timeout; + uint8_t d_reconnectWaitTime; + std::atomic d_exiting{false}; + bool d_asyncConnect{false}; + std::thread d_thread; +}; diff --git a/resolve-context.hh b/resolve-context.hh new file mode 100644 index 0000000..c22abcd --- /dev/null +++ b/resolve-context.hh @@ -0,0 +1,22 @@ +#pragma once + +#include "config.h" + +#ifdef HAVE_PROTOBUF +#include +#endif + +struct ResolveContext { + ResolveContext() + { + } + ResolveContext(const ResolveContext& ctx) + { +#ifdef HAVE_PROTOBUF + this->d_initialRequestId = ctx.d_initialRequestId; +#endif + } +#ifdef HAVE_PROTOBUF + boost::optional d_initialRequestId; +#endif +}; diff --git a/resolver.cc b/resolver.cc new file mode 100644 index 0000000..1669791 --- /dev/null +++ b/resolver.cc @@ -0,0 +1,576 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "utility.hh" +#include "resolver.hh" +#include +#include +#include +#include +#include "misc.hh" +#include +#include +#include "dnsrecords.hh" +#include +#include +#include +#include +#include "dns.hh" +#include "qtype.hh" + +#include "pdnsexception.hh" +#include "arguments.hh" +#include "base64.hh" +#include "dnswriter.hh" +#include "dnsparser.hh" + + +#include "dns_random.hh" +#include +#include "gss_context.hh" +#include "namespaces.hh" + +int makeQuerySocket(const ComboAddress& local, bool udpOrTCP, bool nonLocalBind) +{ + ComboAddress ourLocal(local); + + int sock=socket(ourLocal.sin4.sin_family, udpOrTCP ? SOCK_DGRAM : SOCK_STREAM, 0); + if(sock < 0) { + if(errno == EAFNOSUPPORT && local.sin4.sin_family == AF_INET6) { + return -1; + } + unixDie("Creating local resolver socket for "+ourLocal.toString()); + } + + setCloseOnExec(sock); + + if(nonLocalBind) + Utility::setBindAny(local.sin4.sin_family, sock); + + if(udpOrTCP) { + // udp, try hard to bind an unpredictable port + int tries=10; + while(--tries) { + ourLocal.sin4.sin_port = htons(10000+(dns_random(10000))); + + if (::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) >= 0) + break; + } + // cerr<<"bound udp port "<=0) + close(locals["default4"]); + throw; + } +} + +Resolver::~Resolver() +{ + for(std::map::iterator iter = locals.begin(); iter != locals.end(); iter++) { + if (iter->second >= 0) + close(iter->second); + } +} + +uint16_t Resolver::sendResolve(const ComboAddress& remote, const ComboAddress& local, + const DNSName &domain, int type, bool dnssecOK, + const DNSName& tsigkeyname, const DNSName& tsigalgorithm, + const string& tsigsecret) +{ + uint16_t randomid; + vector packet; + DNSPacketWriter pw(packet, domain, type); + pw.getHeader()->id = randomid = dns_random(0xffff); + + if(dnssecOK) { + pw.addOpt(2800, 0, EDNSOpts::DNSSECOK); + pw.commit(); + } + + if(!tsigkeyname.empty()) { + // cerr<<"Adding TSIG to notification, key name: '"<::iterator lptr; + // see if there is a local + + if ((lptr = locals.find(lstr)) != locals.end()) { + sock = lptr->second; + } else { + // try to make socket + sock = makeQuerySocket(local, true); + if (sock < 0) + throw ResolverException("Unable to create socket to "+remote.toStringWithPort()+": "+stringerror()); + setNonBlocking( sock ); + locals[lstr] = sock; + } + } + + if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) { + throw ResolverException("Unable to ask query of "+remote.toStringWithPort()+": "+stringerror()); + } + return randomid; +} + +uint16_t Resolver::sendResolve(const ComboAddress& remote, const DNSName &domain, + int type, bool dnssecOK, + const DNSName& tsigkeyname, const DNSName& tsigalgorithm, + const string& tsigsecret) +{ + ComboAddress local; + local.sin4.sin_family = 0; + return this->sendResolve(remote, local, domain, type, dnssecOK, tsigkeyname, tsigalgorithm, tsigsecret); +} + +static int parseResult(MOADNSParser& mdp, const DNSName& origQname, uint16_t origQtype, uint16_t id, Resolver::res_t* result) +{ + result->clear(); + + if(mdp.d_header.rcode) + return mdp.d_header.rcode; + + if(origQname.countLabels()) { // not AXFR + if(mdp.d_header.id != id) + throw ResolverException("Remote nameserver replied with wrong id"); + if(mdp.d_header.qdcount != 1) + throw ResolverException("resolver: received answer with wrong number of questions ("+itoa(mdp.d_header.qdcount)+")"); + if(mdp.d_qname != origQname) + throw ResolverException(string("resolver: received an answer to another question (")+mdp.d_qname.toString()+"!="+ origQname.toString()+".)"); + } + + vector ret; + DNSResourceRecord rr; + for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) { + rr.qname = i->first.d_name; + rr.qtype = i->first.d_type; + rr.ttl = i->first.d_ttl; + rr.content = i->first.d_content->getZoneRepresentation(true); + result->push_back(rr); + } + + return 0; +} + +bool Resolver::tryGetSOASerial(DNSName *domain, uint32_t *theirSerial, uint32_t *theirInception, uint32_t *theirExpire, uint16_t* id) +{ + auto fds = std::unique_ptr(new struct pollfd[locals.size()]); + size_t i = 0, k; + int sock; + + for(std::map::iterator iter=locals.begin(); iter != locals.end(); iter++, i++) { + fds[i].fd = iter->second; + fds[i].events = POLLIN; + } + + if (poll(fds.get(), i, 250) < 1) { // wait for 0.25s + return false; + } + + sock = -1; + + // determine who + for(k=0;kempty()) + throw ResolverException("SOA query to '" + fromaddr.toStringWithPort() + "' produced response without domain name (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")"); + + if(mdp.d_answers.empty()) + throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' produced no results (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")"); + + if(mdp.d_qtype != QType::SOA) + throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' returned wrong record type"); + + *theirInception = *theirExpire = 0; + bool gotSOA=false; + for(const MOADNSParser::answers_t::value_type& drc : mdp.d_answers) { + if(drc.first.d_type == QType::SOA) { + shared_ptr src=getRR(drc.first); + if (src) { + *theirSerial=src->d_st.serial; + gotSOA = true; + } + } + if(drc.first.d_type == QType::RRSIG) { + shared_ptr rrc=getRR(drc.first); + if(rrc && rrc->d_type == QType::SOA) { + *theirInception= std::max(*theirInception, rrc->d_siginception); + *theirExpire = std::max(*theirExpire, rrc->d_sigexpire); + } + } + } + if(!gotSOA) + throw ResolverException("Query to '" + fromaddr.toString() + "' for SOA of '" + domain->toString() + "' did not return a SOA"); + return true; +} + +int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res, const ComboAddress &local) +{ + try { + ComboAddress to(ipport, 53); + + int id = sendResolve(to, local, domain, type); + int sock; + + // choose socket based on local + if (local.sin4.sin_family == 0) { + // up to us. + sock = to.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"]; + } else { + std::string lstr = local.toString(); + std::map::iterator lptr; + // see if there is a local + + if ((lptr = locals.find(lstr)) != locals.end()) sock = lptr->second; + else throw ResolverException("sendResolve did not create socket for " + lstr); + } + + int err=waitForData(sock, 0, 3000000); + + if(!err) { + throw ResolverException("Timeout waiting for answer"); + } + if(err < 0) + throw ResolverException("Error waiting for answer: "+stringerror()); + + ComboAddress from; + socklen_t addrlen = sizeof(from); + char buffer[3000]; + int len; + + if((len=recvfrom(sock, buffer, sizeof(buffer), 0,(struct sockaddr*)(&from), &addrlen)) < 0) + throw ResolverException("recvfrom error waiting for answer: "+stringerror()); + + MOADNSParser mdp(false, buffer, len); + return parseResult(mdp, domain, type, id, res); + } + catch(ResolverException &re) { + throw ResolverException(re.reason+" from "+ipport); + } + return -1; +} + +int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res) { + ComboAddress local; + local.sin4.sin_family = 0; + return resolve(ipport, domain, type, res, local); +} + +void Resolver::getSoaSerial(const string &ipport, const DNSName &domain, uint32_t *serial) +{ + vector res; + int ret = resolve(ipport, domain, QType::SOA, &res); + + if(ret || res.empty()) + throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced no answers"); + + if(res[0].qtype.getCode() != QType::SOA) + throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced a "+res[0].qtype.getName()+" record"); + + vectorparts; + stringtok(parts, res[0].content); + if(parts.size()<3) + throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced an unparseable response"); + + try { + *serial=pdns_stou(parts[2]); + } + catch(const std::out_of_range& oor) { + throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced an unparseable serial"); + } +} + +AXFRRetriever::AXFRRetriever(const ComboAddress& remote, + const DNSName& domain, + const TSIGTriplet& tt, + const ComboAddress* laddr, + size_t maxReceivedBytes, + uint16_t timeout) + : d_tsigVerifier(tt, remote, d_trc), d_receivedBytes(0), d_maxReceivedBytes(maxReceivedBytes) +{ + ComboAddress local; + if (laddr != NULL) { + local = (ComboAddress) (*laddr); + } else { + if(remote.sin4.sin_family == AF_INET) + local=ComboAddress(::arg()["query-local-address"]); + else if(!::arg()["query-local-address6"].empty()) + local=ComboAddress(::arg()["query-local-address6"]); + else + local=ComboAddress("::"); + } + d_sock = -1; + try { + d_sock = makeQuerySocket(local, false); // make a TCP socket + if (d_sock < 0) + throw ResolverException("Error creating socket for AXFR request to "+d_remote.toStringWithPort()); + d_buf = shared_array(new char[65536]); + d_remote = remote; // mostly for error reporting + this->connect(timeout); + d_soacount = 0; + + vector packet; + DNSPacketWriter pw(packet, domain, QType::AXFR); + pw.getHeader()->id = dns_random(0xffff); + + if(!tt.name.empty()) { + if (tt.algo == DNSName("hmac-md5")) + d_trc.d_algoName = tt.algo + DNSName("sig-alg.reg.int"); + else + d_trc.d_algoName = tt.algo; + d_trc.d_time = time(0); + d_trc.d_fudge = 300; + d_trc.d_origID=ntohs(pw.getHeader()->id); + d_trc.d_eRcode=0; + addTSIG(pw, d_trc, tt.name, tt.secret, "", false); + } + + uint16_t replen=htons(packet.size()); + Utility::iovec iov[2]; + iov[0].iov_base=reinterpret_cast(&replen); + iov[0].iov_len=2; + iov[1].iov_base=packet.data(); + iov[1].iov_len=packet.size(); + + int ret=Utility::writev(d_sock, iov, 2); + if(ret < 0) + throw ResolverException("Error sending question to "+d_remote.toStringWithPort()+": "+stringerror()); + if(ret != (int)(2+packet.size())) { + throw ResolverException("Partial write on AXFR request to "+d_remote.toStringWithPort()); + } + + int res = waitForData(d_sock, timeout, 0); + + if(!res) + throw ResolverException("Timeout waiting for answer from "+d_remote.toStringWithPort()+" during AXFR"); + if(res<0) + throw ResolverException("Error waiting for answer from "+d_remote.toStringWithPort()+": "+stringerror()); + } + catch(...) { + if(d_sock >= 0) + close(d_sock); + d_sock = -1; + throw; + } +} + +AXFRRetriever::~AXFRRetriever() +{ + close(d_sock); +} + + + +int AXFRRetriever::getChunk(Resolver::res_t &res, vector* records, uint16_t timeout) // Implementation is making sure RFC2845 4.4 is followed. +{ + if(d_soacount > 1) + return false; + + // d_sock is connected and is about to spit out a packet + int len=getLength(timeout); + if(len<0) + throw ResolverException("EOF trying to read axfr chunk from remote TCP client"); + + if (d_maxReceivedBytes > 0 && (d_maxReceivedBytes - d_receivedBytes) < (size_t) len) + throw ResolverException("Reached the maximum number of received bytes during AXFR"); + + timeoutReadn(len, timeout); + + d_receivedBytes += (uint16_t) len; + + MOADNSParser mdp(false, d_buf.get(), len); + + int err; + if(!records) + err=parseResult(mdp, DNSName(), 0, 0, &res); + else { + records->clear(); + for(const auto& r: mdp.d_answers) + records->push_back(r.first); + err = mdp.d_header.rcode; + } + + if(err) + throw ResolverException("AXFR chunk error: " + RCode::to_s(err)); + + for(const MOADNSParser::answers_t::value_type& answer : mdp.d_answers) + if (answer.first.d_type == QType::SOA) + d_soacount++; + + try { + d_tsigVerifier.check(std::string(d_buf.get(), len), mdp); + } + catch(const std::runtime_error& re) { + throw ResolverException(re.what()); + } + + return true; +} + +void AXFRRetriever::timeoutReadn(uint16_t bytes, uint16_t timeoutsec) +{ + time_t start=time(nullptr); + int n=0; + int numread; + while(n +#include +#include +#include "iputils.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#undef res_mkquery + +#include "pdnsexception.hh" +#include "dns.hh" +#include "namespaces.hh" +#include "dnsrecords.hh" +#include "dnssecinfra.hh" +#include "tsigverifier.hh" + +class ResolverException : public PDNSException +{ +public: + ResolverException(const string &reason_) : PDNSException(reason_){} +}; + +// make an IPv4 or IPv6 query socket +int makeQuerySocket(const ComboAddress& local, bool udpOrTCP, bool nonLocalBind=false); +//! Resolver class. Can be used synchronously and asynchronously, over IPv4 and over IPv6 (simultaneously) +class Resolver : public boost::noncopyable +{ +public: + Resolver(); + ~Resolver(); + + typedef vector res_t; + //! synchronously resolve domain|type at IP, store result in result, rcode in ret + int resolve(const string &ip, const DNSName &domain, int type, res_t* result, const ComboAddress& local); + + int resolve(const string &ip, const DNSName &domain, int type, res_t* result); + + //! only send out a resolution request + uint16_t sendResolve(const ComboAddress& remote, const ComboAddress& local, const DNSName &domain, int type, bool dnssecOk=false, + const DNSName& tsigkeyname=DNSName(), const DNSName& tsigalgorithm=DNSName(), const string& tsigsecret=""); + + uint16_t sendResolve(const ComboAddress& remote, const DNSName &domain, int type, bool dnssecOk=false, + const DNSName& tsigkeyname=DNSName(), const DNSName& tsigalgorithm=DNSName(), const string& tsigsecret=""); + + //! see if we got a SOA response from our sendResolve + bool tryGetSOASerial(DNSName *theirDomain, uint32_t* theirSerial, uint32_t* theirInception, uint32_t* theirExpire, uint16_t* id); + + //! convenience function that calls resolve above + void getSoaSerial(const string &, const DNSName &, uint32_t *); + +private: + std::map locals; +}; + +class AXFRRetriever : public boost::noncopyable +{ + public: + AXFRRetriever(const ComboAddress& remote, + const DNSName& zone, + const TSIGTriplet& tt = TSIGTriplet(), + const ComboAddress* laddr = NULL, + size_t maxReceivedBytes=0, + uint16_t timeout=10); + ~AXFRRetriever(); + int getChunk(Resolver::res_t &res, vector* records=0, uint16_t timeout=10); + + private: + void connect(uint16_t timeout); + int getLength(uint16_t timeout); + void timeoutReadn(uint16_t bytes, uint16_t timeoutsec=10); + + shared_array d_buf; + string d_domain; + int d_sock; + int d_soacount; + ComboAddress d_remote; + TSIGTCPVerifier d_tsigVerifier; + + size_t d_receivedBytes; + size_t d_maxReceivedBytes; + TSIGRecordContent d_trc; +}; + + +#endif /* PDNS_RESOLVER_HH */ diff --git a/responsestats.cc b/responsestats.cc new file mode 100644 index 0000000..c98db9a --- /dev/null +++ b/responsestats.cc @@ -0,0 +1,75 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "responsestats.hh" +#include +#include "namespaces.hh" +#include "logger.hh" + +#include "dnsparser.hh" + +ResponseStats::ResponseStats() : d_qtypecounters(new std::atomic[65536]) +{ + d_sizecounters.push_back(make_pair(20,0)); + d_sizecounters.push_back(make_pair(40,0)); + d_sizecounters.push_back(make_pair(60,0)); + d_sizecounters.push_back(make_pair(80,0)); + d_sizecounters.push_back(make_pair(100,0)); + d_sizecounters.push_back(make_pair(150,0)); + for(int n=200; n < 65000 ; n+=200) + d_sizecounters.push_back(make_pair(n,0)); + d_sizecounters.push_back(make_pair(std::numeric_limits::max(),0)); +} + +ResponseStats g_rs; + +static bool pcomp(const pair&a , const pair&b) +{ + return a.first < b.first; +} + +void ResponseStats::submitResponse(uint16_t qtype, uint16_t respsize, bool udpOrTCP) +{ + d_qtypecounters[qtype]++; + pair s(respsize, 0); + sizecounters_t::iterator iter = std::upper_bound(d_sizecounters.begin(), d_sizecounters.end(), s, pcomp); + if(iter!= d_sizecounters.begin()) + --iter; + iter->second++; +} + +map ResponseStats::getQTypeResponseCounts() +{ + map ret; + uint64_t count; + for(unsigned int i = 0 ; i < 65535 ; ++i) { + count= d_qtypecounters[i]; + if(count) + ret[i]=count; + } + return ret; +} + +map ResponseStats::getSizeResponseCounts() +{ + map ret; + for(sizecounters_t::const_iterator iter = d_sizecounters.begin(); + iter != d_sizecounters.end(); + ++iter) { + ret[iter->first]=iter->second; + } + return ret; +} + +string ResponseStats::getQTypeReport() +{ + typedef map qtypenums_t; + qtypenums_t qtypenums = getQTypeResponseCounts(); + ostringstream os; + boost::format fmt("%s\t%d\n"); + for(const qtypenums_t::value_type& val : qtypenums) { + os << (fmt %DNSRecordContent::NumberToType( val.first) % val.second).str(); + } + return os.str(); +} + diff --git a/responsestats.hh b/responsestats.hh new file mode 100644 index 0000000..c82cf05 --- /dev/null +++ b/responsestats.hh @@ -0,0 +1,43 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include "misc.hh" +#include "dnspacket.hh" + +class ResponseStats +{ +public: + ResponseStats(); + + void submitResponse(DNSPacket &p, bool udpOrTCP); + void submitResponse(uint16_t qtype, uint16_t respsize, bool udpOrTCP); + map getQTypeResponseCounts(); + map getSizeResponseCounts(); + string getQTypeReport(); + +private: + boost::scoped_array> d_qtypecounters; + typedef vector > sizecounters_t; + sizecounters_t d_sizecounters; +}; + +extern ResponseStats g_rs; diff --git a/root-addresses.hh b/root-addresses.hh new file mode 100644 index 0000000..a0167b2 --- /dev/null +++ b/root-addresses.hh @@ -0,0 +1,54 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once + +static const char* const rootIps4[]={"198.41.0.4", // a.root-servers.net. + "199.9.14.201", // b.root-servers.net. + "192.33.4.12", // c.root-servers.net. + "199.7.91.13", // d.root-servers.net. + "192.203.230.10", // e.root-servers.net. + "192.5.5.241", // f.root-servers.net. + "192.112.36.4", // g.root-servers.net. + "198.97.190.53", // h.root-servers.net. + "192.36.148.17", // i.root-servers.net. + "192.58.128.30", // j.root-servers.net. + "193.0.14.129", // k.root-servers.net. + "199.7.83.42", // l.root-servers.net. + "202.12.27.33" // m.root-servers.net. + }; +static size_t const rootIps4Count = sizeof(rootIps4) / sizeof(*rootIps4); + +static const char* const rootIps6[]={"2001:503:ba3e::2:30", // a.root-servers.net. + "2001:500:200::b", // b.root-servers.net. + "2001:500:2::c", // c.root-servers.net. + "2001:500:2d::d", // d.root-servers.net. + "2001:500:a8::e", // e.root-servers.net. + "2001:500:2f::f", // f.root-servers.net. + "2001:500:12::d0d", // g.root-servers.net. + "2001:500:1::53", // h.root-servers.net. + "2001:7fe::53", // i.root-servers.net. + "2001:503:c27::2:30", // j.root-servers.net. + "2001:7fd::1", // k.root-servers.net. + "2001:500:9f::42", // l.root-servers.net. + "2001:dc3::35" // m.root-servers.net. + }; +static size_t const rootIps6Count = sizeof(rootIps6) / sizeof(*rootIps6); diff --git a/root-dnssec.hh b/root-dnssec.hh new file mode 100644 index 0000000..415c745 --- /dev/null +++ b/root-dnssec.hh @@ -0,0 +1,26 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ + +#pragma once + +static const char* const rootDSs[]={"19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5", + "20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d"}; diff --git a/rpzloader.cc b/rpzloader.cc new file mode 100644 index 0000000..815fb84 --- /dev/null +++ b/rpzloader.cc @@ -0,0 +1,419 @@ +#include "syncres.hh" +#include "dnsparser.hh" +#include "dnsrecords.hh" +#include "ixfr.hh" +#include "resolver.hh" +#include "logger.hh" +#include "rec-lua-conf.hh" +#include "rpzloader.hh" +#include "zoneparser-tng.hh" + +static Netmask makeNetmaskFromRPZ(const DNSName& name) +{ + auto parts = name.getRawLabels(); + /* + * why 2?, the minimally valid IPv6 address that can be encoded in an RPZ is + * $NETMASK.zz (::/$NETMASK) + * Terrible right? + */ + if(parts.size() < 2 || parts.size() > 9) + throw PDNSException("Invalid IP address in RPZ: "+name.toString()); + + bool isV6 = (stoi(parts[0]) > 32); + bool hadZZ = false; + + for (auto &part : parts) { + // Check if we have an IPv4 octet + for (auto c : part) + if (!isdigit(c)) + isV6 = true; + + if (pdns_iequals(part,"zz")) { + if (hadZZ) + throw PDNSException("more than one 'zz' label found in RPZ name"+name.toString()); + part = ""; + isV6 = true; + hadZZ = true; + } + } + + if (isV6 && parts.size() < 9 && !hadZZ) + throw PDNSException("No 'zz' label found in an IPv6 RPZ name shorter than 9 elements: "+name.toString()); + + if (parts.size() == 5 && !isV6) + return Netmask(parts[4]+"."+parts[3]+"."+parts[2]+"."+parts[1]+"/"+parts[0]); + + string v6; + + for (uint8_t i = parts.size()-1 ; i > 0; i--) { + v6 += parts[i]; + if (parts[i] == "" && i == 1 && i == parts.size()-1) + v6+= "::"; + if (parts[i] == "" && i != parts.size()-1) + v6+= ":"; + if (parts[i] != "" && i != 1) + v6 += ":"; + } + v6 += "/" + parts[0]; + + return Netmask(v6); +} + +void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr zone, bool addOrRemove, boost::optional defpol, uint32_t maxTTL) +{ + static const DNSName drop("rpz-drop."), truncate("rpz-tcp-only."), noaction("rpz-passthru."); + static const DNSName rpzClientIP("rpz-client-ip"), rpzIP("rpz-ip"), + rpzNSDname("rpz-nsdname"), rpzNSIP("rpz-nsip."); + static const std::string rpzPrefix("rpz-"); + + DNSFilterEngine::Policy pol; + + if(dr.d_class != QClass::IN) { + return; + } + + if(dr.d_type == QType::CNAME) { + auto crc = getRR(dr); + if (!crc) { + return; + } + auto crcTarget=crc->getTarget(); + if(defpol) { + pol=*defpol; + } + else if(crcTarget.isRoot()) { + // cerr<<"Wants NXDOMAIN for "<getZoneRepresentation()<<" for "<d_ttl < 0) { + pol.d_ttl = static_cast(std::min(maxTTL, dr.d_ttl)); + } else { + pol.d_ttl = static_cast(std::min(maxTTL, static_cast(pol.d_ttl))); + } + + // now to DO something with that + + if(dr.d_name.isPartOf(rpzNSDname)) { + DNSName filt=dr.d_name.makeRelative(rpzNSDname); + if(addOrRemove) + zone->addNSTrigger(filt, pol); + else + zone->rmNSTrigger(filt, pol); + } else if(dr.d_name.isPartOf(rpzClientIP)) { + DNSName filt=dr.d_name.makeRelative(rpzClientIP); + auto nm=makeNetmaskFromRPZ(filt); + if(addOrRemove) + zone->addClientTrigger(nm, pol); + else + zone->rmClientTrigger(nm, pol); + + } else if(dr.d_name.isPartOf(rpzIP)) { + // cerr<<"Should apply answer content IP policy: "<addResponseTrigger(nm, pol); + else + zone->rmResponseTrigger(nm, pol); + } else if(dr.d_name.isPartOf(rpzNSIP)) { + DNSName filt=dr.d_name.makeRelative(rpzNSIP); + auto nm=makeNetmaskFromRPZ(filt); + if(addOrRemove) + zone->addNSIPTrigger(nm, pol); + else + zone->rmNSIPTrigger(nm, pol); + } else { + if(addOrRemove) + zone->addQNameTrigger(dr.d_name, pol); + else + zone->rmQNameTrigger(dr.d_name, pol); + } +} + +shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr zone, boost::optional defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, uint16_t axfrTimeout) +{ + L< chunk; + time_t last=0; + time_t axfrStart = time(nullptr); + time_t axfrNow = time(nullptr); + shared_ptr sr; + while(axfr.getChunk(nop, &chunk, (axfrStart + axfrTimeout - axfrNow))) { + for(auto& dr : chunk) { + if(dr.d_type==QType::NS || dr.d_type==QType::TSIG) { + continue; + } + + dr.d_name.makeUsRelative(zoneName); + if(dr.d_type==QType::SOA) { + sr = getRR(dr); + continue; + } + + RPZRecordToPolicy(dr, zone, true, defpol, maxTTL); + nrecords++; + } + axfrNow = time(nullptr); + if (axfrNow < axfrStart || axfrNow - axfrStart > axfrTimeout) { + throw PDNSException("Total AXFR time exceeded!"); + } + if(last != time(0)) { + L<getZoneRepresentation()< zone, boost::optional defpol, uint32_t maxTTL) +{ + ZoneParserTNG zpt(fname); + DNSResourceRecord drr; + DNSName domain; + while(zpt.get(drr)) { + try { + if(drr.qtype.getCode() == QType::CNAME && drr.content.empty()) + drr.content="."; + DNSRecord dr(drr); + if(dr.d_type == QType::SOA) { + domain = dr.d_name; + zone->setDomain(domain); + } + else if(dr.d_type == QType::NS) { + continue; + } + else { + dr.d_name=dr.d_name.makeRelative(domain); + RPZRecordToPolicy(dr, zone, true, defpol, maxTTL); + } + } + catch(const PDNSException& pe) { + throw PDNSException("Issue parsing '"+drr.qname.toString()+"' '"+drr.content+"' at "+zpt.getLineOfFile()+": "+pe.reason); + } + } +} + +static std::unordered_map > s_rpzStats; +static std::mutex s_rpzStatsMutex; + +shared_ptr getRPZZoneStats(const std::string& zone) +{ + std::lock_guard l(s_rpzStatsMutex); + if (s_rpzStats.find(zone) == s_rpzStats.end()) { + s_rpzStats[zone] = std::make_shared(); + } + return s_rpzStats[zone]; +} + +static void incRPZFailedTransfers(const std::string& zone) +{ + auto stats = getRPZZoneStats(zone); + if (stats != nullptr) + stats->d_failedTransfers++; +} + +static void setRPZZoneNewState(const std::string& zone, uint32_t serial, uint64_t numberOfRecords, bool wasAXFR) +{ + auto stats = getRPZZoneStats(zone); + if (stats == nullptr) + return; + stats->d_successfulTransfers++; + if (wasAXFR) { + stats->d_fullTransfers++; + } + stats->d_lastUpdate = time(nullptr); + stats->d_serial = serial; + stats->d_numberOfRecords = numberOfRecords; +} + +void RPZIXFRTracker(const ComboAddress& master, boost::optional defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout) +{ + auto luaconfsLocal = g_luaconfs.getLocal(); + /* we can _never_ modify this zone directly, we need to do a full copy then replace the existing zone */ + std::shared_ptr oldZone = luaconfsLocal->dfe.getZone(zoneIdx); + if (!oldZone) { + L<getRefresh(); + DNSName zoneName = oldZone->getDomain(); + std::string polName = oldZone->getName() ? *(oldZone->getName()) : zoneName.toString(); + shared_ptr sr; + + while (!sr) { + /* full copy, as promised */ + std::shared_ptr newZone = std::make_shared(*oldZone); + + try { + sr=loadRPZFromServer(master, zoneName, newZone, defpol, maxTTL, tt, maxReceivedBytes, localAddress, axfrTimeout); + if(refresh == 0) { + refresh = sr->d_st.refresh; + } + newZone->setSerial(sr->d_st.serial); + setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), true); + + g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) { + lci.dfe.setZone(zoneIdx, newZone); + }); + } + catch(const std::exception& e) { + theL()< 0 ? refresh : 10)<<" seconds...)"< 0 ? refresh : 10)<<" seconds...)"<(dr)->d_st.serial<, vector > > deltas; + + ComboAddress local(localAddress); + if (local == ComboAddress()) + local = getQueryLocalAddress(master.sin4.sin_family, 0); + + try { + deltas = getIXFRDeltas(master, zoneName, dr, tt, &local, maxReceivedBytes); + } catch(std::runtime_error& e ){ + L<dfe.getZone(zoneIdx); + /* we need to make a _full copy_ of the zone we are going to work on */ + std::shared_ptr newZone = std::make_shared(*oldZone); + + int totremove=0, totadd=0; + bool fullUpdate = false; + for(const auto& delta : deltas) { + const auto& remove = delta.first; + const auto& add = delta.second; + if(remove.empty()) { + L<clear(); + fullUpdate = true; + } + for(const auto& rr : remove) { // should always contain the SOA + if(rr.d_type == QType::NS) + continue; + if(rr.d_type == QType::SOA) { + auto oldsr = getRR(rr); + if(oldsr && oldsr->d_st.serial == sr->d_st.serial) { + // cout<<"Got good removal of SOA serial "<d_st.serial<(rr); + // L<d_st.serial<d_st.serial<setSerial(sr->d_st.serial); + setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), fullUpdate); + + /* we need to replace the existing zone with the new one, + but we don't want to touch anything else, especially other zones, + since they might have been updated by another RPZ IXFR tracker thread. + */ + g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) { + lci.dfe.setZone(zoneIdx, newZone); + }); + } +} diff --git a/rpzloader.hh b/rpzloader.hh new file mode 100644 index 0000000..efd8e08 --- /dev/null +++ b/rpzloader.hh @@ -0,0 +1,45 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#pragma once +#include "filterpo.hh" +#include +#include "dnsrecords.hh" + +extern bool g_logRPZChanges; + +void loadRPZFromFile(const std::string& fname, std::shared_ptr zone, boost::optional defpol, uint32_t maxTTL); +std::shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr zone, boost::optional defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout); +void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr zone, bool addOrRemove, boost::optional defpol, uint32_t maxTTL); + +void RPZIXFRTracker(const ComboAddress& master, boost::optional defpol, uint32_t maxTTL, size_t polZone, const TSIGTriplet &tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout); + +struct rpzStats +{ + std::atomic d_failedTransfers; + std::atomic d_successfulTransfers; + std::atomic d_fullTransfers; + std::atomic d_numberOfRecords; + std::atomic d_lastUpdate; + std::atomic d_serial; +}; + +shared_ptr getRPZZoneStats(const std::string& zone); diff --git a/rrd/create b/rrd/create new file mode 100755 index 0000000..3835213 --- /dev/null +++ b/rrd/create @@ -0,0 +1,47 @@ +#!/bin/sh + +UPDATE_INTERVAL=60 + +rrdtool create pdns_recursor.rrd -s $UPDATE_INTERVAL \ +DS:questions:COUNTER:600:0:100000 \ +DS:tcp-questions:COUNTER:600:0:100000 \ +DS:cache-entries:GAUGE:600:0:U \ +DS:packetcache-entries:GAUGE:600:0:U \ +DS:throttle-entries:GAUGE:600:0:U \ +DS:concurrent-queries:GAUGE:600:0:50000 \ +DS:noerror-answers:COUNTER:600:0:100000 \ +DS:nxdomain-answers:COUNTER:600:0:100000 \ +DS:servfail-answers:COUNTER:600:0:100000 \ +DS:tcp-outqueries:COUNTER:600:0:100000 \ +DS:outgoing-timeouts:COUNTER:600:0:100000 \ +DS:throttled-out:COUNTER:600:0:100000 \ +DS:nsspeeds-entries:GAUGE:600:0:U \ +DS:negcache-entries:GAUGE:600:0:U \ +DS:all-outqueries:COUNTER:600:0:100000 \ +DS:cache-hits:COUNTER:600:0:100000 \ +DS:cache-misses:COUNTER:600:0:100000 \ +DS:packetcache-hits:COUNTER:600:0:100000 \ +DS:packetcache-misses:COUNTER:600:0:100000 \ +DS:answers0-1:COUNTER:600:0:100000 \ +DS:answers1-10:COUNTER:600:0:100000 \ +DS:answers10-100:COUNTER:600:0:100000 \ +DS:answers100-1000:COUNTER:600:0:100000 \ +DS:answers-slow:COUNTER:600:0:100000 \ +DS:udp-overruns:COUNTER:600:0:100000 \ +DS:qa-latency:GAUGE:600:0:10000000 \ +DS:user-msec:COUNTER:600:0:64000 \ +DS:uptime:GAUGE:600:0:U \ +DS:unexpected-packets:COUNTER:600:0:1000000 \ +DS:resource-limits:COUNTER:600:0:1000000 \ +DS:over-capacity-drops:COUNTER:600:0:1000000 \ +DS:client-parse-errors:COUNTER:600:0:1000000 \ +DS:server-parse-errors:COUNTER:600:0:1000000 \ +DS:unauthorized-udp:COUNTER:600:0:1000000 \ +DS:unauthorized-tcp:COUNTER:600:0:1000000 \ +DS:sys-msec:COUNTER:600:0:6400 \ + RRA:AVERAGE:0.5:1:9600 \ + RRA:AVERAGE:0.5:4:9600 \ + RRA:AVERAGE:0.5:24:6000 \ + RRA:MAX:0.5:1:9600 \ + RRA:MAX:0.5:4:9600 \ + RRA:MAX:0.5:24:6000 diff --git a/rrd/index.html b/rrd/index.html new file mode 100644 index 0000000..0dea1ed --- /dev/null +++ b/rrd/index.html @@ -0,0 +1,59 @@ + + + +

PowerDNS Recursor Performance Graphs

+
+ + + + + + + + + +
QuestionsEnd-user initiated DNS questions
Out-queriesRecursor initiated questions to other +nameservers
ThrottledIf a certain nameserver is not responding, or if +it is, but returning unuseful answers, it is not useful to keep repeating +identical queries. If PowerDNS prevents a duplicate query, and therefore +prevents needless server load and delays, this is called a 'throttled +out-query'
Outgoing timeoutAn out-query that did not generate an +answer within 1 or 2 seconds
Noerror answerA Question that was answered without an error +status
NXDOMAIN answerA Question that was answered with a positive +indication that there is no answer
SERVFAIL answerNo answer could be given because the nameservers +carrying the answer did not respond, or were throttled
Cache hits/missesA query is judged a cache-hit if it could +be answered without generating any out-queries
User/System CPU usageActual amount of CPU used exclusively +by the recursor, either in user or in system (kernel) mode
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + diff --git a/rrd/makegraphs b/rrd/makegraphs new file mode 100755 index 0000000..a0f6699 --- /dev/null +++ b/rrd/makegraphs @@ -0,0 +1,187 @@ +#!/usr/bin/env bash +WWWPREFIX=. +WSIZE=800 +HSIZE=250 + +# only recent rrds offer slope-mode: +GRAPHOPTS=--slope-mode + +function makeGraphs() +{ + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/questions-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Questions and answers per second" \ + -v "packets" \ + DEF:questions=pdns_recursor.rrd:questions:AVERAGE \ + DEF:nxdomainanswers=pdns_recursor.rrd:nxdomain-answers:AVERAGE \ + DEF:noerroranswers=pdns_recursor.rrd:noerror-answers:AVERAGE \ + DEF:servfailanswers=pdns_recursor.rrd:servfail-answers:AVERAGE \ + LINE1:questions#0000ff:"questions/s"\ + AREA:noerroranswers#00ff00:"noerror answers/s" \ + STACK:nxdomainanswers#ffa500:"nxdomain answers/s"\ + STACK:servfailanswers#ff0000:"servfail answers/s" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/tcp-questions-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "TCP questions and answers per second, unauthorized packets/s" \ + -v "packets" \ + DEF:tcpquestions=pdns_recursor.rrd:tcp-questions:AVERAGE \ + DEF:unauthudp=pdns_recursor.rrd:unauthorized-udp:AVERAGE \ + DEF:unauthtcp=pdns_recursor.rrd:unauthorized-tcp:AVERAGE \ + LINE1:tcpquestions#0000ff:"tcp questions/s" \ + LINE1:unauthudp#ff0000:"udp unauth/s" \ + LINE1:unauthtcp#00ff00:"tcp unauth/s" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/packet-errors-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Packet errors per second" \ + -v "packets" \ + DEF:clientparseerrors=pdns_recursor.rrd:client-parse-errors:AVERAGE \ + DEF:serverparseerrors=pdns_recursor.rrd:server-parse-errors:AVERAGE \ + DEF:unexpected=pdns_recursor.rrd:unexpected-packets:AVERAGE \ + DEF:udpoverruns=pdns_recursor.rrd:udp-overruns:AVERAGE \ + LINE1:clientparseerrors#0000ff:"bad packets from clients" \ + LINE1:serverparseerrors#00ff00:"bad packets from servers" \ + LINE1:unexpected#ff0000:"unexpected packets from servers" \ + LINE1:udpoverruns#ff00ff:"udp overruns from remotes" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/limits-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Limitations per second" \ + -v "events" \ + DEF:resourcelimits=pdns_recursor.rrd:resource-limits:AVERAGE \ + DEF:overcapacities=pdns_recursor.rrd:over-capacity-drops:AVERAGE \ + LINE1:resourcelimits#ff0000:"outqueries dropped because of resource limits" \ + LINE1:overcapacities#0000ff:"questions dropped because of mthread limit" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/latencies-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Questions answered within latency" \ + -v "questions" \ + DEF:questions=pdns_recursor.rrd:questions:AVERAGE \ + DEF:answers00=pdns_recursor.rrd:packetcache-hits:AVERAGE \ + DEF:answers01=pdns_recursor.rrd:answers0-1:AVERAGE \ + DEF:answers110=pdns_recursor.rrd:answers1-10:AVERAGE \ + DEF:answers10100=pdns_recursor.rrd:answers10-100:AVERAGE \ + DEF:answers1001000=pdns_recursor.rrd:answers100-1000:AVERAGE \ + DEF:answersslow=pdns_recursor.rrd:answers-slow:AVERAGE \ + LINE1:questions#0000ff:"questions/s" \ + AREA:answers00#00ff00:"<<1 ms" \ + STACK:answers01#00fff0:"<1 ms" \ + STACK:answers110#0000ff:"<10 ms" \ + STACK:answers10100#ff9900:"<100 ms" \ + STACK:answers1001000#ffff00:"<1000 ms" \ + STACK:answersslow#ff0000:">1000 ms" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/qoutq-$2.png -w $WSIZE -h $HSIZE -l 0 \ + -t "Questions/outqueries per second" \ + -v "packets" \ + DEF:questions=pdns_recursor.rrd:questions:AVERAGE \ + DEF:alloutqueries=pdns_recursor.rrd:all-outqueries:AVERAGE \ + LINE1:questions#ff0000:"questions/s"\ + LINE1:alloutqueries#00ff00:"outqueries/s" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/qa-latency-$2.png -w $WSIZE -h $HSIZE -l 0 \ + -t "Questions/answer latency in milliseconds" \ + -v "msec" \ + DEF:qalatency=pdns_recursor.rrd:qa-latency:AVERAGE \ + CDEF:mqalatency=qalatency,1000,/ \ + LINE1:mqalatency#ff0000:"questions/s" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/timeouts-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Outqueries/timeouts per second" \ + -v "events" \ + DEF:alloutqueries=pdns_recursor.rrd:all-outqueries:AVERAGE \ + DEF:outgoingtimeouts=pdns_recursor.rrd:outgoing-timeouts:AVERAGE \ + DEF:throttledout=pdns_recursor.rrd:throttled-out:AVERAGE \ + LINE1:alloutqueries#ff0000:"outqueries/s"\ + LINE1:outgoingtimeouts#00ff00:"outgoing timeouts/s"\ + LINE1:throttledout#0000ff:"throttled outqueries/s" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/caches-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Cache sizes" \ + -v "entries" \ + DEF:cacheentries=pdns_recursor.rrd:cache-entries:AVERAGE \ + DEF:packetcacheentries=pdns_recursor.rrd:packetcache-entries:AVERAGE \ + DEF:negcacheentries=pdns_recursor.rrd:negcache-entries:AVERAGE \ + DEF:nsspeedsentries=pdns_recursor.rrd:nsspeeds-entries:AVERAGE \ + DEF:throttleentries=pdns_recursor.rrd:throttle-entries:AVERAGE \ + LINE1:cacheentries#ff0000:"cache entries" \ + LINE1:packetcacheentries#ffff00:"packet cache entries" \ + LINE1:negcacheentries#0000ff:"negative cache entries" \ + LINE1:nsspeedsentries#00ff00:"NS speeds entries" \ + LINE1:throttleentries#00fff0:"throttle map entries" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/caches2-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Cache sizes" \ + -v "entries" \ + DEF:negcacheentries=pdns_recursor.rrd:negcache-entries:AVERAGE \ + DEF:nsspeedsentries=pdns_recursor.rrd:nsspeeds-entries:AVERAGE \ + DEF:throttleentries=pdns_recursor.rrd:throttle-entries:AVERAGE \ + LINE1:negcacheentries#0000ff:"negative cache entries" \ + LINE1:nsspeedsentries#00ff00:"NS speeds entries" \ + LINE1:throttleentries#ffa000:"throttle map entries" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/load-$2.png -w $WSIZE -h $HSIZE -l 0\ + -v "MThreads" \ + -t "Concurrent queries" \ + DEF:concurrentqueries=pdns_recursor.rrd:concurrent-queries:AVERAGE \ + LINE1:concurrentqueries#0000ff:"concurrent queries" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/hitrate-$2.png -w $WSIZE -h $HSIZE -l 0\ + -v "percentage" \ + -t "cache hits" \ + DEF:cachehits=pdns_recursor.rrd:cache-hits:AVERAGE \ + DEF:cachemisses=pdns_recursor.rrd:cache-misses:AVERAGE \ + DEF:packetcachehits=pdns_recursor.rrd:packetcache-hits:AVERAGE \ + DEF:packetcachemisses=pdns_recursor.rrd:packetcache-misses:AVERAGE \ + CDEF:perc=cachehits,100,*,cachehits,cachemisses,+,/ \ + CDEF:packetperc=packetcachehits,100,*,packetcachehits,packetcachemisses,+,/ \ + LINE1:perc#0000ff:"percentage cache hits" \ + LINE1:packetperc#ff00ff:"percentage packetcache hits" \ + COMMENT:"\l" \ + COMMENT:"Cache hits " \ + GPRINT:perc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:perc:LAST:"last %-3.1lf%%\t" \ + GPRINT:perc:MAX:"max %-3.1lf%%" \ + COMMENT:"\l" \ + COMMENT:"Pkt hits " \ + GPRINT:packetperc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:packetperc:LAST:"last %-3.1lf%%\t" \ + GPRINT:packetperc:MAX:"max %-3.1lf%%" \ + COMMENT:"\l" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/cpuload-$2.png -w $WSIZE -h $HSIZE -l 0\ + -v "percentage" \ + -t "cpu load" \ + DEF:usermsec=pdns_recursor.rrd:user-msec:AVERAGE \ + DEF:sysmsec=pdns_recursor.rrd:sys-msec:AVERAGE \ + DEF:musermsec=pdns_recursor.rrd:user-msec:MAX \ + DEF:msysmsec=pdns_recursor.rrd:sys-msec:MAX \ + CDEF:userperc=usermsec,10,/ \ + CDEF:sysperc=sysmsec,10,/ \ + CDEF:totmperc=usermsec,sysmsec,+,10,/ \ + LINE1:totmperc#ffff00:"max cpu use" \ + AREA:userperc#ff0000:"user cpu percentage" \ + STACK:sysperc#00ff00:"system cpu percentage" \ + COMMENT:"\l" \ + COMMENT:"System cpu " \ + GPRINT:sysperc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:sysperc:LAST:"last %-3.1lf%%\t" \ + GPRINT:sysperc:MAX:"max %-3.1lf%%\t" \ + COMMENT:"\l" \ + COMMENT:"User cpu " \ + GPRINT:userperc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:userperc:LAST:"last %-3.1lf%%\t" \ + GPRINT:userperc:MAX:"max %-3.1lf%%" \ + COMMENT:"\l" + + +} + +makeGraphs 6h 6h +makeGraphs 24h day +#makeGraphs 7d week +#makeGraphs 1m month +#makeGraphs 1y year + + diff --git a/rrd/update b/rrd/update new file mode 100755 index 0000000..988d869 --- /dev/null +++ b/rrd/update @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +SOCKETDIR=/var/run/ +TSTAMP=$(date +%s) + +OS=`uname` +if [ "$OS" == "Linux" ] +then +# echo "Using Linux netstat directive" + NETSTAT_GREP="packet receive error" +elif [ "$OS" == "FreeBSD" ] +then +# echo "Using FreeBSD netstat directive" + NETSTAT_GREP="dropped due to full socket buffers" +else + echo "Unsupported OS found, please report to the PowerDNS team." + exit 1 +fi + + +VARIABLES="questions \ + tcp-questions \ + cache-entries \ + packetcache-entries \ + concurrent-queries \ + nxdomain-answers \ + noerror-answers \ + servfail-answers \ + tcp-outqueries \ + outgoing-timeouts \ + nsspeeds-entries \ + negcache-entries \ + all-outqueries \ + throttled-out \ + packetcache-hits \ + packetcache-misses \ + cache-hits \ + cache-misses \ + answers0-1 \ + answers1-10 \ + answers10-100 \ + answers100-1000 \ + answers-slow \ + qa-latency \ + throttle-entries \ + sys-msec user-msec \ + unauthorized-udp \ + unauthorized-tcp \ + client-parse-errors \ + server-parse-errors \ + uptime unexpected-packets \ + resource-limits \ + over-capacity-drops" + +UVARIABLES=$(echo $VARIABLES | tr '[a-z]' '[A-Z]' | tr - _ ) + +rec_control --socket-dir=$SOCKETDIR GET $VARIABLES | +( + for a in $UVARIABLES + do + read $a + done + rrdtool update pdns_recursor.rrd \ + -t "udp-overruns:"$(for a in $VARIABLES + do + echo -n $a: + done | sed 's/:$//' ) \ +$TSTAMP$( + echo -n : + netstat -s | grep "$NETSTAT_GREP" | awk '{printf $1}' + for a in $UVARIABLES + do + echo -n :${!a} + done + ) +) diff --git a/secpoll-recursor.cc b/secpoll-recursor.cc new file mode 100644 index 0000000..3248b84 --- /dev/null +++ b/secpoll-recursor.cc @@ -0,0 +1,96 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "secpoll-recursor.hh" +#include "syncres.hh" +#include "logger.hh" +#include "arguments.hh" +#include "version.hh" +#include "validate-recursor.hh" + +#include +#ifndef PACKAGEVERSION +#define PACKAGEVERSION getPDNSVersion() +#endif + +uint32_t g_security_status; +string g_security_message; + +void doSecPoll(time_t* last_secpoll) +{ + if(::arg()["security-poll-suffix"].empty()) + return; + + string pkgv(PACKAGEVERSION); + struct timeval now; + gettimeofday(&now, 0); + + /* update last_secpoll right now, even if it fails + we don't want to retry right away and hammer the server */ + *last_secpoll=now.tv_sec; + + SyncRes sr(now); + if (g_dnssecmode != DNSSECMode::Off) { + sr.setDoDNSSEC(true); + sr.setDNSSECValidationRequested(true); + } + + vector ret; + + string version = "recursor-" +pkgv; + string qstring(version.substr(0, 63)+ ".security-status."+::arg()["security-poll-suffix"]); + + if(*qstring.rbegin()!='.') + qstring+='.'; + + boost::replace_all(qstring, "+", "_"); + boost::replace_all(qstring, "~", "_"); + + vState state = Indeterminate; + DNSName query(qstring); + int res=sr.beginResolve(query, QType(QType::TXT), 1, ret); + + if (g_dnssecmode != DNSSECMode::Off && res) { + state = sr.getValidationState(); + } + + if(state == Bogus) { + L<getZoneRepresentation(); + } + + if(!content.empty() && content[0]=='"' && content[content.size()-1]=='"') { + content=content.substr(1, content.length()-2); + } + + pair split = splitField(content, ' '); + + g_security_status = std::stoi(split.first); + g_security_message = split.second; + } + else { + if(pkgv.find("0.0.") != 0) + L< +#include "namespaces.hh" +#include + +void doSecPoll(time_t* ); +extern uint32_t g_security_status; +extern std::string g_security_message; + +#endif diff --git a/selectmplexer.cc b/selectmplexer.cc new file mode 100644 index 0000000..9e3d6f7 --- /dev/null +++ b/selectmplexer.cc @@ -0,0 +1,131 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include "misc.hh" + +#include "namespaces.hh" + +static FDMultiplexer* make() +{ + return new SelectFDMultiplexer(); +} + +static struct RegisterOurselves +{ + RegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(1, &make)); + } +} doIt; + +void SelectFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter) +{ + Callback cb; + cb.d_callback=toDo; + cb.d_parameter=parameter; + memset(&cb.d_ttd, 0, sizeof(cb.d_ttd)); + if(cbmap.count(fd)) + throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice"); + cbmap[fd]=cb; +} + +void SelectFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(d_inrun && d_iter->first==fd) // trying to remove us! + d_iter++; + + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); +} + +int SelectFDMultiplexer::run(struct timeval* now, int timeout) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + fd_set readfds, writefds; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + + int fdmax=0; + + for(callbackmap_t::const_iterator i=d_readCallbacks.begin(); i != d_readCallbacks.end(); ++i) { + FD_SET(i->first, &readfds); + fdmax=max(i->first, fdmax); + } + + for(callbackmap_t::const_iterator i=d_writeCallbacks.begin(); i != d_writeCallbacks.end(); ++i) { + FD_SET(i->first, &writefds); + fdmax=max(i->first, fdmax); + } + + struct timeval tv={timeout / 1000 , (timeout % 1000) * 1000}; + int ret=select(fdmax + 1, &readfds, &writefds, 0, &tv); + gettimeofday(now, 0); // MANDATORY! + + if(ret < 0 && errno!=EINTR) + throw FDMultiplexerException("select returned error: "+stringerror()); + + if(ret < 1) // nothing - thanks AB + return 0; + + d_iter=d_readCallbacks.end(); + d_inrun=true; + + int got = 0; + for(callbackmap_t::iterator i=d_readCallbacks.begin(); i != d_readCallbacks.end() && i->first <= fdmax; ) { + d_iter=i++; + + if(FD_ISSET(d_iter->first, &readfds)) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + got++; + continue; // so we don't refind ourselves as writable + } + } + + for(callbackmap_t::iterator i=d_writeCallbacks.begin(); i != d_writeCallbacks.end() && i->first <= fdmax; ) { + d_iter=i++; + if(FD_ISSET(d_iter->first, &writefds)) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + got++; + } + } + + d_inrun=false; + return got; +} + +#if 0 + +void acceptData(int fd, boost::any& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< +#include +#include +/** This is sort of a light-weight RCU idea. + Suitable for when you frequently consult some "readonly" state, which infrequently + gets changed. One way of dealing with this is fully locking access to the state, but + this is rather wasteful. + + Instead, in the code below, the frequent users of the state get a "readonly" copy of it, + which they can consult. On access, we atomically compare if the local copy is still current + with the global one. If it isn't we do the lock thing, and create a new local copy. + + Meanwhile, to upgrade the global state, methods are offered that do appropriate locking + and upgrade the 'generation' counter, signaling to the local copies that they need to be + refreshed on the next access. + + Two ways to change the global copy are available: + getCopy(), which delivers a deep copy of the current state, followed by setState() + modify(), which accepts a (lambda)function that modifies the state + + NOTE: The actual destruction of the 'old' state happens when the last local state + relinquishes its access to the state. + + "read-only" + Sometimes, a 'state' can contain parts that can safely be modified by multiple users, for + example, atomic counters. In such cases, it may be useful to explicitly declare such counters + as mutable. */ + +template class GlobalStateHolder; + +template +class LocalStateHolder +{ +public: + explicit LocalStateHolder(GlobalStateHolder* source) : d_source(source) + {} + + const T* operator->() // fast const-only access, but see "read-only" above + { + if(d_source->getGeneration() != d_generation) { + d_source->getState(&d_state, & d_generation); + } + + return d_state.get(); + } + const T& operator*() // fast const-only access, but see "read-only" above + { + return *operator->(); + } + + void reset() + { + d_generation=0; + d_state.reset(); + } +private: + std::shared_ptr d_state; + unsigned int d_generation{0}; + const GlobalStateHolder* d_source; +}; + +template +class GlobalStateHolder +{ +public: + GlobalStateHolder() : d_state(std::make_shared()) + {} + LocalStateHolder getLocal() + { + return LocalStateHolder(this); + } + + void setState(T state) //!< Safely & slowly change the global state + { + std::shared_ptr newState = std::make_shared(state); + { + std::lock_guard l(d_lock); + d_state = newState; + d_generation++; + } + } + + T getCopy() const //!< Safely & slowly get a copy of the global state + { + std::lock_guard l(d_lock); + return *d_state; + } + + //! Safely & slowly modify the global state + template + void modify(F act) { + std::lock_guard l(d_lock); + auto state=*d_state; // and yes, these three steps are necessary, can't ever modify state in place, even when locked! + act(state); + d_state = std::make_shared(state); + ++d_generation; + } + + + typedef T value_type; +private: + unsigned int getGeneration() const + { + return d_generation; + } + void getState(std::shared_ptr* state, unsigned int* generation) const + { + std::lock_guard l(d_lock); + *state=d_state; + *generation = d_generation; + } + friend class LocalStateHolder; + mutable std::mutex d_lock; + std::shared_ptr d_state; + std::atomic d_generation{1}; +}; diff --git a/sillyrecords.cc b/sillyrecords.cc new file mode 100644 index 0000000..289cdb1 --- /dev/null +++ b/sillyrecords.cc @@ -0,0 +1,333 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "utility.hh" +#include +#include +#include +#include +#include +#include +#include "dnsrecords.hh" + +static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, + 1000000,10000000,100000000,1000000000}; + +/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/ +static uint8_t precsize_aton(const char **strptr) +{ + unsigned int mval = 0, cmval = 0; + uint8_t retval = 0; + const char *cp; + int exponent; + int mantissa; + + cp = *strptr; + + while (isdigit(*cp)) + mval = mval * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* centimeters */ + cp++; + if (isdigit(*cp)) { + cmval = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + cmval += (*cp++ - '0'); + } + } + } + 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; + + *strptr = cp; + + return (retval); +} + +/* converts ascii lat/lon to unsigned encoded 32-bit number. + * moves pointer. */ +static uint32_t +latlon2ul(const char **latlonstrptr, int *which) +{ + const char *cp; + uint32_t retval; + int deg = 0, min = 0, secs = 0, secsfrac = 0; + + cp = *latlonstrptr; + + while (isdigit(*cp)) + deg = deg * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (!(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + min = min * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (*cp && !(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + secs = secs * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal seconds */ + cp++; + if (isdigit(*cp)) { + secsfrac = (*cp++ - '0') * 100; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0') * 10; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0'); + } + } + } + } + + while (*cp && !isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) + cp++; + + fndhemi: + switch (*cp) { + case 'N': case 'n': + case 'E': case 'e': + retval = ((unsigned)1<<31) + + (((((deg * 60) + min) * 60) + secs) * 1000) + + secsfrac; + break; + case 'S': case 's': + case 'W': case 'w': + retval = ((unsigned)1<<31) + - (((((deg * 60) + min) * 60) + secs) * 1000) + - secsfrac; + break; + default: + retval = 0; /* invalid value -- indicates error */ + break; + } + + switch (*cp) { + case 'N': case 'n': + case 'S': case 's': + *which = 1; /* latitude */ + break; + case 'E': case 'e': + case 'W': case 'w': + *which = 2; /* longitude */ + break; + default: + *which = 0; /* error */ + break; + } + + if (!*cp) + return 0; + + cp++; /* skip the hemisphere */ + + while (*cp && !isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) /* move to next field */ + cp++; + + *latlonstrptr = cp; + + return (retval); +} + +void LOCRecordContent::report(void) +{ + regist(1, QType::LOC, &make, &make, "LOC"); + regist(254, QType::LOC, &make, &make, "LOC"); +} + +DNSRecordContent* LOCRecordContent::make(const string& content) +{ + return new LOCRecordContent(content); +} + + +void LOCRecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfr8BitInt(d_version); + pw.xfr8BitInt(d_size); + pw.xfr8BitInt(d_horizpre); + pw.xfr8BitInt(d_vertpre); + + pw.xfr32BitInt(d_latitude); + pw.xfr32BitInt(d_longitude); + pw.xfr32BitInt(d_altitude); +} + +LOCRecordContent::DNSRecordContent* LOCRecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + LOCRecordContent* ret=new LOCRecordContent(); + pr.xfr8BitInt(ret->d_version); + pr.xfr8BitInt(ret->d_size); + pr.xfr8BitInt(ret->d_horizpre); + pr.xfr8BitInt(ret->d_vertpre); + + pr.xfr32BitInt(ret->d_latitude); + pr.xfr32BitInt(ret->d_longitude); + pr.xfr32BitInt(ret->d_altitude); + + return ret; +} + +LOCRecordContent::LOCRecordContent(const string& content, const string& zone) +{ + // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m + // convert this to d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude + d_version = 0; + + const char *cp, *maxcp; + + uint32_t lltemp1 = 0, lltemp2 = 0; + int altmeters = 0, altfrac = 0, altsign = 1; + d_horizpre = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ + d_vertpre = 0x13; /* default = 1e3 cm = 10.00m */ + d_size = 0x12; /* default = 1e2 cm = 1.00m */ + int which1 = 0, which2 = 0; + + cp = content.c_str(); + maxcp = cp + strlen(content.c_str()); + + lltemp1 = latlon2ul(&cp, &which1); + lltemp2 = latlon2ul(&cp, &which2); + + switch (which1 + which2) { + case 3: /* 1 + 2, the only valid combination */ + if ((which1 == 1) && (which2 == 2)) { /* normal case */ + d_latitude = lltemp1; + d_longitude = lltemp2; + } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/ + d_latitude = lltemp1; + d_longitude = lltemp2; + } else { /* some kind of brokenness */ + return; + } + break; + default: /* we didn't get one of each */ + throw MOADNSException("Error decoding LOC content"); + } + + /* altitude */ + if (*cp == '-') { + altsign = -1; + cp++; + } + + if (*cp == '+') + cp++; + + while (isdigit(*cp)) + altmeters = altmeters * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal meters */ + cp++; + if (isdigit(*cp)) { + altfrac = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + altfrac += (*cp++ - '0'); + } + } + } + + d_altitude = (10000000 + (altsign * (altmeters * 100 + altfrac))); + + while (!isspace(*cp) && (cp < maxcp)) + /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + + if (cp >= maxcp) + goto defaults; + + d_size = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + d_horizpre = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + d_vertpre = precsize_aton(&cp); + + defaults: + ; +} + + +string LOCRecordContent::getZoneRepresentation(bool noDot) const +{ + // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to: + // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m + + double latitude= ((int32_t)d_latitude - (1<<31))/3600000.0; + double longitude=((int32_t)d_longitude - (1<<31))/3600000.0; + double altitude= ((int32_t)d_altitude )/100.0 - 100000; + + double size=0.01*((d_size>>4)&0xf); + int count=d_size & 0xf; + while(count--) + size*=10; + + double horizpre=0.01*((d_horizpre>>4) & 0xf); + count=d_horizpre&0xf; + while(count--) + horizpre*=10; + + double vertpre=0.01*((d_vertpre>>4)&0xf); + count=d_vertpre&0xf; + while(count--) + vertpre*=10; + + double remlat=60.0*(latitude-(int)latitude); + double remlong=60.0*(longitude-(int)longitude); + char ret[80]; + snprintf(ret,sizeof(ret)-1,"%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm", + abs((int)latitude), abs((int) ((latitude-(int)latitude)*60)), + fabs((double)((remlat-(int)remlat)*60.0)), + latitude>0 ? 'N' : 'S', + abs((int)longitude), abs((int) ((longitude-(int)longitude)*60)), + fabs((double)((remlong-(int)remlong)*60.0)), + longitude>0 ? 'E' : 'W', + altitude, size, horizpre, vertpre); + + return ret; +} diff --git a/snmp-agent.cc b/snmp-agent.cc new file mode 100644 index 0000000..eecb36e --- /dev/null +++ b/snmp-agent.cc @@ -0,0 +1,209 @@ +#include "snmp-agent.hh" +#include "misc.hh" + +#ifdef HAVE_NET_SNMP + +#ifndef HAVE_SNMP_SELECT_INFO2 +/* that's terrible, because it means we are going to have trouble with large + FD numbers at some point.. */ +# define netsnmp_large_fd_set fd_set +# define snmp_read2 snmp_read +# define snmp_select_info2 snmp_select_info +# define netsnmp_large_fd_set_init(...) +# define netsnmp_large_fd_set_cleanup(...) +# define NETSNMP_LARGE_FD_SET FD_SET +# define NETSNMP_LARGE_FD_CLR FD_CLR +# define NETSNMP_LARGE_FD_ZERO FD_ZERO +# define NETSNMP_LARGE_FD_ISSET FD_ISSET +#else +# include +#endif + +const oid SNMPAgent::snmpTrapOID[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }; +const size_t SNMPAgent::snmpTrapOIDLen = OID_LENGTH(SNMPAgent::snmpTrapOID); + +int SNMPAgent::setCounter64Value(netsnmp_request_info* request, + uint64_t value) +{ + struct counter64 val64; + val64.high = value >> 32; + val64.low = value & 0xffffffff; + snmp_set_var_typed_value(request->requestvb, + ASN_COUNTER64, + &val64, + sizeof(val64)); + return SNMP_ERR_NOERROR; +} + +bool SNMPAgent::sendTrap(int fd, + netsnmp_variable_list* varList) +{ + ssize_t written = write(fd, &varList, sizeof(varList)); + + if (written != sizeof(varList)) { + snmp_free_varbind(varList); + return false; + } + return true; +} + +void SNMPAgent::handleTrapsEvent() +{ + netsnmp_variable_list* varList = nullptr; + ssize_t got = 0; + + do { + got = read(d_trapPipe[0], &varList, sizeof(varList)); + + if (got == sizeof(varList)) { + send_v2trap(varList); + snmp_free_varbind(varList); + } + } + while (got > 0); +} + +void SNMPAgent::handleSNMPQueryEvent(int fd) +{ + netsnmp_large_fd_set fdset; + netsnmp_large_fd_set_init(&fdset, FD_SETSIZE); + NETSNMP_LARGE_FD_ZERO(&fdset); + NETSNMP_LARGE_FD_SET(fd, &fdset); + snmp_read2(&fdset); +} + +void SNMPAgent::handleTrapsCB(int fd, FDMultiplexer::funcparam_t& var) +{ + SNMPAgent** agent = boost::any_cast(&var); + if (!agent || !*agent) + throw std::runtime_error("Invalid value received in SNMP trap callback"); + + (*agent)->handleTrapsEvent(); +} + +void SNMPAgent::handleSNMPQueryCB(int fd, FDMultiplexer::funcparam_t& var) +{ + SNMPAgent** agent = boost::any_cast(&var); + if (!agent || !*agent) + throw std::runtime_error("Invalid value received in SNMP trap callback"); + + (*agent)->handleSNMPQueryEvent(fd); +} + +static FDMultiplexer* getMultiplexer() +{ + FDMultiplexer* ret = nullptr; + for(const auto& i : FDMultiplexer::getMultiplexerMap()) { + try { + ret = i.second(); + return ret; + } + catch(const FDMultiplexerException& fe) { + } + catch(...) { + } + } + return ret; +} + +#endif /* HAVE_NET_SNMP */ + +void SNMPAgent::worker() +{ +#ifdef HAVE_NET_SNMP + FDMultiplexer* mplexer = getMultiplexer(); + if (mplexer == nullptr) { + throw std::runtime_error("No FD multiplexer found for the SNMP agent!"); + } + + int maxfd = 0; + int block = 1; + netsnmp_large_fd_set fdset; + struct timeval timeout = { 0, 0 }; + struct timeval now; + + /* we want to be notified if a trap is waiting + to be sent */ + mplexer->addReadFD(d_trapPipe[0], &handleTrapsCB, this); + + while(true) { + netsnmp_large_fd_set_init(&fdset, FD_SETSIZE); + NETSNMP_LARGE_FD_ZERO(&fdset); + + block = 1; + timeout = { 0, 0 }; + snmp_select_info2(&maxfd, &fdset, &timeout, &block); + + for (int fd = 0; fd < maxfd; fd++) { + if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) { + mplexer->addReadFD(fd, &handleSNMPQueryCB, this); + } + } + + /* run updates now */ + int res = mplexer->run(&now, (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000)); + + /* we handle timeouts here, the rest has already been handled by callbacks */ + if (res == 0) { + snmp_timeout(); + run_alarms(); + } + + for (int fd = 0; fd < maxfd; fd++) { + if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) { + try { + mplexer->removeReadFD(fd); + } + catch(const FDMultiplexerException& e) { + /* we might get an exception when removing a closed file descriptor, + just ignore it */ + } + } + } + } +#endif /* HAVE_NET_SNMP */ +} + +SNMPAgent::SNMPAgent(const std::string& name, const std::string& masterSocket) +{ +#ifdef HAVE_NET_SNMP + netsnmp_enable_subagent(); + snmp_disable_log(); + if (!masterSocket.empty()) { + netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_X_SOCKET, + masterSocket.c_str()); + } + /* no need to load any MIBS, + and it causes import errors if some modules are not present */ + setenv("MIBS", "", 1); + + init_agent(name.c_str()); + + /* we use select() so don't use SIGALARM to handle alarms. + Note that we need to handle alarms for automatic reconnection + to the master to work. + */ + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_ALARM_DONT_USE_SIG, + 1); + + init_snmp(name.c_str()); + + if (pipe(d_trapPipe) < 0) + unixDie("Creating pipe"); + + if (!setNonBlocking(d_trapPipe[0])) { + close(d_trapPipe[0]); + close(d_trapPipe[1]); + unixDie("Setting pipe non-blocking"); + } + + if (!setNonBlocking(d_trapPipe[1])) { + close(d_trapPipe[0]); + close(d_trapPipe[1]); + unixDie("Setting pipe non-blocking"); + } + +#endif /* HAVE_NET_SNMP */ +} diff --git a/snmp-agent.hh b/snmp-agent.hh new file mode 100644 index 0000000..5d693bb --- /dev/null +++ b/snmp-agent.hh @@ -0,0 +1,66 @@ +#ifndef SNMP_AGENT_HH +#define SNMP_AGENT_HH + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_NET_SNMP +#include +#include +#include +#include +#include +#include +#undef INET6 /* SRSLY? */ +#endif /* HAVE_NET_SNMP */ + +#include "mplexer.hh" + +class SNMPAgent +{ +public: + SNMPAgent(const std::string& name, const std::string& masterSocket); + virtual ~SNMPAgent() + { +#ifdef HAVE_NET_SNMP + close(d_trapPipe[0]); + close(d_trapPipe[1]); +#endif /* HAVE_NET_SNMP */ + } + + void run() + { +#ifdef HAVE_NET_SNMP + d_thread = std::thread(&SNMPAgent::worker, this); +#endif /* HAVE_NET_SNMP */ + } + +#ifdef HAVE_NET_SNMP + static int setCounter64Value(netsnmp_request_info* request, + uint64_t value); +#endif /* HAVE_NET_SNMP */ +protected: +#ifdef HAVE_NET_SNMP + /* OID for snmpTrapOID.0 */ + static const oid snmpTrapOID[]; + static const size_t snmpTrapOIDLen; + + static bool sendTrap(int fd, + netsnmp_variable_list* varList); + + int d_trapPipe[2] = { -1, -1}; +#endif /* HAVE_NET_SNMP */ +private: + void worker(); + static void handleTrapsCB(int fd, FDMultiplexer::funcparam_t& var); + static void handleSNMPQueryCB(int fd, FDMultiplexer::funcparam_t& var); + void handleTrapsEvent(); + void handleSNMPQueryEvent(int fd); + + std::thread d_thread; +}; + +#endif /* SNMP_AGENT_HH */ diff --git a/sodiumsigners.cc b/sodiumsigners.cc new file mode 100644 index 0000000..af194ad --- /dev/null +++ b/sodiumsigners.cc @@ -0,0 +1,140 @@ +extern "C" { +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +} +#include "dnssecinfra.hh" + +class SodiumED25519DNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit SodiumED25519DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo) + {} + string getName() const override { return "Sodium ED25519"; } + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string getPubKeyHash() const override; + std::string sign(const std::string& msg) const override; + bool verify(const std::string& msg, const std::string& signature) const override; + std::string getPublicKeyString() const override; + int getBits() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override + {} + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + unsigned char d_pubkey[crypto_sign_ed25519_PUBLICKEYBYTES]; + unsigned char d_seckey[crypto_sign_ed25519_SECRETKEYBYTES]; +}; + +void SodiumED25519DNSCryptoKeyEngine::create(unsigned int bits) +{ + if(bits != crypto_sign_ed25519_SEEDBYTES * 8) { + throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, SodiumED25519 class"); + } + crypto_sign_ed25519_keypair(d_pubkey, d_seckey); +} + +int SodiumED25519DNSCryptoKeyEngine::getBits() const +{ + return crypto_sign_ed25519_SEEDBYTES * 8; +} + +DNSCryptoKeyEngine::storvector_t SodiumED25519DNSCryptoKeyEngine::convertToISCVector() const +{ + /* + Private-key-format: v1.2 + Algorithm: 15 (ED25519) + PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ= + */ + + storvector_t storvector; + string algorithm = "15 (ED25519)"; + + storvector.push_back(make_pair("Algorithm", algorithm)); + + vector buffer; + storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, crypto_sign_ed25519_SEEDBYTES))); + return storvector; +} + +void SodiumED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap ) +{ + /* + Private-key-format: v1.2 + Algorithm: 15 (ED25519) + PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ= + */ + + drc.d_algorithm = pdns_stou(stormap["algorithm"]); + string privateKey = stormap["privatekey"]; + + if (privateKey.length() != crypto_sign_ed25519_SEEDBYTES) + throw runtime_error("Seed size mismatch in ISCMap, SodiumED25519 class"); + + std::unique_ptr seed(new unsigned char[crypto_sign_ed25519_SEEDBYTES]); + + memcpy(seed.get(), privateKey.c_str(), crypto_sign_ed25519_SEEDBYTES); + crypto_sign_ed25519_seed_keypair(d_pubkey, d_seckey, seed.get()); +} + +std::string SodiumED25519DNSCryptoKeyEngine::getPubKeyHash() const +{ + return this->getPublicKeyString(); +} + +std::string SodiumED25519DNSCryptoKeyEngine::getPublicKeyString() const +{ + return string((char*)d_pubkey, crypto_sign_ed25519_PUBLICKEYBYTES); +} + +void SodiumED25519DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + if (input.length() != crypto_sign_ed25519_PUBLICKEYBYTES) + throw runtime_error("Public key size mismatch, SodiumED25519 class"); + + memcpy(d_pubkey, input.c_str(), crypto_sign_ed25519_PUBLICKEYBYTES); +} + +std::string SodiumED25519DNSCryptoKeyEngine::sign(const std::string& msg) const +{ + unsigned long long smlen = msg.length() + crypto_sign_ed25519_BYTES; + std::unique_ptr sm(new unsigned char[smlen]); + + crypto_sign_ed25519(sm.get(), &smlen, (const unsigned char*)msg.c_str(), msg.length(), d_seckey); + + return string((const char*)sm.get(), crypto_sign_ed25519_BYTES); +} + +bool SodiumED25519DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const +{ + if (signature.length() != crypto_sign_ed25519_BYTES) + return false; + + unsigned long long smlen = msg.length() + crypto_sign_ed25519_BYTES; + std::unique_ptr sm(new unsigned char[smlen]); + + memcpy(sm.get(), signature.c_str(), crypto_sign_ed25519_BYTES); + memcpy(sm.get() + crypto_sign_ed25519_BYTES, msg.c_str(), msg.length()); + + std::unique_ptr m(new unsigned char[smlen]); + + return crypto_sign_ed25519_open(m.get(), &smlen, sm.get(), smlen, d_pubkey) == 0; +} + +namespace { +struct LoaderSodiumStruct +{ + LoaderSodiumStruct() + { + DNSCryptoKeyEngine::report(15, &SodiumED25519DNSCryptoKeyEngine::maker); + } +} loadersodium; +} diff --git a/sortlist.cc b/sortlist.cc new file mode 100644 index 0000000..c174338 --- /dev/null +++ b/sortlist.cc @@ -0,0 +1,74 @@ +#include "sortlist.hh" +#include "dnsrecords.hh" + +void SortList::clear() +{ + d_sortlist.clear(); +} + +int SortList::getMaxOrder(const Netmask& formask) const +{ + int order=0; + + auto place = d_sortlist.lookup(formask); + if(place && place->first == formask) { + for(const auto& o : place->second.d_orders) + order = std::max(order, o->second); // aki, shouldn't this be o.second? + } + + return order; +} + +void SortList::addEntry(const Netmask& formask, const Netmask& valmask, int order) +{ + if(order < 0) { + order=getMaxOrder(formask); + ++order; + } + // cout<<"Adding for netmask "< SortList::getOrderCmp(const ComboAddress& who) const +{ + if(!d_sortlist.match(who)) { + return std::unique_ptr(); + } + auto fnd = d_sortlist.lookup(who); + // cerr<<"Returning sort order for "<second.d_orders.size()<<" entries"<(fnd->second); +} + +// call this with **stable_sort** +bool SortListOrderCmp::operator()(const DNSRecord& ar, const DNSRecord& br) const +{ + bool aAddr = (ar.d_type == QType::A || ar.d_type == QType::AAAA); + bool bAddr = (br.d_type == QType::A || br.d_type == QType::AAAA); + + // anything address related is always 'larger', rest is equal + + if(aAddr && !bAddr) + return false; + else if(!aAddr && bAddr) + return true; + else if(!aAddr && !bAddr) + return false; + + + int aOrder=std::numeric_limits::max(); + int bOrder=aOrder; + + ComboAddress a=getAddr(ar), b=getAddr(br); + + if(d_slo.d_orders.match(a)) + aOrder = d_slo.d_orders.lookup(a)->second; + else { + // cout<<"Could not find anything for "<second; + else { + // cout<<"Could not find anything for "< d_orders; +}; + + +struct SortListOrderCmp +{ + SortListOrderCmp(SortListOrder slo) : d_slo(slo) {} + bool operator()(const DNSRecord& a, const DNSRecord& b) const; + const SortListOrder d_slo; +}; + +class SortList { +public: + void clear(); + void addEntry(const Netmask& covers, const Netmask& answermask, int order=-1); + int getMaxOrder(const Netmask& formask) const; + std::unique_ptr getOrderCmp(const ComboAddress& who) const; +private: + + NetmaskTree d_sortlist; +}; diff --git a/sstuff.hh b/sstuff.hh new file mode 100644 index 0000000..707b1ad --- /dev/null +++ b/sstuff.hh @@ -0,0 +1,398 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 SSTUFF_HH +#define SSTUFF_HH + +#include +#include +#include +#include "iputils.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "namespaces.hh" +#include "namespaces.hh" + + +class NetworkError : public runtime_error +{ +public: + NetworkError(const string& why="Network Error") : runtime_error(why.c_str()) + {} + NetworkError(const char *why="Network Error") : runtime_error(why) + {} +}; + + +typedef int ProtocolType; //!< Supported protocol types + +//! Representation of a Socket and many of the Berkeley functions available +class Socket : public boost::noncopyable +{ + Socket(int fd) + { + d_socket = fd; + d_buflen=4096; + d_buffer=new char[d_buflen]; + } + +public: + //! Construct a socket of specified address family and socket type. + Socket(int af, int st, ProtocolType pt=0) + { + if((d_socket=socket(af,st, pt))<0) + throw NetworkError(strerror(errno)); + setCloseOnExec(d_socket); + + d_buflen=4096; + d_buffer=new char[d_buflen]; + } + + ~Socket() + { + try { + closesocket(d_socket); + } + catch(const PDNSException& e) { + } + + delete[] d_buffer; + } + + //! If the socket is capable of doing so, this function will wait for a connection + Socket *accept() + { + struct sockaddr_in remote; + socklen_t remlen=sizeof(remote); + memset(&remote, 0, sizeof(remote)); + int s=::accept(d_socket,(sockaddr *)&remote, &remlen); + if(s<0) { + if(errno==EAGAIN) + return nullptr; + + throw NetworkError("Accepting a connection: "+string(strerror(errno))); + } + + return new Socket(s); + } + + //! Get remote address + bool getRemote(ComboAddress &remote) { + socklen_t remotelen=sizeof(remote); + return (getpeername(d_socket, (struct sockaddr *)&remote, &remotelen) >= 0); + } + + //! Check remote address against netmaskgroup ng + bool acl(NetmaskGroup &ng) + { + ComboAddress remote; + if (getRemote(remote)) + return ng.match((ComboAddress *) &remote); + + return false; + } + + //! Set the socket to non-blocking + void setNonBlocking() + { + ::setNonBlocking(d_socket); + } + //! Set the socket to blocking + void setBlocking() + { + ::setBlocking(d_socket); + } + + void setReuseAddr() + { + int tmp = 1; + if (setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast(sizeof tmp))<0) + throw NetworkError(string("Setsockopt failed: ")+strerror(errno)); + } + + //! Bind the socket to a specified endpoint + void bind(const ComboAddress &local) + { + int tmp=1; + if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) + throw NetworkError(string("Setsockopt failed: ")+strerror(errno)); + + if(::bind(d_socket,(struct sockaddr *)&local, local.getSocklen())<0) + throw NetworkError("While binding: "+string(strerror(errno))); + } + +#if 0 + //! Bind the socket to a specified endpoint + void bind(const ComboAddress &ep) + { + ComboAddress local; + memset(reinterpret_cast(&local),0,sizeof(local)); + local.sin_family=d_family; + local.sin_addr.s_addr=ep.address.byte; + local.sin_port=htons(ep.port); + + bind(local); + } +#endif + //! Connect the socket to a specified endpoint + void connect(const ComboAddress &ep, int timeout=0) + { + if(::connect(d_socket,(struct sockaddr *)&ep, ep.getSocklen()) < 0) { + if(errno == EINPROGRESS) { + if (timeout > 0) { + /* if a timeout is provided, we wait until the connection has been established */ + int res = waitForRWData(d_socket, false, timeout, 0); + if (res == 0) { + throw NetworkError("timeout while connecting to "+ep.toStringWithPort()); + } else if (res < 0) { + throw NetworkError("while waiting to connect to "+ep.toStringWithPort()+": "+string(strerror(errno))); + } + } + } + else { + throw NetworkError("While connecting to "+ep.toStringWithPort()+": "+string(strerror(errno))); + } + } + } + + + //! For datagram sockets, receive a datagram and learn where it came from + /** For datagram sockets, receive a datagram and learn where it came from + \param dgram Will be filled with the datagram + \param ep Will be filled with the origin of the datagram */ + void recvFrom(string &dgram, ComboAddress &ep) + { + socklen_t remlen=sizeof(ep); + ssize_t bytes; + if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&ep , &remlen)) <0) + throw NetworkError("After recvfrom: "+string(strerror(errno))); + + dgram.assign(d_buffer,bytes); + } + + bool recvFromAsync(string &dgram, ComboAddress &ep) + { + struct sockaddr_in remote; + socklen_t remlen=sizeof(remote); + ssize_t bytes; + if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&remote, &remlen))<0) { + if(errno!=EAGAIN) { + throw NetworkError("After async recvfrom: "+string(strerror(errno))); + } + else { + return false; + } + } + dgram.assign(d_buffer,bytes); + return true; + } + + + //! For datagram sockets, send a datagram to a destination + void sendTo(const char* msg, size_t len, const ComboAddress &ep) + { + if(sendto(d_socket, msg, len, 0, (sockaddr *)&ep, ep.getSocklen())<0) + throw NetworkError("After sendto: "+string(strerror(errno))); + } + + //! For connected datagram sockets, send a datagram + void send(const std::string& msg) + { + if(::send(d_socket, msg.c_str(), msg.size(), 0)<0) + throw NetworkError("After send: "+string(strerror(errno))); + } + + + /** For datagram sockets, send a datagram to a destination + \param dgram The datagram + \param ep The intended destination of the datagram */ + void sendTo(const string &dgram, const ComboAddress &ep) + { + sendTo(dgram.c_str(), dgram.length(), ep); + } + + + //! Write this data to the socket, taking care that all bytes are written out + void writen(const string &data) + { + if(data.empty()) + return; + + size_t toWrite=data.length(); + ssize_t res; + const char *ptr=data.c_str(); + + do { + res=::send(d_socket, ptr, toWrite, 0); + if(res<0) + throw NetworkError("Writing to a socket: "+string(strerror(errno))); + if(!res) + throw NetworkError("EOF on socket"); + toWrite-=(size_t)res; + ptr+=(size_t)res; + }while(toWrite); + + } + + //! tries to write toWrite bytes from ptr to the socket + /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out + \param ptr Location to write from + \param toWrite number of bytes to try + */ + size_t tryWrite(const char *ptr, size_t toWrite) + { + ssize_t res; + res=::send(d_socket,ptr,toWrite,0); + if(res==0) + throw NetworkError("EOF on writing to a socket"); + + if(res>0) + return res; + + if(errno==EAGAIN) + return 0; + + throw NetworkError("Writing to a socket: "+string(strerror(errno))); + } + + //! Writes toWrite bytes from ptr to the socket + /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */ + size_t write(const char *ptr, size_t toWrite) + { + ssize_t res; + res=::send(d_socket,ptr,toWrite,0); + if(res<0) { + throw NetworkError("Writing to a socket: "+string(strerror(errno))); + } + return res; + } + + void writenWithTimeout(const void *buffer, size_t n, int timeout) + { + size_t bytes=n; + const char *ptr = (char*)buffer; + ssize_t ret; + while(bytes) { + ret=::write(d_socket, ptr, bytes); + if(ret < 0) { + if(errno==EAGAIN) { + ret=waitForRWData(d_socket, false, timeout, 0); + if(ret < 0) + throw NetworkError("Waiting for data write"); + if(!ret) + throw NetworkError("Timeout writing data"); + continue; + } + else + throw NetworkError("Writing data: "+stringerror()); + } + if(!ret) { + throw NetworkError("Did not fulfill TCP write due to EOF"); + } + + ptr += (size_t) ret; + bytes -= (size_t) ret; + } + } + + //! reads one character from the socket + int getChar() + { + char c; + + ssize_t res=::recv(d_socket,&c,1,0); + if(res) + return c; + return -1; + } + + void getline(string &data) + { + data=""; + int c; + while((c=getChar())!=-1) { + data+=(char)c; + if(c=='\n') + break; + } + } + + //! Reads a block of data from the socket to a string + void read(string &data) + { + ssize_t res=::recv(d_socket,d_buffer,d_buflen,0); + if(res<0) + throw NetworkError("Reading from a socket: "+string(strerror(errno))); + data.assign(d_buffer,res); + } + + //! Reads a block of data from the socket to a block of memory + size_t read(char *buffer, size_t bytes) + { + ssize_t res=::recv(d_socket,buffer,bytes,0); + if(res<0) + throw NetworkError("Reading from a socket: "+string(strerror(errno))); + return (size_t) res; + } + + ssize_t readWithTimeout(char* buffer, size_t n, int timeout) + { + int err = waitForRWData(d_socket, true, timeout, 0); + + if(err == 0) + throw NetworkError("timeout reading"); + if(err < 0) + throw NetworkError("nonblocking read failed: "+string(strerror(errno))); + + return read(buffer, n); + } + + //! Sets the socket to listen with a default listen backlog of 10 pending connections + void listen(unsigned int length=10) + { + if(::listen(d_socket,length)<0) + throw NetworkError("Setting socket to listen: "+string(strerror(errno))); + } + + //! Returns the internal file descriptor of the socket + int getHandle() const + { + return d_socket; + } + +private: + char *d_buffer; + int d_socket; + size_t d_buflen; +}; + + +#endif diff --git a/syncres.cc b/syncres.cc new file mode 100644 index 0000000..74fa2f2 --- /dev/null +++ b/syncres.cc @@ -0,0 +1,2885 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "syncres.hh" +#include "arguments.hh" +#include "cachecleaner.hh" +#include "dns_random.hh" +#include "dnsparser.hh" +#include "dnsrecords.hh" +#include "ednssubnet.hh" +#include "logger.hh" +#include "lua-recursor4.hh" +#include "rec-lua-conf.hh" +#include "dnsseckeeper.hh" +#include "validate-recursor.hh" + +thread_local SyncRes::ThreadLocalStorage SyncRes::t_sstorage; + +std::unordered_set SyncRes::s_delegationOnly; +std::unique_ptr SyncRes::s_dontQuery{nullptr}; +NetmaskGroup SyncRes::s_ednssubnets; +SuffixMatchNode SyncRes::s_ednsdomains; +EDNSSubnetOpts SyncRes::s_ecsScopeZero; +string SyncRes::s_serverID; +SyncRes::LogMode SyncRes::s_lm; + +unsigned int SyncRes::s_maxnegttl; +unsigned int SyncRes::s_maxcachettl; +unsigned int SyncRes::s_maxqperq; +unsigned int SyncRes::s_maxtotusec; +unsigned int SyncRes::s_maxdepth; +unsigned int SyncRes::s_minimumTTL; +unsigned int SyncRes::s_packetcachettl; +unsigned int SyncRes::s_packetcacheservfailttl; +unsigned int SyncRes::s_serverdownmaxfails; +unsigned int SyncRes::s_serverdownthrottletime; +std::atomic SyncRes::s_authzonequeries; +std::atomic SyncRes::s_queries; +std::atomic SyncRes::s_outgoingtimeouts; +std::atomic SyncRes::s_outgoing4timeouts; +std::atomic SyncRes::s_outgoing6timeouts; +std::atomic SyncRes::s_outqueries; +std::atomic SyncRes::s_tcpoutqueries; +std::atomic SyncRes::s_throttledqueries; +std::atomic SyncRes::s_dontqueries; +std::atomic SyncRes::s_nodelegated; +std::atomic SyncRes::s_unreachables; +std::atomic SyncRes::s_ecsqueries; +std::atomic SyncRes::s_ecsresponses; +uint8_t SyncRes::s_ecsipv4limit; +uint8_t SyncRes::s_ecsipv6limit; +bool SyncRes::s_doIPv6; +bool SyncRes::s_nopacketcache; +bool SyncRes::s_rootNXTrust; +bool SyncRes::s_noEDNS; + +#define LOG(x) if(d_lm == Log) { L <&ret) +{ + vState state = Indeterminate; + s_queries++; + d_wasVariable=false; + d_wasOutOfBand=false; + + if (doSpecialNamesResolve(qname, qtype, qclass, ret)) { + d_queryValidationState = Insecure; // this could fool our stats into thinking a validation took place + return 0; // so do check before updating counters (we do now) + } + + if( (qtype.getCode() == QType::AXFR) || (qtype.getCode() == QType::IXFR) || (qtype.getCode() == QType::RRSIG) || (qtype.getCode() == QType::NSEC3)) + return -1; + + if(qclass==QClass::ANY) + qclass=QClass::IN; + else if(qclass!=QClass::IN) + return -1; + + set beenthere; + int res=doResolve(qname, qtype, ret, 0, beenthere, state); + d_queryValidationState = state; + + if (shouldValidate()) { + if (d_queryValidationState != Indeterminate) { + g_stats.dnssecValidations++; + } + increaseDNSSECStateCounter(d_queryValidationState); + } + + return res; +} + +/*! Handles all special, built-in names + * Fills ret with an answer and returns true if it handled the query. + * + * Handles the following queries (and their ANY variants): + * + * - localhost. IN A + * - localhost. IN AAAA + * - 1.0.0.127.in-addr.arpa. IN PTR + * - 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. IN PTR + * - version.bind. CH TXT + * - version.pdns. CH TXT + * - id.server. CH TXT + */ +bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector &ret) +{ + static const DNSName arpa("1.0.0.127.in-addr.arpa."), ip6_arpa("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), + localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."); + + bool handled = false; + vector > answers; + + if ((qname == arpa || qname == ip6_arpa) && + qclass == QClass::IN) { + handled = true; + if (qtype == QType::PTR || qtype == QType::ANY) + answers.push_back({QType::PTR, "localhost."}); + } + + if (qname == localhost && + qclass == QClass::IN) { + handled = true; + if (qtype == QType::A || qtype == QType::ANY) + answers.push_back({QType::A, "127.0.0.1"}); + if (qtype == QType::AAAA || qtype == QType::ANY) + answers.push_back({QType::AAAA, "::1"}); + } + + if ((qname == versionbind || qname == idserver || qname == versionpdns) && + qclass == QClass::CHAOS) { + handled = true; + if (qtype == QType::TXT || qtype == QType::ANY) { + if(qname == versionbind || qname == versionpdns) + answers.push_back({QType::TXT, "\""+::arg()["version-string"]+"\""}); + else + answers.push_back({QType::TXT, "\""+s_serverID+"\""}); + } + } + + if (handled && !answers.empty()) { + ret.clear(); + d_wasOutOfBand=true; + + DNSRecord dr; + dr.d_name = qname; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_class = qclass; + dr.d_ttl = 86400; + for (const auto& ans : answers) { + dr.d_type = ans.first; + dr.d_content = DNSRecordContent::mastermake(ans.first, qclass, ans.second); + ret.push_back(dr); + } + } + + return handled; +} + + +//! This is the 'out of band resolver', in other words, the authoritative server +void SyncRes::AuthDomain::addSOA(std::vector& records) const +{ + SyncRes::AuthDomain::records_t::const_iterator ziter = d_records.find(boost::make_tuple(getName(), QType::SOA)); + if (ziter != d_records.end()) { + DNSRecord dr = *ziter; + dr.d_place = DNSResourceRecord::AUTHORITY; + records.push_back(dr); + } + else { + // cerr<& records) const +{ + int result = RCode::NoError; + records.clear(); + + // partial lookup + std::pair range = d_records.equal_range(tie(qname)); + + SyncRes::AuthDomain::records_t::const_iterator ziter; + bool somedata = false; + + for(ziter = range.first; ziter != range.second; ++ziter) { + somedata = true; + + if(qtype == QType::ANY || ziter->d_type == qtype || ziter->d_type == QType::CNAME) { + // let rest of nameserver do the legwork on this one + records.push_back(*ziter); + } + else if (ziter->d_type == QType::NS && ziter->d_name.countLabels() > getName().countLabels()) { + // we hit a delegation point! + DNSRecord dr = *ziter; + dr.d_place=DNSResourceRecord::AUTHORITY; + records.push_back(dr); + } + } + + if (!records.empty()) { + /* We have found an exact match, we're done */ + // cerr<&ret, int& res) +{ + d_authzonequeries++; + s_authzonequeries++; + + res = domain.getRecords(qname, qtype.getCode(), ret); + return true; +} + +bool SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, int& res) +{ + string prefix; + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + DNSName authdomain(qname); + domainmap_t::const_iterator iter=getBestAuthZone(&authdomain); + if(iter==t_sstorage.domainmap->end() || !iter->second.isAuth()) { + LOG(prefix<second, qname, qtype, ret, res); +} + +void SyncRes::doEDNSDumpAndClose(int fd) +{ + FILE* fp=fdopen(fd, "w"); + if (!fp) { + return; + } + fprintf(fp,"IP Address\tMode\tMode last updated at\n"); + for(const auto& eds : t_sstorage.ednsstatus) { + fprintf(fp, "%s\t%d\t%s", eds.first.toString().c_str(), (int)eds.second.mode, ctime(&eds.second.modeSetAt)); + } + + fclose(fp); +} + +uint64_t SyncRes::doDumpNSSpeeds(int fd) +{ + FILE* fp=fdopen(dup(fd), "w"); + if(!fp) + return 0; + fprintf(fp, "; nsspeed dump from thread follows\n;\n"); + uint64_t count=0; + + for(const auto& i : t_sstorage.nsSpeeds) + { + count++; + + // an can appear hear in case of authoritative (hosted) zones + fprintf(fp, "%s -> ", i.first.toLogString().c_str()); + for(const auto& j : i.second.d_collection) + { + // typedef vector > collection_t; + fprintf(fp, "%s/%f ", j.first.toString().c_str(), j.second.peek()); + } + fprintf(fp, "\n"); + } + fclose(fp); + return count; +} + +/* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide + to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records + so that if there are RRSIGs for a name, we'll have them. + + However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as: + * No answer + * FormErr + * Nonsense answer + + The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through. + Another cause of "No answer" may simply be a network condition. + Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah. + + Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts. + A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really + clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens + elsewhere. It may not have happened yet. + + For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish. +*/ + +int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional& srcmask, LWResult* res, bool* chained) const +{ + /* what is your QUEST? + the goal is to get as many remotes as possible on the highest level of EDNS support + The levels are: + + 0) UNKNOWN Unknown state + 1) EDNS: Honors EDNS0 + 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0 + 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries + + Everybody starts out assumed to be '0'. + If '0', send out EDNS0 + If you FORMERR us, go to '3', + If no EDNS in response, go to '2' + If '1', send out EDNS0 + If FORMERR, downgrade to 3 + If '2', keep on including EDNS0, see what happens + Same behaviour as 0 + If '3', send bare queries + */ + + SyncRes::EDNSStatus* ednsstatus; + ednsstatus = &t_sstorage.ednsstatus[ip]; // does this include port? YES + + if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) { + *ednsstatus=SyncRes::EDNSStatus(); + // cerr<<"Resetting EDNS Status for "<mode; + SyncRes::EDNSStatus::EDNSMode oldmode = mode; + int EDNSLevel = 0; + auto luaconfsLocal = g_luaconfs.getLocal(); + ResolveContext ctx; +#ifdef HAVE_PROTOBUF + ctx.d_initialRequestId = d_initialRequestId; +#endif + + int ret; + for(int tries = 0; tries < 3; ++tries) { + // cerr<<"Remote '"<outgoingProtobufServer, res, chained); + } + else { + ret=asyncresolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res, chained); + } + if(ret < 0) { + return ret; // transport error, nothing to learn here + } + + if(ret == 0) { // timeout, not doing anything with it now + return ret; + } + else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) { + if(res->d_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp) { + // cerr<<"Downgrading to NOEDNS because of "<d_rcode)<<" for query to "<d_haveEDNS) { + if(mode != EDNSStatus::EDNSIGNORANT) { + mode = EDNSStatus::EDNSIGNORANT; + // cerr<<"We find that "<modeSetAt) + ednsstatus->modeSetAt=d_now.tv_sec; + // cerr<<"Result: ret="<d_haveEDNS<<", new mode: "<&ret, unsigned int depth, set& beenthere, vState& state) +{ + string prefix; + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + LOG(prefix< s_maxdepth) + throw ImmediateServFailException("More than "+std::to_string(s_maxdepth)+" (max-recursion-depth) levels of recursion needed while resolving "+qname.toLogString()); + + int res=0; + + // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS. + if(!(d_updatingRootNS && qtype.getCode()==QType::NS && qname.isRoot())) { + if(d_cacheonly) { // very limited OOB support + LWResult lwr; + LOG(prefix<end()) { + if(iter->second.isAuth()) { + ret.clear(); + d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, res); + return res; + } + else { + const vector& servers = iter->second.d_servers; + const ComboAddress remoteIP = servers.front(); + LOG(prefix< nm; + bool chained = false; + res=asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(), false, false, &d_now, nm, &lwr, &chained); + + d_totUsec += lwr.d_usec; + accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family); + + // filter out the good stuff from lwr.result() + if (res == 1) { + for(const auto& rec : lwr.d_records) { + if(rec.d_place == DNSResourceRecord::ANSWER) + ret.push_back(rec); + } + return 0; + } + else { + return RCode::ServFail; + } + } + } + } + + DNSName authname(qname); + bool wasForwardedOrAuthZone = false; + bool wasAuthZone = false; + domainmap_t::const_iterator iter = getBestAuthZone(&authname); + if(iter != t_sstorage.domainmap->end()) { + wasForwardedOrAuthZone = true; + const vector& servers = iter->second.d_servers; + if(servers.empty()) { + wasAuthZone = true; + } + } + + if(!d_skipCNAMECheck && doCNAMECacheCheck(qname, qtype, ret, depth, res, state, wasAuthZone)) { // will reroute us if needed + d_wasOutOfBand = wasAuthZone; + return res; + } + + if(doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, qtype, ret, depth, res, state)) { + // we done + d_wasOutOfBand = wasAuthZone; + return res; + } + } + + if(d_cacheonly) + return 0; + + LOG(prefix<& speeds): d_speeds(speeds) {} + bool operator()(const ComboAddress& a, const ComboAddress& b) const + { + return d_speeds[a] < d_speeds[b]; + } + std::map& d_speeds; +}; + +/** This function explicitly goes out for A or AAAA addresses +*/ +vector SyncRes::getAddrs(const DNSName &qname, unsigned int depth, set& beenthere, bool cacheOnly) +{ + typedef vector res_t; + res_t res; + + typedef vector ret_t; + ret_t ret; + + QType type; + bool oldCacheOnly = d_cacheonly; + bool oldRequireAuthData = d_requireAuthData; + bool oldValidationRequested = d_DNSSECValidationRequested; + d_requireAuthData = false; + d_DNSSECValidationRequested = false; + d_cacheonly = cacheOnly; + + for(int j=1; j<2+s_doIPv6; j++) + { + bool done=false; + switch(j) { + case 0: + type = QType::ANY; + break; + case 1: + type = QType::A; + break; + case 2: + type = QType::AAAA; + break; + } + + vState newState = Indeterminate; + if(!doResolve(qname, type, res,depth+1, beenthere, newState) && !res.empty()) { // this consults cache, OR goes out + for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i) { + if(i->d_type == QType::A || i->d_type == QType::AAAA) { + if(auto rec = getRR(*i)) + ret.push_back(rec->getCA(53)); + else if(auto aaaarec = getRR(*i)) + ret.push_back(aaaarec->getCA(53)); + done=true; + } + } + } + if(done) { + if(j==1 && s_doIPv6) { // we got an A record, see if we have some AAAA lying around + vector cset; + if(t_RC->get(d_now.tv_sec, qname, QType(QType::AAAA), false, &cset, d_incomingECSFound ? d_incomingECSNetwork : d_requestor) > 0) { + for(auto k=cset.cbegin();k!=cset.cend();++k) { + if(k->d_ttl > (unsigned int)d_now.tv_sec ) { + if (auto drc = getRR(*k)) { + ComboAddress ca=drc->getCA(53); + ret.push_back(ca); + } + } + } + } + } + break; + } + } + + d_requireAuthData = oldRequireAuthData; + d_DNSSECValidationRequested = oldValidationRequested; + d_cacheonly = oldCacheOnly; + + /* we need to remove from the nsSpeeds collection the existing IPs + for this nameserver that are no longer in the set, even if there + is only one or none at all in the current set. + */ + map speeds; + auto& collection = t_sstorage.nsSpeeds[qname].d_collection; + for(const auto& val: ret) { + speeds[val] = collection[val].get(&d_now); + } + + t_sstorage.nsSpeeds[qname].purge(speeds); + + if(ret.size() > 1) { + random_shuffle(ret.begin(), ret.end(), dns_random); + speedOrderCA so(speeds); + stable_sort(ret.begin(), ret.end(), so); + + if(doLog()) { + string prefix=d_prefix; + prefix.append(depth, ' '); + LOG(prefix<<"Nameserver "<& bestns, bool* flawedNSSet, unsigned int depth, set& beenthere) +{ + string prefix; + DNSName subdomain(qname); + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + bestns.clear(); + bool brokeloop; + do { + brokeloop=false; + LOG(prefix< ns; + *flawedNSSet = false; + + if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), false, &ns, d_incomingECSFound ? d_incomingECSNetwork : d_requestor) > 0) { + for(auto k=ns.cbegin();k!=ns.cend(); ++k) { + if(k->d_ttl > (unsigned int)d_now.tv_sec ) { + vector aset; + + const DNSRecord& dr=*k; + auto nrr = getRR(dr); + if(nrr && (!nrr->getNS().isPartOf(subdomain) || t_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A), + false, doLog() ? &aset : 0, d_incomingECSFound ? d_incomingECSNetwork : d_requestor) > 5)) { + bestns.push_back(dr); + LOG(prefix< '"<getNS()<<"'"<getNS().isPartOf(subdomain)); + if(!aset.empty()) { + LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->d_ttl- d_now.tv_sec ))<getNS()<<") which we miss or is expired"<(dr)) { + answer.bestns.insert(make_pair(dr.d_name, nsContent->getNS())); + } + } + + if(beenthere.count(answer)) { + brokeloop=true; + LOG(prefix<::const_iterator j=beenthere.begin();j!=beenthere.end();++j) { + bool neo = !(*j< answer || answer<*j); + LOG(prefix<qname<<"|"<qtype)<<" ("<<(unsigned int)j->bestns.size()<<")"<find(*qname); + if(ret!=t_sstorage.domainmap->end()) + break; + }while(qname->chopOff()); + return ret; +} + +/** doesn't actually do the work, leaves that to getBestNSFromCache */ +DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set&beenthere) +{ + DNSName subdomain(qname); + DNSName authdomain(qname); + + domainmap_t::const_iterator iter=getBestAuthZone(&authdomain); + if(iter!=t_sstorage.domainmap->end()) { + if( iter->second.isAuth() ) + // this gets picked up in doResolveAt, the empty DNSName, combined with the + // empty vector means 'we are auth for this zone' + nsset.insert({DNSName(), {{}, false}}); + else { + // Again, picked up in doResolveAt. An empty DNSName, combined with a + // non-empty vector of ComboAddresses means 'this is a forwarded domain' + // This is actually picked up in retrieveAddressesForNS called from doResolveAt. + nsset.insert({DNSName(), {iter->second.d_servers, iter->second.shouldRecurse() }}); + } + return authdomain; + } + + vector bestns; + getBestNSFromCache(subdomain, qtype, bestns, flawedNSSet, depth, beenthere); + + for(auto k=bestns.cbegin() ; k != bestns.cend(); ++k) { + // The actual resolver code will not even look at the ComboAddress or bool + const auto nsContent = getRR(*k); + if (nsContent) { + nsset.insert({nsContent->getNS(), {{}, false}}); + if(k==bestns.cbegin()) + subdomain=k->d_name; + } + } + return subdomain; +} + +bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone) +{ + string prefix; + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + if((depth>9 && d_outqueries>10 && d_throttledqueries>5) || depth > 15) { + LOG(prefix< cset; + vector> signatures; + vector> authorityRecs; + bool wasAuth; + if(t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), d_requireAuthData, &cset, d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) { + + for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) { + if (j->d_class != QClass::IN) { + continue; + } + + if(j->d_ttl>(unsigned int) d_now.tv_sec) { + + if (!wasAuthZone && shouldValidate() && wasAuth && state == Indeterminate && d_requireAuthData) { + /* This means we couldn't figure out the state when this entry was cached, + most likely because we hadn't computed the zone cuts yet. */ + /* make sure they are computed before validating */ + DNSName subdomain(qname); + /* if we are retrieving a DS, we only care about the state of the parent zone */ + if(qtype == QType::DS) + subdomain.chopOff(); + + computeZoneCuts(subdomain, g_rootdnsname, depth); + + vState recordState = getValidationStatus(qname, false); + if (recordState == Secure) { + LOG(prefix<updateValidationStatus(d_now.tv_sec, qname, QType(QType::CNAME), d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_requireAuthData, state); + } + } + } + + LOG(prefix<d_content->getZoneRepresentation()<<"', validation state is "<d_ttl - d_now.tv_sec; + sigdr.d_content=signature; + sigdr.d_place=DNSResourceRecord::ANSWER; + sigdr.d_class=QClass::IN; + ret.push_back(sigdr); + } + + for(const auto& rec : authorityRecs) { + DNSRecord authDR(*rec); + authDR.d_ttl=j->d_ttl - d_now.tv_sec; + ret.push_back(authDR); + } + + if(qtype != QType::CNAME) { // perhaps they really wanted a CNAME! + setbeenthere; + + vState cnameState = Indeterminate; + const auto cnameContent = getRR(*j); + if (cnameContent) { + res=doResolve(cnameContent->getTarget(), qtype, ret, depth+1, beenthere, cnameState); + LOG(prefix< records; + vector> signatures; + uint32_t signaturesTTL{std::numeric_limits::max()}; +}; +struct CacheKey +{ + DNSName name; + uint16_t type; + DNSResourceRecord::Place place; + bool operator<(const CacheKey& rhs) const { + return tie(name, type) < tie(rhs.name, rhs.type); + } +}; +typedef map tcache_t; +} + +static void reapRecordsFromNegCacheEntryForValidation(tcache_t& tcache, const vector& records) +{ + for (const auto& rec : records) { + if (rec.d_type == QType::RRSIG) { + auto rrsig = getRR(rec); + if (rrsig) { + tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig); + } + } else { + tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(rec); + } + } +} + +/*! + * Convience function to push the records from records into ret with a new TTL + * + * \param records DNSRecords that need to go into ret + * \param ttl The new TTL for these records + * \param ret The vector of DNSRecords that should contian the records with the modified TTL + */ +static void addTTLModifiedRecords(const vector& records, const uint32_t ttl, vector& ret) { + for (const auto& rec : records) { + DNSRecord r(rec); + r.d_ttl = ttl; + ret.push_back(r); + } +} + +void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry& ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth) +{ + DNSName subdomain(qname); + /* if we are retrieving a DS, we only care about the state of the parent zone */ + if(qtype == QType::DS) + subdomain.chopOff(); + + computeZoneCuts(subdomain, g_rootdnsname, depth); + + tcache_t tcache; + reapRecordsFromNegCacheEntryForValidation(tcache, ne.authoritySOA.records); + reapRecordsFromNegCacheEntryForValidation(tcache, ne.authoritySOA.signatures); + reapRecordsFromNegCacheEntryForValidation(tcache, ne.DNSSECRecords.records); + reapRecordsFromNegCacheEntryForValidation(tcache, ne.DNSSECRecords.signatures); + + for (const auto& entry : tcache) { + // this happens when we did store signatures, but passed on the records themselves + if (entry.second.records.empty()) { + continue; + } + + const DNSName& owner = entry.first.name; + + vState recordState = getValidationStatus(owner, false); + if (state == Indeterminate) { + state = recordState; + } + + if (recordState == Secure) { + recordState = SyncRes::validateRecordsWithSigs(depth, qname, qtype, owner, entry.second.records, entry.second.signatures); + } + + if (recordState != Indeterminate && recordState != state) { + updateValidationState(state, recordState); + if (state != Secure) { + break; + } + } + } + + if (state == Secure) { + dState expectedState = res == RCode::NXDomain ? NXDOMAIN : NXQTYPE; + dState denialState = getDenialValidationState(ne, state, expectedState, false); + updateDenialValidationState(ne, state, denialState, expectedState, qtype == QType::DS); + } + if (state != Indeterminate) { + /* validation succeeded, let's update the cache entry so we don't have to validate again */ + t_sstorage.negcache.updateValidationStatus(ne.d_name, ne.d_qtype, state); + } +} + +bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, const QType &qtype, vector&ret, unsigned int depth, int &res, vState& state) +{ + bool giveNegative=false; + + string prefix; + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + // sqname and sqtype are used contain 'higher' names if we have them (e.g. powerdns.com|SOA when we find a negative entry for doesnotexists.powerdns.com|A) + DNSName sqname(qname); + QType sqt(qtype); + uint32_t sttl=0; + // cout<<"Lookup for '"< "< cset; + bool found=false, expired=false; + vector> signatures; + vector> authorityRecs; + uint32_t ttl=0; + bool wasCachedAuth; + if(t_RC->get(d_now.tv_sec, sqname, sqt, d_requireAuthData, &cset, d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) { + + LOG(prefix<updateValidationStatus(d_now.tv_sec, sqname, sqt, d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_requireAuthData, cachedState); + } + } + + for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) { + + LOG(j->d_content->getZoneRepresentation()); + + if (j->d_class != QClass::IN) { + continue; + } + + if(j->d_ttl>(unsigned int) d_now.tv_sec) { + DNSRecord dr=*j; + ttl = (dr.d_ttl-=d_now.tv_sec); + ret.push_back(dr); + LOG("[ttl="< b.countLabels()); +} + +struct speedOrder +{ + speedOrder(map &speeds) : d_speeds(speeds) {} + bool operator()(const DNSName &a, const DNSName &b) const + { + return d_speeds[a] < d_speeds[b]; + } + map& d_speeds; +}; + +inline vector SyncRes::shuffleInSpeedOrder(NsSet &tnameservers, const string &prefix) +{ + vector rnameservers; + rnameservers.reserve(tnameservers.size()); + for(const auto& tns: tnameservers) { + rnameservers.push_back(tns.first); + if(tns.first.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that + return rnameservers; + } + map speeds; + + for(const auto& val: rnameservers) { + double speed; + speed=t_sstorage.nsSpeeds[val].get(&d_now); + speeds[val]=speed; + } + random_shuffle(rnameservers.begin(),rnameservers.end(), dns_random); + speedOrder so(speeds); + stable_sort(rnameservers.begin(),rnameservers.end(), so); + + if(doLog()) { + LOG(prefix<<"Nameservers: "); + for(vector::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) { + if(i!=rnameservers.begin()) { + LOG(", "); + if(!((i-rnameservers.begin())%3)) { + LOG(endl<empty() ? string("") : i->toString())<<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)"); + } + LOG(endl); + } + return rnameservers; +} + +static uint32_t getRRSIGTTL(const time_t now, const std::shared_ptr& rrsig) +{ + uint32_t res = 0; + if (now < rrsig->d_sigexpire) { + res = static_cast(rrsig->d_sigexpire) - now; + } + return res; +} + +static const set nsecTypes = {QType::NSEC, QType::NSEC3}; + +/* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records + * + * \param records The records to parse for the authority SOA and NSEC(3) records + * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to + */ +static void harvestNXRecords(const vector& records, NegCache::NegCacheEntry& ne, const time_t now, uint32_t* lowestTTL) { + for(const auto& rec : records) { + if(rec.d_place != DNSResourceRecord::AUTHORITY) + // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in + // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for + // records MUST be in the same section as the records they cover. + // Hence, we ignore all records outside of the AUTHORITY section. + continue; + + if(rec.d_type == QType::RRSIG) { + auto rrsig = getRR(rec); + if(rrsig) { + if(rrsig->d_type == QType::SOA) { + ne.authoritySOA.signatures.push_back(rec); + if (lowestTTL && isRRSIGNotExpired(now, rrsig)) { + *lowestTTL = min(*lowestTTL, rec.d_ttl); + *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig)); + } + } + if(nsecTypes.count(rrsig->d_type)) { + ne.DNSSECRecords.signatures.push_back(rec); + if (lowestTTL && isRRSIGNotExpired(now, rrsig)) { + *lowestTTL = min(*lowestTTL, rec.d_ttl); + *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig)); + } + } + } + continue; + } + if(rec.d_type == QType::SOA) { + ne.authoritySOA.records.push_back(rec); + if (lowestTTL) { + *lowestTTL = min(*lowestTTL, rec.d_ttl); + } + continue; + } + if(nsecTypes.count(rec.d_type)) { + ne.DNSSECRecords.records.push_back(rec); + if (lowestTTL) { + *lowestTTL = min(*lowestTTL, rec.d_ttl); + } + continue; + } + } +} + +static cspmap_t harvestCSPFromNE(const NegCache::NegCacheEntry& ne) +{ + cspmap_t cspmap; + for(const auto& rec : ne.DNSSECRecords.signatures) { + if(rec.d_type == QType::RRSIG) { + auto rrc = getRR(rec); + if (rrc) { + cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc); + } + } + } + for(const auto& rec : ne.DNSSECRecords.records) { + cspmap[{rec.d_name, rec.d_type}].records.push_back(rec.d_content); + } + return cspmap; +} + +// TODO remove after processRecords is fixed! +// Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret +static void addNXNSECS(vector&ret, const vector& records) +{ + NegCache::NegCacheEntry ne; + harvestNXRecords(records, ne, 0, nullptr); + ret.insert(ret.end(), ne.authoritySOA.signatures.begin(), ne.authoritySOA.signatures.end()); + ret.insert(ret.end(), ne.DNSSECRecords.records.begin(), ne.DNSSECRecords.records.end()); + ret.insert(ret.end(), ne.DNSSECRecords.signatures.begin(), ne.DNSSECRecords.signatures.end()); +} + +bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers) +{ + if(d_wantsRPZ) { + for (auto const &ns : nameservers) { + d_appliedPolicy = dfe.getProcessingPolicy(ns.first, d_discardedPolicies); + if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response + LOG(", however nameserver "< SyncRes::retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector::const_iterator& tns, const unsigned int depth, set& beenthere, const vector& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly) +{ + vector result; + + if(!tns->empty()) { + LOG(prefix< 1) { + LOG("s"); + } + LOG(endl); + + sendRDQuery = nameservers[*tns].second; + pierceDontQuery=true; + } + return result; +} + +bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery) +{ + if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) { + LOG(prefix<match(&remoteIP)) { + LOG(prefix<& records, const std::vector >& signatures, uint32_t signaturesTTL) const +{ + uint32_t lowestTTD = std::numeric_limits::max(); + for(const auto& record : records) + lowestTTD = min(lowestTTD, record.d_ttl); + + /* even if it was not requested for that request (Process, and neither AD nor DO set), + it might be requested at a later time so we need to be careful with the TTL. */ + if (validationEnabled() && !signatures.empty()) { + /* if we are validating, we don't want to cache records after their signatures expire. */ + /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */ + lowestTTD = min(lowestTTD, static_cast(signaturesTTL + d_now.tv_sec)); + + for(const auto& sig : signatures) { + if (isRRSIGNotExpired(d_now.tv_sec, sig)) { + // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */ + lowestTTD = min(lowestTTD, static_cast(sig->d_sigexpire)); + } + } + } + + return lowestTTD; +} + +void SyncRes::updateValidationState(vState& state, const vState stateUpdate) +{ + LOG(d_prefix<<"validation state was "<dsAnchors.empty()) { + LOG(d_prefix<<": No trust anchors configured, everything is Insecure"<negAnchors, zone, reason)) { + LOG(d_prefix<<": got NTA for '"<dsAnchors, zone, ds)) { + LOG(d_prefix<<": got TA for '"<dsAnchors.size()< beenthere; + std::vector dsrecords; + + vState state = Indeterminate; + int rcode = doResolve(zone, QType(QType::DS), dsrecords, depth + 1, beenthere, state); + d_skipCNAMECheck = oldSkipCNAME; + + if (rcode == RCode::NoError || (rcode == RCode::NXDomain && !bogusOnNXD)) { + + uint8_t bestDigestType = 0; + + if (state == Secure) { + bool gotCNAME = false; + for (const auto& record : dsrecords) { + if (record.d_type == QType::DS) { + const auto dscontent = getRR(record); + if (dscontent && isSupportedDS(*dscontent)) { + // Make GOST a lower prio than SHA256 + if (dscontent->d_digesttype == DNSSECKeeper::GOST && bestDigestType == DNSSECKeeper::SHA256) { + continue; + } + if (dscontent->d_digesttype > bestDigestType || (bestDigestType == DNSSECKeeper::GOST && dscontent->d_digesttype == DNSSECKeeper::SHA256)) { + bestDigestType = dscontent->d_digesttype; + } + ds.insert(*dscontent); + } + } + else if (record.d_type == QType::CNAME && record.d_name == zone) { + gotCNAME = true; + } + } + + /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1 + * digests if DS RRs with SHA-256 digests are present in the DS RRset." + * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm". + */ + for (auto dsrec = ds.begin(); dsrec != ds.end(); ) { + if (dsrec->d_digesttype != bestDigestType) { + dsrec = ds.erase(dsrec); + } + else { + ++dsrec; + } + } + + if (rcode == RCode::NoError && ds.empty()) { + if (foundCut) { + if (gotCNAME || denialProvesNoDelegation(zone, dsrecords)) { + /* we are still inside the same Secure zone */ + + *foundCut = false; + return Secure; + } + + *foundCut = true; + } + + return Insecure; + } else if (foundCut && rcode == RCode::NoError && !ds.empty()) { + *foundCut = true; + } + } + + return state; + } + + LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<second != Indeterminate) { + LOG(d_prefix<<": got status "<second]<<" for name "<second; + } + } + } + while (name.chopOff()); + + return result; +} + +bool SyncRes::lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState) +{ + bool foundCut = false; + dsmap_t ds; + vState dsState = getDSRecords(qname, ds, newState == Bogus || existingState == Insecure || existingState == Bogus, depth, false, &foundCut); + + if (dsState != Indeterminate) { + newState = dsState; + } + + return foundCut; +} + +void SyncRes::computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth) +{ + if(!begin.isPartOf(end)) { + LOG(d_prefix<<" "< labelsToAdd = begin.makeRelative(end).getRawLabels(); + + bool oldSkipCNAME = d_skipCNAMECheck; + d_skipCNAMECheck = true; + + while(qname != begin) { + if (labelsToAdd.empty()) + break; + + qname.prependRawLabel(labelsToAdd.back()); + labelsToAdd.pop_back(); + LOG(d_prefix<<": - Looking for a cut at "<second != Indeterminate) { + LOG(d_prefix<<": - Cut already known at "<second; + continue; + } + } + + /* no need to look for NS and DS if we are already insecure or bogus, + just look for (N)TA + */ + if (cutState == Insecure || cutState == Bogus) { + dsmap_t cutDS; + vState newState = getDSRecords(qname, cutDS, true, depth); + if (newState == Indeterminate) { + continue; + } + + LOG(d_prefix<<": New state for "<& dnskeys, const std::vector >& signatures, unsigned int depth) +{ + dsmap_t ds; + if (!signatures.empty()) { + DNSName signer = getSigner(signatures); + + if (!signer.empty() && zone.isPartOf(signer)) { + vState state = getDSRecords(signer, ds, false, depth); + + if (state != Secure) { + return state; + } + } + } + + skeyset_t tentativeKeys; + std::vector > toSign; + + for (const auto& dnskey : dnskeys) { + if (dnskey.d_type == QType::DNSKEY) { + auto content = getRR(dnskey); + if (content) { + tentativeKeys.insert(content); + toSign.push_back(content); + } + } + } + + LOG(d_prefix<<": trying to validate "< records; + std::set beenthere; + LOG(d_prefix<<"Retrieving DNSKeys for "<(key); + if (content) { + keys.insert(content); + } + } + } + } + LOG(d_prefix<<"Retrieved "<& records, const std::vector >& signatures) +{ + skeyset_t keys; + if (!signatures.empty()) { + const DNSName signer = getSigner(signatures); + if (!signer.empty() && name.isPartOf(signer)) { + if ((qtype == QType::DNSKEY || qtype == QType::DS) && signer == qname) { + /* we are already retrieving those keys, sorry */ + return Indeterminate; + } + vState state = getDNSKeys(signer, keys, depth); + if (state != Secure) { + return state; + } + } + } else { + LOG(d_prefix<<"Bogus!"< > recordcontents; + for (const auto& record : records) { + recordcontents.push_back(record.d_content); + } + + LOG(d_prefix<<"Going to validate "< ednsmask, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount) +{ + tcache_t tcache; + + string prefix; + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + std::vector> authorityRecs; + const unsigned int labelCount = qname.countLabels(); + bool isCNAMEAnswer = false; + for(const auto& rec : lwr.d_records) { + if (rec.d_class != QClass::IN) { + continue; + } + + if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname) { + isCNAMEAnswer = true; + } + + /* if we have a positive answer synthetized from a wildcard, + we need to store the corresponding NSEC/NSEC3 records proving + that the exact name did not exist in the negative cache */ + if(needWildcardProof) { + if (nsecTypes.count(rec.d_type)) { + authorityRecs.push_back(std::make_shared(rec)); + } + else if (rec.d_type == QType::RRSIG) { + auto rrsig = getRR(rec); + if (rrsig && nsecTypes.count(rrsig->d_type)) { + authorityRecs.push_back(std::make_shared(rec)); + } + } + } + if(rec.d_type == QType::RRSIG) { + auto rrsig = getRR(rec); + if (rrsig) { + /* As illustrated in rfc4035's Appendix B.6, the RRSIG label + count can be lower than the name's label count if it was + synthetized from the wildcard. Note that the difference might + be > 1. */ + if (rec.d_name == qname && rrsig->d_labels < labelCount) { + LOG(prefix<d_labels; + } + + // cerr<<"Got an RRSIG for "<d_type)<<" with name '"<d_type, rec.d_place}].signatures.push_back(rrsig); + tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signaturesTTL = std::min(tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signaturesTTL, rec.d_ttl); + } + } + } + + // reap all answers from this packet that are acceptable + for(auto& rec : lwr.d_records) { + if(rec.d_type == QType::OPT) { + LOG(prefix<getZoneRepresentation()<<"' from '"<empty()) { + // Check if we are authoritative for a zone in this answer + DNSName tmp_qname(rec.d_name); + auto auth_domain_iter=getBestAuthZone(&tmp_qname); + if(auth_domain_iter!=t_sstorage.domainmap->end() && + auth.countLabels() <= auth_domain_iter->first.countLabels()) { + if (auth_domain_iter->first != auth) { + LOG("NO! - we are authoritative for the zone "<first<second.records.size() + i->second.signatures.size()) > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2) + uint32_t lowestTTD=computeLowestTTD(i->second.records, i->second.signatures, i->second.signaturesTTL); + + for(auto& record : i->second.records) + record.d_ttl = lowestTTD; // boom + } + +// cout<<"Have "<second.records.size()<<" records and "<second.signatures.size()<<" signatures for "<first.name; +// cout<<'|'<first.type)<second.records.empty()) // this happens when we did store signatures, but passed on the records themselves + continue; + + /* Even if the AA bit is set, additional data cannot be considered + as authoritative. This is especially important during validation + because keeping records in the additional section is allowed even + if the corresponding RRSIGs are not included, without setting the TC + bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response: + "When placing a signed RRset in the Additional section, the name + server MUST also place its RRSIG RRs in the Additional section. + If space does not permit inclusion of both the RRset and its + associated RRSIG RRs, the name server MAY retain the RRset while + dropping the RRSIG RRs. If this happens, the name server MUST NOT + set the TC bit solely because these RRSIG RRs didn't fit." + */ + bool isAA = lwr.d_aabit && i->first.place != DNSResourceRecord::ADDITIONAL; + if (isAA && isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) { + /* + rfc2181 states: + Note that the answer section of an authoritative answer normally + contains only authoritative data. However when the name sought is an + alias (see section 10.1.1) only the record describing that alias is + necessarily authoritative. Clients should assume that other records + may have come from the server's cache. Where authoritative answers + are required, the client should query again, using the canonical name + associated with the alias. + */ + isAA = false; + } + + vState recordState = getValidationStatus(i->first.name, false); + LOG(d_prefix<<": got initial zone status "<first.name<first.place != DNSResourceRecord::ADDITIONAL) { + /* the additional entries can be insecure, + like glue: + "Glue address RRsets associated with delegations MUST NOT be signed" + */ + if (i->first.type == QType::DNSKEY && i->first.place == DNSResourceRecord::ANSWER) { + LOG(d_prefix<<"Validating DNSKEY for "<first.name<first.name, i->second.records, i->second.signatures, depth); + } + else { + LOG(d_prefix<<"Validating non-additional record for "<first.name<first.name, i->second.records, i->second.signatures); + /* we might have missed a cut (zone cut within the same auth servers), causing the NS query for an Insecure zone to seem Bogus during zone cut determination */ + if (qtype == QType::NS && i->second.signatures.empty() && recordState == Bogus && haveExactValidationStatus(i->first.name) && getValidationStatus(i->first.name) == Indeterminate) { + recordState = Indeterminate; + } + } + } + } + else { + recordState = Indeterminate; + + /* in a non authoritative answer, we only care about the DS record (or lack of) */ + if ((i->first.type == QType::DS || i->first.type == QType::NSEC || i->first.type == QType::NSEC3) && i->first.place == DNSResourceRecord::AUTHORITY) { + LOG(d_prefix<<"Validating DS record for "<first.name<first.name, i->second.records, i->second.signatures); + } + } + + if (initialState == Secure && state != recordState && isAA) { + updateValidationState(state, recordState); + } + } + else { + if (shouldValidate()) { + LOG(d_prefix<<"Skipping validation because the current state is "<first.type != QType::NSEC3) { + t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, recordState); + } + + if(i->first.place == DNSResourceRecord::ANSWER && ednsmask) + d_wasVariable=true; + } + + return RCode::NoError; +} + +void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry& ne, vState& state, const dState denialState, const dState expectedState, bool allowOptOut) +{ + if (denialState == expectedState) { + ne.d_validationState = Secure; + } + else { + if (denialState == OPTOUT && allowOptOut) { + LOG(d_prefix<<"OPT-out denial found for "<(rec)) { + newtarget=content->getTarget(); + } + } + /* if we have a positive answer synthetized from a wildcard, we need to + return the corresponding NSEC/NSEC3 records from the AUTHORITY section + proving that the exact name did not exist */ + else if(needWildcardProof && (rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::AUTHORITY) { + ret.push_back(rec); // enjoy your DNSSEC + } + // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively + else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname && + ( + rec.d_type==qtype.getCode() || ((lwr.d_aabit || sendRDQuery) && qtype == QType(QType::ANY)) + ) + ) + { + LOG(prefix<getZoneRepresentation()<<"|"< '"<getZoneRepresentation()<<"'"< '"<getZoneRepresentation()<<"', had '"<(rec)) { + nsset.insert(content->getNS()); + } + } + else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::DS && qname.isPartOf(rec.d_name)) { + LOG(prefix< '"<getZoneRepresentation()<<"'"<& ednsmask, const DNSName& auth, bool const sendRDQuery, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool* truncated) +{ + bool chained = false; + int resolveret = RCode::NoError; + s_outqueries++; + d_outqueries++; + + if(d_outqueries + d_throttledqueries > s_maxqperq) { + throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString()); + } + + if(s_maxtotusec && d_totUsec > s_maxtotusec) { + throw ImmediateServFailException("Too much time waiting for "+qname.toLogString()+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries) + ", queries: "+std::to_string(d_outqueries)+", "+std::to_string(d_totUsec/1000)+"msec"); + } + + if(doTCP) { + LOG(prefix<preoutquery(remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) { + LOG(prefix<toString()<<" to query"<toString()<<" on response"< 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP) >= s_serverdownmaxfails) { + LOG(prefix< 0) { + t_sstorage.fails.clear(remoteIP); + } + + if(lwr.d_tcbit) { + *truncated = true; + + if (doTCP) { + LOG(prefix< ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state) +{ + string prefix; + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + if(s_minimumTTL) { + for(auto& rec : lwr.d_records) { + rec.d_ttl = max(rec.d_ttl, s_minimumTTL); + } + } + + bool needWildcardProof = false; + unsigned int wildcardLabelsCount; + *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, wildcardLabelsCount); + if (*rcode != RCode::NoError) { + return true; + } + + LOG(prefix< nsset; + bool realreferral=false, negindic=false; + DNSName newauth; + DNSName newtarget; + + bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, state, needWildcardProof, wildcardLabelsCount); + + if(done){ + LOG(prefix< 10) { + LOG(prefix< beenthere2; + vState cnameState = Indeterminate; + *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2, cnameState); + LOG(prefix<&ret, + unsigned int depth, set&beenthere, vState& state) +{ + auto luaconfsLocal = g_luaconfs.getLocal(); + string prefix; + if(doLog()) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + LOG(prefix<dfe, nameservers)) { + return -2; + } + + LOG(endl); + + for(;;) { // we may get more specific nameservers + vector rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() ); + + for(auto tns=rnameservers.cbegin();;++tns) { + if(tns==rnameservers.cend()) { + LOG(prefix<doAgeCache(d_now.tv_sec, auth, QType::NS, 10)) + g_stats.nsSetInvalidations++; + } + return -1; + } + + bool cacheOnly = false; + // this line needs to identify the 'self-resolving' behaviour + if(qname == *tns && (qtype.getCode() == QType::A || qtype.getCode() == QType::AAAA)) { + /* we might have a glue entry in cache so let's try this NS + but only if we have enough in the cache to know how to reach it */ + LOG(prefix< remoteIPs_t; + remoteIPs_t remoteIPs; + remoteIPs_t::const_iterator remoteIP; + bool pierceDontQuery=false; + bool sendRDQuery=false; + boost::optional ednsmask; + LWResult lwr; + const bool wasForwarded = tns->empty() && (!nameservers[*tns].first.empty()); + int rcode = RCode::NoError; + bool gotNewServers = false; + + if(tns->empty() && !wasForwarded) { + LOG(prefix<dfe, &gotNewServers, &rcode, state); + if (done) { + return rcode; + } + if (gotNewServers) { + break; + } + } + else { + /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */ + remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet, cacheOnly); + + if(remoteIPs.empty()) { + LOG(prefix<toString()); + if(nameserverIPBlockedByRPZ(luaconfsLocal->dfe, *remoteIP)) { + hitPolicy = true; + } + } + LOG(endl); + if (hitPolicy) //implies d_wantsRPZ + return -2; + } + + for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) { + LOG(prefix<toStringWithPort() <<", asking '"<toString() <<"), rcode="<sin4.sin_family==AF_INET6) + lwr.d_usec/=3; + */ + // cout<<"msec: "<dfe, &gotNewServers, &rcode, state); + if (done) { + return rcode; + } + if (gotNewServers) { + break; + } + /* was lame */ + t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); + } + + if (gotNewServers) { + break; + } + + if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked + continue; + + } + } + } + return -1; +} + +void SyncRes::setIncomingECS(boost::optional incomingECS) +{ + d_incomingECS = incomingECS; + if (incomingECS) { + if (d_incomingECS->source.getBits() == 0) { + /* RFC7871 says we MUST NOT send any ECS if the source scope is 0. + But using an empty ECS in that case would mean inserting + a non ECS-specific entry into the cache, preventing any further + ECS-specific query to be sent. + So instead we use the trick described in section 7.1.2: + "The subsequent Recursive Resolver query to the Authoritative Nameserver + will then either not include an ECS option or MAY optionally include + its own address information, which is what the Authoritative + Nameserver will almost certainly use to generate any Tailored + Response in lieu of an option. This allows the answer to be handled + by the same caching mechanism as other queries, with an explicit + indicator of the applicable scope. Subsequent Stub Resolver queries + for /0 can then be answered from this cached response. + */ + d_incomingECS = s_ecsScopeZero; + d_incomingECSNetwork = s_ecsScopeZero.source.getMaskedNetwork(); + } + else { + uint8_t bits = std::min(incomingECS->source.getBits(), (incomingECS->source.isIpv4() ? s_ecsipv4limit : s_ecsipv6limit)); + d_incomingECS->source = Netmask(incomingECS->source.getNetwork(), bits); + d_incomingECSNetwork = d_incomingECS->source.getMaskedNetwork(); + } + } + else { + d_incomingECSNetwork = ComboAddress(); + } +} + +boost::optional SyncRes::getEDNSSubnetMask(const ComboAddress& local, const DNSName&dn, const ComboAddress& rem) +{ + boost::optional result; + ComboAddress trunc; + uint8_t bits; + if(d_incomingECSFound) { + trunc = d_incomingECSNetwork; + bits = d_incomingECS->source.getBits(); + } + else if(!local.isIPv4() || local.sin4.sin_addr.s_addr) { // detect unset 'requestor' + trunc = local; + bits = local.isIPv4() ? 32 : 128; + bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit)); + } + else { + /* nothing usable */ + return result; + } + + if(s_ednsdomains.check(dn) || s_ednssubnets.match(rem)) { + trunc.truncate(bits); + return boost::optional(Netmask(trunc, bits)); + } + + return result; +} + +void SyncRes::parseEDNSSubnetWhitelist(const std::string& wlist) +{ + vector parts; + stringtok(parts, wlist, ",; "); + for(const auto& a : parts) { + try { + s_ednssubnets.addMask(Netmask(a)); + } + catch(...) { + s_ednsdomains.add(DNSName(a)); + } + } +} + +// used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc +int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector& ret) +{ + struct timeval now; + gettimeofday(&now, 0); + + SyncRes sr(now); + int res = sr.beginResolve(qname, QType(qtype), qclass, ret); + + return res; +} + +int SyncRes::getRootNS(struct timeval now, asyncresolve_t asyncCallback) { + SyncRes sr(now); + sr.setDoEDNS0(true); + sr.setUpdatingRootNS(); + sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off); + sr.setDNSSECValidationRequested(g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate); + sr.setAsyncCallback(asyncCallback); + + vector ret; + int res=-1; + try { + res=sr.beginResolve(g_rootdnsname, QType(QType::NS), 1, ret); + if (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate) { + auto state = sr.getValidationState(); + if (state == Bogus) + throw PDNSException("Got Bogus validation result for .|NS"); + } + return res; + } + catch(const PDNSException& e) { + L< +#include +#endif + +#include +#include +#include "utility.hh" +#include "dns.hh" +#include "qtype.hh" +#include +#include +#include +#include +#include +#include +#include +#include "misc.hh" +#include "lwres.hh" +#include +#include +#include +#include "sstuff.hh" +#include "recursor_cache.hh" +#include "recpacketcache.hh" +#include +#include +#include +#include "mtasker.hh" +#include "iputils.hh" +#include "validate.hh" +#include "ednssubnet.hh" +#include "filterpo.hh" +#include "negcache.hh" + +class RecursorLua4; + +typedef map< + DNSName, + pair< + vector, + bool + > +> NsSet; + +template class Throttle : public boost::noncopyable +{ +public: + Throttle() + { + d_limit=3; + d_ttl=60; + d_last_clean=time(0); + } + bool shouldThrottle(time_t now, const Thing& t) + { + if(now > d_last_clean + 300 ) { + + d_last_clean=now; + for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) { + if( i->second.ttd < now) { + d_cont.erase(i++); + } + else + ++i; + } + } + + typename cont_t::iterator i=d_cont.find(t); + if(i==d_cont.end()) + return false; + if(now > i->second.ttd || i->second.count == 0) { + d_cont.erase(i); + return false; + } + i->second.count--; + + return true; // still listed, still blocked + } + void throttle(time_t now, const Thing& t, time_t ttl=0, unsigned int tries=0) + { + typename cont_t::iterator i=d_cont.find(t); + entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit}; + + if(i==d_cont.end()) { + d_cont[t]=e; + } + else if(i->second.ttd > e.ttd || (i->second.count) < e.count) + d_cont[t]=e; + } + + unsigned int size() const + { + return (unsigned int)d_cont.size(); + } + + void clear() + { + d_cont.clear(); + } +private: + unsigned int d_limit; + time_t d_ttl; + time_t d_last_clean; + struct entry + { + time_t ttd; + unsigned int count; + }; + typedef map cont_t; + cont_t d_cont; +}; + + +/** Class that implements a decaying EWMA. + This class keeps an exponentially weighted moving average which, additionally, decays over time. + The decaying is only done on get. +*/ +class DecayingEwma +{ +public: + DecayingEwma() : d_val(0.0) + { + d_needinit=true; + d_last.tv_sec = d_last.tv_usec = 0; + d_lastget=d_last; + } + + DecayingEwma(const DecayingEwma& orig) : d_last(orig.d_last), d_lastget(orig.d_lastget), d_val(orig.d_val), d_needinit(orig.d_needinit) + { + } + + void submit(int val, const struct timeval* tv) + { + struct timeval now=*tv; + + if(d_needinit) { + d_last=now; + d_lastget=now; + d_needinit=false; + d_val = val; + } + else { + float diff= makeFloat(d_last - now); + + d_last=now; + double factor=exp(diff)/2.0; // might be '0.5', or 0.0001 + d_val=(float)((1-factor)*val+ (float)factor*d_val); + } + } + + double get(const struct timeval* tv) + { + struct timeval now=*tv; + float diff=makeFloat(d_lastget-now); + d_lastget=now; + float factor=exp(diff/60.0f); // is 1.0 or less + return d_val*=factor; + } + + double peek(void) const + { + return d_val; + } + + bool stale(time_t limit) const + { + return limit > d_lastget.tv_sec; + } + +private: + struct timeval d_last; // stores time + struct timeval d_lastget; // stores time + float d_val; + bool d_needinit; +}; + +template class Counters : public boost::noncopyable +{ +public: + Counters() + { + } + unsigned long value(const Thing& t) const + { + typename cont_t::const_iterator i=d_cont.find(t); + + if(i==d_cont.end()) { + return 0; + } + return (unsigned long)i->second; + } + unsigned long incr(const Thing& t) + { + typename cont_t::iterator i=d_cont.find(t); + + if(i==d_cont.end()) { + d_cont[t]=1; + return 1; + } + else { + if (i->second < std::numeric_limits::max()) + i->second++; + return (unsigned long)i->second; + } + } + unsigned long decr(const Thing& t) + { + typename cont_t::iterator i=d_cont.find(t); + + if(i!=d_cont.end() && --i->second == 0) { + d_cont.erase(i); + return 0; + } else + return (unsigned long)i->second; + } + void clear(const Thing& t) + { + typename cont_t::iterator i=d_cont.find(t); + + if(i!=d_cont.end()) { + d_cont.erase(i); + } + } + void clear() + { + d_cont.clear(); + } + size_t size() const + { + return d_cont.size(); + } +private: + typedef map cont_t; + cont_t d_cont; +}; + + +class SyncRes : public boost::noncopyable +{ +public: + enum LogMode { LogNone, Log, Store}; + typedef std::function& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult *lwr, bool* chained)> asyncresolve_t; + + struct EDNSStatus + { + EDNSStatus() : mode(UNKNOWN), modeSetAt(0) {} + enum EDNSMode { UNKNOWN=0, EDNSOK=1, EDNSIGNORANT=2, NOEDNS=3 } mode; + time_t modeSetAt; + }; + + //! This represents a number of decaying Ewmas, used to store performance per nameserver-name. + /** Modelled to work mostly like the underlying DecayingEwma. After you've called get, + d_best is filled out with the best address for this collection */ + struct DecayingEwmaCollection + { + void submit(const ComboAddress& remote, int usecs, const struct timeval* now) + { + d_collection[remote].submit(usecs, now); + } + + double get(const struct timeval* now) + { + if(d_collection.empty()) + return 0; + double ret=std::numeric_limits::max(); + double tmp; + for (auto& entry : d_collection) { + if((tmp = entry.second.get(now)) < ret) { + ret=tmp; + d_best=entry.first; + } + } + + return ret; + } + + bool stale(time_t limit) const + { + for(const auto& entry : d_collection) + if(!entry.second.stale(limit)) + return false; + return true; + } + + void purge(const std::map& keep) + { + for (auto iter = d_collection.begin(); iter != d_collection.end(); ) { + if (keep.find(iter->first) != keep.end()) { + ++iter; + } + else { + iter = d_collection.erase(iter); + } + } + } + + typedef std::map collection_t; + collection_t d_collection; + ComboAddress d_best; + }; + + typedef map nsspeeds_t; + typedef map ednsstatus_t; + + vState getDSRecords(const DNSName& zone, dsmap_t& ds, bool onlyTA, unsigned int depth, bool bogusOnNXD=true, bool* foundCut=nullptr); + + class AuthDomain + { + public: + typedef multi_index_container < + DNSRecord, + indexed_by < + ordered_non_unique< + composite_key< DNSRecord, + member, + member + >, + composite_key_compare, std::less > + > + > + > records_t; + + records_t d_records; + vector d_servers; + DNSName d_name; + bool d_rdForward{false}; + + int getRecords(const DNSName& qname, uint16_t qtype, std::vector& records) const; + bool isAuth() const + { + return d_servers.empty(); + } + bool isForward() const + { + return !isAuth(); + } + bool shouldRecurse() const + { + return d_rdForward; + } + const DNSName& getName() const + { + return d_name; + } + + private: + void addSOA(std::vector& records) const; + }; + + typedef map domainmap_t; + typedef Throttle > throttle_t; + typedef Counters fails_t; + + struct ThreadLocalStorage { + NegCache negcache; + nsspeeds_t nsSpeeds; + throttle_t throttle; + ednsstatus_t ednsstatus; + fails_t fails; + std::shared_ptr domainmap; + }; + + static void setDefaultLogMode(LogMode lm) + { + s_lm = lm; + } + static void doEDNSDumpAndClose(int fd); + static uint64_t doDumpNSSpeeds(int fd); + static int getRootNS(struct timeval now, asyncresolve_t asyncCallback); + static void clearDelegationOnly() + { + s_delegationOnly.clear(); + } + static void addDelegationOnly(const DNSName& name) + { + s_delegationOnly.insert(name); + } + static void addDontQuery(const std::string& mask) + { + if (!s_dontQuery) + s_dontQuery = std::unique_ptr(new NetmaskGroup()); + + s_dontQuery->addMask(mask); + } + static void addDontQuery(const Netmask& mask) + { + if (!s_dontQuery) + s_dontQuery = std::unique_ptr(new NetmaskGroup()); + + s_dontQuery->addMask(mask); + } + static void clearDontQuery() + { + s_dontQuery = nullptr; + } + static void parseEDNSSubnetWhitelist(const std::string& wlist); + static void addEDNSSubnet(const Netmask& subnet) + { + s_ednssubnets.addMask(subnet); + } + static void addEDNSDomain(const DNSName& domain) + { + s_ednsdomains.add(domain); + } + static void clearEDNSSubnets() + { + s_ednssubnets.clear(); + } + static void clearEDNSDomains() + { + s_ednsdomains = SuffixMatchNode(); + } + static void pruneNSSpeeds(time_t limit) + { + for(auto i = t_sstorage.nsSpeeds.begin(), end = t_sstorage.nsSpeeds.end(); i != end; ) { + if(i->second.stale(limit)) { + i = t_sstorage.nsSpeeds.erase(i); + } + else { + ++i; + } + } + } + static uint64_t getNSSpeedsSize() + { + return t_sstorage.nsSpeeds.size(); + } + static void submitNSSpeed(const DNSName& server, const ComboAddress& ca, uint32_t usec, const struct timeval* now) + { + t_sstorage.nsSpeeds[server].submit(ca, usec, now); + } + static void clearNSSpeeds() + { + t_sstorage.nsSpeeds.clear(); + } + static EDNSStatus::EDNSMode getEDNSStatus(const ComboAddress& server) + { + const auto& it = t_sstorage.ednsstatus.find(server); + if (it == t_sstorage.ednsstatus.end()) + return EDNSStatus::UNKNOWN; + + return it->second.mode; + } + static uint64_t getEDNSStatusesSize() + { + return t_sstorage.ednsstatus.size(); + } + static void clearEDNSStatuses() + { + t_sstorage.ednsstatus.clear(); + } + static uint64_t getThrottledServersSize() + { + return t_sstorage.throttle.size(); + } + static void clearThrottle() + { + t_sstorage.throttle.clear(); + } + static bool isThrottled(time_t now, const ComboAddress& server, const DNSName& target, uint16_t qtype) + { + return t_sstorage.throttle.shouldThrottle(now, boost::make_tuple(server, target, qtype)); + } + static bool isThrottled(time_t now, const ComboAddress& server) + { + return t_sstorage.throttle.shouldThrottle(now, boost::make_tuple(server, "", 0)); + } + static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries) + { + t_sstorage.throttle.throttle(now, boost::make_tuple(server, "", 0), duration, tries); + } + static uint64_t getFailedServersSize() + { + return t_sstorage.fails.size(); + } + static void clearFailedServers() + { + t_sstorage.fails.clear(); + } + static unsigned long getServerFailsCount(const ComboAddress& server) + { + return t_sstorage.fails.value(server); + } + + static void clearNegCache() + { + t_sstorage.negcache.clear(); + } + + static uint64_t getNegCacheSize() + { + return t_sstorage.negcache.size(); + } + + static void pruneNegCache(unsigned int maxEntries) + { + t_sstorage.negcache.prune(maxEntries); + } + + static uint64_t wipeNegCache(const DNSName& name, bool subtree = false) + { + return t_sstorage.negcache.wipe(name, subtree); + } + + static void setDomainMap(std::shared_ptr newMap) + { + t_sstorage.domainmap = newMap; + } + + static const std::shared_ptr getDomainMap() + { + return t_sstorage.domainmap; + } + + static void setECSScopeZeroAddress(const Netmask& scopeZeroMask) + { + s_ecsScopeZero.source = scopeZeroMask; + } + + explicit SyncRes(const struct timeval& now); + + int beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector&ret); + void setId(int id) + { + if(doLog()) + d_prefix="["+itoa(id)+"] "; + } + + void setLogMode(LogMode lm) + { + d_lm = lm; + } + + bool doLog() const + { + return d_lm != LogNone; + } + + void setCacheOnly(bool state=true) + { + d_cacheonly=state; + } + + void setDoEDNS0(bool state=true) + { + d_doEDNS0=state; + } + + void setDoDNSSEC(bool state=true) + { + d_doDNSSEC=state; + } + + void setDNSSECValidationRequested(bool requested=true) + { + d_DNSSECValidationRequested = requested; + } + + bool isDNSSECValidationRequested() const + { + return d_DNSSECValidationRequested; + } + + bool shouldValidate() const + { + return d_DNSSECValidationRequested && !d_wasOutOfBand; + } + + void setWantsRPZ(bool state=true) + { + d_wantsRPZ=state; + } + + bool getWantsRPZ() const + { + return d_wantsRPZ; + } + + void setIncomingECSFound(bool state=true) + { + d_incomingECSFound=state; + } + + string getTrace() const + { + return d_trace.str(); + } + + void setLuaEngine(shared_ptr pdl) + { + d_pdl = pdl; + } + + bool wasVariable() const + { + return d_wasVariable; + } + + bool wasOutOfBand() const + { + return d_wasOutOfBand; + } + + struct timeval getNow() const + { + return d_now; + } + + void setSkipCNAMECheck(bool skip = false) + { + d_skipCNAMECheck = skip; + } + + void setIncomingECS(boost::optional incomingECS); + +#ifdef HAVE_PROTOBUF + void setInitialRequestId(boost::optional initialRequestId) + { + d_initialRequestId = initialRequestId; + } +#endif + + void setAsyncCallback(asyncresolve_t func) + { + d_asyncResolve = func; + } + + vState getValidationState() const + { + return d_queryValidationState; + } + + static thread_local ThreadLocalStorage t_sstorage; + + static std::atomic s_queries; + static std::atomic s_outgoingtimeouts; + static std::atomic s_outgoing4timeouts; + static std::atomic s_outgoing6timeouts; + static std::atomic s_throttledqueries; + static std::atomic s_dontqueries; + static std::atomic s_authzonequeries; + static std::atomic s_outqueries; + static std::atomic s_tcpoutqueries; + static std::atomic s_nodelegated; + static std::atomic s_unreachables; + static std::atomic s_ecsqueries; + static std::atomic s_ecsresponses; + + static string s_serverID; + static unsigned int s_minimumTTL; + static unsigned int s_maxqperq; + static unsigned int s_maxtotusec; + static unsigned int s_maxdepth; + static unsigned int s_maxnegttl; + static unsigned int s_maxcachettl; + static unsigned int s_packetcachettl; + static unsigned int s_packetcacheservfailttl; + static unsigned int s_serverdownmaxfails; + static unsigned int s_serverdownthrottletime; + static uint8_t s_ecsipv4limit; + static uint8_t s_ecsipv6limit; + static bool s_doIPv6; + static bool s_noEDNSPing; + static bool s_noEDNS; + static bool s_rootNXTrust; + static bool s_nopacketcache; + + std::unordered_map d_discardedPolicies; + DNSFilterEngine::Policy d_appliedPolicy; + unsigned int d_authzonequeries; + unsigned int d_outqueries; + unsigned int d_tcpoutqueries; + unsigned int d_throttledqueries; + unsigned int d_timeouts; + unsigned int d_unreachables; + unsigned int d_totUsec; + ComboAddress d_requestor; + +private: + + static std::unordered_set s_delegationOnly; + static NetmaskGroup s_ednssubnets; + static SuffixMatchNode s_ednsdomains; + static EDNSSubnetOpts s_ecsScopeZero; + static LogMode s_lm; + static std::unique_ptr s_dontQuery; + + struct GetBestNSAnswer + { + DNSName qname; + set > bestns; + uint8_t qtype; // only A and AAAA anyhow + bool operator<(const GetBestNSAnswer &b) const + { + return boost::tie(qname, qtype, bestns) < + boost::tie(b.qname, b.qtype, b.bestns); + } + }; + + typedef std::map zonesStates_t; + + int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector&ret, + unsigned int depth, set&beenthere, vState& state); + bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool* truncated); + bool processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state); + + int doResolve(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, set& beenthere, vState& state); + bool doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector&ret, int& res); + bool doOOBResolve(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, int &res); + domainmap_t::const_iterator getBestAuthZone(DNSName* qname) const; + bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, int &res, vState& state, bool wasAuthZone); + bool doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, const QType &qtype, vector&ret, unsigned int depth, int &res, vState& state); + void getBestNSFromCache(const DNSName &qname, const QType &qtype, vector&bestns, bool* flawedNSSet, unsigned int depth, set& beenthere); + DNSName getBestNSNamesFromCache(const DNSName &qname, const QType &qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set&beenthere); + + inline vector shuffleInSpeedOrder(NsSet &nameservers, const string &prefix); + bool moreSpecificThan(const DNSName& a, const DNSName &b) const; + vector getAddrs(const DNSName &qname, unsigned int depth, set& beenthere, bool cacheOnly); + + bool nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers); + bool nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress&); + bool throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery); + + vector retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector::const_iterator& tns, const unsigned int depth, set& beenthere, const vector& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly); + RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount); + bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector& ret, set& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const unsigned int wildcardLabelsCount); + + bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector &ret); + + int asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional& srcmask, LWResult* res, bool* chained) const; + + boost::optional getEDNSSubnetMask(const ComboAddress& local, const DNSName&dn, const ComboAddress& rem); + + bool validationEnabled() const; + uint32_t computeLowestTTD(const std::vector& records, const std::vector >& signatures, uint32_t signaturesTTL) const; + void updateValidationState(vState& state, const vState stateUpdate); + vState validateRecordsWithSigs(unsigned int depth, const DNSName& qname, const QType& qtype, const DNSName& name, const std::vector& records, const std::vector >& signatures); + vState validateDNSKeys(const DNSName& zone, const std::vector& dnskeys, const std::vector >& signatures, unsigned int depth); + vState getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth); + dState getDenialValidationState(NegCache::NegCacheEntry& ne, const vState state, const dState expectedState, bool referralToUnsigned); + void updateDenialValidationState(NegCache::NegCacheEntry& ne, vState& state, const dState denialState, const dState expectedState, bool allowOptOut); + void computeNegCacheValidationStatus(NegCache::NegCacheEntry& ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth); + vState getTA(const DNSName& zone, dsmap_t& ds); + bool haveExactValidationStatus(const DNSName& domain); + vState getValidationStatus(const DNSName& subdomain, bool allowIndeterminate=true); + + bool lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState); + void computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth); + + void setUpdatingRootNS() + { + d_updatingRootNS = true; + } + + zonesStates_t d_cutStates; + ostringstream d_trace; + shared_ptr d_pdl; + boost::optional d_incomingECS; + ComboAddress d_incomingECSNetwork; +#ifdef HAVE_PROTOBUF + boost::optional d_initialRequestId; +#endif + asyncresolve_t d_asyncResolve{nullptr}; + struct timeval d_now; + string d_prefix; + vState d_queryValidationState{Indeterminate}; + + /* When d_cacheonly is set to true, we will only check the cache. + * This is set when the RD bit is unset in the incoming query + */ + bool d_cacheonly; + bool d_doDNSSEC; + bool d_DNSSECValidationRequested{false}; + bool d_doEDNS0{true}; + bool d_incomingECSFound{false}; + bool d_requireAuthData{true}; + bool d_skipCNAMECheck{false}; + bool d_updatingRootNS{false}; + bool d_wantsRPZ{true}; + bool d_wasOutOfBand{false}; + bool d_wasVariable{false}; + + LogMode d_lm; +}; + +class Socket; +/* external functions, opaque to us */ +int asendtcp(const string& data, Socket* sock); +int arecvtcp(string& data, size_t len, Socket* sock, bool incompleteOkay); + + +struct PacketID +{ + PacketID() : id(0), type(0), sock(0), inNeeded(0), inIncompleteOkay(false), outPos(0), nearMisses(0), fd(-1) + { + remote.reset(); + } + + uint16_t id; // wait for a specific id/remote pair + uint16_t type; // and this is its type + ComboAddress remote; // this is the remote + DNSName domain; // this is the question + + Socket* sock; // or wait for an event on a TCP fd + string inMSG; // they'll go here + size_t inNeeded; // if this is set, we'll read until inNeeded bytes are read + bool inIncompleteOkay; + + string outMSG; // the outgoing message that needs to be sent + string::size_type outPos; // how far we are along in the outMSG + + typedef set chain_t; + mutable chain_t chain; + mutable uint32_t nearMisses; // number of near misses - host correct, id wrong + int fd; + + bool operator<(const PacketID& b) const + { + int ourSock= sock ? sock->getHandle() : 0; + int bSock = b.sock ? b.sock->getHandle() : 0; + if( tie(remote, ourSock, type) < tie(b.remote, bSock, b.type)) + return true; + if( tie(remote, ourSock, type) > tie(b.remote, bSock, b.type)) + return false; + + return tie(domain, fd, id) < tie(b.domain, b.fd, b.id); + } +}; + +struct PacketIDBirthdayCompare: public std::binary_function +{ + bool operator()(const PacketID& a, const PacketID& b) const + { + int ourSock= a.sock ? a.sock->getHandle() : 0; + int bSock = b.sock ? b.sock->getHandle() : 0; + if( tie(a.remote, ourSock, a.type) < tie(b.remote, bSock, b.type)) + return true; + if( tie(a.remote, ourSock, a.type) > tie(b.remote, bSock, b.type)) + return false; + + return a.domain < b.domain; + } +}; +extern thread_local std::unique_ptr t_RC; +extern thread_local std::unique_ptr t_packetCache; +typedef MTasker MT_t; +MT_t* getMT(); + +struct RecursorStats +{ + std::atomic servFails; + std::atomic nxDomains; + std::atomic noErrors; + std::atomic answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow; + std::atomic auth4Answers0_1, auth4Answers1_10, auth4Answers10_100, auth4Answers100_1000, auth4AnswersSlow; + std::atomic auth6Answers0_1, auth6Answers1_10, auth6Answers10_100, auth6Answers100_1000, auth6AnswersSlow; + std::atomic ourtime0_1, ourtime1_2, ourtime2_4, ourtime4_8, ourtime8_16, ourtime16_32, ourtimeSlow; + double avgLatencyUsec{0}; + double avgLatencyOursUsec{0}; + std::atomic qcounter; // not increased for unauth packets + std::atomic ipv6qcounter; + std::atomic tcpqcounter; + std::atomic unauthorizedUDP; // when this is increased, qcounter isn't + std::atomic unauthorizedTCP; // when this is increased, qcounter isn't + std::atomic policyDrops; + std::atomic tcpClientOverflow; + std::atomic clientParseError; + std::atomic serverParseError; + std::atomic tooOldDrops; + std::atomic queryPipeFullDrops; + std::atomic unexpectedCount; + std::atomic caseMismatchCount; + std::atomic spoofCount; + std::atomic resourceLimits; + std::atomic overCapacityDrops; + std::atomic ipv6queries; + std::atomic chainResends; + std::atomic nsSetInvalidations; + std::atomic ednsPingMatches; + std::atomic ednsPingMismatches; + std::atomic noPingOutQueries, noEdnsOutQueries; + std::atomic packetCacheHits; + std::atomic noPacketError; + std::atomic ignoredCount; + time_t startupTime; + std::atomic dnssecQueries; + unsigned int maxMThreadStackUsage; + std::atomic dnssecValidations; // should be the sum of all dnssecResult* stats + std::map > dnssecResults; + std::map > policyResults; +}; + +//! represents a running TCP/IP client session +class TCPConnection : public boost::noncopyable +{ +public: + TCPConnection(int fd, const ComboAddress& addr); + ~TCPConnection(); + + int getFD() const + { + return d_fd; + } + enum stateenum {BYTE0, BYTE1, GETQUESTION, DONE} state{BYTE0}; + uint16_t qlen{0}; + uint16_t bytesread{0}; + const ComboAddress d_remote; + char data[65535]; // damn + size_t queriesCount{0}; + + static unsigned int getCurrentConnections() { return s_currentConnections; } +private: + const int d_fd; + static AtomicCounter s_currentConnections; //!< total number of current TCP connections +}; + +class ImmediateServFailException +{ +public: + ImmediateServFailException(string r){reason=r;}; + + string reason; //! Print this to tell the user what went wrong +}; + +typedef boost::circular_buffer addrringbuf_t; +extern thread_local std::unique_ptr t_servfailremotes, t_largeanswerremotes, t_remotes; + +extern thread_local std::unique_ptr > > t_queryring, t_servfailqueryring; +extern thread_local std::shared_ptr t_allowFrom; +string doQueueReloadLuaScript(vector::const_iterator begin, vector::const_iterator end); +string doTraceRegex(vector::const_iterator begin, vector::const_iterator end); +void parseACLs(); +extern RecursorStats g_stats; +extern unsigned int g_numThreads; +extern uint16_t g_outgoingEDNSBufsize; +extern std::atomic g_maxCacheEntries, g_maxPacketCacheEntries; +extern bool g_lowercaseOutgoing; + + +std::string reloadAuthAndForwards(); +ComboAddress parseIPAndPort(const std::string& input, uint16_t port); +ComboAddress getQueryLocalAddress(int family, uint16_t port); +typedef boost::function pipefunc_t; +void broadcastFunction(const pipefunc_t& func); +void distributeAsyncFunction(const std::string& question, const pipefunc_t& func); + +int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector& ret); + +template T broadcastAccFunction(const boost::function& func); + +std::shared_ptr parseAuthAndForwards(); +uint64_t* pleaseGetNsSpeedsSize(); +uint64_t* pleaseGetCacheSize(); +uint64_t* pleaseGetNegCacheSize(); +uint64_t* pleaseGetCacheHits(); +uint64_t* pleaseGetCacheMisses(); +uint64_t* pleaseGetConcurrentQueries(); +uint64_t* pleaseGetThrottleSize(); +uint64_t* pleaseGetPacketCacheHits(); +uint64_t* pleaseGetPacketCacheSize(); +uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree=false); +uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree); +uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree=false); +void doCarbonDump(void*); +void primeHints(void); + +extern __thread struct timeval g_now; + +#ifdef HAVE_PROTOBUF +extern thread_local std::unique_ptr t_uuidGenerator; +#endif diff --git a/test-arguments_cc.cc b/test-arguments_cc.cc new file mode 100644 index 0000000..70f04f3 --- /dev/null +++ b/test-arguments_cc.cc @@ -0,0 +1,61 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include "arguments.hh" +#include "namespaces.hh" + +BOOST_AUTO_TEST_SUITE(test_arguments_cc) + +BOOST_AUTO_TEST_CASE(test_file_parse) { + char path[]="/tmp/pdns-test-conf.XXXXXX"; + int fd=mkstemp(path); + if(fd < 0) + BOOST_FAIL("Unable to generate a temporary file"); + + string config= +R"(launch=launch=1234 +test=123\ +456 +test2=here # and here it stops +fail=no +success=on +really=yes)"; + + int len=write(fd, config.c_str(), config.size()); + + BOOST_CHECK_EQUAL(len, config.size()); + if(!len) + return; + close(fd); + + try { + ArgvMap arg; + for(auto& a : {"launch", "test", "test2", "fail", "success", "really"} ) + arg.set(a,a); + arg.set("default", "default")="no"; + arg.file(path); + unlink(path); + + BOOST_CHECK_EQUAL(arg["launch"], "launch=1234"); + BOOST_CHECK_EQUAL(arg["test"], "123456"); + BOOST_CHECK_EQUAL(arg.asNum("test"), 123456); + BOOST_CHECK_EQUAL(arg["test2"], "here"); + BOOST_CHECK_EQUAL(arg.mustDo("fail"), false); + BOOST_CHECK_EQUAL(arg.mustDo("success"), true); + BOOST_CHECK_EQUAL(arg.mustDo("really"), true); + BOOST_CHECK_EQUAL(arg["default"], "no"); + + } + catch(PDNSException& e) { + unlink(path); + cerr<<"Exception: "< +#include + +#include +#include "base32.hh" + +BOOST_AUTO_TEST_SUITE(test_base32_cc) + +BOOST_AUTO_TEST_CASE(test_base32_basic) { + typedef boost::tuple case_t; + typedef std::list cases_t; + + // RFC test vectors + cases_t cases = boost::assign::list_of + (case_t(std::string(""), std::string(""))) + (case_t(std::string("f"), std::string("co======"))) + (case_t(std::string("fo"), std::string("cpng===="))) + (case_t(std::string("foo"), std::string("cpnmu==="))) + (case_t(std::string("foob"), std::string("cpnmuog="))) + (case_t(std::string("fooba"), std::string("cpnmuoj1"))) + (case_t(std::string("foobar"), std::string("cpnmuoj1e8======"))) + ; + + for(const case_t& val : cases) { + std::string res; + res = toBase32Hex(val.get<0>()); + BOOST_CHECK_EQUAL(res, val.get<1>()); + res = fromBase32Hex(val.get<1>()); + BOOST_CHECK_EQUAL(res, val.get<0>()); + } +}; + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/test-base64_cc.cc b/test-base64_cc.cc new file mode 100644 index 0000000..029e664 --- /dev/null +++ b/test-base64_cc.cc @@ -0,0 +1,77 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include "base64.hh" + +using namespace boost; + +BOOST_AUTO_TEST_SUITE(base64_cc) + +BOOST_AUTO_TEST_CASE(test_Base64_Roundtrip) { + std::string before("Some Random String"), after; + std::string encoded = Base64Encode(before); + B64Decode(encoded, after); + BOOST_CHECK_EQUAL(before, after); +} + +/* for a in $(seq 1 32); + do + plain=$(pwgen -1 -s $a) + echo \(\"$plain\",\"$(echo -n $plain | openssl enc -base64)\"\) ; + done +*/ + +BOOST_AUTO_TEST_CASE(test_Base64_Encode) { + typedef std::map cases_t; + cases_t cases; + assign::insert(cases) + ("", "") + ("z","eg==") + ("x4","eDQ=") + ("J07","SjA3") + ("kl8F","a2w4Rg==") + ("2NUx9","Mk5VeDk=") + ("hwXQ8C","aHdYUThD") + ("V7ZHmlG","VjdaSG1sRw==") + ("FuNFLSd5","RnVORkxTZDU=") + ("YVGwy3Vbi","WVZHd3kzVmJp") + ("6ueW4V3oLG","NnVlVzRWM29MRw==") + ("d5zR7AWIBIQ","ZDV6UjdBV0lCSVE=") + ("WJjZ6xgpRMCD","V0pqWjZ4Z3BSTUNE") + ("e8I52L0vC9Kfq","ZThJNTJMMHZDOUtmcQ==") + ("ufxMi8EZgTDja8","dWZ4TWk4RVpnVERqYTg=") + ("MiNPxzxUkNXCFg1","TWlOUHh6eFVrTlhDRmcx") + ("abqIPosEky85gFVM","YWJxSVBvc0VreTg1Z0ZWTQ==") + ("Qccuox8igoyRKEeTo","UWNjdW94OGlnb3lSS0VlVG8=") + ("wbaw6g6WWo4iiYXosV","d2JhdzZnNldXbzRpaVlYb3NW") + ("ZIfJZIA3Kd0a6iIr0vc","WklmSlpJQTNLZDBhNmlJcjB2Yw==") + ("SUhE1RK7xrRfvYOiaPMQ","U1VoRTFSSzd4clJmdllPaWFQTVE=") + ("ZAWsEeB4bcTUzTr828VTd","WkFXc0VlQjRiY1RVelRyODI4VlRk") + ("xc9rpu0F5ztR7r3jElr2BS","eGM5cnB1MEY1enRSN3IzakVscjJCUw==") + ("xvEWPkZjqVjIZwsL5WhijES","eHZFV1BrWmpxVmpJWndzTDVXaGlqRVM=") + ("yy4yAmcBKCNF3hWriWbDnKmF","eXk0eUFtY0JLQ05GM2hXcmlXYkRuS21G") + ("9wKEMpl8OlFvnD10wwhoK7BjY","OXdLRU1wbDhPbEZ2bkQxMHd3aG9LN0JqWQ==") + ("SB6yLm39pDVIUiQ5g73BvyRzBs","U0I2eUxtMzlwRFZJVWlRNWc3M0J2eVJ6QnM=") + ("Acu4kk1puF98lIzd1b9bt8ha7Er","QWN1NGtrMXB1Rjk4bEl6ZDFiOWJ0OGhhN0Vy") + ("P4X6efItE6cn03ksLTvniqMQlel3","UDRYNmVmSXRFNmNuMDNrc0xUdm5pcU1RbGVsMw==") + ("RnQSvhIOz3ywuHCoSotJGKjBdCVbx","Um5RU3ZoSU96M3l3dUhDb1NvdEpHS2pCZENWYng=") + ("ykybXtN0lelsLSzyzd4DTP3sYp8YGu","eWt5Ylh0TjBsZWxzTFN6eXpkNERUUDNzWXA4WUd1") + ("eSHBt7Xx5F7A4HFtabXEzDLD01bnSiG","ZVNIQnQ3WHg1RjdBNEhGdGFiWEV6RExEMDFiblNpRw==") + ("dq4KydZjmcoQQ45VYBP2EDR8FqKaMul0","ZHE0S3lkWmptY29RUTQ1VllCUDJFRFI4RnFLYU11bDA="); + + for(const cases_t::value_type& val : cases) { + std::string encoded = Base64Encode(val.first), decoded; + BOOST_CHECK_EQUAL(encoded, val.second); + decoded.clear(); + B64Decode(val.second, decoded); + BOOST_CHECK_EQUAL(decoded, val.first); + } +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-common.hh b/test-common.hh new file mode 100644 index 0000000..50de3b7 --- /dev/null +++ b/test-common.hh @@ -0,0 +1,42 @@ + +#include "dnsrecords.hh" +#include "iputils.hh" + +static inline std::shared_ptr getRecordContent(uint16_t type, const std::string& content) +{ + std::shared_ptr result = nullptr; + + if (type == QType::NS) { + result = std::make_shared(DNSName(content)); + } + else if (type == QType::A) { + result = std::make_shared(ComboAddress(content)); + } + else if (type == QType::AAAA) { + result = std::make_shared(ComboAddress(content)); + } + else if (type == QType::CNAME) { + result = std::make_shared(DNSName(content)); + } + else if (type == QType::OPT) { + result = std::make_shared(); + } + else { + result = DNSRecordContent::mastermake(type, QClass::IN, content); + } + + return result; +} + +static inline void addRecordToList(std::vector& records, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=3600) +{ + DNSRecord rec; + rec.d_place = place; + rec.d_name = name; + rec.d_type = type; + rec.d_ttl = ttl; + + rec.d_content = getRecordContent(type, content); + + records.push_back(rec); +} diff --git a/test-dns_random_hh.cc b/test-dns_random_hh.cc new file mode 100644 index 0000000..1dda1ad --- /dev/null +++ b/test-dns_random_hh.cc @@ -0,0 +1,57 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +// Disable this code for gcc 4.8 and lower +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ > 8) || !__GNUC__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include +#include +#include +#include + +#include "dns_random.hh" +#include "namespaces.hh" + + +using namespace boost; +using namespace boost::accumulators; + +typedef accumulator_set< + double + , stats + > acc_t; + + + +BOOST_AUTO_TEST_SUITE(test_dns_random_hh) + + + +BOOST_AUTO_TEST_CASE(test_dns_random_average) { + + dns_random_init("loremipsumdolorx"); + acc_t acc; + + for(unsigned int n=0; n < 100000; ++n) { + acc(dns_random(100000)/100000.0); + } + BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2% + BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0); + + + // please add covariance tests, chi-square, Kolmogorov-Smirnov +} + + + +BOOST_AUTO_TEST_SUITE_END() + +#endif diff --git a/test-dnsname_cc.cc b/test-dnsname_cc.cc new file mode 100644 index 0000000..42c8401 --- /dev/null +++ b/test-dnsname_cc.cc @@ -0,0 +1,893 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#include +#include +#include +#include +#include "dnsname.hh" +#include "misc.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" +#include +using namespace boost; +using std::string; + +BOOST_AUTO_TEST_SUITE(dnsname_cc) + +BOOST_AUTO_TEST_CASE(test_basic) { + string before("www.ds9a.nl."); + DNSName b(before); + BOOST_CHECK_EQUAL(b.getRawLabels().size(), 3); + string after(b.toString()); + BOOST_CHECK_EQUAL(before, after); + + DNSName jpmens("ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test."); + + BOOST_CHECK_EQUAL(jpmens.toString(), "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test."); + + DNSName wwwds9anl("www.ds9a.nl."); + DNSName wwwds9anl1("www.ds9a\002nl."); + DNSName nl("nl."); + BOOST_CHECK(wwwds9anl.isPartOf(nl)); + BOOST_CHECK(!wwwds9anl1.isPartOf(nl)); + BOOST_CHECK(wwwds9anl.isPartOf(wwwds9anl)); + + BOOST_CHECK(!nl.isPartOf(wwwds9anl)); + + BOOST_CHECK(wwwds9anl == wwwds9anl); + + BOOST_CHECK(DNSName("wWw.ds9A.Nl.") == DNSName("www.ds9a.nl.")); + BOOST_CHECK(DNSName("www.ds9a.nl.") == DNSName("www.ds9a.nl.")); + + BOOST_CHECK(DNSName("www.ds9a.nl.").toString() == "www.ds9a.nl."); + + + { // Check root vs empty + DNSName name("."); // root + DNSName parent; // empty + BOOST_CHECK(name != parent); + } + + { // Check name part of root + DNSName name("a."); + DNSName parent("."); + BOOST_CHECK(name.isPartOf(parent)); + } + + { // Label boundary + DNSName name("a\002bb."); + DNSName parent("bb."); + BOOST_CHECK(!name.isPartOf(parent)); + } + + { // Multi label parent + DNSName name("a.bb.ccc.dddd."); + DNSName parent("ccc.dddd."); + BOOST_CHECK(name.isPartOf(parent)); + } + + { // Last char diff + DNSName name("a.bb.ccc.dddd."); + DNSName parent("ccc.dddx."); + BOOST_CHECK(!name.isPartOf(parent)); + } + + { // Equal length identical + DNSName name("aaaa.bbb.cc.d."); + DNSName parent("aaaa.bbb.cc.d."); + BOOST_CHECK(name.isPartOf(parent)); + } + + { // Equal length first char diff + DNSName name("xaaa.bbb.cc.d."); + DNSName parent("aaaa.bbb.cc.d."); + BOOST_CHECK(!name.isPartOf(parent)); + } + + { // Make relative + DNSName name("aaaa.bbb.cc.d."); + DNSName parent("cc.d."); + BOOST_CHECK_EQUAL( name.makeRelative(parent), DNSName("aaaa.bbb.")); + } + + { // Labelreverse + DNSName name("aaaa.bbb.cc.d."); + BOOST_CHECK( name.labelReverse() == DNSName("d.cc.bbb.aaaa.")); + } + + { // empty() empty + DNSName name; + BOOST_CHECK(name.empty()); + } + + { // empty() root + DNSName name("."); + BOOST_CHECK(!name.empty()); + + DNSName rootnodot(""); + BOOST_CHECK_EQUAL(name, rootnodot); + + string empty; + DNSName rootnodot2(empty); + BOOST_CHECK_EQUAL(rootnodot2, name); + } + + DNSName left("ds9a.nl."); + left.prependRawLabel("www"); + BOOST_CHECK( left == DNSName("WwW.Ds9A.Nl.")); + + left.appendRawLabel("com"); + + BOOST_CHECK( left == DNSName("WwW.Ds9A.Nl.com.")); + + DNSName unset; + + unset.appendRawLabel("www"); + unset.appendRawLabel("powerdns.com"); + unset.appendRawLabel("com"); + + BOOST_CHECK_EQUAL(unset.toString(), "www.powerdns\\.com.com."); + + DNSName rfc4343_2_2(R"(Donald\032E\.\032Eastlake\0323rd.example.)"); + DNSName example("example."); + BOOST_CHECK(rfc4343_2_2.isPartOf(example)); + + auto labels=rfc4343_2_2.getRawLabels(); + BOOST_CHECK_EQUAL(*labels.begin(), "Donald E. Eastlake 3rd"); + BOOST_CHECK_EQUAL(*labels.rbegin(), "example"); + BOOST_CHECK_EQUAL(labels.size(), 2); + + + DNSName build; + build.appendRawLabel("Donald E. Eastlake 3rd"); + build.appendRawLabel("example"); + BOOST_CHECK_EQUAL(build.toString(), R"(Donald\032E\.\032Eastlake\0323rd.example.)"); + BOOST_CHECK_THROW(DNSName broken("bert..hubert."), std::runtime_error); + + DNSName n; + n.appendRawLabel("powerdns.dnsmaster"); + n.appendRawLabel("powerdns"); + n.appendRawLabel("com"); + + BOOST_CHECK_EQUAL(n.toString(), "powerdns\\.dnsmaster.powerdns.com."); + + // BOOST_CHECK(DNSName().toString() != "."); + + DNSName p; + string label("power"); + label.append(1, (char)0); + label.append("dns"); + p.appendRawLabel(label); + p.appendRawLabel("com"); + + BOOST_CHECK_EQUAL(p.toString(), "power\\000dns.com."); +} + +BOOST_AUTO_TEST_CASE(test_trim) { + DNSName w("www.powerdns.com."); + BOOST_CHECK_EQUAL(w.countLabels(), 3); + w.trimToLabels(2); + BOOST_CHECK_EQUAL(w.toString(), "powerdns.com."); + DNSName w2("powerdns.com."); + BOOST_CHECK(w==w2); + + DNSName root("."); + BOOST_CHECK_EQUAL(root.countLabels(), 0); +} + +BOOST_AUTO_TEST_CASE(test_toolong) { + + BOOST_CHECK_THROW(DNSName w("1234567890123456789012345678901234567890123456789012345678901234567890.com."), std::range_error); + + BOOST_CHECK_THROW(DNSName w("12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.234567890.789012345678901.234567890.234567890.789012345678901.234567890.234567890.com."), std::range_error); +} + +BOOST_AUTO_TEST_CASE(test_dnsstrings) { + DNSName w("www.powerdns.com."); + BOOST_CHECK_EQUAL(w.toDNSString(), string("\003www\010powerdns\003com\000", 18)); +} + +BOOST_AUTO_TEST_CASE(test_empty) { + DNSName empty; + BOOST_CHECK_THROW(empty.toString(), std::out_of_range); + BOOST_CHECK_THROW(empty.toStringNoDot(), std::out_of_range); + BOOST_CHECK_THROW(empty.toDNSString(), std::out_of_range); + BOOST_CHECK(empty.empty()); + BOOST_CHECK(!empty.isRoot()); + BOOST_CHECK(!empty.isWildcard()); + BOOST_CHECK_EQUAL(empty, empty); + BOOST_CHECK(!(empty < empty)); + + DNSName root("."); + BOOST_CHECK(empty < root); + + BOOST_CHECK_THROW(empty.isPartOf(root), std::out_of_range); + BOOST_CHECK_THROW(root.isPartOf(empty), std::out_of_range); +} + +BOOST_AUTO_TEST_CASE(test_specials) { + DNSName root("."); + + BOOST_CHECK(root.isRoot()); + BOOST_CHECK(root != DNSName()); + + DNSName wcard("*.powerdns.com"); + BOOST_CHECK(wcard.isWildcard()); + + DNSName notwcard("www.powerdns.com"); + BOOST_CHECK(!notwcard.isWildcard()); +} + + +BOOST_AUTO_TEST_CASE(test_chopping) { + DNSName w("www.powerdns.com."); + BOOST_CHECK_EQUAL(w.toString(), "www.powerdns.com."); + BOOST_CHECK(w.chopOff()); + BOOST_CHECK_EQUAL(w.toString(), "powerdns.com."); + BOOST_CHECK(w.chopOff()); + BOOST_CHECK_EQUAL(w.toString(), "com."); + BOOST_CHECK(w.chopOff()); + BOOST_CHECK_EQUAL(w.toString(), "."); + BOOST_CHECK(!w.chopOff()); + BOOST_CHECK(!w.chopOff()); + + w.prependRawLabel("net"); + w.prependRawLabel("root-servers"); + w.prependRawLabel("a"); + BOOST_CHECK_EQUAL(w.toString(), "a.root-servers.net."); +} + +BOOST_AUTO_TEST_CASE(test_Append) { + DNSName dn("www."), powerdns("powerdns.com."); + DNSName tot=dn+powerdns; + + BOOST_CHECK_EQUAL(tot.toString(), "www.powerdns.com."); + BOOST_CHECK(tot == DNSName("www.powerdns.com.")); + + dn+=powerdns; + + BOOST_CHECK(dn == DNSName("www.powerdns.com.")); +} + +BOOST_AUTO_TEST_CASE(test_packetCompress) { + reportBasicTypes(); + vector packet; + DNSPacketWriter dpw(packet, DNSName("www.ds9a.nl."), QType::AAAA); + dpw.startRecord(DNSName("ds9a.nl"), QType::SOA); + SOARecordContent src("ns1.powerdns.nl admin.powerdns.nl 1 2 3 4 5"); + src.toPacket(dpw); + AAAARecordContent aaaa("::1"); + dpw.startRecord(DNSName("www.dS9A.nl"), QType::AAAA); + aaaa.toPacket(dpw); + dpw.startRecord(DNSName("www.ds9A.nl"), QType::AAAA); + aaaa.toPacket(dpw); + dpw.startRecord(DNSName("www.dS9a.nl"), QType::AAAA); + aaaa.toPacket(dpw); + dpw.startRecord(DNSName("www2.DS9a.nl"), QType::AAAA); + aaaa.toPacket(dpw); + dpw.startRecord(DNSName("www2.dS9a.nl"), QType::AAAA); + aaaa.toPacket(dpw); + dpw.commit(); + string str((const char*)&packet[0], (const char*)&packet[0] + packet.size()); + size_t pos = 0; + int count=0; + while((pos = str.find("ds9a", pos)) != string::npos) { + ++pos; + ++count; + } + BOOST_CHECK_EQUAL(count, 1); + pos = 0; + count=0; + while((pos = str.find("powerdns", pos)) != string::npos) { + ++pos; + ++count; + } + BOOST_CHECK_EQUAL(count, 1); + +} + +BOOST_AUTO_TEST_CASE(test_packetCompressLong) { + reportBasicTypes(); + vector packet; + DNSName loopback("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa"); + DNSPacketWriter dpw(packet, loopback, QType::PTR); + + dpw.startRecord(loopback, QType::PTR); + PTRRecordContent prc(DNSName("localhost")); + prc.toPacket(dpw); + dpw.commit(); + DNSName roundtrip((char*)&packet[0], packet.size(), 12, false); + BOOST_CHECK_EQUAL(loopback,roundtrip); + + packet.clear(); + DNSName longer("1.2.3.4.5.6.7.8.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa"); + DNSPacketWriter dpw2(packet, longer, QType::PTR); + + dpw2.startRecord(DNSName("a.b.c.d.e")+longer, QType::PTR); + PTRRecordContent prc2(DNSName("localhost")); + prc2.toPacket(dpw2); + dpw2.commit(); + +} + + + + +BOOST_AUTO_TEST_CASE(test_PacketParse) { + vector packet; + reportBasicTypes(); + DNSName root("."); + DNSPacketWriter dpw1(packet, g_rootdnsname, QType::AAAA); + DNSName p((char*)&packet[0], packet.size(), 12, false); + BOOST_CHECK_EQUAL(p, root); + unsigned char* buffer=&packet[0]; + /* set invalid label len: + - packet.size() == 17 (sizeof(dnsheader) + 1 + 2 + 2) + - label len < packet.size() but + - offset is 12, label len of 15 should be rejected + because offset + 15 >= packet.size() + */ + buffer[sizeof(dnsheader)] = 15; + BOOST_CHECK_THROW(DNSName((char*)&packet[0], packet.size(), 12, false), std::range_error); +} + + +BOOST_AUTO_TEST_CASE(test_hash) { + DNSName a("wwW.Ds9A.Nl"), b("www.ds9a.nl"); + BOOST_CHECK_EQUAL(a.hash(), b.hash()); + + vector counts(1500); + + for(unsigned int n=0; n < 100000; ++n) { + DNSName dn(std::to_string(n)+"."+std::to_string(n*2)+"ds9a.nl"); + DNSName dn2(std::to_string(n)+"."+std::to_string(n*2)+"Ds9a.nL"); + BOOST_CHECK_EQUAL(dn.hash(), dn2.hash()); + counts[dn.hash() % counts.size()]++; + } + + double sum = std::accumulate(std::begin(counts), std::end(counts), 0.0); + double m = sum / counts.size(); + + double accum = 0.0; + std::for_each (std::begin(counts), std::end(counts), [&](const double d) { + accum += (d - m) * (d - m); + }); + + double stdev = sqrt(accum / (counts.size()-1)); + BOOST_CHECK(stdev < 10); +} + +BOOST_AUTO_TEST_CASE(test_hashContainer) { + std::unordered_set s; + s.insert(DNSName("www.powerdns.com")); + BOOST_CHECK(s.count(DNSName("WwW.PoWerDNS.CoM"))); + BOOST_CHECK_EQUAL(s.size(), 1); + s.insert(DNSName("www.POWERDNS.com")); + BOOST_CHECK_EQUAL(s.size(), 1); + s.insert(DNSName("www2.POWERDNS.com")); + BOOST_CHECK_EQUAL(s.size(), 2); + + s.clear(); + unsigned int n=0; + for(; n < 100000; ++n) + s.insert(DNSName(std::to_string(n)+".test.nl")); + BOOST_CHECK_EQUAL(s.size(), n); + +} + + +BOOST_AUTO_TEST_CASE(test_QuestionHash) { + vector packet; + reportBasicTypes(); + DNSPacketWriter dpw1(packet, DNSName("www.ds9a.nl."), QType::AAAA); + + auto hash1=hashQuestion((char*)&packet[0], packet.size(), 0); + DNSPacketWriter dpw2(packet, DNSName("wWw.Ds9A.nL."), QType::AAAA); + auto hash2=hashQuestion((char*)&packet[0], packet.size(), 0); + BOOST_CHECK_EQUAL(hash1, hash2); + + vector counts(1500); + + for(unsigned int n=0; n < 100000; ++n) { + packet.clear(); + DNSPacketWriter dpw3(packet, DNSName(std::to_string(n)+"."+std::to_string(n*2)+"."), QType::AAAA); + counts[hashQuestion((char*)&packet[0], packet.size(), 0) % counts.size()]++; + } + + double sum = std::accumulate(std::begin(counts), std::end(counts), 0.0); + double m = sum / counts.size(); + + double accum = 0.0; + std::for_each (std::begin(counts), std::end(counts), [&](const double d) { + accum += (d - m) * (d - m); + }); + + double stdev = sqrt(accum / (counts.size()-1)); + BOOST_CHECK(stdev < 10); +} + + +BOOST_AUTO_TEST_CASE(test_packetParse) { + vector packet; + reportBasicTypes(); + DNSPacketWriter dpw(packet, DNSName("www.ds9a.nl."), QType::AAAA); + + uint16_t qtype, qclass; + DNSName dn((char*)&packet[0], packet.size(), 12, false, &qtype, &qclass); + BOOST_CHECK_EQUAL(dn.toString(), "www.ds9a.nl."); + BOOST_CHECK(qtype == QType::AAAA); + BOOST_CHECK_EQUAL(qclass, 1); + + dpw.startRecord(DNSName("ds9a.nl."), DNSRecordContent::TypeToNumber("NS")); + NSRecordContent nrc("ns1.powerdns.com"); + nrc.toPacket(dpw); + + dpw.commit(); + + /* packet now looks like this: + 012345678901 12 bytes of header + 3www4ds9a2nl0 13 bytes of name + 0001 0001 4 bytes of qtype and qclass + answername 2 bytes + 0001 0001 4 bytes of qtype and class + 0000 0000 4 bytes of TTL + 0000 2 bytes of content length + content name */ + + DNSName dn2((char*)&packet[0], packet.size(), 12+13+4, true, &qtype, &qclass); + BOOST_CHECK_EQUAL(dn2.toString(), "ds9a.nl."); + BOOST_CHECK(qtype == QType::NS); + BOOST_CHECK_EQUAL(qclass, 1); + + DNSName dn3((char*)&packet[0], packet.size(), 12+13+4+2 + 4 + 4 + 2, true); + BOOST_CHECK_EQUAL(dn3.toString(), "ns1.powerdns.com."); + try { + DNSName dn4((char*)&packet[0], packet.size(), 12+13+4, false); // compressed, should fail + BOOST_CHECK(0); + } + catch(...){} +} + +BOOST_AUTO_TEST_CASE(test_escaping) { + DNSName n; + string label; + + for(int i = 0; i < 250; ++i) { + if(!((i+1)%63)) { + n.appendRawLabel(label); + label.clear(); + } + label.append(1,(char)i); + } + if(!label.empty()) + n.appendRawLabel(label); + + DNSName n2(n.toString()); + BOOST_CHECK(n==n2); +} + +BOOST_AUTO_TEST_CASE(test_suffixmatch) { + SuffixMatchNode smn; + DNSName ezdns("ezdns.it."); + smn.add(ezdns.getRawLabels()); + + smn.add(DNSName("org.").getRawLabels()); + + DNSName wwwpowerdnscom("www.powerdns.com."); + DNSName wwwezdnsit("www.ezdns.it."); + BOOST_CHECK(smn.check(wwwezdnsit)); + BOOST_CHECK(!smn.check(wwwpowerdnscom)); + + BOOST_CHECK(smn.check(DNSName("www.powerdns.org."))); + BOOST_CHECK(smn.check(DNSName("www.powerdns.oRG."))); + + smn.add(DNSName("news.bbc.co.uk.")); + BOOST_CHECK(smn.check(DNSName("news.bbc.co.uk."))); + BOOST_CHECK(smn.check(DNSName("www.news.bbc.co.uk."))); + BOOST_CHECK(smn.check(DNSName("www.www.www.www.www.news.bbc.co.uk."))); + BOOST_CHECK(!smn.check(DNSName("images.bbc.co.uk."))); + + BOOST_CHECK(!smn.check(DNSName("www.news.gov.uk."))); + + smn.add(g_rootdnsname); // block the root + BOOST_CHECK(smn.check(DNSName("a.root-servers.net."))); + + DNSName examplenet("example.net."); + DNSName net("net."); + smn.add(examplenet); + smn.add(net); + BOOST_CHECK(smn.check(examplenet)); + BOOST_CHECK(smn.check(net)); +} + +BOOST_AUTO_TEST_CASE(test_suffixmatch_tree) { + SuffixMatchTree smt; + DNSName ezdns("ezdns.it."); + smt.add(ezdns, ezdns); + + smt.add(DNSName("org.").getRawLabels(), DNSName("org.")); + + DNSName wwwpowerdnscom("www.powerdns.com."); + DNSName wwwezdnsit("www.ezdns.it."); + BOOST_REQUIRE(smt.lookup(wwwezdnsit)); + BOOST_CHECK_EQUAL(*smt.lookup(wwwezdnsit), ezdns); + BOOST_CHECK(smt.lookup(wwwpowerdnscom) == nullptr); + + BOOST_REQUIRE(smt.lookup(DNSName("www.powerdns.org."))); + BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.powerdns.org.")), DNSName("org.")); + BOOST_REQUIRE(smt.lookup(DNSName("www.powerdns.oRG."))); + BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.powerdns.oRG.")), DNSName("org.")); + + smt.add(DNSName("news.bbc.co.uk."), DNSName("news.bbc.co.uk.")); + BOOST_REQUIRE(smt.lookup(DNSName("news.bbc.co.uk."))); + BOOST_CHECK_EQUAL(*smt.lookup(DNSName("news.bbc.co.uk.")), DNSName("news.bbc.co.uk.")); + BOOST_REQUIRE(smt.lookup(DNSName("www.news.bbc.co.uk."))); + BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.news.bbc.co.uk.")), DNSName("news.bbc.co.uk.")); + BOOST_REQUIRE(smt.lookup(DNSName("www.www.www.www.www.news.bbc.co.uk."))); + BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.www.www.www.www.news.bbc.co.uk.")), DNSName("news.bbc.co.uk.")); + BOOST_CHECK(smt.lookup(DNSName("images.bbc.co.uk.")) == nullptr); + BOOST_CHECK(smt.lookup(DNSName("www.news.gov.uk.")) == nullptr); + + smt.add(g_rootdnsname, g_rootdnsname); // block the root + BOOST_REQUIRE(smt.lookup(DNSName("a.root-servers.net."))); + BOOST_CHECK_EQUAL(*smt.lookup(DNSName("a.root-servers.net.")), g_rootdnsname); + + DNSName apowerdnscom("a.powerdns.com."); + DNSName bpowerdnscom("b.powerdns.com."); + smt.add(apowerdnscom, apowerdnscom); + smt.add(bpowerdnscom, bpowerdnscom); + BOOST_REQUIRE(smt.lookup(apowerdnscom)); + BOOST_CHECK_EQUAL(*smt.lookup(apowerdnscom), apowerdnscom); + BOOST_REQUIRE(smt.lookup(bpowerdnscom)); + BOOST_CHECK_EQUAL(*smt.lookup(bpowerdnscom), bpowerdnscom); + + DNSName examplenet("example.net."); + DNSName net("net."); + smt.add(examplenet, examplenet); + smt.add(net, net); + BOOST_REQUIRE(smt.lookup(examplenet)); + BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet); + BOOST_REQUIRE(smt.lookup(net)); + BOOST_CHECK_EQUAL(*smt.lookup(net), net); +} + + +BOOST_AUTO_TEST_CASE(test_concat) { + DNSName first("www."), second("powerdns.com."); + BOOST_CHECK_EQUAL((first+second).toString(), "www.powerdns.com."); +} + +BOOST_AUTO_TEST_CASE(test_compare_naive) { + BOOST_CHECK(DNSName("abc.com.") < DNSName("zdf.com.")); + BOOST_CHECK(DNSName("Abc.com.") < DNSName("zdf.com.")); + BOOST_CHECK(DNSName("Abc.com.") < DNSName("Zdf.com.")); + BOOST_CHECK(DNSName("abc.com.") < DNSName("Zdf.com.")); +} + +BOOST_AUTO_TEST_CASE(test_compare_empty) { + DNSName a, b; + BOOST_CHECK(!(a vec; + for(const std::string& b : {"bert.com.", "alpha.nl.", "articles.xxx.", + "Aleph1.powerdns.com.", "ZOMG.powerdns.com.", "aaa.XXX.", "yyy.XXX.", + "test.powerdns.com.", "\\128.com"}) { + vec.push_back(DNSName(b)); + } + sort(vec.begin(), vec.end(), CanonDNSNameCompare()); + // for(const auto& v : vec) + // cerr<<'"'< right; + for(const auto& b: {"bert.com.", "Aleph1.powerdns.com.", + "test.powerdns.com.", + "ZOMG.powerdns.com.", + "\\128.com.", + "alpha.nl.", + "aaa.XXX.", + "articles.xxx.", + "yyy.XXX."}) + right.push_back(DNSName(b)); + + + BOOST_CHECK(vec==right); +} + + +BOOST_AUTO_TEST_CASE(test_empty_label) { // empty label + + { // append + DNSName dn("www."); + BOOST_CHECK_THROW(dn.appendRawLabel(""), std::range_error); + } + + { // prepend + DNSName dn("www."); + BOOST_CHECK_THROW(dn.prependRawLabel(""), std::range_error); + } +} + +BOOST_AUTO_TEST_CASE(test_label_length_max) { // 63 char label + + string label("123456789012345678901234567890123456789012345678901234567890123"); + + { // append + DNSName dn("www."); + dn.appendRawLabel(label); + BOOST_CHECK_EQUAL(dn.toString(), "www." + label + "."); + } + + { // prepend + DNSName dn("www."); + dn.prependRawLabel(label); + BOOST_CHECK_EQUAL(dn.toString(), label + ".www."); + } +} + +BOOST_AUTO_TEST_CASE(test_label_length_too_long) { // 64 char label + + string label("1234567890123456789012345678901234567890123456789012345678901234"); + + { // append + DNSName dn("www."); + BOOST_CHECK_THROW(dn.appendRawLabel(label), std::range_error); + } + + { // prepend + DNSName dn("www."); + BOOST_CHECK_THROW(dn.prependRawLabel(label), std::range_error); + } +} + +BOOST_AUTO_TEST_CASE(test_name_length_max) { // 255 char name + + string name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789."); + string label("123"); + + { // append + DNSName dn(name); + dn.appendRawLabel(label); + BOOST_CHECK_EQUAL(dn.toString().size(), 254); + } + + { // prepend + DNSName dn(name); + dn.prependRawLabel(label); + BOOST_CHECK_EQUAL(dn.toString().size(), 254); + } + + { // concat + DNSName dn(name); + + dn += DNSName(label + "."); + BOOST_CHECK_EQUAL(dn.toString().size(), 254); + } +} + +BOOST_AUTO_TEST_CASE(test_name_length_too_long) { // 256 char name + + string name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789."); + string label("1234"); + + { // append + DNSName dn(name); + BOOST_CHECK_THROW(dn.appendRawLabel(label), std::range_error); + } + + { // prepend + DNSName dn(name); + BOOST_CHECK_THROW(dn.prependRawLabel(label), std::range_error); + } + + { // concat + DNSName dn(name); + BOOST_CHECK_THROW(dn += DNSName(label + "."), std::range_error); + } +} + + +BOOST_AUTO_TEST_CASE(test_invalid_label_length) { // Invalid label length in qname + + string name("\x02""ns\x07""example\x04""com\x00", 16); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error); +} + +BOOST_AUTO_TEST_CASE(test_compression) { // Compression test + + string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05", 21); + + DNSName dn(name.c_str(), name.size(), 15, true); + BOOST_CHECK_EQUAL(dn.toString(), "www.example.com."); +} + +BOOST_AUTO_TEST_CASE(test_compression_qtype_qclass) { // Compression test with QClass and QType extraction + + uint16_t qtype = 0; + uint16_t qclass = 0; + + { + string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""\x01", 25); + DNSName dn(name.c_str(), name.size(), 15, true, &qtype, &qclass); + BOOST_CHECK_EQUAL(dn.toString(), "www.example.com."); + BOOST_CHECK_EQUAL(qtype, 1); + BOOST_CHECK_EQUAL(qclass, 1); + } + + { + /* same but this time we are one byte short for the qclass */ + string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""", 24); + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true, &qtype, &qclass), std::range_error); + } + + { + /* this time with a compression pointer such as (labellen << 8) != 0, see #4718 */ + string name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00""\x01", 25); + name.insert(0, 256, '0'); + + DNSName dn(name.c_str(), name.size(), 271, true, &qtype, &qclass); + BOOST_CHECK_EQUAL(dn.toString(), "www.example.com."); + BOOST_CHECK_EQUAL(qtype, 1); + BOOST_CHECK_EQUAL(qclass, 1); + } + + { + /* same but this time we are one byte short for the qclass */ + string name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00", 24); + name.insert(0, 256, '0'); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 271, true, &qtype, &qclass), std::range_error); + } +} + +BOOST_AUTO_TEST_CASE(test_compression_single_bit_set) { // first 2 bits as 10 or 01, not 11 + + // first 2 bits: 10 + { + string name("\x03""com\x00""\x07""example\x80""\x00""\x03""www\x80""\x05", 21); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true), std::range_error); + } + + // first 2 bits: 01 + { + string name("\x03""com\x00""\x07""example\x40""\x00""\x03""www\x40""\x05", 21); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true), std::range_error); + } + +} + +BOOST_AUTO_TEST_CASE(test_pointer_pointer_root) { // Pointer to pointer to root + + string name("\x00""\xc0""\x00""\x03""com\xc0""\x01",9); + + DNSName dn(name.c_str(), name.size(), 3, true); + BOOST_CHECK_EQUAL(dn.toString(), "com."); +} + +BOOST_AUTO_TEST_CASE(test_bad_compression_pointer) { // Pointing beyond packet boundary + + std::string name("\x03""com\x00""\x07""example\xc0""\x11""xc0""\x00", 17); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.length(), 5, true), std::range_error); +} + +BOOST_AUTO_TEST_CASE(test_compression_loop) { // Compression loop (add one label) + + std::string name("\x03""www\xc0""\x00", 6); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.length(), 0, true), std::range_error); +} + +BOOST_AUTO_TEST_CASE(test_compression_loop1) { // Compression loop (pointer loop) + + string name("\xc0""\x00", 2); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error); +} + +BOOST_AUTO_TEST_CASE(test_compression_loop2) { // Compression loop (deep recursion) + + int i; + string name("\x00\xc0\x00", 3); + for (i=0; i<98; ++i) { + name.append( 1, ((i >> 7) & 0xff) | 0xc0); + name.append( 1, ((i << 1) & 0xff) | 0x01); + } + BOOST_CHECK_NO_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true)); + + ++i; + name.append( 1, ((i >> 7) & 0xff) | 0xc0); + name.append( 1, ((i << 1) & 0xff) | 0x01); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true), std::range_error); +} + +BOOST_AUTO_TEST_CASE(test_wirelength) { // Testing if we get the correct value from the wirelength function + DNSName name("www.powerdns.com"); + BOOST_CHECK_EQUAL(name.wirelength(), 18); + + DNSName sname("powerdns.com"); + sname.prependRawLabel(string("ww\x00""w", 4)); + BOOST_CHECK_EQUAL(sname.wirelength(), 19); + + sname = DNSName("powerdns.com"); + sname.prependRawLabel(string("www\x00", 4)); + BOOST_CHECK_EQUAL(sname.wirelength(), 19); +} + +BOOST_AUTO_TEST_CASE(test_getrawlabel) { + DNSName name("a.bb.ccc.dddd."); + BOOST_CHECK_EQUAL(name.getRawLabel(0), "a"); + BOOST_CHECK_EQUAL(name.getRawLabel(1), "bb"); + BOOST_CHECK_EQUAL(name.getRawLabel(2), "ccc"); + BOOST_CHECK_EQUAL(name.getRawLabel(3), "dddd"); + BOOST_CHECK_THROW(name.getRawLabel(name.countLabels()), std::out_of_range); +} + +BOOST_AUTO_TEST_CASE(test_getlastlabel) { + DNSName name("www.powerdns.com"); + DNSName ans = name.getLastLabel(); + + // Check the const-ness + BOOST_CHECK_EQUAL(name, DNSName("www.powerdns.com")); + + // Check if the last label is indeed returned + BOOST_CHECK_EQUAL(ans, DNSName("com")); +} + +BOOST_AUTO_TEST_CASE(test_getcommonlabels) { + const DNSName name1("www.powerdns.com"); + const DNSName name2("a.long.list.of.labels.powerdns.com"); + + BOOST_CHECK_EQUAL(name1.getCommonLabels(name1), name1); + BOOST_CHECK_EQUAL(name2.getCommonLabels(name2), name2); + + BOOST_CHECK_EQUAL(name1.getCommonLabels(name2), DNSName("powerdns.com")); + BOOST_CHECK_EQUAL(name2.getCommonLabels(name1), DNSName("powerdns.com")); + + const DNSName name3("www.powerdns.org"); + BOOST_CHECK_EQUAL(name1.getCommonLabels(name3), DNSName()); + BOOST_CHECK_EQUAL(name2.getCommonLabels(name3), DNSName()); + BOOST_CHECK_EQUAL(name3.getCommonLabels(name1), DNSName()); + BOOST_CHECK_EQUAL(name3.getCommonLabels(name2), DNSName()); + + const DNSName name4("WWw.PowErDnS.org"); + BOOST_CHECK_EQUAL(name3.getCommonLabels(name4), name3); + BOOST_CHECK_EQUAL(name4.getCommonLabels(name3), name4); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-dnsparser_hh.cc b/test-dnsparser_hh.cc new file mode 100644 index 0000000..6165743 --- /dev/null +++ b/test-dnsparser_hh.cc @@ -0,0 +1,21 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include "dnsparser.hh" + +BOOST_AUTO_TEST_SUITE(test_dnsparser_hh) + +BOOST_AUTO_TEST_CASE(test_type_lowercase) { + std::string lc("type12345"); + std::string uc("TYPE12345"); + + uint16_t lc_result = DNSRecordContent::TypeToNumber(lc); + uint16_t uc_result = DNSRecordContent::TypeToNumber(uc); + BOOST_CHECK_EQUAL(lc_result, 12345); + BOOST_CHECK_EQUAL(lc_result, uc_result); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-dnsrecordcontent.cc b/test-dnsrecordcontent.cc new file mode 100644 index 0000000..9eb6829 --- /dev/null +++ b/test-dnsrecordcontent.cc @@ -0,0 +1,46 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include "dnsrecords.hh" +#include "iputils.hh" + +BOOST_AUTO_TEST_SUITE(test_dnsrecordcontent) + +BOOST_AUTO_TEST_CASE(test_equality) { + reportAllTypes(); + ComboAddress ip("1.2.3.4"), ip2("10.0.0.1"), ip6("::1"); + ARecordContent a1(ip), a2(ip), a3(ip2); + AAAARecordContent aaaa(ip6), aaaa1(ip6); + + BOOST_CHECK(a1==a2); + BOOST_CHECK(!(a1==a3)); + + BOOST_CHECK(aaaa == aaaa1); + + + auto rec1=DNSRecordContent::makeunique(QType::A, 1, "192.168.0.1"); + auto rec2=DNSRecordContent::makeunique(QType::A, 1, "192.168.222.222"); + auto rec3=DNSRecordContent::makeunique(QType::AAAA, 1, "::1"); + auto recMX=DNSRecordContent::makeunique(QType::MX, 1, "25 smtp.powerdns.com"); + auto recMX2=DNSRecordContent::makeunique(QType::MX, 1, "26 smtp.powerdns.com"); + auto recMX3=DNSRecordContent::makeunique(QType::MX, 1, "26 SMTP.powerdns.com"); + BOOST_CHECK(!(*rec1==*rec2)); + BOOST_CHECK(*rec1==*rec1); + BOOST_CHECK(*rec3==*rec3); + + BOOST_CHECK(*recMX==*recMX); + BOOST_CHECK(*recMX2==*recMX3); + BOOST_CHECK(!(*recMX==*recMX3)); + + + BOOST_CHECK(!(*rec1==*rec3)); + + NSRecordContent ns1(DNSName("ns1.powerdns.com")), ns2(DNSName("NS1.powerdns.COM")), ns3(DNSName("powerdns.net")); + BOOST_CHECK(ns1==ns2); + BOOST_CHECK(!(ns1==ns3)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-dnsrecords_cc.cc b/test-dnsrecords_cc.cc new file mode 100644 index 0000000..df4102a --- /dev/null +++ b/test-dnsrecords_cc.cc @@ -0,0 +1,330 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include +#include +#include "dnsrecords.hh" + +#define CASE_L(type, inval, zoneval, lineval, broken) case_t(type, std::string(inval), std::string(zoneval), std::string(lineval, sizeof(lineval)-1), broken) +#define CASE_S(type, zoneval, lineval, broken) CASE_L(type, zoneval, zoneval, lineval, broken) +BOOST_AUTO_TEST_SUITE(test_dnsrecords_cc) + +#define REC_CHECK_EQUAL(a,b) { if (val.get<4>()) { BOOST_WARN_EQUAL(a,b); } else { BOOST_CHECK_EQUAL(a,b); } } +#define REC_CHECK_MESSAGE(cond,msg) { if (val.get<4>()) { BOOST_WARN_MESSAGE(cond,msg); } else { BOOST_CHECK_MESSAGE(cond,msg); } } +#define REC_FAIL_XSUCCESS(msg) { if (val.get<4>()) { BOOST_CHECK_MESSAGE(false, std::string("Test has unexpectedly passed: ") + msg); } } // fail if test succeeds +#define REC_FAIL_XSUCCESS2(msg) { if (val.get<2>()) { BOOST_CHECK_MESSAGE(false, std::string("Test has unexpectedly passed: ") + msg); } } // fail if test succeeds (for the bad records test case) + +typedef enum { zone, wire } case_type_enum_t; + +BOOST_AUTO_TEST_CASE(test_record_types) { + // tuple contains + typedef boost::tuple case_t; + typedef std::list cases_t; + reportAllTypes(); + MRRecordContent::report(); + IPSECKEYRecordContent::report(); + KXRecordContent::report(); + DHCIDRecordContent::report(); + TSIGRecordContent::report(); + TKEYRecordContent::report(); + +// NB!!! WHEN ADDING A TEST MAKE SURE YOU PUT IT NEXT TO IT'S KIND +// TO MAKE SURE TEST NUMBERING DOES NOT BREAK + +// why yes, they are unordered by name, how nice of you to notice + + cases_t cases = boost::assign::list_of + (CASE_S(QType::A, "127.0.0.1", "\x7F\x00\x00\x01",false)) +// local nameserver + (CASE_L(QType::NS, "ns.rec.test.", "ns.rec.test.", "\x02ns\xc0\x11",false)) +// non-local nameserver + (CASE_S(QType::NS, "ns.example.com.", "\x02ns\x07""example\x03""com\x00",false)) +// local alias + (CASE_L(QType::CNAME, "name.rec.test.", "name.rec.test.", "\x04name\xc0\x11",false)) +// non-local alias + (CASE_S(QType::CNAME, "name.example.com.", "\x04name\x07""example\x03""com\x00",false)) +// max label length (63) + (CASE_S(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.example.com.", "\x3f""123456789012345678901234567890123456789012345678901234567890123\x07""example\x03""com\x00", false)) +// local max name length (255) + (CASE_S(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012.rec.test.", "\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x34""1234567890123456789012345678901234567890123456789012\xc0\x11", false)) +// non-local max name length (255) + (CASE_S(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.", "\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x3d""1234567890123456789012345678901234567890123456789012345678901\x00", false)) +// local names + (CASE_S(QType::SOA, "ns.rec.test. hostmaster.test.rec. 2013051201 3600 3600 604800 120", "\x02ns\xc0\x11\x0ahostmaster\x04test\x03rec\x00\x77\xfc\xb9\x41\x00\x00\x0e\x10\x00\x00\x0e\x10\x00\x09\x3a\x80\x00\x00\x00\x78",false)) +// local name without dots + (CASE_L(QType::SOA, "ns.rec.test. hostmaster.test.rec. 2013051201 3600 3600 604800 120", "ns.rec.test. hostmaster.test.rec. 2013051201 3600 3600 604800 120", "\x02ns\xc0\x11\x0ahostmaster\x04test\x03rec\x00\x77\xfc\xb9\x41\x00\x00\x0e\x10\x00\x00\x0e\x10\x00\x09\x3a\x80\x00\x00\x00\x78",false)) +// non-local names + (CASE_S(QType::SOA, "ns.example.com. hostmaster.example.com. 2013051201 3600 3600 604800 120", "\x02ns\x07""example\x03""com\x00\x0ahostmaster\xc0\x28\x77\xfc\xb9\x41\x00\x00\x0e\x10\x00\x00\x0e\x10\x00\x09\x3a\x80\x00\x00\x00\x78",false)) + +// BROKEN TESTS (2) (deprecated) +// local name + (CASE_S(QType::MR, "newmailbox.rec.test.", "\x0anewmailbox\xc0\x11",false)) +// non-local name + (CASE_S(QType::MR, "newmailbox.example.com.", "\x0anewmailbox\x07""example\x03""com\x00",false)) + +// local name + (CASE_L(QType::PTR, "ptr.rec.test.", "ptr.rec.test.", "\x03ptr\xc0\x11",false)) +// non-local name + (CASE_L(QType::PTR, "ptr.example.com.", "ptr.example.com.", "\x03ptr\x07""example\x03""com\x00",false)) + (CASE_S(QType::HINFO, "\"i686\" \"Linux\"", "\x04i686\x05Linux",false)) + (CASE_L(QType::HINFO, "i686 \"Linux\"", "\"i686\" \"Linux\"", "\x04i686\x05Linux",true)) + (CASE_L(QType::HINFO, "\"i686\" Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux",false)) + (CASE_L(QType::HINFO, "i686 Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux",true)) +// local name + (CASE_S(QType::MX, "10 mx.rec.test.", "\x00\x0a\02mx\xc0\x11",false)) +// non-local name + (CASE_S(QType::MX, "20 mx.example.com.", "\x00\x14\02mx\x07""example\x03""com\x00",false)) +// root label + (CASE_S(QType::MX, "20 .", "\x00\x14\x00",false)) + + (CASE_S(QType::TXT, "\"short text\"", "\x0ashort text",false)) + (CASE_S(QType::TXT, "\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\"", "\xff""long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a""2222222222",false)) + (CASE_L(QType::TXT, "\"long record test 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222\"", "\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\"", "\xff""long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a""2222222222",false)) + (CASE_L(QType::TXT, "\"\\195\\133LAND ISLANDS\"", "\"\\195\\133LAND ISLANDS\"", "\x0e\xc3\x85LAND ISLANDS", false)) + (CASE_L(QType::TXT, "\"\xc3\x85LAND ISLANDS\"", "\"\\195\\133LAND ISLANDS\"", "\x0e\xc3\x85LAND ISLANDS", false)) + (CASE_L(QType::TXT, "\"nonbreakingtxt\"", "\"nonbreakingtxt\"", "\x0enonbreakingtxt",false)) +// local name + (CASE_S(QType::RP, "admin.rec.test. admin-info.rec.test.", "\x05""admin\x03rec\x04test\x00\x0a""admin-info\x03rec\x04test\x00",false)) +// non-local name + (CASE_S(QType::RP, "admin.example.com. admin-info.example.com.", "\x05""admin\x07""example\x03""com\x00\x0a""admin-info\x07""example\x03""com\x00",false)) +// local name + (CASE_S(QType::AFSDB, "1 afs-server.rec.test.", "\x00\x01\x0a""afs-server\x03rec\x04test\x00",false)) +// non-local name + (CASE_S(QType::AFSDB, "1 afs-server.example.com.", "\x00\x01\x0a""afs-server\x07""example\x03""com\x00",false)) +// deprecated (and i don't know what i am doing wrong) + (CASE_S(QType::KEY, "0 3 3 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x00\x00\x03\x03\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52",false)) + (CASE_L(QType::LOC, "32 7 19 S 116 2 25 E", "32 7 19.000 S 116 2 25.000 E 0.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x96\x80",false)) + (CASE_L(QType::LOC, "32 7 19 S 116 2 25 E 10m", "32 7 19.000 S 116 2 25.000 E 10.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x9a\x68",false)) + (CASE_L(QType::LOC, "42 21 54 N 71 06 18 W -24m 30m", "42 21 54.000 N 71 6 18.000 W -24.00m 30.00m 10000.00m 10.00m", "\x00\x33\x16\x13\x89\x17\x2d\xd0\x70\xbe\x15\xf0\x00\x98\x8d\x20",false)) + (CASE_L(QType::LOC, "42 21 43.952 N 71 5 6.344 W -24m 1m 200m", "42 21 43.952 N 71 5 6.344 W -24.00m 1.00m 200.00m 10.00m", "\x00\x12\x24\x13\x89\x17\x06\x90\x70\xbf\x2d\xd8\x00\x98\x8d\x20",false)) + (CASE_S(QType::AAAA, "fe80::250:56ff:fe9b:114", "\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14",false)) + (CASE_S(QType::AAAA, "2a02:1b8:10:2::151", "\x2a\x02\x01\xb8\x00\x10\x00\x02\x00\x00\x00\x00\x00\x00\x01\x51",false)) + (CASE_S(QType::AAAA, "::1", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",false)) +// local name + (CASE_S(QType::SRV, "10 10 5060 sip.rec.test.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x03rec\x04test\x00",false)) +// non-local name + (CASE_S(QType::SRV, "10 10 5060 sip.example.com.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x07""example\x03""com\x00",false)) +// root name + (CASE_S(QType::SRV, "10 10 5060 .", "\x00\x0a\x00\x0a\x13\xc4\x00",false)) + + (CASE_S(QType::NAPTR, "100 10 \"\" \"\" \"/urn:cid:.+@([^\\\\.]+\\\\.)(.*)$/\\\\2/i\" .", "\x00\x64\x00\x0a\x00\x00\x20/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\x00",false)) + (CASE_S(QType::NAPTR, "100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.rec.test.", "\x00\x64\x00\x32\x01s\x10http+I2L+I2C+I2R\x00\x05_http\x04_tcp\x03rec\x04test\x00",false)) + (CASE_S(QType::KX, "10 mail.rec.test.", "\x00\x0a\x04mail\x03rec\x04test\x00",false)) + +// X.509 as per PKIX + (CASE_S(QType::CERT, "1 0 0 MIIB9DCCAV2gAwIBAgIJAKxUfFVXhw7HMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNVBAMMCHJlYy50ZXN0MB4XDTEzMDUxMjE5NDgwOVoXDTEzMDYxMTE5NDgwOVowEzERMA8GA1UEAwwIcmVjLnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANKCu5aN/ewOXRPfzAo27XMXhYFCThCjfInTAUIEkzs6jBFZ/eyyIa/kFoiD0tAKwfFfykYU+9XgXeLjetD7rYt3SN3bzzCznoBGbGHHM0Fecrn0LV+tC/NfBB61Yx7e0AMUxmxIeLNRQW5ca5CW8qcIiiQ4fl0BScUjc5+E9QLHAgMBAAGjUDBOMB0GA1UdDgQWBBRzcVu/2bwrgkES+FhYbxZqr7mUgjAfBgNVHSMEGDAWgBRzcVu/2bwrgkES+FhYbxZqr7mUgjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFVQ8dZBOasOhsWzA/xpAV0WdsqVkxBxrkGIRlbHHBFqOBOOz2MFSzUNx4mDy0qDKI28gcWmWaVsxoQ9VFLD6YRJuUoM8MDNcZDJbKpfDumjvvfnUAK+SiM2c4Ur3xpf0wanCA60/q2bOtFiB0tfAH6RVuIgMC3qjHAIaKEld+fE", "\x00\x01\x00\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_L(QType::DS, "20642 8 2 04443ABE7E94C3985196BEAE5D548C727B044DDA5151E60D7CD76A9F D931D00E", "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e",false)) + (CASE_L(QType::DS, "20642 8 2 04443ABE7E94C3985196BEAE5D548C727B044DDA5151E60D7CD76A9F D931D00E", "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e",false)) + (CASE_S(QType::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88", "\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88",false)) +// as per RFC4025 + (CASE_L(QType::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc253 8d88", "1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88", "\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88",false)) +// as per RFC4025 + (CASE_S(QType::IPSECKEY, "255 0 0", "\xff\x00\x00",false)) + (CASE_S(QType::IPSECKEY, "255 0 1 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\xff\x00\x01\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52",false)) + (CASE_S(QType::IPSECKEY, "255 1 0 127.0.0.1", "\xff\x01\x00\x7f\x00\x00\x01", false)) + (CASE_S(QType::IPSECKEY, "255 2 0 fe80::250:56ff:fe9b:114", "\xff\x02\x00\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14", false)) + (CASE_S(QType::IPSECKEY, "10 1 1 127.0.0.1 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x0a\x01\x01\x7f\x00\x00\x01\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52", false)) + (CASE_S(QType::IPSECKEY, "10 2 1 fe80::250:56ff:fe9b:114 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x0a\x02\x01\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52", false)) + (CASE_S(QType::IPSECKEY, "10 3 1 gw.rec.test. V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x0a\x03\x01\x02gw\x03rec\x04test\x00\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52",false)) + + (CASE_S(QType::RRSIG, "SOA 8 3 300 20130523000000 20130509000000 54216 rec.test. ecWKD/OsdAiXpbM/sgPT82KVD/WiQnnqcxoJgiH3ixHa+LOAcYU7FG7V4BRRJxLriY1e0rB2gAs3kCel9D4bzfK6wAqG4Di/eHUgHptRlaR2ycELJ4t1pjzrnuGiIzA1wM2izRmeE+Xoy1367Qu0pOz5DLzTfQITWFsB2iUzN4Y=", "\x00\x06\x08\x03\x00\x00\x01\x2c\x51\x9d\x5c\x00\x51\x8a\xe7\x00\xd3\xc8\x03\x72\x65\x63\x04\x74\x65\x73\x74\x00\x79\xc5\x8a\x0f\xf3\xac\x74\x08\x97\xa5\xb3\x3f\xb2\x03\xd3\xf3\x62\x95\x0f\xf5\xa2\x42\x79\xea\x73\x1a\x09\x82\x21\xf7\x8b\x11\xda\xf8\xb3\x80\x71\x85\x3b\x14\x6e\xd5\xe0\x14\x51\x27\x12\xeb\x89\x8d\x5e\xd2\xb0\x76\x80\x0b\x37\x90\x27\xa5\xf4\x3e\x1b\xcd\xf2\xba\xc0\x0a\x86\xe0\x38\xbf\x78\x75\x20\x1e\x9b\x51\x95\xa4\x76\xc9\xc1\x0b\x27\x8b\x75\xa6\x3c\xeb\x9e\xe1\xa2\x23\x30\x35\xc0\xcd\xa2\xcd\x19\x9e\x13\xe5\xe8\xcb\x5d\xfa\xed\x0b\xb4\xa4\xec\xf9\x0c\xbc\xd3\x7d\x02\x13\x58\x5b\x01\xda\x25\x33\x37\x86",false)) + (CASE_S(QType::NSEC, "a.rec.test. A NS SOA MX AAAA RRSIG NSEC DNSKEY", "\x01""a\x03rec\x04test\x00\x00\x07\x62\x01\x00\x08\x00\x03\x80",false)) + (CASE_S(QType::DNSKEY, "257 3 5 AwEAAZVtlHc8O4TVmlGx/PGJTc7hbVjMR7RywxLuAm1dqgyHvgNRD7chYLsALOdZKW6VRvusbyhoOPilnh8XpucBDqjGD6lIemsURz7drZEqcLupVA0TPxXABZ6auJ3jumqIhSOcLj9rpSwI4xuWt0yu6LR9tL2q8+A0yEZxcAaKS+Wq0fExJ93NxgXl1/fY+JcYQvonjd31GxXXef9uf0exXyzowh5h8+IIBETU+ZiYVB5BqiwkICZL/OX57idm99ycA2/tIen66F8u2ueTvgPcecnoqHvW0MtLQKzeNmqdGNthHhV5di0SZdMZQeo/izs68uN2WzqQDZy9Ec2JwBTbxWE=", "\x01\x01\x03\x05\x03\x01\x00\x01\x95\x6d\x94\x77\x3c\x3b\x84\xd5\x9a\x51\xb1\xfc\xf1\x89\x4d\xce\xe1\x6d\x58\xcc\x47\xb4\x72\xc3\x12\xee\x02\x6d\x5d\xaa\x0c\x87\xbe\x03\x51\x0f\xb7\x21\x60\xbb\x00\x2c\xe7\x59\x29\x6e\x95\x46\xfb\xac\x6f\x28\x68\x38\xf8\xa5\x9e\x1f\x17\xa6\xe7\x01\x0e\xa8\xc6\x0f\xa9\x48\x7a\x6b\x14\x47\x3e\xdd\xad\x91\x2a\x70\xbb\xa9\x54\x0d\x13\x3f\x15\xc0\x05\x9e\x9a\xb8\x9d\xe3\xba\x6a\x88\x85\x23\x9c\x2e\x3f\x6b\xa5\x2c\x08\xe3\x1b\x96\xb7\x4c\xae\xe8\xb4\x7d\xb4\xbd\xaa\xf3\xe0\x34\xc8\x46\x71\x70\x06\x8a\x4b\xe5\xaa\xd1\xf1\x31\x27\xdd\xcd\xc6\x05\xe5\xd7\xf7\xd8\xf8\x97\x18\x42\xfa\x27\x8d\xdd\xf5\x1b\x15\xd7\x79\xff\x6e\x7f\x47\xb1\x5f\x2c\xe8\xc2\x1e\x61\xf3\xe2\x08\x04\x44\xd4\xf9\x98\x98\x54\x1e\x41\xaa\x2c\x24\x20\x26\x4b\xfc\xe5\xf9\xee\x27\x66\xf7\xdc\x9c\x03\x6f\xed\x21\xe9\xfa\xe8\x5f\x2e\xda\xe7\x93\xbe\x03\xdc\x79\xc9\xe8\xa8\x7b\xd6\xd0\xcb\x4b\x40\xac\xde\x36\x6a\x9d\x18\xdb\x61\x1e\x15\x79\x76\x2d\x12\x65\xd3\x19\x41\xea\x3f\x8b\x3b\x3a\xf2\xe3\x76\x5b\x3a\x90\x0d\x9c\xbd\x11\xcd\x89\xc0\x14\xdb\xc5\x61",false)) + + (CASE_S(QType::DHCID, "AAAB92JtyyO73zqENgu9LVua+0PZoeCcKapTw4asbYmx5F4=", "\x00\x00\x01\xf7\x62\x6d\xcb\x23\xbb\xdf\x3a\x84\x36\x0b\xbd\x2d\x5b\x9a\xfb\x43\xd9\xa1\xe0\x9c\x29\xaa\x53\xc3\x86\xac\x6d\x89\xb1\xe4\x5e",false)) + (CASE_S(QType::DHCID, "AAEB92JtyyO73zqENgu9LVua+0PZoeCcKapTw4asbYmx5F4=", "\x00\x01\x01\xf7\x62\x6d\xcb\x23\xbb\xdf\x3a\x84\x36\x0b\xbd\x2d\x5b\x9a\xfb\x43\xd9\xa1\xe0\x9c\x29\xaa\x53\xc3\x86\xac\x6d\x89\xb1\xe4\x5e",false)) + (CASE_S(QType::DHCID, "AAIB92JtyyO73zqENgu9LVua+0PZoeCcKapTw4asbYmx5F4=", "\x00\x02\x01\xf7\x62\x6d\xcb\x23\xbb\xdf\x3a\x84\x36\x0b\xbd\x2d\x5b\x9a\xfb\x43\xd9\xa1\xe0\x9c\x29\xaa\x53\xc3\x86\xac\x6d\x89\xb1\xe4\x5e",false)) + + (CASE_S(QType::NSEC3, "1 1 1 f00b RPF1JGFCCNFA7STPTIJ9FPFNM40A4FLL NS SOA RRSIG DNSKEY NSEC3PARAM", "\x01\x01\x00\x01\x02\xf0\x0b\x14\xde\x5e\x19\xc1\xec\x65\xde\xa3\xf3\xb9\xec\xa6\x97\xe5\xf7\xb1\x00\xa2\x3e\xb5\x00\x07\x22\x00\x00\x00\x00\x02\x90",false)) + (CASE_S(QType::NSEC3PARAM, "1 0 1 f00b", "\x01\x00\x00\x01\x02\xf0\x0b",false)) + + (CASE_S(QType::TLSA, "0 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x00\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::TLSA, "0 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x00\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + (CASE_S(QType::TLSA, "1 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x01\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::TLSA, "1 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x01\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + (CASE_S(QType::TLSA, "1 0 1 6acea2f68b03d9efe97a967e137aca6ac3a89490d532d87806d9e9c257668453", "\x01\x00\x01\x6a\xce\xa2\xf6\x8b\x03\xd9\xef\xe9\x7a\x96\x7e\x13\x7a\xca\x6a\xc3\xa8\x94\x90\xd5\x32\xd8\x78\x06\xd9\xe9\xc2\x57\x66\x84\x53",false)) + (CASE_S(QType::TLSA, "1 0 2 e6dce237992803488d11d828b7728deddd4577de73d7d078338c8a45880beddff98e076a28bf8e3068da8e73667b802a721c95d7323b038c60200a430cb6fbd4", "\x01\x00\x02\xe6\xdc\xe2\x37\x99\x28\x03\x48\x8d\x11\xd8\x28\xb7\x72\x8d\xed\xdd\x45\x77\xde\x73\xd7\xd0\x78\x33\x8c\x8a\x45\x88\x0b\xed\xdf\xf9\x8e\x07\x6a\x28\xbf\x8e\x30\x68\xda\x8e\x73\x66\x7b\x80\x2a\x72\x1c\x95\xd7\x32\x3b\x03\x8c\x60\x20\x0a\x43\x0c\xb6\xfb\xd4",false)) + (CASE_S(QType::TLSA, "2 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x02\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::TLSA, "2 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x02\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + + (CASE_S(QType::TLSA, "3 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x03\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::TLSA, "3 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x03\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + + (CASE_S(QType::SMIMEA, "0 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x00\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::SMIMEA, "0 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x00\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + (CASE_S(QType::SMIMEA, "1 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x01\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::SMIMEA, "1 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x01\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + (CASE_S(QType::SMIMEA, "1 0 1 6acea2f68b03d9efe97a967e137aca6ac3a89490d532d87806d9e9c257668453", "\x01\x00\x01\x6a\xce\xa2\xf6\x8b\x03\xd9\xef\xe9\x7a\x96\x7e\x13\x7a\xca\x6a\xc3\xa8\x94\x90\xd5\x32\xd8\x78\x06\xd9\xe9\xc2\x57\x66\x84\x53",false)) + (CASE_S(QType::SMIMEA, "1 0 2 e6dce237992803488d11d828b7728deddd4577de73d7d078338c8a45880beddff98e076a28bf8e3068da8e73667b802a721c95d7323b038c60200a430cb6fbd4", "\x01\x00\x02\xe6\xdc\xe2\x37\x99\x28\x03\x48\x8d\x11\xd8\x28\xb7\x72\x8d\xed\xdd\x45\x77\xde\x73\xd7\xd0\x78\x33\x8c\x8a\x45\x88\x0b\xed\xdf\xf9\x8e\x07\x6a\x28\xbf\x8e\x30\x68\xda\x8e\x73\x66\x7b\x80\x2a\x72\x1c\x95\xd7\x32\x3b\x03\x8c\x60\x20\x0a\x43\x0c\xb6\xfb\xd4",false)) + (CASE_S(QType::SMIMEA, "2 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x02\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::SMIMEA, "2 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x02\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + (CASE_S(QType::SMIMEA, "3 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x03\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false)) + (CASE_S(QType::SMIMEA, "3 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x03\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false)) + + (CASE_S(QType::OPENPGPKEY, "mQINBFUIXh0BEADNPlL6NpWEaR2KJx6p19scIVpsBIo7UqzCIzeFbRJaGDhn/HlQgcwAalcVNmWUX0ZQsrdn9CEfLWuFu9ON2o1TslYiwn+oSAlH2raFm2eyJTp/iM7IUUCte5jmf3d+L9rjVI7JjmMnbVo6SVY2KDDD72dULcg7IqYcCAN4CT+tPZP5y4cYf+DxRlpxhxvqqiGyAi6lAcJ24/8fJ4hsG0lS1vU12LWeWTHa5aRMM+x9kmv3GYdXG+FxFqZw52kZEnAscpC2ymbX+1YFCr8sjGYGde/D+5cLvuu4PGNZ4fkSeS+0yXve/s6u1mX6RkkF6SOGWuJfBJOGdWzYwber9kqgqpHTjpr8HOybzVroBijtTlB/tommIUd4BTk9Jv4fv2gA4UkC13UM9KBF1NnzUnKC+Js49O3mj0HZDoCrkWMnZyDsEmhMyQPU6YRFHWmB6OTKeD/Znk+b1uz+HIBgrbNuiG/A0c00Vnj7lR4p94oOuypI00XusLsJwPsjI4EgFGKdoRtM0spJhi+3gf88Vq0NENBaFVHLBGWVFaVrffurGcDZYUAdnvm8jSPCgBPfFxpZutexNkLjyaaXjDtga5/n5gSd/3RpWCvp9u3W5jcTNDZF4TORnOXUWHcot/+XmyH8/+cn8ydt0prOLGQ+FtdI+AWyMCXHen6aaZ1jeSLZqwARAQABtFpwZG5zIHJlZ3Jlc3Npb24gdGVzdGluZyBrZXkgKG9ubHkgZm9yIHRlc3RpbmcgdGhlIG9wZW5wZ3BrZXkgcnIpIDxyZWdyZXNzaW9uQHBvd2VyZG5zLm9yZz6JAjcEEwEIACEFAlUIXh0CGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQPr/KqoyK2Z7A6Q//YOBu8nwt+fguSo/vyCln0PqnTiBm4RvE2gPDUnsKuoXoP5F56XHBXKl9kEgmycht/nc7c7NRHzUhacM2RQau6CgNZE8KLaqDTKlEuc/ANtrnGGYG8gMId4TlzU5taLEA8yrHIHnwnMuDDpx1a0ETkbYCrj7CynqdhXCABqFjgRL7Qb37UnLPE7YdFt7fRGwZVLnb3GVZLKHurZ0TANvLdRVDST3f0lCcYMppPbHAvi2MIU71FPGkms++tj4gTltq0VRvrMNm1e5v4+hHZ++QN4sm4+DJGlo7l850gnMXc7c7GkRGtg8gV0h5k5jX5icdgxyvENTuBQ+QprkYTRh9uYzpoTQ+NYRZlgaJxxaDIv1K/kb3oPtnAEKJBC02IZbB0EiS3R5pxYXhUNoWV7ez2A4hX1L+tfvlgCAbbQ/cBLvqXgpgsf9x4ygSi52vQBy3twZyrtLsogxacxADfPcyleHtju/+lSku+Z6+W6OojA0kY2HlaMyQATJLIXd+6NE/tYy70RsU9Oq0OyVTjxh21SPLsExeSwSfciVSLn7IuKGIOV82MEHFhpo1Uhv+G52J8T1fI730sS4Tl5DekLaCz1pg/FmI/EQeAsYqm98uDAaFQcs6gDse8VYGmp2XYsoCW72as8ElKmMIbQ/xD7qxDORLmjCtVoyKH19+s6Pp61a5Ag0EVQheHQEQAMN6pcLJUhw9bfO5kqhLv4prt0AqVBUok6U8tIaEc9vDaasBcFHXgPsoOG97DXB6BdvsHuK/5uMVH5PNe58MLp08iCoIt0C0CbN3+D9Qbeg37AyKyFanB/CXq1tPKVCJc6BMNkO/BswnUsTTmlcd4GovpaJUOOZzblGUQBbhzRohhmOGfdsScGeeYME/yNFqzt1ZArV4va1hOLOUpNFv9TOy0ZVi/yDi+sYA9fCSZU9alWI/cbBct5I+3bh1l26umlZsYQm8uqnSgiQWpRm6UJO6xQbmUN9GzCYyKCmpzZRduqqjjtiF10W1yzioTfTtq2cvU6PdINYY8w2UuOjRd9gChtvGuduOIwqlRTYSaXX1dDoFe1vWqZzRm+pIDumO9eX5jMmzFXLDG2pD2l97zoSjVFf/pYoBasgX43e3V/aEk9PUgXbYFm2QxFMcIYSO9GEDMoE+QxoMXf1UjLxMCK5gD5iHL3Ff2zyXLzlTZE+fHPMLcAkzcp2u6pJ9xpAGekqqeqnISXZ2o8yXsqv8NVvl1zaSiSqU+kak9mIg/2+WC9W1qO2PeSLW2tiis980QnmyDOBg2oL01ITh/u+GTodEGwfRYJoNAJgUjcUMpWl0LuoG8lG6wukhA4QYFWpf2QPVgTR63VbpFgwCnUcSEPqHB0BRCsDHsd0k+/YSuPolABEBAAGJAh8EGAEIAAkFAlUIXh0CGwwACgkQPr/KqoyK2Z6zPA/+PkJTzP8kQw4GW0x2ZxXfOmkRVYpSEoHehf6y9YFN00+T8pb71RGItvuX5v6oPKPClOnIVg2WVHOq6Q3HsXEzl7oIbOtPE98WXHiVXud/djc54uHz9WjSPfy/idP7SMslo29BHR/K9nQkiGtayD57wdxgbLXObE3fA0gl4AsWl1EZzNcWVL4SIrvnBGpYIUGBcsTIiP3p09bu4Qf6HjJRXZlBuizigIgeO39l/G6tb6GA1cnbq4y6aCtQeXHLrnvak1jRqznlJWUqS1mQgOPF1MuOduHAvQbfMBQXAEfgOTzuH9PuKoGm7MePwTrU5GsOpNgS4LbvIRODJxYD+vIwA5BniijgfN9aj9KQVMURrd4Np7i0EVmj8P9FtNgYsEaDt7laGpNB9+9Y9heb6kNEulF7KI7y8CKikgvFGHHCyX2BCCbQBqi6wbEGq16qkTJmesYu9ig4v4xD/Q/cLJFziJLjEcWsL7hq7q2o6e7NL6hf5aTH0/bdeMXMqRzDCAFQ5Z+x0QUCgVonxzj+CuTD/LeOs/QHu/9emvm9EOMYY/X9vidLf58PT/AMqMiYbNWty6qY6k2LMw74Yd4+hO+Tjrk8MrqbCUs9h6ih9IOCo68JTWQQbgWSk2TAyd3U4OqTyBnHWr0HhHDRTOxyDbZUtXbk/r4Q4gTcAt+qjpswPyk=", "\x99\x02\x0d\x04\x55\x08\x5e\x1d\x01\x10\x00\xcd\x3e\x52\xfa\x36\x95\x84\x69\x1d\x8a\x27\x1e\xa9\xd7\xdb\x1c\x21\x5a\x6c\x04\x8a\x3b\x52\xac\xc2\x23\x37\x85\x6d\x12\x5a\x18\x38\x67\xfc\x79\x50\x81\xcc\x00\x6a\x57\x15\x36\x65\x94\x5f\x46\x50\xb2\xb7\x67\xf4\x21\x1f\x2d\x6b\x85\xbb\xd3\x8d\xda\x8d\x53\xb2\x56\x22\xc2\x7f\xa8\x48\x09\x47\xda\xb6\x85\x9b\x67\xb2\x25\x3a\x7f\x88\xce\xc8\x51\x40\xad\x7b\x98\xe6\x7f\x77\x7e\x2f\xda\xe3\x54\x8e\xc9\x8e\x63\x27\x6d\x5a\x3a\x49\x56\x36\x28\x30\xc3\xef\x67\x54\x2d\xc8\x3b\x22\xa6\x1c\x08\x03\x78\x09\x3f\xad\x3d\x93\xf9\xcb\x87\x18\x7f\xe0\xf1\x46\x5a\x71\x87\x1b\xea\xaa\x21\xb2\x02\x2e\xa5\x01\xc2\x76\xe3\xff\x1f\x27\x88\x6c\x1b\x49\x52\xd6\xf5\x35\xd8\xb5\x9e\x59\x31\xda\xe5\xa4\x4c\x33\xec\x7d\x92\x6b\xf7\x19\x87\x57\x1b\xe1\x71\x16\xa6\x70\xe7\x69\x19\x12\x70\x2c\x72\x90\xb6\xca\x66\xd7\xfb\x56\x05\x0a\xbf\x2c\x8c\x66\x06\x75\xef\xc3\xfb\x97\x0b\xbe\xeb\xb8\x3c\x63\x59\xe1\xf9\x12\x79\x2f\xb4\xc9\x7b\xde\xfe\xce\xae\xd6\x65\xfa\x46\x49\x05\xe9\x23\x86\x5a\xe2\x5f\x04\x93\x86\x75\x6c\xd8\xc1\xb7\xab\xf6\x4a\xa0\xaa\x91\xd3\x8e\x9a\xfc\x1c\xec\x9b\xcd\x5a\xe8\x06\x28\xed\x4e\x50\x7f\xb6\x89\xa6\x21\x47\x78\x05\x39\x3d\x26\xfe\x1f\xbf\x68\x00\xe1\x49\x02\xd7\x75\x0c\xf4\xa0\x45\xd4\xd9\xf3\x52\x72\x82\xf8\x9b\x38\xf4\xed\xe6\x8f\x41\xd9\x0e\x80\xab\x91\x63\x27\x67\x20\xec\x12\x68\x4c\xc9\x03\xd4\xe9\x84\x45\x1d\x69\x81\xe8\xe4\xca\x78\x3f\xd9\x9e\x4f\x9b\xd6\xec\xfe\x1c\x80\x60\xad\xb3\x6e\x88\x6f\xc0\xd1\xcd\x34\x56\x78\xfb\x95\x1e\x29\xf7\x8a\x0e\xbb\x2a\x48\xd3\x45\xee\xb0\xbb\x09\xc0\xfb\x23\x23\x81\x20\x14\x62\x9d\xa1\x1b\x4c\xd2\xca\x49\x86\x2f\xb7\x81\xff\x3c\x56\xad\x0d\x10\xd0\x5a\x15\x51\xcb\x04\x65\x95\x15\xa5\x6b\x7d\xfb\xab\x19\xc0\xd9\x61\x40\x1d\x9e\xf9\xbc\x8d\x23\xc2\x80\x13\xdf\x17\x1a\x59\xba\xd7\xb1\x36\x42\xe3\xc9\xa6\x97\x8c\x3b\x60\x6b\x9f\xe7\xe6\x04\x9d\xff\x74\x69\x58\x2b\xe9\xf6\xed\xd6\xe6\x37\x13\x34\x36\x45\xe1\x33\x91\x9c\xe5\xd4\x58\x77\x28\xb7\xff\x97\x9b\x21\xfc\xff\xe7\x27\xf3\x27\x6d\xd2\x9a\xce\x2c\x64\x3e\x16\xd7\x48\xf8\x05\xb2\x30\x25\xc7\x7a\x7e\x9a\x69\x9d\x63\x79\x22\xd9\xab\x00\x11\x01\x00\x01\xb4\x5a\x70\x64\x6e\x73\x20\x72\x65\x67\x72\x65\x73\x73\x69\x6f\x6e\x20\x74\x65\x73\x74\x69\x6e\x67\x20\x6b\x65\x79\x20\x28\x6f\x6e\x6c\x79\x20\x66\x6f\x72\x20\x74\x65\x73\x74\x69\x6e\x67\x20\x74\x68\x65\x20\x6f\x70\x65\x6e\x70\x67\x70\x6b\x65\x79\x20\x72\x72\x29\x20\x3c\x72\x65\x67\x72\x65\x73\x73\x69\x6f\x6e\x40\x70\x6f\x77\x65\x72\x64\x6e\x73\x2e\x6f\x72\x67\x3e\x89\x02\x37\x04\x13\x01\x08\x00\x21\x05\x02\x55\x08\x5e\x1d\x02\x1b\x03\x05\x0b\x09\x08\x07\x02\x06\x15\x08\x09\x0a\x0b\x02\x04\x16\x02\x03\x01\x02\x1e\x01\x02\x17\x80\x00\x0a\x09\x10\x3e\xbf\xca\xaa\x8c\x8a\xd9\x9e\xc0\xe9\x0f\xff\x60\xe0\x6e\xf2\x7c\x2d\xf9\xf8\x2e\x4a\x8f\xef\xc8\x29\x67\xd0\xfa\xa7\x4e\x20\x66\xe1\x1b\xc4\xda\x03\xc3\x52\x7b\x0a\xba\x85\xe8\x3f\x91\x79\xe9\x71\xc1\x5c\xa9\x7d\x90\x48\x26\xc9\xc8\x6d\xfe\x77\x3b\x73\xb3\x51\x1f\x35\x21\x69\xc3\x36\x45\x06\xae\xe8\x28\x0d\x64\x4f\x0a\x2d\xaa\x83\x4c\xa9\x44\xb9\xcf\xc0\x36\xda\xe7\x18\x66\x06\xf2\x03\x08\x77\x84\xe5\xcd\x4e\x6d\x68\xb1\x00\xf3\x2a\xc7\x20\x79\xf0\x9c\xcb\x83\x0e\x9c\x75\x6b\x41\x13\x91\xb6\x02\xae\x3e\xc2\xca\x7a\x9d\x85\x70\x80\x06\xa1\x63\x81\x12\xfb\x41\xbd\xfb\x52\x72\xcf\x13\xb6\x1d\x16\xde\xdf\x44\x6c\x19\x54\xb9\xdb\xdc\x65\x59\x2c\xa1\xee\xad\x9d\x13\x00\xdb\xcb\x75\x15\x43\x49\x3d\xdf\xd2\x50\x9c\x60\xca\x69\x3d\xb1\xc0\xbe\x2d\x8c\x21\x4e\xf5\x14\xf1\xa4\x9a\xcf\xbe\xb6\x3e\x20\x4e\x5b\x6a\xd1\x54\x6f\xac\xc3\x66\xd5\xee\x6f\xe3\xe8\x47\x67\xef\x90\x37\x8b\x26\xe3\xe0\xc9\x1a\x5a\x3b\x97\xce\x74\x82\x73\x17\x73\xb7\x3b\x1a\x44\x46\xb6\x0f\x20\x57\x48\x79\x93\x98\xd7\xe6\x27\x1d\x83\x1c\xaf\x10\xd4\xee\x05\x0f\x90\xa6\xb9\x18\x4d\x18\x7d\xb9\x8c\xe9\xa1\x34\x3e\x35\x84\x59\x96\x06\x89\xc7\x16\x83\x22\xfd\x4a\xfe\x46\xf7\xa0\xfb\x67\x00\x42\x89\x04\x2d\x36\x21\x96\xc1\xd0\x48\x92\xdd\x1e\x69\xc5\x85\xe1\x50\xda\x16\x57\xb7\xb3\xd8\x0e\x21\x5f\x52\xfe\xb5\xfb\xe5\x80\x20\x1b\x6d\x0f\xdc\x04\xbb\xea\x5e\x0a\x60\xb1\xff\x71\xe3\x28\x12\x8b\x9d\xaf\x40\x1c\xb7\xb7\x06\x72\xae\xd2\xec\xa2\x0c\x5a\x73\x10\x03\x7c\xf7\x32\x95\xe1\xed\x8e\xef\xfe\x95\x29\x2e\xf9\x9e\xbe\x5b\xa3\xa8\x8c\x0d\x24\x63\x61\xe5\x68\xcc\x90\x01\x32\x4b\x21\x77\x7e\xe8\xd1\x3f\xb5\x8c\xbb\xd1\x1b\x14\xf4\xea\xb4\x3b\x25\x53\x8f\x18\x76\xd5\x23\xcb\xb0\x4c\x5e\x4b\x04\x9f\x72\x25\x52\x2e\x7e\xc8\xb8\xa1\x88\x39\x5f\x36\x30\x41\xc5\x86\x9a\x35\x52\x1b\xfe\x1b\x9d\x89\xf1\x3d\x5f\x23\xbd\xf4\xb1\x2e\x13\x97\x90\xde\x90\xb6\x82\xcf\x5a\x60\xfc\x59\x88\xfc\x44\x1e\x02\xc6\x2a\x9b\xdf\x2e\x0c\x06\x85\x41\xcb\x3a\x80\x3b\x1e\xf1\x56\x06\x9a\x9d\x97\x62\xca\x02\x5b\xbd\x9a\xb3\xc1\x25\x2a\x63\x08\x6d\x0f\xf1\x0f\xba\xb1\x0c\xe4\x4b\x9a\x30\xad\x56\x8c\x8a\x1f\x5f\x7e\xb3\xa3\xe9\xeb\x56\xb9\x02\x0d\x04\x55\x08\x5e\x1d\x01\x10\x00\xc3\x7a\xa5\xc2\xc9\x52\x1c\x3d\x6d\xf3\xb9\x92\xa8\x4b\xbf\x8a\x6b\xb7\x40\x2a\x54\x15\x28\x93\xa5\x3c\xb4\x86\x84\x73\xdb\xc3\x69\xab\x01\x70\x51\xd7\x80\xfb\x28\x38\x6f\x7b\x0d\x70\x7a\x05\xdb\xec\x1e\xe2\xbf\xe6\xe3\x15\x1f\x93\xcd\x7b\x9f\x0c\x2e\x9d\x3c\x88\x2a\x08\xb7\x40\xb4\x09\xb3\x77\xf8\x3f\x50\x6d\xe8\x37\xec\x0c\x8a\xc8\x56\xa7\x07\xf0\x97\xab\x5b\x4f\x29\x50\x89\x73\xa0\x4c\x36\x43\xbf\x06\xcc\x27\x52\xc4\xd3\x9a\x57\x1d\xe0\x6a\x2f\xa5\xa2\x54\x38\xe6\x73\x6e\x51\x94\x40\x16\xe1\xcd\x1a\x21\x86\x63\x86\x7d\xdb\x12\x70\x67\x9e\x60\xc1\x3f\xc8\xd1\x6a\xce\xdd\x59\x02\xb5\x78\xbd\xad\x61\x38\xb3\x94\xa4\xd1\x6f\xf5\x33\xb2\xd1\x95\x62\xff\x20\xe2\xfa\xc6\x00\xf5\xf0\x92\x65\x4f\x5a\x95\x62\x3f\x71\xb0\x5c\xb7\x92\x3e\xdd\xb8\x75\x97\x6e\xae\x9a\x56\x6c\x61\x09\xbc\xba\xa9\xd2\x82\x24\x16\xa5\x19\xba\x50\x93\xba\xc5\x06\xe6\x50\xdf\x46\xcc\x26\x32\x28\x29\xa9\xcd\x94\x5d\xba\xaa\xa3\x8e\xd8\x85\xd7\x45\xb5\xcb\x38\xa8\x4d\xf4\xed\xab\x67\x2f\x53\xa3\xdd\x20\xd6\x18\xf3\x0d\x94\xb8\xe8\xd1\x77\xd8\x02\x86\xdb\xc6\xb9\xdb\x8e\x23\x0a\xa5\x45\x36\x12\x69\x75\xf5\x74\x3a\x05\x7b\x5b\xd6\xa9\x9c\xd1\x9b\xea\x48\x0e\xe9\x8e\xf5\xe5\xf9\x8c\xc9\xb3\x15\x72\xc3\x1b\x6a\x43\xda\x5f\x7b\xce\x84\xa3\x54\x57\xff\xa5\x8a\x01\x6a\xc8\x17\xe3\x77\xb7\x57\xf6\x84\x93\xd3\xd4\x81\x76\xd8\x16\x6d\x90\xc4\x53\x1c\x21\x84\x8e\xf4\x61\x03\x32\x81\x3e\x43\x1a\x0c\x5d\xfd\x54\x8c\xbc\x4c\x08\xae\x60\x0f\x98\x87\x2f\x71\x5f\xdb\x3c\x97\x2f\x39\x53\x64\x4f\x9f\x1c\xf3\x0b\x70\x09\x33\x72\x9d\xae\xea\x92\x7d\xc6\x90\x06\x7a\x4a\xaa\x7a\xa9\xc8\x49\x76\x76\xa3\xcc\x97\xb2\xab\xfc\x35\x5b\xe5\xd7\x36\x92\x89\x2a\x94\xfa\x46\xa4\xf6\x62\x20\xff\x6f\x96\x0b\xd5\xb5\xa8\xed\x8f\x79\x22\xd6\xda\xd8\xa2\xb3\xdf\x34\x42\x79\xb2\x0c\xe0\x60\xda\x82\xf4\xd4\x84\xe1\xfe\xef\x86\x4e\x87\x44\x1b\x07\xd1\x60\x9a\x0d\x00\x98\x14\x8d\xc5\x0c\xa5\x69\x74\x2e\xea\x06\xf2\x51\xba\xc2\xe9\x21\x03\x84\x18\x15\x6a\x5f\xd9\x03\xd5\x81\x34\x7a\xdd\x56\xe9\x16\x0c\x02\x9d\x47\x12\x10\xfa\x87\x07\x40\x51\x0a\xc0\xc7\xb1\xdd\x24\xfb\xf6\x12\xb8\xfa\x25\x00\x11\x01\x00\x01\x89\x02\x1f\x04\x18\x01\x08\x00\x09\x05\x02\x55\x08\x5e\x1d\x02\x1b\x0c\x00\x0a\x09\x10\x3e\xbf\xca\xaa\x8c\x8a\xd9\x9e\xb3\x3c\x0f\xfe\x3e\x42\x53\xcc\xff\x24\x43\x0e\x06\x5b\x4c\x76\x67\x15\xdf\x3a\x69\x11\x55\x8a\x52\x12\x81\xde\x85\xfe\xb2\xf5\x81\x4d\xd3\x4f\x93\xf2\x96\xfb\xd5\x11\x88\xb6\xfb\x97\xe6\xfe\xa8\x3c\xa3\xc2\x94\xe9\xc8\x56\x0d\x96\x54\x73\xaa\xe9\x0d\xc7\xb1\x71\x33\x97\xba\x08\x6c\xeb\x4f\x13\xdf\x16\x5c\x78\x95\x5e\xe7\x7f\x76\x37\x39\xe2\xe1\xf3\xf5\x68\xd2\x3d\xfc\xbf\x89\xd3\xfb\x48\xcb\x25\xa3\x6f\x41\x1d\x1f\xca\xf6\x74\x24\x88\x6b\x5a\xc8\x3e\x7b\xc1\xdc\x60\x6c\xb5\xce\x6c\x4d\xdf\x03\x48\x25\xe0\x0b\x16\x97\x51\x19\xcc\xd7\x16\x54\xbe\x12\x22\xbb\xe7\x04\x6a\x58\x21\x41\x81\x72\xc4\xc8\x88\xfd\xe9\xd3\xd6\xee\xe1\x07\xfa\x1e\x32\x51\x5d\x99\x41\xba\x2c\xe2\x80\x88\x1e\x3b\x7f\x65\xfc\x6e\xad\x6f\xa1\x80\xd5\xc9\xdb\xab\x8c\xba\x68\x2b\x50\x79\x71\xcb\xae\x7b\xda\x93\x58\xd1\xab\x39\xe5\x25\x65\x2a\x4b\x59\x90\x80\xe3\xc5\xd4\xcb\x8e\x76\xe1\xc0\xbd\x06\xdf\x30\x14\x17\x00\x47\xe0\x39\x3c\xee\x1f\xd3\xee\x2a\x81\xa6\xec\xc7\x8f\xc1\x3a\xd4\xe4\x6b\x0e\xa4\xd8\x12\xe0\xb6\xef\x21\x13\x83\x27\x16\x03\xfa\xf2\x30\x03\x90\x67\x8a\x28\xe0\x7c\xdf\x5a\x8f\xd2\x90\x54\xc5\x11\xad\xde\x0d\xa7\xb8\xb4\x11\x59\xa3\xf0\xff\x45\xb4\xd8\x18\xb0\x46\x83\xb7\xb9\x5a\x1a\x93\x41\xf7\xef\x58\xf6\x17\x9b\xea\x43\x44\xba\x51\x7b\x28\x8e\xf2\xf0\x22\xa2\x92\x0b\xc5\x18\x71\xc2\xc9\x7d\x81\x08\x26\xd0\x06\xa8\xba\xc1\xb1\x06\xab\x5e\xaa\x91\x32\x66\x7a\xc6\x2e\xf6\x28\x38\xbf\x8c\x43\xfd\x0f\xdc\x2c\x91\x73\x88\x92\xe3\x11\xc5\xac\x2f\xb8\x6a\xee\xad\xa8\xe9\xee\xcd\x2f\xa8\x5f\xe5\xa4\xc7\xd3\xf6\xdd\x78\xc5\xcc\xa9\x1c\xc3\x08\x01\x50\xe5\x9f\xb1\xd1\x05\x02\x81\x5a\x27\xc7\x38\xfe\x0a\xe4\xc3\xfc\xb7\x8e\xb3\xf4\x07\xbb\xff\x5e\x9a\xf9\xbd\x10\xe3\x18\x63\xf5\xfd\xbe\x27\x4b\x7f\x9f\x0f\x4f\xf0\x0c\xa8\xc8\x98\x6c\xd5\xad\xcb\xaa\x98\xea\x4d\x8b\x33\x0e\xf8\x61\xde\x3e\x84\xef\x93\x8e\xb9\x3c\x32\xba\x9b\x09\x4b\x3d\x87\xa8\xa1\xf4\x83\x82\xa3\xaf\x09\x4d\x64\x10\x6e\x05\x92\x93\x64\xc0\xc9\xdd\xd4\xe0\xea\x93\xc8\x19\xc7\x5a\xbd\x07\x84\x70\xd1\x4c\xec\x72\x0d\xb6\x54\xb5\x76\xe4\xfe\xbe\x10\xe2\x04\xdc\x02\xdf\xaa\x8e\x9b\x30\x3f\x29",false)) + + (CASE_S(QType::SPF, "\"v=spf1 a:mail.rec.test ~all\"", "\x1bv=spf1 a:mail.rec.test ~all",false)) + (CASE_S(QType::EUI48, "00-11-22-33-44-55", "\x00\x11\x22\x33\x44\x55",false)) + (CASE_S(QType::EUI64, "00-11-22-33-44-55-66-77", "\x00\x11\x22\x33\x44\x55\x66\x77",false)) + (CASE_S(QType::TSIG, "HMAC-MD5.SIG-ALG.REG.INT. 1368386956 60 16 TkbpD66/Mtgo8GUEFZIwhg== 12345 0 0", "\x08HMAC-MD5\x07SIG-ALG\x03REG\x03INT\x00\x00\x00\x51\x8f\xed\x8c\x00\x3c\x00\x10\x4e\x46\xe9\x0f\xae\xbf\x32\xd8\x28\xf0\x65\x04\x15\x92\x30\x86\x30\x39\x00\x00\x00\x00",false)) + (CASE_S(QType::TSIG, "HMAC-MD5.SIG-ALG.REG.INT. 1368386956 60 16 TkbpD66/Mtgo8GUEFZIwhg== 12345 18 16 TkbpD66/Mtgo8GUEFZIwhg==", "\x08HMAC-MD5\x07SIG-ALG\x03REG\x03INT\x00\x00\x00\x51\x8f\xed\x8c\x00\x3c\x00\x10\x4e\x46\xe9\x0f\xae\xbf\x32\xd8\x28\xf0\x65\x04\x15\x92\x30\x86\x30\x39\x00\x12\x00\x10\x4e\x46\xe9\x0f\xae\xbf\x32\xd8\x28\xf0\x65\x04\x15\x92\x30\x86",false)) + (CASE_S(QType::TKEY, "gss-tsig. 12345 12345 3 21 4 dGVzdA== 4 dGVzdA==", "\x08gss-tsig\x00\x00\x00\x30\x39\x00\x00\x30\x39\x00\x03\x00\x15\x00\x04test\x00\x04test", false)) +/* (CASE_S(QType::ADDR, "zone format", "line format",false)) */ + (CASE_S(QType::DLV, "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e",false)) + (CASE_S(QType::URI, "10000 1 \"ftp://ftp1.example.com/public\"", "\x27\x10\x00\x01\x66\x74\x70\x3a\x2f\x2f\x66\x74\x70\x31\x2e\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x70\x75\x62\x6c\x69\x63", false)) + (CASE_S(QType::URI, "10 1 \"ftp://ftp1.example.com/public/with/a/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/long/url\"", "\x00\x0a\x00\x01\x66\x74\x70\x3a\x2f\x2f\x66\x74\x70\x31\x2e\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x70\x75\x62\x6c\x69\x63\x2f\x77\x69\x74\x68\x2f\x61\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x6c\x6f\x6e\x67\x2f\x75\x72\x6c", false)) + (CASE_S(QType::CAA, "0 issue \"example.net\"", "\x00\x05\x69\x73\x73\x75\x65\x65\x78\x61\x6d\x70\x6c\x65\x2e\x6e\x65\x74",false)) + (CASE_S((QType::typeenum)65226,"\\# 3 414243","\x41\x42\x43",false)) +; + + int n=0; + int lq=-1; + for(const cases_t::value_type& val : cases) { + QType q(val.get<0>()); + if (lq != q.getCode()) n = 0; + lq = q.getCode(); + n++; + BOOST_TEST_CHECKPOINT("Checking record type " << q.getName() << " test #" << n); + BOOST_TEST_MESSAGE("Checking record type " << q.getName() << " test #" << n); + try { + std::string recData; + if (q.getCode() != QType::TSIG) { + auto rec = DNSRecordContent::mastermake(q.getCode(), 1, val.get<1>()); + BOOST_CHECK_MESSAGE(rec != NULL, "mastermake( " << q.getCode() << ", 1, " << val.get<1>() << ") returned NULL"); + if (rec == NULL) continue; + // now verify the record (note that this will be same as *zone* value (except for certain QTypes) + + switch(q.getCode()) { + case QType::NS: + case QType::PTR: + case QType::MX: + case QType::CNAME: + case QType::SOA: + case QType::TXT: + // check *input* value instead + REC_CHECK_EQUAL(rec->getZoneRepresentation(), val.get<1>()); + break; + default: + REC_CHECK_EQUAL(rec->getZoneRepresentation(), val.get<2>()); + } + recData = rec->serialize(DNSName("rec.test")); + } else { + std::shared_ptr rec3 = DNSRecordContent::unserialize(DNSName("rec.test"),q.getCode(),(val.get<3>())); + // TSIG special, only works the other way + recData = rec3->serialize(DNSName("rec.test")); + } + std::shared_ptr rec2 = DNSRecordContent::unserialize(DNSName("rec.test"),q.getCode(),recData); + BOOST_CHECK_MESSAGE(rec2 != NULL, "unserialize(rec.test, " << q.getCode() << ", recData) returned NULL"); + if (rec2 == NULL) continue; + // now verify the zone representation (here it can be different!) + REC_CHECK_EQUAL(rec2->getZoneRepresentation(), val.get<2>()); + // and last, check the wire format (using hex format for error readability) + string cmpData = makeHexDump(val.get<3>()); + recData = makeHexDump(recData); + REC_CHECK_EQUAL(recData, cmpData); + } catch (std::runtime_error &err) { + REC_CHECK_MESSAGE(false, "Failed to verify " << q.getName() << ": " << err.what()); + continue; + } + REC_FAIL_XSUCCESS(q.getName() << " test #" << n << " has unexpectedly passed") + } +} + +bool test_dnsrecords_cc_predicate( std::exception const &ex ) { return true; } + +// these *MUST NOT* parse properly! +BOOST_AUTO_TEST_CASE(test_record_types_bad_values) { + // qtype, value, zone/wire format, broken + typedef boost::tuple case_t; + typedef std::list cases_t; + + cases_t cases = boost::assign::list_of + (case_t(QType::A, "932.521.256.42", zone, false)) // hollywood IP + (case_t(QType::A, "932.521", zone, false)) // truncated IP + (case_t(QType::A, "\xca\xec\x00", wire, false)) // truncated wire value + (case_t(QType::A, "127.0.0.1 evil data", zone, false)) // trailing garbage + (case_t(QType::AAAA, "23:00", zone, false)) // time when this test was written + (case_t(QType::AAAA, "23:00::15::43", zone, false)) // double compression + (case_t(QType::AAAA, "2a23:00::15::", zone, false)) // ditto + (case_t(QType::AAAA, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff", zone, false)) // truncated wire value +// empty label, must be broken + (case_t(QType::CNAME, "name..example.com.", zone, false)) +// overly large label (64), must be broken + (case_t(QType::CNAME, "1234567890123456789012345678901234567890123456789012345678901234.example.com.", zone, false)) +// local overly large name (256), must be broken + (case_t(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123.rec.test.", zone, false)) +// non-local overly large name (256), must be broken + (case_t(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012.", zone, false)) + (case_t(QType::SOA, "ns.rec.test hostmaster.test.rec 20130512010 3600 3600 604800 120", zone, false)) // too long serial +; + + int n=0; + int lq=-1; + + for(const cases_t::value_type& val : cases) { + QType q(val.get<0>()); + if (lq != q.getCode()) n = 0; + lq = q.getCode(); + n++; + BOOST_TEST_CHECKPOINT("Checking bad value for record type " << q.getName() << " test #" << n); + BOOST_TEST_MESSAGE("Checking bad value for record type " << q.getName() << " test #" << n); + + vector packet; + DNSPacketWriter pw(packet, DNSName("unit.test"), q.getCode()); + + if (val.get<2>()) { + bool success=true; + BOOST_WARN_EXCEPTION( { auto drc = DNSRecordContent::mastermake(q.getCode(), 1, val.get<1>()); pw.startRecord(DNSName("unit.test"), q.getCode()); drc->toPacket(pw); success=false; }, std::exception, test_dnsrecords_cc_predicate ); + if (success==false) REC_FAIL_XSUCCESS2(q.getName() << " test #" << n << " has unexpectedly passed"); // a bad record was detected when it was supposed not to be detected + } else { + BOOST_CHECK_EXCEPTION( { auto drc = DNSRecordContent::mastermake(q.getCode(), 1, val.get<1>()); pw.startRecord(DNSName("unit.test"), q.getCode()); drc->toPacket(pw); }, std::exception, test_dnsrecords_cc_predicate ); + } + }; +} + +// special opt record test, because opt is odd +BOOST_AUTO_TEST_CASE(test_opt_record_in) { + EDNSOpts eo; + + // test that nsid gets parsed into system + std::string packet("\xf0\x01\x01\x00\x00\x01\x00\x01\x00\x00\x00\x01\x03www\x08powerdns\x03""com\x00\x00\x01\x00\x01\x03www\x08powerdns\x03""com\x00\x00\x01\x00\x01\x00\x00\x00\x10\x00\x04\x7f\x00\x00\x01\x00\x00\x29\x05\x00\x00\x00\x00\x00\x00\x0c\x00\x03\x00\x08powerdns",89); + OPTRecordContent::report(); + + MOADNSParser mdp(true, (char*)&*packet.begin(), (unsigned int)packet.size()); + + BOOST_CHECK_EQUAL(getEDNSOpts(mdp, &eo), true); + + // this should contain NSID now + BOOST_CHECK_EQUAL(eo.d_packetsize, 1280); + + // it should contain NSID option with value 'powerdns', and nothing else + BOOST_CHECK_EQUAL(eo.d_options.size(), 1); + BOOST_CHECK_EQUAL(eo.d_options[0].first, 3); // nsid + BOOST_CHECK_EQUAL(eo.d_options[0].second, "powerdns"); +} + +BOOST_AUTO_TEST_CASE(test_opt_record_out) { + vector pak; + vector > opts; + + DNSPacketWriter pw(pak, DNSName("www.powerdns.com"), QType::A); + pw.startRecord(DNSName("www.powerdns.com"), QType::A, 16, 1, DNSResourceRecord::ANSWER); + pw.xfrIP(htonl(0x7f000001)); + opts.push_back(pair(3, "powerdns")); + pw.addOpt(1280, 0, 0, opts); + pw.getHeader()->id = htons(0xf001); + pw.getHeader()->rd = 1; + pw.commit(); + + // see if we can build a DNS packet that looks like this... + std::string packet("\xf0\x01\x01\x00\x00\x01\x00\x01\x00\x00\x00\x01\x03www\x08powerdns\x03""com\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x10\x00\x04\x7f\x00\x00\x01\x00\x00\x29\x05\x00\x00\x00\x00\x00\x00\x0c\x00\x03\x00\x08powerdns",73); + + BOOST_CHECK_EQUAL(makeHexDump(std::string(pak.begin(),pak.end())), makeHexDump(packet)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-ednsoptions_cc.cc b/test-ednsoptions_cc.cc new file mode 100644 index 0000000..2a4cab0 --- /dev/null +++ b/test-ednsoptions_cc.cc @@ -0,0 +1,171 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include "dnsname.hh" +#include "dnswriter.hh" +#include "ednscookies.hh" +#include "ednsoptions.hh" +#include "ednssubnet.hh" +#include "iputils.hh" + +/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */ +int getEDNSOption(char* optRR, size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize); + +BOOST_AUTO_TEST_SUITE(ednsoptions_cc) + +static void getRawQueryWithECSAndCookie(const DNSName& name, const Netmask& ecs, const std::string& clientCookie, const std::string& serverCookie, std::vector& query) +{ + DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); + pw.commit(); + + EDNSCookiesOpt cookiesOpt; + cookiesOpt.client = clientCookie; + cookiesOpt.server = serverCookie; + string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); + EDNSSubnetOpts ecsOpts; + ecsOpts.source = ecs; + string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); + DNSPacketWriter::optvect_t opts; + opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); + opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); + opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); + pw.addOpt(512, 0, 0, opts); + pw.commit(); +} + +BOOST_AUTO_TEST_CASE(test_getEDNSOption) { + DNSName name("www.powerdns.com."); + Netmask ecs("127.0.0.1/32"); + vector query; + + getRawQueryWithECSAndCookie(name, ecs, "deadbeef", "deadbeef", query); + + const struct dnsheader* dh = reinterpret_cast(query.data()); + size_t questionLen = query.size(); + unsigned int consumed = 0; + DNSName dnsname = DNSName(reinterpret_cast(query.data()), questionLen, sizeof(dnsheader), false, nullptr, nullptr, &consumed); + + size_t pos = sizeof(dnsheader) + consumed + 4; + /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2) = 11 */ + BOOST_REQUIRE_EQUAL(ntohs(dh->arcount), 1); + BOOST_REQUIRE(questionLen > pos + 11); + /* OPT root label (1) followed by type (2) */ + BOOST_REQUIRE_EQUAL(query.at(pos), 0); + BOOST_REQUIRE(query.at(pos+2) == QType::OPT); + + char* ecsStart = nullptr; + size_t ecsLen = 0; + int res = getEDNSOption(reinterpret_cast(query.data())+pos+9, questionLen - pos - 9, EDNSOptionCode::ECS, &ecsStart, &ecsLen); + BOOST_CHECK_EQUAL(res, 0); + + EDNSSubnetOpts eso; + BOOST_REQUIRE(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)); + + BOOST_CHECK(eso.source == ecs); +} + +BOOST_AUTO_TEST_CASE(test_getEDNSOptions) { + DNSName name("www.powerdns.com."); + Netmask ecs("127.0.0.1/32"); + vector query; + + getRawQueryWithECSAndCookie(name, ecs, "deadbeef", "deadbeef", query); + + const struct dnsheader* dh = reinterpret_cast(query.data()); + size_t questionLen = query.size(); + unsigned int consumed = 0; + DNSName dnsname = DNSName(reinterpret_cast(query.data()), questionLen, sizeof(dnsheader), false, nullptr, nullptr, &consumed); + + size_t pos = sizeof(dnsheader) + consumed + 4; + /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2) = 11 */ + BOOST_REQUIRE_EQUAL(ntohs(dh->arcount), 1); + BOOST_REQUIRE(questionLen > pos + 11); + /* OPT root label (1) followed by type (2) */ + BOOST_REQUIRE_EQUAL(query.at(pos), 0); + BOOST_REQUIRE(query.at(pos+2) == QType::OPT); + + std::map options; + int res = getEDNSOptions(reinterpret_cast(query.data())+pos+9, questionLen - pos - 9, options); + BOOST_REQUIRE_EQUAL(res, 0); + + /* 3 EDNS options but two of them are EDNS Cookie, so we only keep one */ + BOOST_CHECK_EQUAL(options.size(), 2); + + auto it = options.find(EDNSOptionCode::ECS); + BOOST_REQUIRE(it != options.end()); + BOOST_REQUIRE(it->second.content != nullptr); + BOOST_REQUIRE_GT(it->second.size, 0); + + EDNSSubnetOpts eso; + BOOST_REQUIRE(getEDNSSubnetOptsFromString(it->second.content, it->second.size, &eso)); + BOOST_CHECK(eso.source == ecs); + + it = options.find(EDNSOptionCode::COOKIE); + BOOST_REQUIRE(it != options.end()); + BOOST_REQUIRE(it->second.content != nullptr); + BOOST_REQUIRE_GT(it->second.size, 0); +} + +static void checkECSOptionValidity(const std::string& sourceStr, uint8_t sourceMask, uint8_t scopeMask) +{ + ComboAddress source(sourceStr); + EDNSSubnetOpts ecsOpts; + ecsOpts.source = Netmask(source, sourceMask); + + string ecsOptionStr = makeEDNSSubnetOptsString(ecsOpts); + + /* 2 bytes for family, one for source mask and one for scope mask */ + const size_t ecsHeaderSize = 4; + uint8_t sourceBytes = ((sourceMask - 1) >> 3) + 1; + BOOST_REQUIRE_EQUAL(ecsOptionStr.size(), (ecsHeaderSize + sourceBytes)); + /* family */ + BOOST_REQUIRE_EQUAL(ntohs(*(reinterpret_cast(&ecsOptionStr.at(0)))), source.isIPv4() ? 1 : 2); + /* source mask */ + BOOST_REQUIRE_EQUAL(static_cast(ecsOptionStr.at(2)), sourceMask); + BOOST_REQUIRE_EQUAL(static_cast(ecsOptionStr.at(3)), scopeMask); + ComboAddress truncated(source); + truncated.truncate(sourceMask); + + if (sourceMask > 0) { + ComboAddress res; + + if (source.isIPv4()) { + memset(&res.sin4, 0, sizeof(res.sin4)); + res.sin4.sin_family = AF_INET; + memcpy(&res.sin4.sin_addr.s_addr, &ecsOptionStr.at(4), sourceBytes); + BOOST_REQUIRE(res == truncated); + } + else { + memset(&res.sin6, 0, sizeof(res.sin6)); + res.sin6.sin6_family = AF_INET6; + memcpy(&res.sin6.sin6_addr.s6_addr, &ecsOptionStr.at(4), sourceBytes); + BOOST_REQUIRE(res == truncated); + } + } + + EDNSSubnetOpts parsed; + BOOST_REQUIRE(getEDNSSubnetOptsFromString(ecsOptionStr, &parsed)); + BOOST_REQUIRE(parsed.source == Netmask(truncated, sourceMask)); + BOOST_REQUIRE_EQUAL(ecsOpts.scope.getBits(), parsed.scope.getBits()); +} + +BOOST_AUTO_TEST_CASE(test_makeEDNSSubnetOptsString) { + + checkECSOptionValidity("192.0.2.255", 0, 0); + checkECSOptionValidity("192.0.2.255", 8, 0); + checkECSOptionValidity("255.255.255.255", 9, 0); + checkECSOptionValidity("192.0.2.255", 31, 0); + checkECSOptionValidity("192.0.2.255", 32, 0); + checkECSOptionValidity("2001:DB8::FFFF", 0, 0); + checkECSOptionValidity("2001:DB8::FFFF", 32, 0); + checkECSOptionValidity("2001:DB8::FFFF", 127, 0); + checkECSOptionValidity("2001:DB8::FFFF", 128, 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-iputils_hh.cc b/test-iputils_hh.cc new file mode 100644 index 0000000..cb9899a --- /dev/null +++ b/test-iputils_hh.cc @@ -0,0 +1,319 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include "iputils.hh" + +using namespace boost; + +BOOST_AUTO_TEST_SUITE(iputils_hh) + +BOOST_AUTO_TEST_CASE(test_ComboAddress) { + ComboAddress local("127.0.0.1", 53); + BOOST_CHECK(local==local); + BOOST_CHECK_EQUAL(local.sin4.sin_family, AF_INET); + BOOST_CHECK_EQUAL(local.sin4.sin_port, htons(53)); + BOOST_CHECK_EQUAL(local.sin4.sin_addr.s_addr, htonl(0x7f000001UL)); + + ComboAddress remote("130.161.33.15", 53); + BOOST_CHECK(!(local == remote)); + BOOST_CHECK_EQUAL(remote.sin4.sin_port, htons(53)); + + ComboAddress withport("213.244.168.210:53"); + BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(53)); + + ComboAddress withportO("213.244.168.210:53", 5300); + BOOST_CHECK_EQUAL(withportO.sin4.sin_port, htons(53)); + + withport = ComboAddress("[::]:53"); + BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(53)); + + withport = ComboAddress("[::]:5300", 53); + BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(5300)); + + // Verify that 2 'empty' ComboAddresses are equal, used in syncres.hh to + // signal auth-zones + ComboAddress a = ComboAddress(); + ComboAddress b = ComboAddress(); + BOOST_CHECK(a == b); + + // Verify that 2 ComboAddresses are not the same + ComboAddress c = ComboAddress("127.0.0.1:53"); + ComboAddress d = ComboAddress("127.0.0.1:52"); + ComboAddress e = ComboAddress("127.0.0.2:53"); + + BOOST_CHECK(a != c); + BOOST_CHECK(c != d); + BOOST_CHECK(c != e); + BOOST_CHECK(d != e); + BOOST_CHECK(!(a != b)); + + // Verify that we don't allow invalid port numbers + BOOST_CHECK_THROW(ComboAddress("127.0.0.1:70000"), PDNSException); // Port no. too high + BOOST_CHECK_THROW(ComboAddress("127.0.0.1:-6"), PDNSException); // Port no. too low + BOOST_CHECK_THROW(ComboAddress("[::1]:70000"), PDNSException); // Port no. too high + BOOST_CHECK_THROW(ComboAddress("[::1]:-6"), PDNSException); // Port no. too low +} + +BOOST_AUTO_TEST_CASE(test_ComboAddressCompare) { + ComboAddress a, b; + a.reset(); + b.reset(); + BOOST_CHECK(!(ab)); +} + +BOOST_AUTO_TEST_CASE(test_ComboAddressTruncate) { + ComboAddress ca4("130.161.252.29"); + ca4.truncate(24); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0"); + ca4.truncate(16); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.0.0"); + + + + ca4 = ComboAddress("130.161.252.29"); + ComboAddress orig(ca4); + for(int n=32; n; --n) { + ca4.truncate(n); + + uint32_t p; + memcpy(&p, (char*)&ca4.sin4.sin_addr.s_addr, 4); + std::bitset<32> result(htonl(p)); + + memcpy(&p, (char*)&orig.sin4.sin_addr.s_addr, 4); + std::bitset<32> manual(htonl(p)); + + auto tokill=32-n; + for(int i =0; i< tokill; ++i) + manual.set(i, 0); + + BOOST_CHECK_EQUAL(result, manual); + } + + ca4 = ComboAddress("130.161.252.29"); + ca4.truncate(31); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.28"); + + ca4.truncate(30); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.28"); + + ca4.truncate(29); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.24"); + + ca4.truncate(23); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0"); + + ca4.truncate(22); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0"); + + ca4.truncate(21); + BOOST_CHECK_EQUAL(ca4.toString(), "130.161.248.0"); + + ComboAddress ca6("2001:888:2000:1d::2"); + ca6.truncate(120); + BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::"); + ca6.truncate(64); + BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::"); + ca6.truncate(72); // 0102 304 0506 78 + BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::"); + ca6.truncate(56); + BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000::"); + ca6.truncate(48); + BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000::"); + ca6.truncate(32); + BOOST_CHECK_EQUAL(ca6.toString(), "2001:888::"); + ca6.truncate(16); + BOOST_CHECK_EQUAL(ca6.toString(), "2001::"); + ca6.truncate(8); + BOOST_CHECK_EQUAL(ca6.toString(), "2000::"); + + + orig=ca6=ComboAddress("2001:888:2000:1d::2"); + for(int n=128; n; --n) { + ca6.truncate(n); + + std::bitset<128> result, manual; + for(int i=0; i < 16; ++i) { + result<<=8; + result|= std::bitset<128>(*((unsigned char*)&ca6.sin6.sin6_addr.s6_addr + i)); + + manual<<=8; + manual|= std::bitset<128>(*((unsigned char*)&orig.sin6.sin6_addr.s6_addr + i)); + } + + auto tokill=128-n; + for(int i =0; i< tokill; ++i) + manual.set(i, 0); + + BOOST_CHECK_EQUAL(result, manual); + } +} + + +BOOST_AUTO_TEST_CASE(test_Mapping) +{ + ComboAddress lh("::1"); + BOOST_CHECK_EQUAL(lh.toString(), "::1"); +} + +BOOST_AUTO_TEST_CASE(test_Netmask) { + ComboAddress local("127.0.0.1", 53); + ComboAddress remote("130.161.252.29", 53); + + Netmask nm("127.0.0.1/24"); + BOOST_CHECK(nm.getBits() == 24); + BOOST_CHECK(nm.match(local)); + BOOST_CHECK(!nm.match(remote)); + BOOST_CHECK(nm.isIpv4()); + BOOST_CHECK(!nm.isIpv6()); + + Netmask nm6("fe80::92fb:a6ff:fe4a:51da/64"); + BOOST_CHECK(nm6.getBits() == 64); + BOOST_CHECK(nm6.match("fe80::92fb:a6ff:fe4a:51db")); + BOOST_CHECK(!nm6.match("fe81::92fb:a6ff:fe4a:51db")); + BOOST_CHECK(!nm6.isIpv4()); + BOOST_CHECK(nm6.isIpv6()); + + Netmask nmp("130.161.252.29/32"); + BOOST_CHECK(nmp.match(remote)); + + Netmask nmp6("fe80::92fb:a6ff:fe4a:51da/128"); + BOOST_CHECK(nmp6.match("fe80::92fb:a6ff:fe4a:51da")); + BOOST_CHECK(!nmp6.match("fe81::92fb:a6ff:fe4a:51db")); + + Netmask all("0.0.0.0/0"); + BOOST_CHECK(all.match(local) && all.match(remote)); + + Netmask all6("::/0"); + BOOST_CHECK(all6.match("::1") && all6.match("fe80::92fb:a6ff:fe4a:51da")); + + + Netmask fromCombo1(ComboAddress("192.0.2.1:53"), 32); + Netmask fromCombo2(ComboAddress("192.0.2.1:54"), 32); + BOOST_CHECK(fromCombo1 == fromCombo2); + BOOST_CHECK(fromCombo1.match("192.0.2.1")); + BOOST_CHECK(fromCombo1.match(ComboAddress("192.0.2.1:80"))); + BOOST_CHECK(fromCombo1.getNetwork() == ComboAddress("192.0.2.1")); + BOOST_CHECK(fromCombo1.getMaskedNetwork() == ComboAddress("192.0.2.1")); + + Netmask nm25("192.0.2.255/25"); + BOOST_CHECK(nm25.getBits() == 25); + BOOST_CHECK(nm25.getNetwork() == ComboAddress("192.0.2.255")); + BOOST_CHECK(nm25.getMaskedNetwork() == ComboAddress("192.0.2.128")); + + /* Make sure that more specific Netmasks are lesser than less specific ones, + as this is very useful when matching. */ + Netmask specific32("192.0.0.0/32"); + Netmask specific24("192.0.0.0/24"); + Netmask specific16("192.0.0.0/16"); + BOOST_CHECK(specific32 < specific24); + BOOST_CHECK(specific24 > specific32); + BOOST_CHECK(specific24 < specific16); + BOOST_CHECK(specific16 > specific24); + + Netmask sameMask1("192.0.0.0/16"); + Netmask sameMask2("192.0.0.1/16"); + BOOST_CHECK(sameMask1 < sameMask2); + BOOST_CHECK(sameMask2 > sameMask1); + + /* An empty Netmask should be larger than + every others. */ + Netmask empty = Netmask(); + Netmask full("255.255.255.255/32"); + BOOST_CHECK(empty > all); + BOOST_CHECK(all < empty); + BOOST_CHECK(empty > full); + BOOST_CHECK(full < empty); +} + +BOOST_AUTO_TEST_CASE(test_NetmaskGroup) { + + { + NetmaskGroup ng; + ng.addMask("10.0.1.0"); + BOOST_CHECK(ng.match(ComboAddress("10.0.1.0"))); + ng.toMasks("127.0.0.0/8, 10.0.0.0/24"); + BOOST_CHECK(ng.match(ComboAddress("127.0.0.1"))); + BOOST_CHECK(ng.match(ComboAddress("10.0.0.3"))); + BOOST_CHECK(ng.match(ComboAddress("10.0.1.0"))); + BOOST_CHECK(!ng.match(ComboAddress("128.1.2.3"))); + BOOST_CHECK(!ng.match(ComboAddress("10.0.1.1"))); + BOOST_CHECK(!ng.match(ComboAddress("::1"))); + ng.addMask("::1"); + BOOST_CHECK(ng.match(ComboAddress("::1"))); + BOOST_CHECK(!ng.match(ComboAddress("::2"))); + ng.addMask("fe80::/16"); + BOOST_CHECK(ng.match(ComboAddress("fe80::1"))); + BOOST_CHECK(!ng.match(ComboAddress("fe81::1"))); + BOOST_CHECK_EQUAL(ng.toString(), "10.0.1.0/32, 127.0.0.0/8, 10.0.0.0/24, ::1/128, fe80::/16"); + + /* negative entries using the explicit flag */ + ng.addMask("172.16.0.0/16", true); + BOOST_CHECK(ng.match(ComboAddress("172.16.1.1"))); + BOOST_CHECK(ng.match(ComboAddress("172.16.4.50"))); + ng.addMask("172.16.4.0/24", false); + BOOST_CHECK(ng.match(ComboAddress("172.16.1.1"))); + BOOST_CHECK(!ng.match(ComboAddress("172.16.4.50"))); + ng.addMask("fe80::/24", false); + BOOST_CHECK(!ng.match(ComboAddress("fe80::1"))); + BOOST_CHECK(!ng.match(ComboAddress("fe81::1"))); + /* not in fe80::/24 but in fe80::/16, should match */ + BOOST_CHECK(ng.match(ComboAddress("fe80:0100::1"))); + + /* negative entries using '!' */ + BOOST_CHECK(ng.match(ComboAddress("172.16.10.80"))); + ng.addMask("!172.16.10.0/24"); + BOOST_CHECK(!ng.match(ComboAddress("172.16.10.80"))); + ng.addMask("2001:db8::/32"); + ng.addMask("!2001:db8::/64"); + BOOST_CHECK(!ng.match(ComboAddress("2001:db8::1"))); + /* not in 2001:db8::/64 but in 2001:db8::/32, should match */ + BOOST_CHECK(ng.match(ComboAddress("2001:db8:1::1"))); + + BOOST_CHECK_EQUAL(ng.toString(), "10.0.1.0/32, 127.0.0.0/8, 10.0.0.0/24, ::1/128, fe80::/16, 172.16.0.0/16, !172.16.4.0/24, !fe80::/24, !172.16.10.0/24, 2001:db8::/32, !2001:db8::/64"); + } + + { + /* this time using Netmask objects instead of strings */ + NetmaskGroup ng; + ng.addMask(Netmask("10.0.1.0")); + BOOST_CHECK(ng.match(ComboAddress("10.0.1.0"))); + ng.addMask(Netmask("127.0.0.0/8")); + ng.addMask(Netmask("10.0.0.0/24")); + BOOST_CHECK(ng.match(ComboAddress("127.0.0.1"))); + BOOST_CHECK(ng.match(ComboAddress("10.0.0.3"))); + BOOST_CHECK(ng.match(ComboAddress("10.0.1.0"))); + BOOST_CHECK(!ng.match(ComboAddress("128.1.2.3"))); + BOOST_CHECK(!ng.match(ComboAddress("10.0.1.1"))); + BOOST_CHECK(!ng.match(ComboAddress("::1"))); + ng.addMask(Netmask("::1")); + BOOST_CHECK(ng.match(ComboAddress("::1"))); + BOOST_CHECK(!ng.match(ComboAddress("::2"))); + ng.addMask(Netmask("fe80::/16")); + BOOST_CHECK(ng.match(ComboAddress("fe80::1"))); + BOOST_CHECK(!ng.match(ComboAddress("fe81::1"))); + BOOST_CHECK_EQUAL(ng.toString(), "10.0.1.0/32, 127.0.0.0/8, 10.0.0.0/24, ::1/128, fe80::/16"); + + /* negative entries using the explicit flag */ + ng.addMask(Netmask("172.16.0.0/16"), true); + BOOST_CHECK(ng.match(ComboAddress("172.16.1.1"))); + BOOST_CHECK(ng.match(ComboAddress("172.16.4.50"))); + ng.addMask(Netmask("172.16.4.0/24"), false); + BOOST_CHECK(ng.match(ComboAddress("172.16.1.1"))); + BOOST_CHECK(!ng.match(ComboAddress("172.16.4.50"))); + ng.addMask("fe80::/24", false); + BOOST_CHECK(!ng.match(ComboAddress("fe80::1"))); + BOOST_CHECK(!ng.match(ComboAddress("fe81::1"))); + /* not in fe80::/24 but in fe80::/16, should match */ + BOOST_CHECK(ng.match(ComboAddress("fe80:0100::1"))); + + BOOST_CHECK_EQUAL(ng.toString(), "10.0.1.0/32, 127.0.0.0/8, 10.0.0.0/24, ::1/128, fe80::/16, 172.16.0.0/16, !172.16.4.0/24, !fe80::/24"); + } +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-ixfr_cc.cc b/test-ixfr_cc.cc new file mode 100644 index 0000000..63f4bdd --- /dev/null +++ b/test-ixfr_cc.cc @@ -0,0 +1,303 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "test-common.hh" +#include "ixfr.hh" + +BOOST_AUTO_TEST_SUITE(ixfr_cc) + +BOOST_AUTO_TEST_CASE(test_ixfr_rfc1995_axfr) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::NS, "NS.JAIN.AD.JP."); + addRecordToList(records, DNSName("NS.JAIN.AD.JP."), QType::A, "133.69.136.1"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(ret.at(0).first.size(), 0); + BOOST_REQUIRE_EQUAL(ret.at(0).second.size(), records.size()); + for (size_t idx = 0; idx < records.size(); idx++) { + BOOST_CHECK(ret.at(0).second.at(idx) == records.at(idx)); + } +} + +BOOST_AUTO_TEST_CASE(test_ixfr_rfc1995_incremental) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 2 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.4"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 2 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.4"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)); + // two sequences + BOOST_CHECK_EQUAL(ret.size(), 2); + // the first one has one removal, two additions (plus the corresponding SOA removal/addition) + BOOST_CHECK_EQUAL(ret.at(0).first.size(), 1 + 1); + BOOST_CHECK_EQUAL(ret.at(0).second.size(), 2 + 1); + + // check removals + BOOST_CHECK_EQUAL(ret.at(0).first.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).first.at(1).d_type, QType(QType::A).getCode()); + + // check additions + BOOST_CHECK_EQUAL(ret.at(0).second.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).second.at(1).d_type, QType(QType::A).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).second.at(2).d_type, QType(QType::A).getCode()); + + // the second one has one removal, one addition + BOOST_CHECK_EQUAL(ret.at(1).first.size(), 1 + 1); + BOOST_CHECK_EQUAL(ret.at(1).second.size(), 1 + 1); + + // check removals + BOOST_CHECK_EQUAL(ret.at(1).first.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(1).first.at(1).d_type, QType(QType::A).getCode()); + + // check additions + BOOST_CHECK_EQUAL(ret.at(1).second.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(1).second.at(1).d_type, QType(QType::A).getCode()); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_rfc1995_condensed_incremental) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)); + // one sequence + BOOST_CHECK_EQUAL(ret.size(), 1); + // it has one removal, two additions (plus the corresponding SOA removal/addition) + BOOST_CHECK_EQUAL(ret.at(0).first.size(), 1 + 1); + BOOST_CHECK_EQUAL(ret.at(0).second.size(), 2 + 1); + + // check removals + BOOST_CHECK_EQUAL(ret.at(0).first.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).first.at(1).d_type, QType(QType::A).getCode()); + + // check additions + BOOST_CHECK_EQUAL(ret.at(0).second.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).second.at(1).d_type, QType(QType::A).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).second.at(2).d_type, QType(QType::A).getCode()); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_no_additions_in_first_sequence) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 2 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 2 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.5"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)); + // two sequences + BOOST_CHECK_EQUAL(ret.size(), 2); + // the first one has one removal, no additions (plus the corresponding SOA removal/addition) + BOOST_CHECK_EQUAL(ret.at(0).first.size(), 1 + 1); + BOOST_CHECK_EQUAL(ret.at(0).second.size(), 0 + 1); + + // check removals + BOOST_CHECK_EQUAL(ret.at(0).first.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).first.at(1).d_type, QType(QType::A).getCode()); + + // check additions + BOOST_CHECK_EQUAL(ret.at(0).second.at(0).d_type, QType(QType::SOA).getCode()); + + // the second one has one removal, one addition + BOOST_CHECK_EQUAL(ret.at(1).first.size(), 1 + 1); + BOOST_CHECK_EQUAL(ret.at(1).second.size(), 1 + 1); + + // check removals + BOOST_CHECK_EQUAL(ret.at(1).first.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(1).first.at(1).d_type, QType(QType::A).getCode()); + + // check additions + BOOST_CHECK_EQUAL(ret.at(1).second.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(1).second.at(1).d_type, QType(QType::A).getCode()); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_no_removals_in_first_sequence) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 2 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.4"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 2 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.4"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)); + // two sequences + BOOST_CHECK_EQUAL(ret.size(), 2); + // the first one has no removal, two additions (plus the corresponding SOA removal/addition) + BOOST_CHECK_EQUAL(ret.at(0).first.size(), 0 + 1); + BOOST_CHECK_EQUAL(ret.at(0).second.size(), 2 + 1); + + // check removals + BOOST_CHECK_EQUAL(ret.at(0).first.at(0).d_type, QType(QType::SOA).getCode()); + + // check additions + BOOST_CHECK_EQUAL(ret.at(0).second.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).second.at(1).d_type, QType(QType::A).getCode()); + BOOST_CHECK_EQUAL(ret.at(0).second.at(1).d_type, QType(QType::A).getCode()); + + // the second one has one removal, one addition + BOOST_CHECK_EQUAL(ret.at(1).first.size(), 1 + 1); + BOOST_CHECK_EQUAL(ret.at(1).second.size(), 1 + 1); + + // check removals + BOOST_CHECK_EQUAL(ret.at(1).first.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(1).first.at(1).d_type, QType(QType::A).getCode()); + + // check additions + BOOST_CHECK_EQUAL(ret.at(1).second.at(0).d_type, QType(QType::SOA).getCode()); + BOOST_CHECK_EQUAL(ret.at(1).second.at(1).d_type, QType(QType::A).getCode()); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_same_serial) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)); + + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_records) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + + auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_master_soa) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); +; + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + auto ret = processIXFRRecords(master, zone, records, nullptr); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_trailing_soa) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2"); + + BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_soa_after_removals) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5"); + + BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_mistmatching_serial_before_and_after_additions) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 2 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + + BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_ixfr_trailing_record_after_end) { + const ComboAddress master("[2001:DB8::1]:53"); + const DNSName zone("JAIN.AD.JP."); + + auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + vector records; + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800"); + addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2"); + addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800"); + addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3"); + + BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast(masterSOA)), std::runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/test-misc_hh.cc b/test-misc_hh.cc new file mode 100644 index 0000000..d43693d --- /dev/null +++ b/test-misc_hh.cc @@ -0,0 +1,180 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include +#include "misc.hh" +#include "dns.hh" +#include +#include + +using std::string; + +BOOST_AUTO_TEST_SUITE(misc_hh) +typedef pair typedns_t; + +BOOST_AUTO_TEST_CASE(test_CIStringCompare) { + set nsset; + nsset.insert("abc"); + nsset.insert("ns.example.com"); + nsset.insert(""); + nsset.insert("def"); + nsset.insert("aBc"); + nsset.insert("ns.example.com"); + BOOST_CHECK_EQUAL(nsset.size(), 4); + + ostringstream s; + for(set::const_iterator i=nsset.begin();i!=nsset.end();++i) { + s<<"("<<*i<<")"; + } + BOOST_CHECK_EQUAL(s.str(), "()(abc)(def)(ns.example.com)"); +} + +BOOST_AUTO_TEST_CASE(test_CIStringPairCompare) { + set nsset2; + nsset2.insert(make_pair("ns.example.com", 1)); + nsset2.insert(make_pair("abc", 1)); + nsset2.insert(make_pair("", 1)); + nsset2.insert(make_pair("def", 1)); + nsset2.insert(make_pair("abc", 2)); + nsset2.insert(make_pair("abc", 1)); + nsset2.insert(make_pair("ns.example.com", 0)); + nsset2.insert(make_pair("abc", 2)); + nsset2.insert(make_pair("ABC", 2)); + BOOST_CHECK_EQUAL(nsset2.size(), 6); + + ostringstream s; + for(set::const_iterator i=nsset2.begin();i!=nsset2.end();++i) { + s<<"("<first<<"|"<second<<")"; + } + BOOST_CHECK_EQUAL(s.str(), "(|1)(abc|1)(abc|2)(def|1)(ns.example.com|0)(ns.example.com|1)"); +} + +BOOST_AUTO_TEST_CASE(test_pdns_ilexicographical_compare) { + typedef boost::tuple case_t; + typedef std::list cases_t; + + cases_t cases = boost::assign::list_of + (case_t(std::string(""), std::string(""), false)) + (case_t(std::string(""), std::string("abc"), true)) + (case_t(std::string("abc"), std::string(""), false)) + (case_t(std::string("abc"), std::string("abcd"), true)) + (case_t(std::string("abcd"), std::string("abc"), false)) + (case_t(std::string("abd"), std::string("abc"), false)) + (case_t(std::string("abc"), std::string("abd"), true)) + (case_t(std::string("abc"), std::string("Abc"), false)) + (case_t(std::string("Abc"), std::string("abc"), false)) + ; + + for(const case_t& val : cases) { + bool res; + res = pdns_ilexicographical_compare(val.get<0>(), val.get<1>()); + BOOST_CHECK_EQUAL(res, val.get<2>()); + } +} + +BOOST_AUTO_TEST_CASE(test_pdns_iequals) { + typedef boost::tuple case_t; + typedef std::list cases_t; + + cases_t cases = boost::assign::list_of + (case_t(std::string(""), std::string(""), true)) + (case_t(std::string(""), std::string("abc"), false)) + (case_t(std::string("abc"), std::string(""), false)) + (case_t(std::string("abc"), std::string("abcd"), false)) + (case_t(std::string("abcd"), std::string("abc"), false)) + (case_t(std::string("abd"), std::string("abc"), false)) + (case_t(std::string("abc"), std::string("abd"), false)) + (case_t(std::string("abc"), std::string("Abc"), true)) + (case_t(std::string("Abc"), std::string("abc"), true)) + ; + + for(const case_t& val : cases) { + bool res; + res = pdns_iequals(val.get<0>(), val.get<1>()); + BOOST_CHECK_EQUAL(res, val.get<2>()); + } +} + +BOOST_AUTO_TEST_CASE(test_stripDot) { + BOOST_CHECK_EQUAL(stripDot("."), ""); + BOOST_CHECK_EQUAL(stripDot(""), ""); + BOOST_CHECK_EQUAL(stripDot("www.powerdns.com."), "www.powerdns.com"); + BOOST_CHECK_EQUAL(stripDot("www.powerdns.com"), "www.powerdns.com"); +} + +BOOST_AUTO_TEST_CASE(test_labelReverse) { + BOOST_CHECK_EQUAL(DNSName("www.powerdns.com").labelReverse().toString(" ", false), "com powerdns www"); +} + + +BOOST_AUTO_TEST_CASE(test_AtomicCounter) { + AtomicCounter ac(0); + ++ac; + ++ac; + BOOST_CHECK_EQUAL(ac, 2); +} + +BOOST_AUTO_TEST_CASE(test_endianness) { + uint32_t i = 1; +#if BYTE_ORDER == BIG_ENDIAN + BOOST_CHECK_EQUAL(i, htonl(i)); +#elif BYTE_ORDER == LITTLE_ENDIAN + uint32_t j=0x01000000; + BOOST_CHECK_EQUAL(i, ntohl(j)); +#else + BOOST_FAIL("Did not detect endianness at all"); +#endif +} + +BOOST_AUTO_TEST_CASE(test_parseService) { + ServiceTuple tp; + parseService("smtp.powerdns.com:25", tp); + BOOST_CHECK_EQUAL(tp.host, "smtp.powerdns.com"); + BOOST_CHECK_EQUAL(tp.port, 25); + parseService("smtp.powerdns.com", tp); + BOOST_CHECK_EQUAL(tp.port, 25); +} + +BOOST_AUTO_TEST_CASE(test_ternary) { + int maxqps=1024; + BOOST_CHECK_EQUAL(defTer(maxqps, 16384), maxqps); + BOOST_CHECK_EQUAL(defTer(0, 16384), 16384); + + int* qps=0; + BOOST_CHECK_EQUAL(*defTer(qps, &maxqps), 1024); +} + +BOOST_AUTO_TEST_CASE(test_SimpleMatch) { + BOOST_CHECK_EQUAL(SimpleMatch("").match(std::string("")), true); + BOOST_CHECK_EQUAL(SimpleMatch("?").match(std::string("")), false); + BOOST_CHECK_EQUAL(SimpleMatch("*").match(std::string("")), true); + + BOOST_CHECK_EQUAL(SimpleMatch("abc").match(std::string("abc")), true); + BOOST_CHECK_EQUAL(SimpleMatch("abc").match(std::string("ab")), false); + BOOST_CHECK_EQUAL(SimpleMatch("abc").match(std::string("bc")), false); + + BOOST_CHECK_EQUAL(SimpleMatch("?").match(std::string("a")), true); + BOOST_CHECK_EQUAL(SimpleMatch("a?c").match(std::string("abc")), true); + BOOST_CHECK_EQUAL(SimpleMatch("a?c").match(std::string("ab")), false); + BOOST_CHECK_EQUAL(SimpleMatch("a?c").match(std::string("bc")), false); + + BOOST_CHECK_EQUAL(SimpleMatch("*").match(std::string("*")), true); + BOOST_CHECK_EQUAL(SimpleMatch("a*c").match(std::string("abc")), true); + BOOST_CHECK_EQUAL(SimpleMatch("a*c").match(std::string("ab")), false); + BOOST_CHECK_EQUAL(SimpleMatch("a*c").match(std::string("bc")), false); + + BOOST_CHECK_EQUAL(SimpleMatch("*").match(std::string("abcdefghj")), true); + BOOST_CHECK_EQUAL(SimpleMatch("*a").match(std::string("abca")), true); + BOOST_CHECK_EQUAL(SimpleMatch("*a").match(std::string("abcb")), false); + BOOST_CHECK_EQUAL(SimpleMatch("abc*").match(std::string("abcabcabcabacabac")), true); + BOOST_CHECK_EQUAL(SimpleMatch("abc*").match(std::string("abc")), true); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/test-mtasker.cc b/test-mtasker.cc new file mode 100644 index 0000000..f6f1b5b --- /dev/null +++ b/test-mtasker.cc @@ -0,0 +1,60 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include "mtasker.hh" + +BOOST_AUTO_TEST_SUITE(mtasker_cc) + +static int g_result; + +static void doSomething(void* p) +{ + MTasker<>* mt = reinterpret_cast*>(p); + int i=12, o; + mt->waitEvent(i, &o); + g_result = o; + +} + +BOOST_AUTO_TEST_CASE(test_Simple) { + MTasker<> mt; + mt.makeThread(doSomething, &mt); + struct timeval now; + gettimeofday(&now, 0); + bool first=true; + int o=24; + for(;;) { + while(mt.schedule(&now)); + if(first) { + mt.sendEvent(12, &o); + first=false; + } + if(mt.noProcesses()) + break; + } + BOOST_CHECK_EQUAL(g_result, o); +} + +static void willThrow(void* p) +{ + throw std::runtime_error("Help!"); +} + + +BOOST_AUTO_TEST_CASE(test_MtaskerException) { + BOOST_CHECK_THROW( { + MTasker<> mt; + mt.makeThread(willThrow, 0); + struct timeval now; + + for(;;) { + mt.schedule(&now); + } + }, std::exception); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-negcache_cc.cc b/test-negcache_cc.cc new file mode 100644 index 0000000..77418c9 --- /dev/null +++ b/test-negcache_cc.cc @@ -0,0 +1,420 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#include + +#include "negcache.hh" +#include "dnsrecords.hh" +#include "utility.hh" + +static recordsAndSignatures genRecsAndSigs(const DNSName& name, const uint16_t qtype, const string& content, bool sigs) { + recordsAndSignatures ret; + + DNSRecord rec; + rec.d_name = name; + rec.d_type = qtype; + rec.d_ttl = 600; + rec.d_place = DNSResourceRecord::AUTHORITY; + rec.d_content = DNSRecordContent::mastermake(qtype, QClass::IN, content); + + ret.records.push_back(rec); + + if (sigs) { + rec.d_type = QType::RRSIG; + rec.d_content = std::make_shared(QType(qtype).getName() + " 5 3 600 2037010100000000 2037010100000000 24567 dummy data"); + ret.signatures.push_back(rec); + } + + return ret; +} + +static NegCache::NegCacheEntry genNegCacheEntry(const DNSName& name, const DNSName& auth, const struct timeval& now, const uint16_t qtype=0) { + NegCache::NegCacheEntry ret; + + ret.d_name = name; + ret.d_qtype = QType(qtype); + ret.d_auth = auth; + ret.d_ttd = now.tv_sec + 600; + ret.authoritySOA = genRecsAndSigs(auth, QType::SOA, "ns1 hostmaster 1 2 3 4 5", true); + ret.DNSSECRecords = genRecsAndSigs(auth, QType::NSEC, "deadbeef", true); + + return ret; +} + +BOOST_AUTO_TEST_SUITE(negcache_cc) + +BOOST_AUTO_TEST_CASE(test_get_entry) { + /* Add a full name negative entry to the cache and attempt to get an entry for + * the A record. Should yield the full name does not exist entry + */ + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.get(qname, QType(1), now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_qtype.getName(), QType(0).getName()); + BOOST_CHECK_EQUAL(ne.d_auth, auth); +} + +BOOST_AUTO_TEST_CASE(test_get_entry_exact_type) { + /* Add a full name negative entry to the cache and attempt to get an entry for + * the A record, asking only for an exact match. + */ + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.get(qname, QType(1), now, ne, true); + + BOOST_CHECK_EQUAL(ret, false); +} + +BOOST_AUTO_TEST_CASE(test_get_NODATA_entry) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now, 1)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.get(qname, QType(1), now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_qtype.getName(), QType(1).getName()); + BOOST_CHECK_EQUAL(ne.d_auth, auth); + + NegCache::NegCacheEntry ne2; + ret = cache.get(qname, QType(16), now, ne2); + BOOST_CHECK_EQUAL(ret, false); +} + +BOOST_AUTO_TEST_CASE(test_getRootNXTrust_entry) { + DNSName qname("com"); + DNSName auth("."); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.getRootNXTrust(qname, now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_qtype.getName(), QType(0).getName()); + BOOST_CHECK_EQUAL(ne.d_auth, auth); +} + +BOOST_AUTO_TEST_CASE(test_add_and_get_expired_entry) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + now.tv_sec -= 1000; + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + + now.tv_sec += 1000; + bool ret = cache.get(qname, QType(1), now, ne); + + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ne.d_name, DNSName()); + BOOST_CHECK_EQUAL(ne.d_auth, DNSName()); + BOOST_CHECK(ne.authoritySOA.records.empty()); +} + +BOOST_AUTO_TEST_CASE(test_getRootNXTrust_expired_entry) { + DNSName qname("com"); + DNSName auth("."); + + struct timeval now; + Utility::gettimeofday(&now, 0); + now.tv_sec -= 1000; + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + + now.tv_sec += 1000; + bool ret = cache.getRootNXTrust(qname, now, ne); + + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ne.d_name, DNSName()); + BOOST_CHECK_EQUAL(ne.d_auth, DNSName()); + BOOST_CHECK(ne.authoritySOA.records.empty()); +} + +BOOST_AUTO_TEST_CASE(test_add_updated_entry) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + DNSName auth2("com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + // Should override the existing entry for www2.powerdns.com + cache.add(genNegCacheEntry(qname, auth2, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.get(qname, QType(1), now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_auth, auth2); +} + +BOOST_AUTO_TEST_CASE(test_getRootNXTrust) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + DNSName qname2("com"); + DNSName auth2("."); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + cache.add(genNegCacheEntry(qname2, auth2, now)); + + NegCache::NegCacheEntry ne; + bool ret = cache.getRootNXTrust(qname, now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname2); + BOOST_CHECK_EQUAL(ne.d_auth, auth2); +} + +BOOST_AUTO_TEST_CASE(test_getRootNXTrust_full_domain_only) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + DNSName qname2("com"); + DNSName auth2("."); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + cache.add(genNegCacheEntry(qname2, auth2, now, 1)); // Add the denial for COM|A + + NegCache::NegCacheEntry ne; + bool ret = cache.getRootNXTrust(qname, now, ne); + + BOOST_CHECK_EQUAL(ret, false); +} + +BOOST_AUTO_TEST_CASE(test_prune) { + string qname(".powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 400); + + cache.prune(100); + + BOOST_CHECK_EQUAL(cache.size(), 100); +} + +BOOST_AUTO_TEST_CASE(test_wipe_single) { + string qname(".powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + ne = genNegCacheEntry(auth, auth, now); + cache.add(ne); + + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 401); + + // Should only wipe the powerdns.com entry + cache.wipe(auth); + BOOST_CHECK_EQUAL(cache.size(), 400); + + NegCache::NegCacheEntry ne2; + bool ret = cache.get(auth, QType(1), now, ne2); + + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ne2.d_auth, DNSName()); + BOOST_CHECK_EQUAL(ne2.d_name, DNSName()); + + cache.wipe(DNSName("1.powerdns.com")); + BOOST_CHECK_EQUAL(cache.size(), 399); + + NegCache::NegCacheEntry ne3; + ret = cache.get(auth, QType(1), now, ne3); + + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ne3.d_auth, DNSName()); + BOOST_CHECK_EQUAL(ne3.d_name, DNSName()); +} + +BOOST_AUTO_TEST_CASE(test_wipe_subtree) { + string qname(".powerdns.com"); + string qname2("powerdns.org"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + ne = genNegCacheEntry(auth, auth, now); + cache.add(ne); + + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname2), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 801); + + // Should wipe all the *.powerdns.com and powerdns.com entries + cache.wipe(auth, true); + BOOST_CHECK_EQUAL(cache.size(), 400); +} + +BOOST_AUTO_TEST_CASE(test_clear) { + string qname(".powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 400); + cache.clear(); + BOOST_CHECK_EQUAL(cache.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_dumpToFile) { + NegCache cache; + vector expected; + expected.push_back("www1.powerdns.com. 600 IN TYPE0 VIA powerdns.com. ; (Indeterminate)\n"); + expected.push_back("www1.powerdns.com. 600 IN NSEC deadbeef. ; (Indeterminate)\n"); + expected.push_back("www1.powerdns.com. 600 IN RRSIG NSEC 5 3 600 20370101000000 20370101000000 24567 dummy. data ;\n"); + expected.push_back("www2.powerdns.com. 600 IN TYPE0 VIA powerdns.com. ; (Indeterminate)\n"); + expected.push_back("www2.powerdns.com. 600 IN NSEC deadbeef. ; (Indeterminate)\n"); + expected.push_back("www2.powerdns.com. 600 IN RRSIG NSEC 5 3 600 20370101000000 20370101000000 24567 dummy. data ;\n"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + cache.add(genNegCacheEntry(DNSName("www1.powerdns.com"), DNSName("powerdns.com"), now)); + cache.add(genNegCacheEntry(DNSName("www2.powerdns.com"), DNSName("powerdns.com"), now)); + + FILE* fp; + fp = tmpfile(); + if (!fp) + BOOST_FAIL("Temporary file could not be opened"); + + cache.dumpToFile(fp); + + rewind(fp); + char *line = nullptr; + size_t len = 0; + ssize_t read; + + for (const auto& str : expected) { + read = getline(&line, &len, fp); + if (read == -1) + BOOST_FAIL("Unable to read a line from the temp file"); + BOOST_CHECK_EQUAL(line, str); + } + fclose(fp); +} + +BOOST_AUTO_TEST_CASE(test_count) { + string qname(".powerdns.com"); + string qname2("powerdns.org"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + ne = genNegCacheEntry(auth, auth, now); + cache.add(ne); + + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname2), auth, now); + cache.add(ne); + } + + uint64_t count; + count = cache.count(auth); + BOOST_CHECK_EQUAL(count, 1); + count = cache.count(auth, QType(1)); + BOOST_CHECK_EQUAL(count, 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-nmtree.cc b/test-nmtree.cc new file mode 100644 index 0000000..a2fd11b --- /dev/null +++ b/test-nmtree.cc @@ -0,0 +1,142 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include "iputils.hh" + +using namespace boost; + +BOOST_AUTO_TEST_SUITE(nmtree) + +BOOST_AUTO_TEST_CASE(test_basic) { + NetmaskTree nmt; + nmt.insert(Netmask("130.161.252.0/24")).second=0; + nmt.insert(Netmask("130.161.0.0/16")).second=1; + nmt.insert(Netmask("130.0.0.0/8")).second=2; + + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("213.244.168.210")), (void*)0); + auto found=nmt.lookup(ComboAddress("130.161.252.29")); + BOOST_CHECK(found); + BOOST_CHECK_EQUAL(found->second, 0); + found=nmt.lookup(ComboAddress("130.161.180.1")); + BOOST_CHECK(found); + BOOST_CHECK_EQUAL(found->second, 1); + + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.255.255.255"))->second, 2); + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.161.252.255"))->second, 0); + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.161.253.255"))->second, 1); + + found=nmt.lookup(ComboAddress("130.145.180.1")); + BOOST_CHECK(found); + BOOST_CHECK_EQUAL(found->second, 2); + + nmt.clear(); + BOOST_CHECK(!nmt.lookup(ComboAddress("130.161.180.1"))); + + nmt.insert(Netmask("::1")).second=1; + nmt.insert(Netmask("::/0")).second=0; + nmt.insert(Netmask("fe80::/16")).second=2; + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.161.253.255")), (void*)0); + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("::2"))->second, 0); + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("::ffff"))->second, 0); + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("::1"))->second, 1); + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("fe80::1"))->second, 2); +} + +BOOST_AUTO_TEST_CASE(test_single) { + NetmaskTree nmt; + nmt.insert(Netmask("127.0.0.0/8")).second=1; + BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("127.0.0.1"))->second, 1); +} + +BOOST_AUTO_TEST_CASE(test_scale) { + string start="192.168."; + NetmaskTree works; + for(int i=0; i < 256; ++i) { + for(int j=0; j < 256; ++j) { + works.insert(Netmask(start+std::to_string(i)+"."+std::to_string(j))).second=i*j; + } + } + + for(int i=0; i < 256; ++i) { + for(int j=0; j < 256; ++j) { + BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+"."+std::to_string(j)))->second, i*j); + } + } + + start="130.161."; + for(int i=0; i < 256; ++i) { + for(int j=0; j < 256; ++j) { + BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+"."+std::to_string(j))), (void*)0); + } + } + + start="2000:123:"; + for(int i=0; i < 256; ++i) { + for(int j=0; j < 256; ++j) { + works.insert(Netmask(start+std::to_string(i)+":"+std::to_string(j)+"::/64")).second=i*j; + } + } + + for(int i=0; i < 256; ++i) { + for(int j=0; j < 256; ++j) { + BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+":"+std::to_string(j)+"::"+std::to_string(i)+":"+std::to_string(j)))->second, i*j); + } + } + + start="2001:123:"; + for(int i=0; i < 256; ++i) { + for(int j=0; j < 256; ++j) { + BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+":"+std::to_string(j)+"::"+std::to_string(i)+":"+std::to_string(j))), (void*)0); + } + } +} + +BOOST_AUTO_TEST_CASE(test_removal) { + std::string prefix = "192."; + NetmaskTree nmt(true); + + size_t count = 0; + for(unsigned int i = 0; i < 256; ++i) { + for(unsigned int j = 16; j <= 32; ++j) { + nmt.insert(Netmask(prefix + std::to_string(i) +".127.255/"+std::to_string(j))).second = j; + count++; + } + } + + BOOST_CHECK_EQUAL(nmt.size(), count); + + for(unsigned int i = 0; i < 256; ++i) { + ComboAddress key(prefix + std::to_string(i) + ".127.255"); + const auto result = nmt.lookup(key); + BOOST_CHECK_EQUAL(result->first.getBits(), 32); + BOOST_CHECK_EQUAL(result->first.getMaskedNetwork().toString(), key.toString()); + BOOST_CHECK_EQUAL(result->second, 32); + } + + for(unsigned int i = 0; i < 256; ++i) { + for(unsigned int j = 32; j >= 16; --j) { + ComboAddress key(prefix + std::to_string(i) + ".127.255"); + nmt.erase(Netmask(key, j)); + const auto result = nmt.lookup(key); + + if (j > 16) { + BOOST_REQUIRE(result != nullptr); + BOOST_CHECK_EQUAL(result->first.getBits(), j-1); + BOOST_CHECK_EQUAL(result->first.getMaskedNetwork().toString(), Netmask(key, j-1).getMaskedNetwork().toString()); + BOOST_CHECK_EQUAL(result->second, j - 1); + } + else { + BOOST_CHECK(result == nullptr); + } + } + } + + BOOST_CHECK_EQUAL(nmt.size(), 0); + BOOST_CHECK(nmt.empty()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-rcpgenerator_cc.cc b/test-rcpgenerator_cc.cc new file mode 100644 index 0000000..42bcfe2 --- /dev/null +++ b/test-rcpgenerator_cc.cc @@ -0,0 +1,34 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include "rcpgenerator.hh" +#include "misc.hh" +#include + +using std::string; + +BOOST_AUTO_TEST_SUITE(rcp_generator_cc) + +BOOST_AUTO_TEST_CASE(test_xfrIP6) { + RecordTextReader rtr("::1"); + string rawIPv6; + rtr.xfrIP6(rawIPv6); + string loopback6; + loopback6.append(15, 0); + loopback6.append(1,1); + BOOST_CHECK_EQUAL(makeHexDump(rawIPv6), makeHexDump(loopback6)); + + RecordTextReader rtr2("2a01:4f8:d12:1880::5"); + rtr2.xfrIP6(rawIPv6); + string ip6("\x2a\x01\x04\xf8\x0d\x12\x18\x80\x00\x00\x00\x00\x00\x00\x00\x05", 16); + BOOST_CHECK_EQUAL(makeHexDump(rawIPv6), makeHexDump(ip6)); + + +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/test-recpacketcache_cc.cc b/test-recpacketcache_cc.cc new file mode 100644 index 0000000..f2e68e1 --- /dev/null +++ b/test-recpacketcache_cc.cc @@ -0,0 +1,199 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include "recpacketcache.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" +#include "dns_random.hh" +#include "iputils.hh" +#include + + +BOOST_AUTO_TEST_SUITE(recpacketcache_cc) + +BOOST_AUTO_TEST_CASE(test_recPacketCacheSimple) { + RecursorPacketCache rpc; + string fpacket; + unsigned int tag=0; + uint32_t age=0; + uint32_t qhash=0; + uint32_t ttd=3600; + BOOST_CHECK_EQUAL(rpc.size(), 0); + + DNSName qname("www.powerdns.com"); + vector packet; + DNSPacketWriter pw(packet, qname, QType::A); + pw.getHeader()->rd=true; + pw.getHeader()->qr=false; + pw.getHeader()->id=random(); + string qpacket((const char*)&packet[0], packet.size()); + pw.startRecord(qname, QType::A, ttd); + + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash), false); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &qhash), false); + + ARecordContent ar("127.0.0.1"); + ar.toPacket(pw); + pw.commit(); + string rpacket((const char*)&packet[0], packet.size()); + + rpc.insertResponsePacket(tag, qhash, qname, QType::A, QClass::IN, rpacket, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 1); + rpc.doPruneTo(0); + BOOST_CHECK_EQUAL(rpc.size(), 0); + rpc.insertResponsePacket(tag, qhash, qname, QType::A, QClass::IN, rpacket, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 1); + rpc.doWipePacketCache(qname); + BOOST_CHECK_EQUAL(rpc.size(), 0); + + rpc.insertResponsePacket(tag, qhash, qname, QType::A, QClass::IN, rpacket, time(0), ttd); + uint32_t qhash2 = 0; + bool found = rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash2); + BOOST_CHECK_EQUAL(found, true); + BOOST_CHECK_EQUAL(qhash, qhash2); + BOOST_CHECK_EQUAL(fpacket, rpacket); + found = rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &qhash2); + BOOST_CHECK_EQUAL(found, true); + BOOST_CHECK_EQUAL(qhash, qhash2); + BOOST_CHECK_EQUAL(fpacket, rpacket); + + packet.clear(); + qname+=DNSName("co.uk"); + DNSPacketWriter pw2(packet, qname, QType::A); + + pw2.getHeader()->rd=true; + pw2.getHeader()->qr=false; + pw2.getHeader()->id=random(); + qpacket.assign((const char*)&packet[0], packet.size()); + + found = rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash); + BOOST_CHECK_EQUAL(found, false); + found = rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &qhash); + BOOST_CHECK_EQUAL(found, false); + + rpc.doWipePacketCache(DNSName("com"), 0xffff, true); + BOOST_CHECK_EQUAL(rpc.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_recPacketCache_Tags) { + /* Insert a response with tag1, the exact same query with a different tag + should lead to a miss. Inserting a different response with the second tag + should not override the first one, and we should get a hit for the + query with either tags, with the response matching the tag. + */ + RecursorPacketCache rpc; + string fpacket; + const unsigned int tag1=0; + const unsigned int tag2=42; + uint32_t age=0; + uint32_t qhash=0; + uint32_t temphash=0; + uint32_t ttd=3600; + BOOST_CHECK_EQUAL(rpc.size(), 0); + + DNSName qname("www.powerdns.com"); + vector packet; + DNSPacketWriter pw(packet, qname, QType::A); + pw.getHeader()->rd=true; + pw.getHeader()->qr=false; + pw.getHeader()->id=random(); + string qpacket(reinterpret_cast(&packet[0]), packet.size()); + pw.startRecord(qname, QType::A, ttd); + + /* Both interfaces (with and without the qname/qtype/qclass) should get the same hash */ + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag1, qpacket, time(nullptr), &fpacket, &age, &qhash), false); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag1, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), false); + BOOST_CHECK_EQUAL(qhash, temphash); + + /* Different tag, should still get get the same hash, for both interfaces */ + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag2, qpacket, time(nullptr), &fpacket, &age, &temphash), false); + BOOST_CHECK_EQUAL(qhash, temphash); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag2, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), false); + BOOST_CHECK_EQUAL(qhash, temphash); + + { + ARecordContent ar("127.0.0.1"); + ar.toPacket(pw); + pw.commit(); + } + string r1packet(reinterpret_cast(&packet[0]), packet.size()); + + { + ARecordContent ar("127.0.0.2"); + ar.toPacket(pw); + pw.commit(); + } + string r2packet(reinterpret_cast(&packet[0]), packet.size()); + + BOOST_CHECK(r1packet != r2packet); + + /* inserting a response for tag1 */ + rpc.insertResponsePacket(tag1, qhash, qname, QType::A, QClass::IN, r1packet, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 1); + + /* inserting a different response for tag2, should not override the first one */ + rpc.insertResponsePacket(tag2, qhash, qname, QType::A, QClass::IN, r2packet, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 2); + + /* remove all responses from the cache */ + rpc.doPruneTo(0); + BOOST_CHECK_EQUAL(rpc.size(), 0); + + /* reinsert both */ + rpc.insertResponsePacket(tag1, qhash, qname, QType::A, QClass::IN, r1packet, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 1); + + rpc.insertResponsePacket(tag2, qhash, qname, QType::A, QClass::IN, r2packet, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 2); + + /* remove the responses by qname, should remove both */ + rpc.doWipePacketCache(qname); + BOOST_CHECK_EQUAL(rpc.size(), 0); + + /* insert the response for tag1 */ + rpc.insertResponsePacket(tag1, qhash, qname, QType::A, QClass::IN, r1packet, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 1); + + /* we can retrieve it */ + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag1, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), true); + BOOST_CHECK_EQUAL(qhash, temphash); + BOOST_CHECK_EQUAL(fpacket, r1packet); + + /* with both interfaces */ + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag1, qpacket, time(nullptr), &fpacket, &age, &temphash), true); + BOOST_CHECK_EQUAL(qhash, temphash); + BOOST_CHECK_EQUAL(fpacket, r1packet); + + /* but not with the second tag */ + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag2, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), false); + /* we should still get the same hash */ + BOOST_CHECK_EQUAL(temphash, qhash); + + /* adding a response for the second tag */ + rpc.insertResponsePacket(tag2, qhash, qname, QType::A, QClass::IN, r2packet, time(0), ttd); + BOOST_CHECK_EQUAL(rpc.size(), 2); + + /* We still get the correct response for the first tag */ + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag1, qpacket, time(nullptr), &fpacket, &age, &temphash), true); + BOOST_CHECK_EQUAL(qhash, temphash); + BOOST_CHECK_EQUAL(fpacket, r1packet); + + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag1, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), true); + BOOST_CHECK_EQUAL(qhash, temphash); + BOOST_CHECK_EQUAL(fpacket, r1packet); + + /* and the correct response for the second tag */ + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag2, qpacket, time(nullptr), &fpacket, &age, &temphash), true); + BOOST_CHECK_EQUAL(qhash, temphash); + BOOST_CHECK_EQUAL(fpacket, r2packet); + + BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag2, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), true); + BOOST_CHECK_EQUAL(qhash, temphash); + BOOST_CHECK_EQUAL(fpacket, r2packet); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-recursorcache_cc.cc b/test-recursorcache_cc.cc new file mode 100644 index 0000000..6695de3 --- /dev/null +++ b/test-recursorcache_cc.cc @@ -0,0 +1,854 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include "iputils.hh" +#include "recursor_cache.hh" + +BOOST_AUTO_TEST_SUITE(recursorcache_cc) + +BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) { + MemRecursorCache MRC; + + std::vector records; + std::vector> authRecords; + std::vector> signatures; + time_t now = time(nullptr); + + BOOST_CHECK_EQUAL(MRC.size(), 0); + MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_GT(MRC.bytes(), 1); + BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1); + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.bytes(), 0); + + uint64_t counter = 0; + try { + for(counter = 0; counter < 100000; ++counter) { + DNSName a = DNSName("hello ")+DNSName(std::to_string(counter)); + BOOST_CHECK_EQUAL(DNSName(a.toString()), a); + + MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, boost::none); + if(!MRC.doWipeCache(a, false)) + BOOST_FAIL("Could not remove entry we just added to the cache!"); + MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, boost::none); + } + + BOOST_CHECK_EQUAL(MRC.size(), counter); + + uint64_t delcounter = 0; + for(delcounter=0; delcounter < counter/100; ++delcounter) { + DNSName a = DNSName("hello ")+DNSName(std::to_string(delcounter)); + BOOST_CHECK_EQUAL(MRC.doWipeCache(a, false, QType::A), 1); + } + + BOOST_CHECK_EQUAL(MRC.size(), counter-delcounter); + + std::vector retrieved; + ComboAddress who("192.0.2.1"); + uint64_t matches = 0; + int64_t expected = counter-delcounter; + + for(; delcounter < counter; ++delcounter) { + if(MRC.get(now, DNSName("hello ")+DNSName(std::to_string(delcounter)), QType(QType::A), false, &retrieved, who, nullptr)) { + matches++; + } + } + BOOST_CHECK_EQUAL(matches, expected); + BOOST_CHECK_EQUAL(retrieved.size(), records.size()); + + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + + time_t ttd = now + 30; + DNSName power("powerdns.com."); + DNSRecord dr1; + ComboAddress dr1Content("2001:DB8::1"); + dr1.d_name = power; + dr1.d_type = QType::AAAA; + dr1.d_class = QClass::IN; + dr1.d_content = std::make_shared(dr1Content); + dr1.d_ttl = static_cast(ttd); + dr1.d_place = DNSResourceRecord::ANSWER; + + DNSRecord dr2; + ComboAddress dr2Content("192.0.2.42"); + dr2.d_name = power; + dr2.d_type = QType::A; + dr2.d_class = QClass::IN; + dr2.d_content = std::make_shared(dr2Content); + dr2.d_ttl = static_cast(ttd); + // the place should not matter to the cache + dr2.d_place = DNSResourceRecord::AUTHORITY; + + // insert a subnet specific entry + records.push_back(dr1); + MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, boost::optional("192.0.2.1/25")); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + retrieved.clear(); + // subnet specific should be returned for a matching subnet + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::AAAA), false, &retrieved, ComboAddress("192.0.2.2"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + + retrieved.clear(); + // subnet specific should not be returned for a different subnet + BOOST_CHECK_LT(MRC.get(now, power, QType(QType::AAAA), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), 0); + BOOST_CHECK_EQUAL(retrieved.size(), 0); + + // remove everything + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + + // insert a NON-subnet specific entry + records.clear(); + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + // NON-subnet specific should always be returned + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + retrieved.clear(); + + // insert a subnet specific entry for the same name but a different QType + records.clear(); + records.push_back(dr1); + MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, boost::optional("192.0.2.1/25")); + // we should not have replaced the existing entry + BOOST_CHECK_EQUAL(MRC.size(), 2); + + // insert a TXT one, we will use that later + records.clear(); + records.push_back(dr1); + MRC.replace(now, power, QType(QType::TXT), records, signatures, authRecords, true, boost::none); + // we should not have replaced any existing entry + BOOST_CHECK_EQUAL(MRC.size(), 3); + + // we should still get the NON-subnet specific entry + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + retrieved.clear(); + + // we should get the subnet specific entry if we are from the right subnet + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::AAAA), false, &retrieved, ComboAddress("192.0.2.3"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + retrieved.clear(); + + // but nothing from a different subnet + BOOST_CHECK_LT(MRC.get(now, power, QType(QType::AAAA), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), 0); + BOOST_CHECK_EQUAL(retrieved.size(), 0); + retrieved.clear(); + + // QType::ANY should return any qtype, so from the right subnet we should get all of them + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::ANY), false, &retrieved, ComboAddress("192.0.2.3"), nullptr), (ttd-now)); + BOOST_CHECK_EQUAL(retrieved.size(), 3); + for (const auto& rec : retrieved) { + BOOST_CHECK(rec.d_type == QType::A || rec.d_type == QType::AAAA || rec.d_type == QType::TXT); + } + // check that the place is always set to ANSWER + for (const auto& rec : retrieved) { + BOOST_CHECK(rec.d_place == DNSResourceRecord::ANSWER); + } + retrieved.clear(); + + // but only the non-subnet specific from the another subnet + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::ANY), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (ttd-now)); + BOOST_CHECK_EQUAL(retrieved.size(), 2); + for (const auto& rec : retrieved) { + BOOST_CHECK(rec.d_type == QType::A || rec.d_type == QType::TXT); + } + retrieved.clear(); + + // QType::ADDR should return both A and AAAA but no TXT, so two entries from the right subnet + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::ADDR), false, &retrieved, ComboAddress("192.0.2.3"), nullptr), (ttd-now)); + BOOST_CHECK_EQUAL(retrieved.size(), 2); + bool gotA = false; + bool gotAAAA = false; + for (const auto& rec : retrieved) { + BOOST_CHECK(rec.d_type == QType::A || rec.d_type == QType::AAAA); + if (rec.d_type == QType::A) { + gotA = true; + } + else if (rec.d_type == QType::AAAA) { + gotAAAA = true; + } + } + BOOST_CHECK(gotA); + BOOST_CHECK(gotAAAA); + retrieved.clear(); + + // but only the non-subnet specific one from the another subnet + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::ADDR), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK(retrieved.at(0).d_type == QType::A); + retrieved.clear(); + + // entries are only valid until ttd, we should not get anything after that because they are expired + BOOST_CHECK_LT(MRC.get(ttd + 5, power, QType(QType::ADDR), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), 0); + BOOST_CHECK_EQUAL(retrieved.size(), 0); + retrieved.clear(); + + // let's age the records for our existing QType::TXT entry so they are now only valid for 5s + uint32_t newTTL = 5; + BOOST_CHECK_EQUAL(MRC.doAgeCache(now, power, QType::TXT, newTTL), true); + + // we should still be able to retrieve it + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::TXT), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), newTTL); + BOOST_CHECK_EQUAL(retrieved.size(), 1); + BOOST_CHECK(retrieved.at(0).d_type == QType::TXT); + // please note that this is still a TTD at this point + BOOST_CHECK_EQUAL(retrieved.at(0).d_ttl, now + newTTL); + retrieved.clear(); + + // but 10s later it should be gone + BOOST_CHECK_LT(MRC.get(now + 10, power, QType(QType::TXT), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), 0); + BOOST_CHECK_EQUAL(retrieved.size(), 0); + retrieved.clear(); + + // wipe everything + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + records.clear(); + + // insert auth record + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (ttd-now)); + BOOST_CHECK_EQUAL(retrieved.size(), 1); + + DNSRecord dr3; + ComboAddress dr3Content("192.0.2.84"); + dr3.d_name = power; + dr3.d_type = QType::A; + dr3.d_class = QClass::IN; + dr3.d_content = std::make_shared(dr3Content); + dr3.d_ttl = static_cast(ttd + 100); + // the place should not matter to the cache + dr3.d_place = DNSResourceRecord::AUTHORITY; + + // this is important for our tests + BOOST_REQUIRE_GT(dr3.d_ttl, ttd); + + records.clear(); + records.push_back(dr3); + + // non-auth should not replace valid auth + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + + // but non-auth _should_ replace expired auth + MRC.replace(ttd + 1, power, QType(QType::A), records, signatures, authRecords, false, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.get(ttd + 1, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (dr3.d_ttl - (ttd + 1))); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr3Content.toString()); + + // auth should replace non-auth + records.clear(); + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + // let's first check that non-auth is not returned when we need authoritative data + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), true, &retrieved, ComboAddress("127.0.0.1"), nullptr), -now); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + + /**** Most specific netmask tests ****/ + + // wipe everything + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + records.clear(); + + // insert an entry for 192.0.0.1/8 + records.clear(); + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional("192.0.0.1/8")); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* same as dr2 except for the actual IP */ + DNSRecord dr4; + ComboAddress dr4Content("192.0.2.126"); + dr4.d_name = power; + dr4.d_type = QType::A; + dr4.d_class = QClass::IN; + dr4.d_content = std::make_shared(dr4Content); + dr4.d_ttl = static_cast(ttd); + dr4.d_place = DNSResourceRecord::AUTHORITY; + + // insert an other entry but for 192.168.0.1/31 + records.clear(); + records.push_back(dr4); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional("192.168.0.1/31")); + // we should not have replaced any existing entry + BOOST_CHECK_EQUAL(MRC.size(), 2); + + // insert the same than the first one but for 192.168.0.2/32 + records.clear(); + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional("192.168.0.2/32")); + // we should not have replaced any existing entry + BOOST_CHECK_EQUAL(MRC.size(), 3); + + // we should get the most specific entry for 192.168.0.1, so the second one + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.168.0.1"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr4Content.toString()); + retrieved.clear(); + + // wipe everything + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + records.clear(); + + // insert an entry for 192.0.0.1/8, non auth + records.clear(); + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::optional("192.0.0.1/8")); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + // we should not get it when we need authoritative data + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), true, &retrieved, ComboAddress("192.168.0.1"), nullptr), -1); + BOOST_REQUIRE_EQUAL(retrieved.size(), 0); + retrieved.clear(); + + // but we should when we are OK with non-auth + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.168.0.1"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + retrieved.clear(); + } + catch(const PDNSException& e) { + cerr<<"Had error: "< records; + std::vector> signatures; + std::vector> authRecs; + BOOST_CHECK_EQUAL(MRC.size(), 0); + time_t now = time(nullptr); + DNSName power1("powerdns.com."); + DNSName power2("powerdns-1.com."); + time_t ttd = now - 30; + std::vector retrieved; + ComboAddress who("192.0.2.1"); + + /* entry for power, which expired 30s ago */ + DNSRecord dr1; + ComboAddress dr1Content("2001:DB8::1"); + dr1.d_name = power1; + dr1.d_type = QType::AAAA; + dr1.d_class = QClass::IN; + dr1.d_content = std::make_shared(dr1Content); + dr1.d_ttl = static_cast(ttd); + dr1.d_place = DNSResourceRecord::ANSWER; + + /* entry for power1, which expired 30 ago too */ + DNSRecord dr2; + ComboAddress dr2Content("2001:DB8::2"); + dr2.d_name = power2; + dr2.d_type = QType::AAAA; + dr2.d_class = QClass::IN; + dr2.d_content = std::make_shared(dr2Content); + dr2.d_ttl = static_cast(ttd); + dr2.d_place = DNSResourceRecord::ANSWER; + + /* insert both entries */ + records.push_back(dr1); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + records.push_back(dr2); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + BOOST_CHECK_EQUAL(MRC.size(), 2); + + /* the one for power2 having been inserted + more recently should be removed last */ + /* we ask that only entry remains in the cache */ + MRC.doPrune(1); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* the remaining entry should be power2, but to get it + we need to go back in the past a bit */ + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), 1); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + /* check that power1 is gone */ + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), -1); + + /* clear everything up */ + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + records.clear(); + + /* insert both entries back */ + records.push_back(dr1); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + records.push_back(dr2); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + BOOST_CHECK_EQUAL(MRC.size(), 2); + + /* trigger a miss (expired) for power2 */ + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -now); + + /* power2 should have been moved to the front of the expunge + queue, and should this time be removed first */ + /* we ask that only entry remains in the cache */ + MRC.doPrune(1); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* the remaining entry should be power1, but to get it + we need to go back in the past a bit */ + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), 1); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + /* check that power2 is gone */ + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -1); +} + +BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) { + MemRecursorCache MRC; + + std::vector records; + std::vector> signatures; + std::vector> authRecs; + BOOST_CHECK_EQUAL(MRC.size(), 0); + time_t now = time(nullptr); + DNSName power1("powerdns.com."); + DNSName power2("powerdns-1.com."); + time_t ttd = now + 30; + std::vector retrieved; + ComboAddress who("192.0.2.1"); + + /* entry for power, which will expire in 30s */ + DNSRecord dr1; + ComboAddress dr1Content("2001:DB8::1"); + dr1.d_name = power1; + dr1.d_type = QType::AAAA; + dr1.d_class = QClass::IN; + dr1.d_content = std::make_shared(dr1Content); + dr1.d_ttl = static_cast(ttd); + dr1.d_place = DNSResourceRecord::ANSWER; + + /* entry for power1, which will expire in 30s too */ + DNSRecord dr2; + ComboAddress dr2Content("2001:DB8::2"); + dr2.d_name = power2; + dr2.d_type = QType::AAAA; + dr2.d_class = QClass::IN; + dr2.d_content = std::make_shared(dr2Content); + dr2.d_ttl = static_cast(ttd); + dr2.d_place = DNSResourceRecord::ANSWER; + + /* insert both entries */ + records.push_back(dr1); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + records.push_back(dr2); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + BOOST_CHECK_EQUAL(MRC.size(), 2); + + /* the one for power2 having been inserted + more recently should be removed last */ + /* we ask that only entry remains in the cache */ + MRC.doPrune(1); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* the remaining entry should be power2 */ + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), ttd-now); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + /* check that power1 is gone */ + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), -1); + + /* clear everything up */ + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + records.clear(); + + /* insert both entries back */ + records.push_back(dr1); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + records.push_back(dr2); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + BOOST_CHECK_EQUAL(MRC.size(), 2); + + /* replace the entry for power1 */ + records.push_back(dr1); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + BOOST_CHECK_EQUAL(MRC.size(), 2); + + /* the replaced entry for power1 should have been moved + to the back of the expunge queue, so power2 should be at the front + and should this time be removed first */ + /* we ask that only entry remains in the cache */ + MRC.doPrune(1); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* the remaining entry should be power1 */ + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), ttd-now); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + /* check that power2 is gone */ + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -1); + + /* clear everything up */ + MRC.doWipeCache(DNSName("."), true); + BOOST_CHECK_EQUAL(MRC.size(), 0); + records.clear(); + + /* insert both entries back */ + records.push_back(dr1); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + records.push_back(dr2); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + records.clear(); + BOOST_CHECK_EQUAL(MRC.size(), 2); + + /* get a hit for power1 */ + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), ttd-now); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + + /* the entry for power1 should have been moved to the back of the expunge queue + due to the hit, so power2 should be at the front and should this time be removed first */ + /* we ask that only entry remains in the cache */ + MRC.doPrune(1); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* the remaining entry should be power1 */ + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), ttd-now); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + /* check that power2 is gone */ + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -1); + + MRC.doPrune(0); + BOOST_CHECK_EQUAL(MRC.size(), 0); + + /* add a lot of netmask-specific entries */ + for (size_t i = 0; i <= 255; i++) { + records.clear(); + + DNSRecord r1; + ComboAddress r1Content("192.0.2." + std::to_string(i)); + r1.d_name = power1; + r1.d_type = QType::A; + r1.d_class = QClass::IN; + r1.d_content = std::make_shared(r1Content); + r1.d_ttl = static_cast(ttd); + r1.d_place = DNSResourceRecord::ANSWER; + records.push_back(r1); + + MRC.replace(now, power1, QType(QType::A), records, signatures, authRecs, true, Netmask(r1Content, 32)); + } + + BOOST_CHECK_EQUAL(MRC.size(), 256); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* remove a bit less than half of them */ + size_t keep = 129; + MRC.doPrune(keep); + BOOST_CHECK_EQUAL(MRC.size(), keep); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* check that we can still retrieve the remaining ones */ + size_t found = 0; + for (size_t i = 0; i <= 255; i++) { + retrieved.clear(); + ComboAddress whoLoop("192.0.2." + std::to_string(i)); + + auto ret = MRC.get(now, power1, QType(QType::A), false, &retrieved, whoLoop); + if (ret > 0) { + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), whoLoop.toString()); + found++; + } + else { + BOOST_REQUIRE_EQUAL(ret, -1); + BOOST_REQUIRE_EQUAL(retrieved.size(), 0); + } + } + + BOOST_CHECK_EQUAL(found, keep); + + /* remove the rest */ + MRC.doPrune(0); + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); +} + +BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) { + MemRecursorCache MRC; + + const DNSName power("powerdns.com."); + std::vector records; + std::vector> authRecords; + std::vector> signatures; + time_t now = time(nullptr); + std::vector retrieved; + ComboAddress who("192.0.2.1"); + + time_t ttl = 10; + time_t ttd = now + ttl; + DNSRecord dr1; + ComboAddress dr1Content("192.0.2.255"); + dr1.d_name = power; + dr1.d_type = QType::A; + dr1.d_class = QClass::IN; + dr1.d_content = std::make_shared(dr1Content); + dr1.d_ttl = static_cast(ttd); + dr1.d_place = DNSResourceRecord::ANSWER; + + DNSRecord dr2; + ComboAddress dr2Content("192.0.2.127"); + dr2.d_name = power; + dr2.d_type = QType::A; + dr2.d_class = QClass::IN; + dr2.d_content = std::make_shared(dr2Content); + dr2.d_ttl = static_cast(now + 5); + dr2.d_place = DNSResourceRecord::ANSWER; + + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + + /* no entry in the ECS index, no non-specific entry either */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, who), -1); + + /* insert a non-specific entry */ + records.push_back(dr1); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + + /* retrieve the non-specific entry */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, who), ttd - now); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + + /* wipe everything */ + MRC.doPrune(0); + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + + /* insert a specific entry */ + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* there is an ECS index for that entry but no match, and no non-specific entry */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.4")), -1); + BOOST_REQUIRE_EQUAL(retrieved.size(), 0); + + /* there is an ECS index for that entry and we get a match */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.1")), ttd - now); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + + /* there is an ECS index for that entry and we get a match, + but it has expired. No other match, no non-specific entry */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now + ttl + 1, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.1")), -1); + BOOST_REQUIRE_EQUAL(retrieved.size(), 0); + + /* The ECS index should now be empty, but the cache entry has not been expunged yet */ + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* wipe everything */ + MRC.doPrune(0); + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + + /* insert a specific entry */ + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/24")); + + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* insert a slightly more specific one, but expiring sooner */ + records.clear(); + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/26")); + + BOOST_CHECK_EQUAL(MRC.size(), 2); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* check that we get the most specific one as long as it's still valid */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.1")), 5); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); + + /* there is an ECS index for that entry and we get a match, + but it has expired. + The second ECS is a match too, and is valid. */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now + 5 + 1, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.1")), (ttd - (now +5 + 1))); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + + /* The ECS index should not be empty */ + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + BOOST_CHECK_EQUAL(MRC.size(), 2); + + /* wipe everything */ + MRC.doPrune(0); + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + + /* insert a non-specific entry */ + records.clear(); + records.push_back(dr1); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + + /* insert a subnet-specific entry */ + records.clear(); + records.push_back(dr2); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.42/32")); + + BOOST_CHECK_EQUAL(MRC.size(), 2); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* there is an ECS index for that entry and it doesn't match. No other match, but we have a non-specific entry */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.255")), ttd - now); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); + + BOOST_CHECK_EQUAL(MRC.size(), 2); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* wipe everything */ + MRC.doPrune(0); + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); +} + +BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe) { + MemRecursorCache MRC; + + const DNSName power("powerdns.com."); + std::vector records; + std::vector> authRecords; + std::vector> signatures; + time_t now = time(nullptr); + std::vector retrieved; + ComboAddress who("192.0.2.1"); + + time_t ttl = 10; + time_t ttd = now + ttl; + DNSRecord dr1; + ComboAddress dr1Content("192.0.2.255"); + dr1.d_name = power; + dr1.d_type = QType::A; + dr1.d_class = QClass::IN; + dr1.d_content = std::make_shared(dr1Content); + dr1.d_ttl = static_cast(ttd); + dr1.d_place = DNSResourceRecord::ANSWER; + + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); + + /* no entry in the ECS index, no non-specific entry either */ + retrieved.clear(); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, who), -1); + + /* insert a specific entry */ + records.push_back(dr1); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + /* insert two sub-domains entries */ + DNSName sub1("a.powerdns.com."); + dr1.d_name = sub1; + records.clear(); + records.push_back(dr1); + MRC.replace(now, sub1, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + + BOOST_CHECK_EQUAL(MRC.size(), 2); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 2); + + DNSName sub2("z.powerdns.com."); + dr1.d_name = sub2; + records.clear(); + records.push_back(dr1); + MRC.replace(now, sub2, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + + BOOST_CHECK_EQUAL(MRC.size(), 3); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 3); + + /* insert two entries for different domains */ + DNSName other1("b\bpowerdns.com."); + dr1.d_name = other1; + records.clear(); + records.push_back(dr1); + MRC.replace(now, other1, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + + BOOST_CHECK_EQUAL(MRC.size(), 4); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 4); + + DNSName other2("c\bpowerdns.com."); + dr1.d_name = other2; + records.clear(); + records.push_back(dr1); + MRC.replace(now, other2, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + + BOOST_CHECK_EQUAL(MRC.size(), 5); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 5); + + /* wipe everything under the powerdns.com domain */ + BOOST_CHECK_EQUAL(MRC.doWipeCache(power, true), 3); + BOOST_CHECK_EQUAL(MRC.size(), 2); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 2); + + /* now wipe the other domains too */ + BOOST_CHECK_EQUAL(MRC.doWipeCache(other1, true), 1); + BOOST_CHECK_EQUAL(MRC.size(), 1); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1); + + BOOST_CHECK_EQUAL(MRC.doWipeCache(other2, true), 1); + BOOST_CHECK_EQUAL(MRC.size(), 0); + BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-signers.cc b/test-signers.cc new file mode 100644 index 0000000..716ae8d --- /dev/null +++ b/test-signers.cc @@ -0,0 +1,280 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include +#include + +#include "base64.hh" +#include "dnsseckeeper.hh" +#include "dnssecinfra.hh" +#include "misc.hh" +BOOST_AUTO_TEST_SUITE(test_signers) + +static const std::string message = "Very good, young padawan."; + +static const struct signerParams +{ + std::string iscMap; + std::string dsSHA1; + std::string dsSHA256; + std::string dsSHA384; + std::vector signature; + std::string zoneRepresentation; + std::string name; + std::string rfcMsgDump; + std::string rfcB64Signature; + unsigned int bits; + uint16_t flags; + uint16_t rfcFlags; + uint8_t algorithm; + bool isDeterministic; +} signers[] = { + /* RSA from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */ + { "Algorithm: 8\n" + "Modulus: qtunSiHnYq4XRLBehKAw1Glxb+48oIpAC7w3Jhpj570bb2uHt6orWGqnuyRtK8oqUi2ABoV0PFm8+IPgDMEdCQ==\n" + "PublicExponent: AQAB\n" + "PrivateExponent: MiItniUAngXzMeaGdWgDq/AcpvlCtOCcFlVt4TJRKkfp8DNRSxIxG53NNlOFkp1W00iLHqYC2GrH1qkKgT9l+Q==\n" + "Prime1: 3sZmM+5FKFy5xaRt0n2ZQOZ2C+CoKzVil6/al9LmYVs=\n" + "Prime2: xFcNWSIW6v8dDL2JQ1kxFDm/8RVeUSs1BNXXnvCjBGs=\n" + "Exponent1: WuUwhjfN1+4djlrMxHmisixWNfpwI1Eg7Ss/UXsnrMk=\n" + "Exponent2: vfMqas1cNsXRqP3Fym6D2Pl2BRuTQBv5E1B/ZrmQPTk=\n" + "Coefficient: Q10z43cA3hkwOkKsj5T0W5jrX97LBwZoY5lIjDCa4+M=\n", + "1506 8 1 172a500b374158d1a64ba3073cdbbc319b2fdf2c", + "1506 8 2 253b099ff47b02c6ffa52695a30a94c6681c56befe0e71a5077d6f79514972f9", + "1506 8 4 22ea940600dc2d9a98b1126c26ac0dc5c91b31eb50fe784b36ad675e9eecfe6573c1f85c53b6bc94580f3ac443d13c4c", + /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */ + { 0x93, 0x93, 0x5f, 0xd8, 0xa1, 0x2b, 0x4c, 0x0b, 0xf3, 0x67, 0x42, 0x13, 0x52, 0x00, 0x35, 0xdc, 0x09, 0xe0, 0xdf, 0xe0, 0x3e, 0xc2, 0xcf, 0x64, 0xab, 0x9f, 0x9f, 0x51, 0x5f, 0x5c, 0x27, 0xbe, 0x13, 0xd6, 0x17, 0x07, 0xa6, 0xe4, 0x3b, 0x63, 0x44, 0x85, 0x06, 0x13, 0xaa, 0x01, 0x3c, 0x58, 0x52, 0xa3, 0x98, 0x20, 0x65, 0x03, 0xd0, 0x40, 0xc8, 0xa0, 0xe9, 0xd2, 0xc0, 0x03, 0x5a, 0xab }, + "256 3 8 AwEAAarbp0oh52KuF0SwXoSgMNRpcW/uPKCKQAu8NyYaY+e9G29rh7eqK1hqp7skbSvKKlItgAaFdDxZvPiD4AzBHQk=", + "rsa.", + "", + "", + 512, + 256, + 0, + DNSSECKeeper::RSASHA256, + true + }, +#ifdef HAVE_BOTAN + /* ECC-GOST from rfc5933 */ + { "Algorithm: 12\n" + "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n", + "59732 12 1 794287b8033625ae938c0341fd800fd5ce45a728", + "59732 12 2 a7c24528480884ef4f5c0aaf85b3a20323a96722ccda26045aa7d304c9942868", + "59732 12 4 6f43cc67087875a5f2115adbc29604f0b5a43be6f28be0deaf71e08168967f7a1a8218d063a6f9137133a721e60eed4f", + { 0x1f, 0x3f, 0x2a, 0x2d, 0xc6, 0x72, 0x1d, 0xc8, 0xc4, 0x1f, 0x8b, 0xa1, 0xe8, 0x07, 0x83, 0x25, 0x9a, 0xbd, 0xc3, 0x80, 0xc1, 0x67, 0x80, 0xb7, 0x07, 0xed, 0xcb, 0xb0, 0x45, 0x5e, 0x46, 0x00, 0xcb, 0xa2, 0x7c, 0xf4, 0x7a, 0xa1, 0x81, 0x0c, 0xb2, 0xd1, 0xa1, 0xba, 0xb4, 0x53, 0xed, 0x8c, 0x10, 0x79, 0x12, 0x84, 0x9f, 0x9a, 0x69, 0xf5, 0x6d, 0x00, 0x4f, 0x06, 0x30, 0xba, 0xaa, 0xe6 }, + "256 3 12 aRS/DcPWGQj2wVJydT8EcAVoC0kXn5pDVm2IMvDDPXeD32dsSKcmq8KNVzigjL4OXZTV+t/6w4X1gpNrZiC01g==", + "gost.", + "00 01 0c 03 00 00 0e 10 70 db d8 80 38 6d 43 80 e9 54 07 65 78 61 6d 70 6c 65 03 6e 65 74 00 03 77 77 77 07 65 78 61 6d 70 6c 65 03 6e 65 74 00 00 01 00 01 00 00 0e 10 00 04 c0 00 02 01 ", + /* from rfc5933 */ + "7vzzz6iLOmvtjs5FjVjSHT8XnRKFY15ki6KpkNPkUnS8iIns0Kv4APT+D9ibmHhGri6Sfbyyzi67+wBbbW/jrA==", + 256, + 256, + 256, + DNSSECKeeper::ECCGOST, + false + }, +#endif /* HAVE_BOTAN */ +#ifdef HAVE_LIBCRYPTO_ECDSA + /* ECDSA-P256-SHA256 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */ + { "Algorithm: 13\n" + "PrivateKey: iyLIPdk3DOIxVmmSYlmTstbtUPiVlEyDX46psyCwNVQ=\n", + "5345 13 1 954103ac7c43810ce9f414e80f30ab1cbe49b236", + "5345 13 2 bac2107036e735b50f85006ce409a19a3438cab272e70769ebda032239a3d0ca", + "5345 13 4 a0ac6790483872be72a258314200a88ab75cdd70f66a18a09f0f414c074df0989fdb1df0e67d82d4312cda67b93a76c1", + /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */ + { 0xa2, 0x95, 0x76, 0xb5, 0xf5, 0x7e, 0xbd, 0xdd, 0xf5, 0x62, 0xa2, 0xc3, 0xa4, 0x8d, 0xd4, 0x53, 0x5c, 0xba, 0x29, 0x71, 0x8c, 0xcc, 0x28, 0x7b, 0x58, 0xf3, 0x1e, 0x4e, 0x58, 0xe2, 0x36, 0x7e, 0xa0, 0x1a, 0xb6, 0xe6, 0x29, 0x71, 0x1b, 0xd3, 0x8c, 0x88, 0xc3, 0xee, 0x12, 0x0e, 0x69, 0x70, 0x55, 0x99, 0xec, 0xd5, 0xf6, 0x4f, 0x4b, 0xe2, 0x41, 0xd9, 0x10, 0x7e, 0x67, 0xe5, 0xad, 0x2f, }, + "256 3 13 8uD7C4THTM/w7uhryRSToeE/jKT78/p853RX0L5EwrZrSLBubLPiBw7gbvUP6SsIga5ZQ4CSAxNmYA/gZsuXzA==", + "ecdsa.", + "", + "", + 256, + 256, + 0, + DNSSECKeeper::ECDSA256, + false + }, +#endif /* HAVE_LIBCRYPTO_ECDSA */ +#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) + /* ed25519 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h, + also from rfc8080 section 6.1 */ + { "Algorithm: 15\n" + "PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=\n", + "3612 15 1 501249721e1f09a79d30d5c6c4dca1dc1da4ed5d", + "3612 15 2 1b1c8766b2a96566ff196f77c0c4194af86aaa109c5346ff60231a27d2b07ac0", + "3612 15 4 d11831153af4985efbd0ae792c967eb4aff3c35488db95f7e2f85dcec74ae8f59f9a72641798c91c67c675db1d710c18", + /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */ + { 0x0a, 0x9e, 0x51, 0x5f, 0x16, 0x89, 0x49, 0x27, 0x0e, 0x98, 0x34, 0xd3, 0x48, 0xef, 0x5a, 0x6e, 0x85, 0x2f, 0x7c, 0xd6, 0xd7, 0xc8, 0xd0, 0xf4, 0x2c, 0x68, 0x8c, 0x1f, 0xf7, 0xdf, 0xeb, 0x7c, 0x25, 0xd6, 0x1a, 0x76, 0x3e, 0xaf, 0x28, 0x1f, 0x1d, 0x08, 0x10, 0x20, 0x1c, 0x01, 0x77, 0x1b, 0x5a, 0x48, 0xd6, 0xe5, 0x1c, 0xf9, 0xe3, 0xe0, 0x70, 0x34, 0x5e, 0x02, 0x49, 0xfb, 0x9e, 0x05 }, + "256 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=", + "ed25519.", + // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data + "00 0f 0f 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 0e 1d 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 ", + // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935 + "oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3fx8A4M3e23mRZ9VrbpMngwcrqNAg==", + 256, + 256, + 257, + DNSSECKeeper::ED25519, + true + }, +#endif /* defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) */ +}; + +static void checkRR(const signerParams& signer) +{ + DNSKEYRecordContent drc; + auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap); + DNSSECPrivateKey dpk; + dpk.setKey(dcke); + dpk.d_flags = signer.rfcFlags; + + vector > rrs; + /* values taken from rfc8080 for ed25519 and ed448, rfc5933 for gost */ + DNSName qname(dpk.d_algorithm == 12 ? "www.example.net." : "example.com."); + + reportBasicTypes(); + + RRSIGRecordContent rrc; + uint32_t expire = 1440021600; + uint32_t inception = 1438207200; + + if (dpk.d_algorithm == 12) { + rrc.d_signer = DNSName("example.net."); + inception = 946684800; + expire = 1893456000; + rrs.push_back(DNSRecordContent::makeunique(QType::A, QClass::IN, "192.0.2.1")); + } + else { + rrc.d_signer = qname; + rrs.push_back(DNSRecordContent::makeunique(QType::MX, QClass::IN, "10 mail.example.com.")); + } + + rrc.d_originalttl = 3600; + rrc.d_sigexpire = expire; + rrc.d_siginception = inception; + rrc.d_type = rrs.at(0)->getType(); + rrc.d_labels = qname.countLabels(); + rrc.d_tag = dpk.getTag(); + rrc.d_algorithm = dpk.d_algorithm; + + string msg = getMessageForRRSET(qname, rrc, rrs, false); + + BOOST_CHECK_EQUAL(makeHexDump(msg), signer.rfcMsgDump); + + string signature = dcke->sign(msg); + + BOOST_CHECK(dcke->verify(msg, signature)); + + if (signer.isDeterministic) { + string b64 = Base64Encode(signature); + BOOST_CHECK_EQUAL(b64, signer.rfcB64Signature); + } + else { + std::string raw; + B64Decode(signer.rfcB64Signature, raw); + BOOST_CHECK(dcke->verify(msg, raw)); + } +} + +BOOST_AUTO_TEST_CASE(test_generic_signers) +{ + for (const auto signer : signers) { + DNSKEYRecordContent drc; + auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap); + + BOOST_CHECK_EQUAL(dcke->getAlgorithm(), signer.algorithm); + BOOST_CHECK_EQUAL(dcke->getBits(), signer.bits); + BOOST_CHECK_EQUAL(dcke->checkKey(), true); + + BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm); + + DNSSECPrivateKey dpk; + dpk.setKey(dcke); + dpk.d_flags = signer.flags; + drc = dpk.getDNSKEY(); + + BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm); + BOOST_CHECK_EQUAL(drc.d_protocol, 3); + BOOST_CHECK_EQUAL(drc.getZoneRepresentation(), signer.zoneRepresentation); + + DNSName name(signer.name); + auto ds1 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA1); + if (!signer.dsSHA1.empty()) { + BOOST_CHECK_EQUAL(ds1.getZoneRepresentation(), signer.dsSHA1); + } + + auto ds2 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA256); + if (!signer.dsSHA256.empty()) { + BOOST_CHECK_EQUAL(ds2.getZoneRepresentation(), signer.dsSHA256); + } + + auto ds4 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA384); + if (!signer.dsSHA384.empty()) { + BOOST_CHECK_EQUAL(ds4.getZoneRepresentation(), signer.dsSHA384); + } + + auto signature = dcke->sign(message); + BOOST_CHECK(dcke->verify(message, signature)); + + if (signer.isDeterministic) { + BOOST_CHECK_EQUAL(signature, std::string(signer.signature.begin(), signer.signature.end())); + } else { + /* since the signing process is not deterministic, we can't directly compare our signature + with the one we have. Still the one we have should also validate correctly. */ + BOOST_CHECK(dcke->verify(message, std::string(signer.signature.begin(), signer.signature.end()))); + } + + if (!signer.rfcMsgDump.empty() && !signer.rfcB64Signature.empty()) { + checkRR(signer); + } + } +} + +#ifdef HAVE_LIBDECAF +BOOST_AUTO_TEST_CASE(test_ed448_signer) { + vector > rrs; + DNSName qname("example.com."); + DNSKEYRecordContent drc; + + // TODO: make this a collection of inputs and resulting sigs for various algos + shared_ptr engine = DNSCryptoKeyEngine::makeFromISCString(drc, +"Private-key-format: v1.2\n" +"Algorithm: 16 (ED448)\n" +"PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA\n"); + + DNSSECPrivateKey dpk; + dpk.setKey(engine); + + reportBasicTypes(); + + rrs.push_back(DNSRecordContent::makeunique(QType::MX, 1, "10 mail.example.com.")); + + RRSIGRecordContent rrc; + rrc.d_originalttl = 3600; + rrc.d_sigexpire = 1440021600; + rrc.d_siginception = 1438207200; + rrc.d_signer = qname; + rrc.d_type = QType::MX; + rrc.d_labels = 2; + // TODO: derive the next two from the key + rrc.d_tag = 9713; + rrc.d_algorithm = 16; + + string msg = getMessageForRRSET(qname, rrc, rrs, false); + + // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data + BOOST_CHECK_EQUAL(makeHexDump(msg), "00 0f 10 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 25 f1 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 "); + + string signature = engine->sign(msg); + string b64 = Base64Encode(signature); + + // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935 + BOOST_CHECK_EQUAL(b64, "3cPAHkmlnxcDHMyg7vFC34l0blBhuG1qpwLmjInI8w1CMB29FkEAIJUA0amxWndkmnBZ6SKiwZSAxGILn/NBtOXft0+Gj7FSvOKxE/07+4RQvE581N3Aj/JtIyaiYVdnYtyMWbSNyGEY2213WKsJlwEA"); +} +#endif + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test-syncres_cc.cc b/test-syncres_cc.cc new file mode 100644 index 0000000..02234b1 --- /dev/null +++ b/test-syncres_cc.cc @@ -0,0 +1,10024 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#include + +#include "syncres.hh" +#include "arguments.hh" +#include "base32.hh" +#include "dnssecinfra.hh" +#include "dnsseckeeper.hh" +#include "lua-recursor4.hh" +#include "namespaces.hh" +#include "rec-lua-conf.hh" +#include "root-dnssec.hh" +#include "test-common.hh" +#include "utility.hh" +#include "validate-recursor.hh" + +RecursorStats g_stats; +GlobalStateHolder g_luaconfs; +thread_local std::unique_ptr t_RC{nullptr}; +unsigned int g_numThreads = 1; +bool g_lowercaseOutgoing = false; + +/* Fake some required functions we didn't want the trouble to + link with */ +ArgvMap &arg() +{ + static ArgvMap theArg; + return theArg; +} + +int getMTaskerTID() +{ + return 0; +} + +bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector& res, int& ret) const +{ + return false; +} + +int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) +{ + return 0; +} + +/* primeHints() is only here for now because it + was way too much trouble to link with the real one. + We should fix this, empty functions are one thing, but this is + bad. +*/ + +#include "root-addresses.hh" + +void primeHints(void) +{ + vector nsset; + if(!t_RC) + t_RC = std::unique_ptr(new MemRecursorCache()); + + DNSRecord arr, aaaarr, nsrr; + nsrr.d_name=g_rootdnsname; + arr.d_type=QType::A; + aaaarr.d_type=QType::AAAA; + nsrr.d_type=QType::NS; + arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000; + + for(char c='a';c<='m';++c) { + char templ[40]; + strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1); + templ[sizeof(templ)-1] = '\0'; + *templ=c; + aaaarr.d_name=arr.d_name=DNSName(templ); + nsrr.d_content=std::make_shared(DNSName(templ)); + arr.d_content=std::make_shared(ComboAddress(rootIps4[c-'a'])); + vector aset; + aset.push_back(arr); + t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector>(), vector>(), true); // auth, nuke it all + if (rootIps6[c-'a'] != NULL) { + aaaarr.d_content=std::make_shared(ComboAddress(rootIps6[c-'a'])); + + vector aaaaset; + aaaaset.push_back(aaaarr); + t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector>(), vector>(), true); + } + + nsset.push_back(nsrr); + } + t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector>(), vector>(), false); // and stuff in the cache +} + +LuaConfigItems::LuaConfigItems() +{ + for (const auto &dsRecord : rootDSs) { + auto ds=unique_ptr(dynamic_cast(DSRecordContent::make(dsRecord))); + dsAnchors[g_rootdnsname].insert(*ds); + } +} + +/* Some helpers functions */ + +static void init(bool debug=false) +{ + L.setName("test"); + L.disableSyslog(true); + + if (debug) { + L.setLoglevel((Logger::Urgency)(6)); // info and up + L.toConsole(Logger::Info); + } + else { + L.setLoglevel(Logger::None); + L.toConsole(Logger::Error); + } + + seedRandom("/dev/urandom"); + reportAllTypes(); + + t_RC = std::unique_ptr(new MemRecursorCache()); + + SyncRes::s_maxqperq = 50; + SyncRes::s_maxtotusec = 1000*7000; + SyncRes::s_maxdepth = 40; + SyncRes::s_maxnegttl = 3600; + SyncRes::s_maxcachettl = 86400; + SyncRes::s_packetcachettl = 3600; + SyncRes::s_packetcacheservfailttl = 60; + SyncRes::s_serverdownmaxfails = 64; + SyncRes::s_serverdownthrottletime = 60; + SyncRes::s_doIPv6 = true; + SyncRes::s_ecsipv4limit = 24; + SyncRes::s_ecsipv6limit = 56; + SyncRes::s_rootNXTrust = true; + SyncRes::s_minimumTTL = 0; + SyncRes::s_serverID = "PowerDNS Unit Tests Server ID"; + SyncRes::clearEDNSSubnets(); + SyncRes::clearEDNSDomains(); + SyncRes::clearDelegationOnly(); + SyncRes::clearDontQuery(); + + SyncRes::clearNSSpeeds(); + BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0); + SyncRes::clearEDNSStatuses(); + BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0); + SyncRes::clearThrottle(); + BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0); + SyncRes::clearFailedServers(); + BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0); + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dfe.clear(); + luaconfsCopy.dsAnchors.clear(); + for (const auto &dsRecord : rootDSs) { + auto ds=unique_ptr(dynamic_cast(DSRecordContent::make(dsRecord))); + luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds); + } + luaconfsCopy.negAnchors.clear(); + g_luaconfs.setState(luaconfsCopy); + + g_dnssecmode = DNSSECMode::Off; + g_dnssecLOG = debug; + g_maxNSEC3Iterations = 2500; + + ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests"; +} + +static void initSR(std::unique_ptr& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0) +{ + struct timeval now; + if (fakeNow > 0) { + now.tv_sec = fakeNow; + now.tv_usec = 0; + } + else { + Utility::gettimeofday(&now, 0); + } + + init(debug); + + sr = std::unique_ptr(new SyncRes(now)); + sr->setDoEDNS0(true); + if (dnssec) { + sr->setDoDNSSEC(dnssec); + } + + sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log); + + SyncRes::setDomainMap(std::make_shared()); + SyncRes::clearNegCache(); +} + +static void setDNSSECValidation(std::unique_ptr& sr, const DNSSECMode& mode) +{ + sr->setDNSSECValidationRequested(true); + g_dnssecmode = mode; +} + +static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false) +{ + res->d_rcode = rcode; + res->d_aabit = aa; + res->d_tcbit = tc; + res->d_haveEDNS = edns; +} + +static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60) +{ + addRecordToList(res->d_records, name, type, content, place, ttl); +} + +static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60) +{ + addRecordToLW(res, DNSName(name), type, content, place, ttl); +} + +static bool isRootServer(const ComboAddress& ip) +{ + if (ip.isIPv4()) { + for (size_t idx = 0; idx < rootIps4Count; idx++) { + if (ip.toString() == rootIps4[idx]) { + return true; + } + } + } + else { + for (size_t idx = 0; idx < rootIps6Count; idx++) { + if (ip.toString() == rootIps6[idx]) { + return true; + } + } + } + + return false; +} + +static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, vector >& toSign, boost::optional algo=boost::none, boost::optional inception=boost::none) +{ + time_t now = time(nullptr); + DNSKEYRecordContent drc = dpk.getDNSKEY(); + const std::shared_ptr rc = dpk.getKey(); + + rrc.d_type = signQType; + rrc.d_labels = signQName.countLabels() - signQName.isWildcard(); + rrc.d_originalttl = signTTL; + rrc.d_siginception = inception ? *inception : (now - 10); + rrc.d_sigexpire = now + sigValidity; + rrc.d_signer = signer; + rrc.d_tag = 0; + rrc.d_tag = drc.getTag(); + rrc.d_algorithm = algo ? *algo : drc.d_algorithm; + + std::string msg = getMessageForRRSET(signQName, rrc, toSign); + + rrc.d_signature = rc->sign(msg); +} + +typedef std::unordered_map > testkeysset_t; + +static bool addRRSIG(const testkeysset_t& keys, std::vector& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional algo=boost::none, boost::optional wildcard=boost::none) +{ + if (records.empty()) { + return false; + } + + const auto it = keys.find(signer); + if (it == keys.cend()) { + throw std::runtime_error("No DNSKEY found for " + signer.toString() + ", unable to compute the requested RRSIG"); + } + + size_t recordsCount = records.size(); + const DNSName& name = records[recordsCount-1].d_name; + const uint16_t type = records[recordsCount-1].d_type; + + std::vector > recordcontents; + for (const auto record : records) { + if (record.d_name == name && record.d_type == type) { + recordcontents.push_back(record.d_content); + } + } + + RRSIGRecordContent rrc; + computeRRSIG(it->second.first, signer, wildcard ? *wildcard : records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo); + if (broken) { + rrc.d_signature[0] ^= 42; + } + + DNSRecord rec; + rec.d_type = QType::RRSIG; + rec.d_place = records[recordsCount-1].d_place; + rec.d_name = records[recordsCount-1].d_name; + rec.d_ttl = records[recordsCount-1].d_ttl; + + rec.d_content = std::make_shared(rrc); + records.push_back(rec); + + return true; +} + +static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector& records) +{ + const auto it = keys.find(signer); + if (it == keys.cend()) { + throw std::runtime_error("No DNSKEY found for " + signer.toString()); + } + + DNSRecord rec; + rec.d_place = DNSResourceRecord::ANSWER; + rec.d_name = signer; + rec.d_type = QType::DNSKEY; + rec.d_ttl = ttl; + + rec.d_content = std::make_shared(it->second.first.getDNSKEY()); + records.push_back(rec); +} + +static bool addDS(const DNSName& domain, uint32_t ttl, std::vector& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY) +{ + const auto it = keys.find(domain); + if (it == keys.cend()) { + return false; + } + + DNSRecord rec; + rec.d_name = domain; + rec.d_type = QType::DS; + rec.d_place = place; + rec.d_ttl = ttl; + rec.d_content = std::make_shared(it->second.second); + + records.push_back(rec); + return true; +} + +static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set& types, uint32_t ttl, std::vector& records) +{ + NSECRecordContent nrc; + nrc.d_next = next; + nrc.d_set = types; + + DNSRecord rec; + rec.d_name = domain; + rec.d_ttl = ttl; + rec.d_type = QType::NSEC; + rec.d_content = std::make_shared(nrc); + rec.d_place = DNSResourceRecord::AUTHORITY; + + records.push_back(rec); +} + +static void addNSEC3RecordToLW(const DNSName& hashedName, const std::string& hashedNext, const std::string& salt, unsigned int iterations, const std::set& types, uint32_t ttl, std::vector& records) +{ + NSEC3RecordContent nrc; + nrc.d_algorithm = 1; + nrc.d_flags = 0; + nrc.d_iterations = iterations; + nrc.d_salt = salt; + nrc.d_nexthash = hashedNext; + nrc.d_set = types; + + DNSRecord rec; + rec.d_name = hashedName; + rec.d_ttl = ttl; + rec.d_type = QType::NSEC3; + rec.d_content = std::make_shared(nrc); + rec.d_place = DNSResourceRecord::AUTHORITY; + + records.push_back(rec); +} + +static void addNSEC3UnhashedRecordToLW(const DNSName& domain, const DNSName& zone, const std::string& next, const std::set& types, uint32_t ttl, std::vector& records, unsigned int iterations=10) +{ + static const std::string salt = "deadbeef"; + std::string hashed = hashQNameWithSalt(salt, iterations, domain); + + addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records); +} + +static void addNSEC3NarrowRecordToLW(const DNSName& domain, const DNSName& zone, const std::set& types, uint32_t ttl, std::vector& records, unsigned int iterations=10) +{ + static const std::string salt = "deadbeef"; + std::string hashed = hashQNameWithSalt(salt, iterations, domain); + std::string hashedNext(hashed); + incrementHash(hashedNext); + decrementHash(hashed); + + addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records); +} + +static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys) +{ + auto dcke = std::shared_ptr(DNSCryptoKeyEngine::make(algo)); + dcke->create((algo <= 10) ? 2048 : dcke->getBits()); + DNSSECPrivateKey dpk; + dpk.d_flags = 256; + dpk.setKey(dcke); + DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest); + keys[name] = std::pair(dpk,ds); +} + +static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map& dsAnchors) +{ + generateKeyMaterial(name, algo, digest, keys); + dsAnchors[name].insert(keys[name].second); +} + +static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true) +{ + if (type == QType::DS) { + auth.chopOff(); + + setLWResult(res, 0, true, false, true); + + if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) { + addRRSIG(keys, res->d_records, auth, 300); + } + else { + addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + + /* if the auth zone is signed, we need to provide a secure denial */ + const auto it = keys.find(auth); + if (it != keys.cend()) { + /* sign the SOA */ + addRRSIG(keys, res->d_records, auth, 300); + /* add a NSEC denying the DS */ + std::set types = { QType::NSEC }; + if (proveCut) { + types.insert(QType::NS); + } + + addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + } + } + + return 1; + } + + if (type == QType::DNSKEY) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + + return 0; +} + +/* Real tests */ + +BOOST_AUTO_TEST_SUITE(syncres_cc) + +BOOST_AUTO_TEST_CASE(test_root_primed) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("a.root-servers.net."); + + /* we are primed, we should be able to resolve A a.root-servers.net. without any query */ + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(ret[0].d_name, target); + + ret.clear(); + res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::AAAA); + BOOST_CHECK_EQUAL(ret[0].d_name, target); +} + +BOOST_AUTO_TEST_CASE(test_root_primed_ns) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + const DNSName target("."); + + /* we are primed, but we should not be able to NS . without any query + because the . NS entry is not stored as authoritative */ + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 13); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_root_not_primed) { + std::unique_ptr sr; + initSR(sr); + + size_t queriesCount = 0; + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == g_rootdnsname && type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } + + return 0; + }); + + /* we are not primed yet, so SyncRes will have to call primeHints() + then call getRootNS(), for which at least one of the root servers needs to answer */ + vector ret; + int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) { + std::unique_ptr sr; + initSR(sr); + std::set downServers; + + /* we are not primed yet, so SyncRes will have to call primeHints() + then call getRootNS(), for which at least one of the root servers needs to answer. + None will, so it should ServFail. + */ + sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + downServers.insert(ip); + return 0; + }); + + vector ret; + int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK(downServers.size() > 0); + /* we explicitly refuse to mark the root servers down */ + for (const auto& server : downServers) { + BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0); + } +} + +BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) { + std::unique_ptr sr; + initSR(sr); + + ComboAddress noEDNSServer; + size_t queriesWithEDNS = 0; + size_t queriesWithoutEDNS = 0; + + sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &noEDNSServer](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + if (EDNS0Level != 0) { + queriesWithEDNS++; + noEDNSServer = ip; + + setLWResult(res, RCode::FormErr); + return 1; + } + + queriesWithoutEDNS++; + + if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.1"); + return 1; + } + + return 0; + }); + + primeHints(); + + /* fake that the root NS doesn't handle EDNS, check that we fallback */ + vector ret; + int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesWithEDNS, 1); + BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1); + BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1); + BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS); +} + +BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) { + std::unique_ptr sr; + initSR(sr); + + size_t queriesWithEDNS = 0; + size_t queriesWithoutEDNS = 0; + + sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + if (EDNS0Level != 0) { + queriesWithEDNS++; + setLWResult(res, RCode::NotImp); + return 1; + } + + queriesWithoutEDNS++; + + if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.1"); + return 1; + } + + return 0; + }); + + primeHints(); + + /* fake that the NS doesn't handle EDNS, check that we fallback */ + vector ret; + int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesWithEDNS, 1); + BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1); +} + +BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) { + std::unique_ptr sr; + initSR(sr); + + sr->setAsyncCallback([](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + if (!doTCP) { + setLWResult(res, 0, false, true, false); + return 1; + } + if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.1"); + return 1; + } + + return 0; + }); + + primeHints(); + + /* fake that the NS truncates every request over UDP, we should fallback to TCP */ + vector ret; + int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); +} + +BOOST_AUTO_TEST_CASE(test_tc_over_tcp) { + std::unique_ptr sr; + initSR(sr); + + size_t tcpQueriesCount = 0; + + sr->setAsyncCallback([&tcpQueriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + if (!doTCP) { + setLWResult(res, 0, true, true, false); + return 1; + } + + /* first TCP query is answered with a TC response */ + tcpQueriesCount++; + if (tcpQueriesCount == 1) { + setLWResult(res, 0, true, true, false); + } + else { + setLWResult(res, 0, true, false, false); + } + + addRecordToLW(res, domain, QType::A, "192.0.2.1"); + return 1; + }); + + primeHints(); + + vector ret; + int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(tcpQueriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_all_nss_down) { + std::unique_ptr sr; + initSR(sr); + std::set downServers; + + primeHints(); + + sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800); + return 1; + } + else { + downServers.insert(ip); + return 0; + } + }); + + DNSName target("powerdns.com."); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(downServers.size(), 4); + + for (const auto& server : downServers) { + BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1); + BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A)); + } +} + +BOOST_AUTO_TEST_CASE(test_all_nss_network_error) { + std::unique_ptr sr; + initSR(sr); + std::set downServers; + + primeHints(); + + sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800); + return 1; + } + else { + downServers.insert(ip); + return 0; + } + }); + + /* exact same test than the previous one, except instead of a time out we fake a network error */ + DNSName target("powerdns.com."); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(downServers.size(), 4); + + for (const auto& server : downServers) { + BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1); + BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A)); + } +} + +BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + DNSName target("www.powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + if (domain == target) { + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800); + } + else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) { + addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.3:53")) { + setLWResult(res, 0, true, false, true); + if (domain == DNSName("pdns-public-ns2.powerdns.net.")) { + if (type == QType::A) { + addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3"); + } + else if (type == QType::AAAA) { + addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3"); + } + } + else if (domain == target) { + if (type == QType::A) { + addRecordToLW(res, domain, QType::A, "192.0.2.1"); + } + else if (type == QType::AAAA) { + addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1"); + } + } + return 1; + } + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_os_limit_errors) { + std::unique_ptr sr; + initSR(sr); + std::set downServers; + + primeHints(); + + sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800); + return 1; + } + else { + if (downServers.size() < 3) { + /* only the last one will answer */ + downServers.insert(ip); + return -2; + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42"); + return 1; + } + } + }); + + DNSName target("powerdns.com."); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(downServers.size(), 3); + + /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */ + for (const auto& server : downServers) { + BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0); + BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A)); + } +} + +BOOST_AUTO_TEST_CASE(test_glued_referral) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + /* this will cause issue with qname minimization if we ever implement it */ + if (domain != target) { + return 0; + } + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800); + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::A, "192.0.2.4"); + return 1; + } + else { + return 0; + } + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(ret[0].d_name, target); +} + +BOOST_AUTO_TEST_CASE(test_glueless_referral) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + + if (domain.isPartOf(DNSName("com."))) { + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + } else if (domain.isPartOf(DNSName("org."))) { + addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + } + else { + setLWResult(res, RCode::NXDomain, false, false, true); + return 1; + } + + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) { + if (domain == target) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + return 1; + } + else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2"); + addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2"); + return 1; + } + else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3"); + addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3"); + return 1; + } + + setLWResult(res, RCode::NXDomain, false, false, true); + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::A, "192.0.2.4"); + return 1; + } + else { + return 0; + } + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(ret[0].d_name, target); +} + +BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + SyncRes::addEDNSDomain(target); + + EDNSSubnetOpts incomingECS; + incomingECS.source = Netmask("192.0.2.128/32"); + sr->setIncomingECSFound(true); + sr->setIncomingECS(incomingECS); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + BOOST_REQUIRE(srcmask); + BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); +} + +BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32")); + + EDNSSubnetOpts incomingECS; + incomingECS.source = Netmask("2001:DB8::FF/128"); + sr->setIncomingECSFound(true); + sr->setIncomingECS(incomingECS); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + BOOST_REQUIRE(!srcmask); + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + BOOST_REQUIRE(srcmask); + BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56"); + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(ret[0].d_name, target); +} + +BOOST_AUTO_TEST_CASE(test_following_cname) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("cname.powerdns.com."); + const DNSName cnameTarget("cname-target.powerdns.com"); + + sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + if (domain == target) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); + return 1; + } + else if (domain == cnameTarget) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + } + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK_EQUAL(ret[0].d_name, target); + BOOST_CHECK(ret[1].d_type == QType::A); + BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget); +} + +BOOST_AUTO_TEST_CASE(test_cname_nxdomain) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("cname.powerdns.com."); + const DNSName cnameTarget("cname-target.powerdns.com"); + + sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + if (domain == target) { + setLWResult(res, RCode::NXDomain, true, false, false); + addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); + addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + } else if (domain == cnameTarget) { + setLWResult(res, RCode::NXDomain, true, false, false); + addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + return 1; + } + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK_EQUAL(ret[0].d_name, target); + BOOST_CHECK(ret[1].d_type == QType::SOA); + + /* a second time, to check the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK_EQUAL(ret[0].d_name, target); + BOOST_CHECK(ret[1].d_type == QType::SOA); +} + +BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + /* In this test we directly get the NS server for cname.powerdns.com., + and we don't know whether it's also authoritative for + cname-target.powerdns.com or powerdns.com, so we shouldn't accept + the additional A record for cname-target.powerdns.com. */ + const DNSName target("cname.powerdns.com."); + const DNSName cnameTarget("cname-target.powerdns.com"); + + sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + + setLWResult(res, 0, false, false, true); + + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + if (domain == target) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL); + return 1; + } else if (domain == cnameTarget) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3"); + return 1; + } + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_REQUIRE(ret[0].d_type == QType::CNAME); + BOOST_CHECK_EQUAL(ret[0].d_name, target); + BOOST_CHECK_EQUAL(getRR(ret[0])->getTarget(), cnameTarget); + BOOST_REQUIRE(ret[1].d_type == QType::A); + BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget); + BOOST_CHECK(getRR(ret[1])->getCA() == ComboAddress("192.0.2.3")); +} + +BOOST_AUTO_TEST_CASE(test_cname_loop) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t count = 0; + const DNSName target("cname.powerdns.com."); + + sr->setAsyncCallback([target,&count](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + count++; + + if (isRootServer(ip)) { + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + if (domain == target) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, domain.toString()); + return 1; + } + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_GT(ret.size(), 0); + BOOST_CHECK_EQUAL(count, 2); +} + +BOOST_AUTO_TEST_CASE(test_cname_depth) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t depth = 0; + const DNSName target("cname.powerdns.com."); + + sr->setAsyncCallback([target,&depth](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com"); + depth++; + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), depth); + /* we have an arbitrary limit at 10 when following a CNAME chain */ + BOOST_CHECK_EQUAL(depth, 10 + 2); +} + +BOOST_AUTO_TEST_CASE(test_time_limit) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queries = 0; + const DNSName target("cname.powerdns.com."); + + sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queries++; + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + /* Pretend that this query took 2000 ms */ + res->d_usec = 2000; + + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + return 1; + } + + return 0; + }); + + /* Set the maximum time to 1 ms */ + SyncRes::s_maxtotusec = 1000; + + try { + vector ret; + sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK(false); + } + catch(const ImmediateServFailException& e) { + } + BOOST_CHECK_EQUAL(queries, 1); +} + +BOOST_AUTO_TEST_CASE(test_referral_depth) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queries = 0; + const DNSName target("www.powerdns.com."); + + sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queries++; + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + + if (domain == DNSName("www.powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + } + else if (domain == DNSName("ns.powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + } + else if (domain == DNSName("ns1.powerdns.org.")) { + addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + } + else if (domain == DNSName("ns2.powerdns.org.")) { + addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + } + else if (domain == DNSName("ns3.powerdns.org.")) { + addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + } + else if (domain == DNSName("ns4.powerdns.org.")) { + addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800); + } + + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + return 1; + } + + return 0; + }); + + /* Set the maximum depth low */ + SyncRes::s_maxdepth = 10; + + try { + vector ret; + sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK(false); + } + catch(const ImmediateServFailException& e) { + } +} + +BOOST_AUTO_TEST_CASE(test_cname_qperq) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queries = 0; + const DNSName target("cname.powerdns.com."); + + sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queries++; + + if (isRootServer(ip)) { + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com"); + return 1; + } + + return 0; + }); + + /* Set the maximum number of questions very low */ + SyncRes::s_maxqperq = 5; + + try { + vector ret; + sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK(false); + } + catch(const ImmediateServFailException& e) { + BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq); + } +} + +BOOST_AUTO_TEST_CASE(test_throttled_server) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("throttled.powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + size_t queriesToNS = 0; + + sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ns) { + + queriesToNS++; + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + + return 1; + } + + return 0; + }); + + /* mark ns as down */ + SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); + /* we should not have sent any queries to ns */ + BOOST_CHECK_EQUAL(queriesToNS, 0); +} + +BOOST_AUTO_TEST_CASE(test_throttled_server_count) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const ComboAddress ns("192.0.2.1:53"); + + const size_t blocks = 10; + /* mark ns as down for 'blocks' queries */ + SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks); + + for (size_t idx = 0; idx < blocks; idx++) { + BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns)); + } + + /* we have been throttled 'blocks' times, we should not be throttled anymore */ + BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns)); +} + +BOOST_AUTO_TEST_CASE(test_throttled_server_time) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const ComboAddress ns("192.0.2.1:53"); + + const size_t seconds = 1; + /* mark ns as down for 'seconds' seconds */ + SyncRes::doThrottle(time(nullptr), ns, seconds, 10000); + + BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns)); + + sleep(seconds + 1); + + /* we should not be throttled anymore */ + BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns)); +} + +BOOST_AUTO_TEST_CASE(test_dont_query_server) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("throttled.powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + size_t queriesToNS = 0; + + sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ns) { + + queriesToNS++; + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + + return 1; + } + + return 0; + }); + + /* prevent querying this NS */ + SyncRes::addDontQuery(Netmask(ns)); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); + /* we should not have sent any queries to ns */ + BOOST_CHECK_EQUAL(queriesToNS, 0); +} + +BOOST_AUTO_TEST_CASE(test_root_nx_trust) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target1("powerdns.com."); + const DNSName target2("notpowerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + size_t queriesCount = 0; + + sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + if (isRootServer(ip)) { + + if (domain == target1) { + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + } + + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 1); + /* one for target1 and one for the entire TLD */ + BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2); + + ret.clear(); + res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 1); + /* one for target1 and one for the entire TLD */ + BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2); + + /* we should have sent only one query */ + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) { + std::unique_ptr sr; + init(); + initSR(sr, true, false); + + primeHints(); + + const DNSName target1("powerdns.com."); + const DNSName target2("notpowerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + size_t queriesCount = 0; + + /* This time the root denies target1 with a "com." SOA instead of a "." one. + We should add target1 to the negcache, but not "com.". */ + + sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + if (isRootServer(ip)) { + + if (domain == target1) { + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + } + + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 1); + + /* even with root-nx-trust on and a NX answer from the root, + we should not have cached the entire TLD this time. */ + BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); + + ret.clear(); + res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_REQUIRE(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(ret[0].d_name, target2); + BOOST_CHECK(getRR(ret[0])->getCA() == ComboAddress("192.0.2.2")); + + BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); + + BOOST_CHECK_EQUAL(queriesCount, 3); +} + +BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target1("powerdns.com."); + const DNSName target2("notpowerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + size_t queriesCount = 0; + + sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + if (isRootServer(ip)) { + + if (domain == target1) { + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + } + + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + + return 1; + } + + return 0; + }); + + SyncRes::s_rootNXTrust = false; + + vector ret; + int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 1); + /* one for target1 */ + BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1); + + ret.clear(); + res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + /* one for target1 */ + BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1); + + /* we should have sent three queries */ + BOOST_CHECK_EQUAL(queriesCount, 3); +} + +BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("www.powerdns.com."); + const DNSName cnameTarget("cname.powerdns.com."); + + SyncRes::addEDNSDomain(DNSName("powerdns.com.")); + + EDNSSubnetOpts incomingECS; + incomingECS.source = Netmask("192.0.2.128/32"); + sr->setIncomingECSFound(true); + sr->setIncomingECS(incomingECS); + + sr->setAsyncCallback([target,cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + BOOST_REQUIRE(srcmask); + BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == target) { + /* Type 2 NXDOMAIN (rfc2308 section-2.1) */ + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); + addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + } + else if (domain == cnameTarget) { + /* we shouldn't get there since the Type NXDOMAIN should have been enough, + but we might if we still chase the CNAME. */ + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + } + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 2); + /* no negative cache entry because the response was variable */ + BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0); +} + +BOOST_AUTO_TEST_CASE(test_ns_speed) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + std::map nsCounts; + + sr->setAsyncCallback([target,&nsCounts](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else { + nsCounts[ip]++; + + if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) { + BOOST_CHECK_LT(nsCounts.size(), 3); + + /* let's time out on pdns-public-ns2.powerdns.com. */ + return 0; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + BOOST_CHECK_EQUAL(nsCounts.size(), 3); + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.254"); + return 1; + } + + return 0; + } + + return 0; + }); + + struct timeval now; + gettimeofday(&now, 0); + + /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one, + then pdns-public-ns1.powerdns.com. on IPv4 */ + SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now); + SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now); + SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now); + SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now); + SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now); + SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(nsCounts.size(), 3); + BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1); + BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1); + BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1); +} + +BOOST_AUTO_TEST_CASE(test_flawed_nsset) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.254"); + return 1; + } + + return 0; + }); + + /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */ + time_t now = sr->getNow().tv_sec; + std::vector records; + std::vector > sigs; + addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600); + + t_RC->replace(now, target, QType(QType::NS), records, sigs, vector>(), true, boost::optional()); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + size_t queriesCount = 0; + + sr->setAsyncCallback([&queriesCount,target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + if (isRootServer(ip) && domain == target) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + return 1; + } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){ + setLWResult(res, 0, true, false, true); + addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); + /* one query to get NSs, then A and AAAA for each NS */ + BOOST_CHECK_EQUAL(queriesCount, 5); +} + +BOOST_AUTO_TEST_CASE(test_cache_hit) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + return 0; + }); + + /* we populate the cache with eveything we need */ + time_t now = sr->getNow().tv_sec; + std::vector records; + std::vector > sigs; + + addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600); + t_RC->replace(now, target , QType(QType::A), records, sigs, vector>(), true, boost::optional()); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_no_rd) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + size_t queriesCount = 0; + + sr->setCacheOnly(); + + sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("cachettl.powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + + sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200); + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10); + + return 1; + } + + return 0; + }); + + const time_t now = sr->getNow().tv_sec; + SyncRes::s_minimumTTL = 60; + SyncRes::s_maxcachettl = 3600; + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL); + + const ComboAddress who; + vector cached; + BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0); + BOOST_REQUIRE_EQUAL(cached.size(), 1); + BOOST_REQUIRE_GT(cached[0].d_ttl, now); + BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL); + + cached.clear(); + BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0); + BOOST_REQUIRE_EQUAL(cached.size(), 1); + BOOST_REQUIRE_GT(cached[0].d_ttl, now); + BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl); +} + +BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + return 1; + } + + return 0; + }); + + /* we populate the cache with entries that expired 60s ago*/ + time_t now = sr->getNow().tv_sec; + std::vector records; + std::vector > sigs; + addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60); + + t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector>(), true, boost::optional()); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_REQUIRE(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(getRR(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort()); +} + +BOOST_AUTO_TEST_CASE(test_delegation_only) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + /* Thanks, Verisign */ + SyncRes::addDelegationOnly(DNSName("com.")); + SyncRes::addDelegationOnly(DNSName("net.")); + + const DNSName target("nx-powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_unauth_any) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ComboAddress("192.0.2.1:53")) { + + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_no_data) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + setLWResult(res, 0, true, false, true); + return 1; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_skip_opt_any) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRecordToLW(res, domain, QType::ANY, "0 0"); + addRecordToLW(res, domain, QType::OPT, ""); + return 1; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + /* the NSEC and RRSIG contents are complete garbage, please ignore them */ + addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + return 1; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) { + std::unique_ptr sr; + initSR(sr, true); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + /* the NSEC and RRSIG contents are complete garbage, please ignore them */ + addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + return 1; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 4); +} + +BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + /* the NSEC and RRSIG contents are complete garbage, please ignore them */ + addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + return 1; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) { + std::unique_ptr sr; + initSR(sr, true); + + primeHints(); + + const DNSName target("powerdns.com."); + + sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + /* the NSEC and RRSIG contents are complete garbage, please ignore them */ + addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY); + return 1; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 4); +} + +BOOST_AUTO_TEST_CASE(test_qclass_none) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */ + size_t queriesCount = 0; + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + return 0; + }); + + const DNSName target("powerdns.com."); + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret); + BOOST_CHECK_EQUAL(res, -1); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_special_types) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */ + size_t queriesCount = 0; + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + cerr<<"asyncresolve called to ask "< ret; + int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, -1); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(queriesCount, 0); + + res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, -1); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(queriesCount, 0); + + res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, -1); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(queriesCount, 0); + + res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, -1); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_special_names) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + /* special names should be handled internally */ + + size_t queriesCount = 0; + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + return 0; + }); + + vector ret; + int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::PTR); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::PTR); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::PTR), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::PTR); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::ANY), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::PTR); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(getRR(ret[0])->getCA().toString(), "127.0.0.1"); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::AAAA); + BOOST_CHECK_EQUAL(getRR(ret[0])->getCA().toString(), "::1"); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& rec : ret) { + BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA); + if (rec.d_type == QType::A) { + BOOST_CHECK_EQUAL(getRR(rec)->getCA().toString(), "127.0.0.1"); + } + else { + BOOST_CHECK_EQUAL(getRR(rec)->getCA().toString(), "::1"); + } + } + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::TXT); + BOOST_CHECK_EQUAL(getRR(ret[0])->d_text, "\"PowerDNS Unit Tests\""); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::TXT); + BOOST_CHECK_EQUAL(getRR(ret[0])->d_text, "\"PowerDNS Unit Tests\""); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::TXT); + BOOST_CHECK_EQUAL(getRR(ret[0])->d_text, "\"PowerDNS Unit Tests\""); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::TXT); + BOOST_CHECK_EQUAL(getRR(ret[0])->d_text, "\"PowerDNS Unit Tests\""); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::TXT); + BOOST_CHECK_EQUAL(getRR(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\""); + BOOST_CHECK_EQUAL(queriesCount, 0); + + ret.clear(); + res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::TXT); + BOOST_CHECK_EQUAL(getRR(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\""); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("rpz.powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + + sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, false, true, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + DNSFilterEngine::Policy pol; + pol.d_kind = DNSFilterEngine::PolicyKind::Drop; + std::shared_ptr zone = std::make_shared(); + zone->setName("Unit test policy 0"); + zone->addNSIPTrigger(Netmask(ns, 32), pol); + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dfe.addZone(zone); + g_luaconfs.setState(luaconfsCopy); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, -2); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("rpz.powerdns.com."); + const ComboAddress ns("[2001:DB8::42]:53"); + + sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + DNSFilterEngine::Policy pol; + pol.d_kind = DNSFilterEngine::PolicyKind::Drop; + std::shared_ptr zone = std::make_shared(); + zone->setName("Unit test policy 0"); + zone->addNSIPTrigger(Netmask(ns, 128), pol); + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dfe.addZone(zone); + g_luaconfs.setState(luaconfsCopy); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, -2); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("rpz.powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + const DNSName nsName("ns1.powerdns.com."); + + sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + DNSFilterEngine::Policy pol; + pol.d_kind = DNSFilterEngine::PolicyKind::Drop; + std::shared_ptr zone = std::make_shared(); + zone->setName("Unit test policy 0"); + zone->addNSTrigger(nsName, pol); + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dfe.addZone(zone); + g_luaconfs.setState(luaconfsCopy); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, -2); + BOOST_CHECK_EQUAL(ret.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("rpz.powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + const DNSName nsName("ns1.powerdns.com."); + + sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } else if (ip == ns) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + DNSFilterEngine::Policy pol; + pol.d_kind = DNSFilterEngine::PolicyKind::Drop; + std::shared_ptr zone = std::make_shared(); + zone->setName("Unit test policy 0"); + zone->addNSIPTrigger(Netmask(ns, 128), pol); + zone->addNSTrigger(nsName, pol); + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dfe.addZone(zone); + g_luaconfs.setState(luaconfsCopy); + + /* RPZ is disabled for this query, we should not be blocked */ + sr->setWantsRPZ(false); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_forward_zone_nord) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + const ComboAddress forwardedNS("192.0.2.42:53"); + + SyncRes::AuthDomain ad; + ad.d_rdForward = false; + ad.d_servers.push_back(forwardedNS); + (*SyncRes::t_sstorage.domainmap)[target] = ad; + + sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (ip == forwardedNS) { + BOOST_CHECK_EQUAL(sendRDQuery, false); + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + /* simulate a no-RD query */ + sr->setCacheOnly(); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_forward_zone_rd) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + const ComboAddress forwardedNS("192.0.2.42:53"); + + SyncRes::AuthDomain ad; + ad.d_rdForward = false; + ad.d_servers.push_back(forwardedNS); + (*SyncRes::t_sstorage.domainmap)[target] = ad; + + sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (ip == forwardedNS) { + BOOST_CHECK_EQUAL(sendRDQuery, false); + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + const ComboAddress forwardedNS("192.0.2.42:53"); + + SyncRes::AuthDomain ad; + ad.d_rdForward = true; + ad.d_servers.push_back(forwardedNS); + (*SyncRes::t_sstorage.domainmap)[target] = ad; + + sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (ip == forwardedNS) { + BOOST_CHECK_EQUAL(sendRDQuery, false); + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + /* simulate a no-RD query */ + sr->setCacheOnly(); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("powerdns.com."); + const ComboAddress ns("192.0.2.1:53"); + const ComboAddress forwardedNS("192.0.2.42:53"); + + SyncRes::AuthDomain ad; + ad.d_rdForward = true; + ad.d_servers.push_back(forwardedNS); + (*SyncRes::t_sstorage.domainmap)[target] = ad; + + sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + if (ip == forwardedNS) { + BOOST_CHECK_EQUAL(sendRDQuery, true); + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_oob) { + std::unique_ptr sr; + initSR(sr, true); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("test.xx."); + const ComboAddress targetAddr("127.0.0.1"); + const DNSName authZone("test.xx"); + + SyncRes::AuthDomain ad; + DNSRecord dr; + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::A; + dr.d_ttl = 1800; + dr.d_content = std::make_shared(targetAddr); + ad.d_records.insert(dr); + + (*SyncRes::t_sstorage.domainmap)[authZone] = ad; + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, 0); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 0); + BOOST_CHECK(sr->wasOutOfBand()); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + + /* a second time, to check that the OOB flag is set when the query cache is used */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, 0); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 0); + BOOST_CHECK(sr->wasOutOfBand()); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + + /* a third time, to check that the validation is disabled when the OOB flag is set */ + ret.clear(); + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, 0); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 0); + BOOST_CHECK(sr->wasOutOfBand()); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) { + std::unique_ptr sr; + initSR(sr, true); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("cname.test.xx."); + const DNSName targetCname("cname-target.test.xx."); + const ComboAddress targetCnameAddr("127.0.0.1"); + const DNSName authZone("test.xx"); + + SyncRes::AuthDomain ad; + DNSRecord dr; + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::CNAME; + dr.d_ttl = 1800; + dr.d_content = std::make_shared(targetCname); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = targetCname; + dr.d_type = QType::A; + dr.d_ttl = 1800; + dr.d_content = std::make_shared(targetCnameAddr); + ad.d_records.insert(dr); + + (*SyncRes::t_sstorage.domainmap)[authZone] = ad; + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, 0); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK(ret[1].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 0); + BOOST_CHECK(sr->wasOutOfBand()); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + + /* a second time, to check that the OOB flag is set when the query cache is used */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, 0); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK(ret[1].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 0); + BOOST_CHECK(sr->wasOutOfBand()); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + + /* a third time, to check that the validation is disabled when the OOB flag is set */ + ret.clear(); + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, 0); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK(ret[1].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 0); + BOOST_CHECK(sr->wasOutOfBand()); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("powerdns.com."); + const ComboAddress addr("192.0.2.5"); + + SyncRes::AuthDomain ad; + ad.d_name = target; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(addr); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[target] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(getRR(ret[0])->getCA().toString(), addr.toString()); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("powerdns.com."); + const DNSName authZone("internal.powerdns.com."); + const ComboAddress addr("192.0.2.5"); + + SyncRes::AuthDomain ad; + ad.d_name = authZone; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = authZone; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = authZone; + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(addr); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[authZone] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount,target,authZone](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + if (domain == target) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK_EQUAL(getRR(ret[0])->getTarget().toString(), authZone.toString()); + BOOST_CHECK(ret[1].d_type == QType::A); + BOOST_CHECK_EQUAL(getRR(ret[1])->getCA().toString(), addr.toString()); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("powerdns.com."); + const DNSName externalCNAME("www.open-xchange.com."); + const ComboAddress addr("192.0.2.5"); + + SyncRes::AuthDomain ad; + ad.d_name = target; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::CNAME; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(externalCNAME); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[target] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount,externalCNAME,addr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + if (domain == externalCNAME) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::CNAME); + BOOST_CHECK_EQUAL(getRR(ret[0])->getTarget().toString(), externalCNAME.toString()); + BOOST_CHECK(ret[1].d_type == QType::A); + BOOST_CHECK_EQUAL(getRR(ret[1])->getCA().toString(), addr.toString()); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("nodata.powerdns.com."); + const DNSName authZone("powerdns.com"); + + SyncRes::AuthDomain ad; + ad.d_name = authZone; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(ComboAddress("192.0.2.1")); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = authZone; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[authZone] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::SOA); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_nx) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("nx.powerdns.com."); + const DNSName authZone("powerdns.com"); + + SyncRes::AuthDomain ad; + ad.d_name = authZone; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("powerdns.com."); + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[authZone] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::SOA); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) { + std::unique_ptr sr; + initSR(sr, true, false); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("www.test.powerdns.com."); + const ComboAddress targetAddr("192.0.2.2"); + const DNSName ns("ns1.test.powerdns.com."); + const ComboAddress nsAddr("192.0.2.1"); + const DNSName authZone("powerdns.com"); + + SyncRes::AuthDomain ad; + ad.d_name = authZone; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = authZone; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("test.powerdns.com."); + dr.d_type = QType::NS; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(ns); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = ns; + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(nsAddr); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[authZone] = ad; + SyncRes::setDomainMap(map); + + testkeysset_t keys; + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr,authZone,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone); + } + + if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + return 1; + } + + return 0; + }); + + sr->setDNSSECValidationRequested(true); + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 4); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("test.powerdns.com."); + const ComboAddress targetAddr("192.0.2.2"); + const DNSName ns("ns1.test.powerdns.com."); + const ComboAddress nsAddr("192.0.2.1"); + const DNSName authZone("powerdns.com"); + + SyncRes::AuthDomain ad; + ad.d_name = authZone; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = authZone; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("test.powerdns.com."); + dr.d_type = QType::NS; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(ns); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = ns; + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(nsAddr); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[authZone] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("test.powerdns.com."); + const ComboAddress targetAddr("192.0.2.2"); + const DNSName authZone("powerdns.com"); + + SyncRes::AuthDomain ad; + ad.d_name = authZone; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = authZone; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("*.powerdns.com."); + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(targetAddr); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[authZone] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("test.powerdns.com."); + const ComboAddress targetAddr("192.0.2.2"); + const DNSName authZone("powerdns.com"); + + SyncRes::AuthDomain ad; + ad.d_name = authZone; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = authZone; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("*.powerdns.com."); + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(targetAddr); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[authZone] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::SOA); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + size_t queriesCount = 0; + const DNSName target("powerdns.com."); + const ComboAddress addr("192.0.2.5"); + + SyncRes::AuthDomain ad; + ad.d_name = target; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::SOA; + dr.d_ttl = 3600; + dr.d_content = std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"); + ad.d_records.insert(dr); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = target; + dr.d_type = QType::A; + dr.d_ttl = 3600; + dr.d_content = std::make_shared(addr); + ad.d_records.insert(dr); + + auto map = std::make_shared(); + (*map)[target] = ad; + SyncRes::setDomainMap(map); + + sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + queriesCount++; + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + return 1; + }); + + /* simulate a no-RD query */ + sr->setCacheOnly(); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(getRR(ret[0])->getCA().toString(), addr.toString()); + BOOST_CHECK_EQUAL(queriesCount, 0); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) { + init(); + + auto dcke = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dcke->create(dcke->getBits()); + // cerr<convertToISC()< > recordcontents; + recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1")); + + DNSName qname("powerdns.com."); + + time_t now = time(nullptr); + RRSIGRecordContent rrc; + /* this RRSIG is valid for the current second only */ + computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now); + + skeyset_t keyset; + keyset.insert(std::make_shared(dpk.getDNSKEY())); + + std::vector > sigs; + sigs.push_back(std::make_shared(rrc)); + + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset)); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t zskeys; + testkeysset_t kskeys; + + /* Generate key material for "." */ + auto dckeZ = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dckeZ->create(dckeZ->getBits()); + DNSSECPrivateKey ksk; + ksk.d_flags = 257; + ksk.setKey(dckeZ); + DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256); + + auto dckeK = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dckeK->create(dckeK->getBits()); + DNSSECPrivateKey zsk; + zsk.d_flags = 256; + zsk.setKey(dckeK); + DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256); + + kskeys[target] = std::pair(ksk, kskds); + zskeys[target] = std::pair(zsk, zskds); + + /* Set the root DS */ + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,zskeys,kskeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(zskeys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(kskeys, domain, 300, res->d_records); + addDNSKEY(zskeys, domain, 300, res->d_records); + addRRSIG(kskeys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + /* No DNSKEY */ + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t dskeys; + testkeysset_t keys; + + /* Generate key material for "." */ + auto dckeDS = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dckeDS->create(dckeDS->getBits()); + DNSSECPrivateKey dskey; + dskey.d_flags = 257; + dskey.setKey(dckeDS); + DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256); + + auto dcke = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dcke->create(dcke->getBits()); + DNSSECPrivateKey dpk; + dpk.d_flags = 256; + dpk.setKey(dcke); + DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256); + + dskeys[target] = std::pair(dskey, drc); + keys[target] = std::pair(dpk, uselessdrc); + + /* Set the root DS */ + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + testkeysset_t rrsigkeys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + auto dckeRRSIG = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dckeRRSIG->create(dckeRRSIG->getBits()); + DNSSECPrivateKey rrsigkey; + rrsigkey.d_flags = 257; + rrsigkey.setKey(dckeRRSIG); + DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256); + + rrsigkeys[target] = std::pair(rrsigkey, rrsigds); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys,rrsigkeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(rrsigkeys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(rrsigkeys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + /* No RRSIG */ + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* 13 NS + 0 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 13); + /* no RRSIG so no query for DNSKEYs */ + BOOST_CHECK_EQUAL(queriesCount, 1); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 13); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + /* Generate key material for "." */ + auto dcke = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dcke->create(dcke->getBits()); + DNSSECPrivateKey dpk; + dpk.d_flags = 256; + dpk.setKey(dcke); + /* Fake algorithm number (private) */ + dpk.d_algorithm = 253; + + DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256); + keys[target] = std::pair(dpk, drc); + /* Fake algorithm number (private) */ + drc.d_algorithm = 253; + + /* Set the root DS */ + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + /* no supported DS so no query for DNSKEYs */ + BOOST_CHECK_EQUAL(queriesCount, 1); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + /* Generate key material for "." */ + auto dcke = std::shared_ptr(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256)); + dcke->create(dcke->getBits()); + DNSSECPrivateKey dpk; + dpk.d_flags = 256; + dpk.setKey(dcke); + DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256); + /* Fake digest number (reserved) */ + drc.d_digesttype = 0; + + keys[target] = std::pair(dpk, drc); + + /* Set the root DS */ + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + /* no supported DS so no query for DNSKEYs */ + BOOST_CHECK_EQUAL(queriesCount, 1); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300, true); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + /* FORCE WRONG ALGO */ + addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + + if (type == QType::DS || type == QType::DNSKEY) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) { + return 0; + } + + if (type == QType::DS && domain == target) { + /* remove the last record, which is the DS's RRSIG */ + res->d_records.pop_back(); + } + + return 1; + } + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + /* Include the DS but omit the RRSIG*/ + addDS(DNSName("com."), 300, res->d_records, keys); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + + if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* now we ask directly for the DS */ + ret.clear(); + res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + + if (type == QType::DS || type == QType::DNSKEY) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) { + return 0; + } + + if (type == QType::DS && domain == target) { + /* remove the last record, which is the DS's RRSIG */ + res->d_records.pop_back(); + } + + return 1; + } + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + /* Include the DS but omit the RRSIG*/ + addDS(DNSName("com."), 300, res->d_records, keys); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + if (domain == target) { + auth = DNSName("powerdns.com."); + } + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(auth, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, auth, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 8); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 8); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + if (domain == target) { + auth = DNSName("powerdns.com."); + } + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(auth, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, auth, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 8); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 8); + + /* this time we ask for the NS that should be in the cache, to check + the validation status */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + if (domain == target) { + auth = DNSName("powerdns.com."); + } + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + } + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 7); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 7); + + /* this time we ask for the NS that should be in the cache, to check + the validation status */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 8); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + /* Add a NTA for "powerdns.com" */ + luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com"; + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + if (domain == target) { + auth = DNSName("powerdns.com."); + } + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(auth, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, auth, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + /* Should be insecure because of the NTA */ + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 5); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + /* Should be insecure because of the NTA */ + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 5); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + /* Add a NTA for "powerdns.com" */ + luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com"; + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + } + return 1; + } + } + + return 0; + }); + + /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */ + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + /* Should be insecure because of the NTA */ + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(domain, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, domain, 300); + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 8); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 8); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("nx.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + if (domain == target) { + auth = DNSName("powerdns.com."); + } + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, auth, 300); + addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(auth, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + } + else { + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, auth, 300); + addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + /* add wildcard denial */ + addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 9); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 9); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + } + else { + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + /* we need to add the proof that this name does not exist, so the wildcard may apply */ + addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 9); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 9); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + DNSName auth("com."); + setLWResult(res, 0, true, false, true); + + addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + addRRSIG(keys, res->d_records, auth, 300); + /* add a NSEC denying the DS AND the existence of a cut (no NS) */ + addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + return 1; + } + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, true, false, true); + /* no data */ + addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* no record for this name */ + addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* a wildcard matches but has no record for this type */ + addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 6); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 6); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + DNSName auth("com."); + setLWResult(res, 0, true, false, true); + + addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + addRRSIG(keys, res->d_records, auth, 300); + /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */ + /* first the closest encloser */ + addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + /* then the next closer */ + addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + /* a wildcard matches but has no record for this type */ + addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + return 1; + } + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, true, false, true); + /* no data */ + addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* no record for this name */ + /* first the closest encloser */ + addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* then the next closer */ + addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* a wildcard matches but has no record for this type */ + addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 8); + BOOST_CHECK_EQUAL(queriesCount, 6); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 8); + BOOST_CHECK_EQUAL(queriesCount, 6); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + DNSName auth("com."); + setLWResult(res, 0, true, false, true); + + addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + addRRSIG(keys, res->d_records, auth, 300); + /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */ + /* first the closest encloser */ + addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100); + addRRSIG(keys, res->d_records, auth, 300); + /* then the next closer */ + addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100); + addRRSIG(keys, res->d_records, auth, 300); + /* a wildcard matches but has no record for this type */ + addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + return 1; + } + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, true, false, true); + /* no data */ + addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* no record for this name */ + /* first the closest encloser */ + addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* then the next closer */ + addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + /* a wildcard matches but has no record for this type */ + addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + return 1; + } + } + + return 0; + }); + + /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */ + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 8); + BOOST_CHECK_EQUAL(queriesCount, 6); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 8); + BOOST_CHECK_EQUAL(queriesCount, 6); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.sub.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + if (domain == DNSName("sub.powerdns.com")) { + addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + } + else if (domain == target) { + addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + } + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + } + else { + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + /* we need to add the proof that this name does not exist, so the wildcard may apply */ + /* first the closest encloser */ + addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + /* then the next closer */ + addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 10); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 10); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + } + else { + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + /* we need to add the proof that this name does not exist, so the wildcard may apply */ + /* first the closest encloser */ + addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + /* then the next closer */ + addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + } + return 1; + } + } + + return 0; + }); + + /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations, + we should end up Insecure */ + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 9); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 6); + BOOST_CHECK_EQUAL(queriesCount, 9); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + } + else { + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + size_t dsQueriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + DNSName auth(domain); + auth.chopOff(); + dsQueriesCount++; + + setLWResult(res, 0, true, false, true); + addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER); + addRRSIG(keys, res->d_records, auth, 300); + return 1; + } + else if (type == QType::DNSKEY) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + /* No DS on referral, and no denial of the DS either */ + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + /* No DS on referral, and no denial of the DS either */ + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + } + else { + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + BOOST_CHECK_EQUAL(dsQueriesCount, 3); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + BOOST_CHECK_EQUAL(dsQueriesCount, 3); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + DNSName auth(domain); + auth.chopOff(); + + setLWResult(res, 0, true, false, true); + if (domain == target) { + addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + addRRSIG(keys, res->d_records, target, 300); + } + else { + addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER); + addRRSIG(keys, res->d_records, auth, 300); + } + return 1; + } + else if (type == QType::DNSKEY) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + setLWResult(res, RCode::Refused, false, false, true); + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300); + } + + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) { + /* check that we don't accept a signer below us */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + DNSName auth(domain); + auth.chopOff(); + + setLWResult(res, 0, true, false, true); + if (domain == target) { + addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + addRRSIG(keys, res->d_records, target, 300); + } + else { + addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER); + addRRSIG(keys, res->d_records, auth, 300); + } + return 1; + } + else if (type == QType::DNSKEY) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + if (domain == DNSName("www.powerdns.com.")) { + addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300); + } + else { + addRRSIG(keys, res->d_records, domain, 300); + } + return 1; + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, domain, 300); + } + + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 9); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + size_t dsQueriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + DNSName auth(domain); + auth.chopOff(); + dsQueriesCount++; + + setLWResult(res, 0, true, false, true); + if (domain == DNSName("com.")) { + addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER); + } + else { + addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records); + } + addRRSIG(keys, res->d_records, auth, 300); + return 1; + } + else if (type == QType::DNSKEY) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + /* No DS on referral, and no denial of the DS either */ + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + /* No DS on referral, and no denial of the DS either */ + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + } + } + else { + addRecordToLW(res, domain, QType::A, "192.0.2.42"); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 7); + BOOST_CHECK_EQUAL(dsQueriesCount, 2); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 7); + BOOST_CHECK_EQUAL(dsQueriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(domain, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, domain, 300); + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records); + /* NO RRSIG for the NSEC record! */ + } + return 1; + } + } + + return 0; + }); + + /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */ + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_CHECK_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 8); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 8); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(domain, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, domain, 300); + + /* NO NSEC record! */ + } + return 1; + } + } + + return 0; + }); + + /* no NSEC record in a secure zone, should be Bogus! */ + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_CHECK_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 8); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 8); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + if (domain == target) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + return 1; + } else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + } + else { + addRecordToLW(res, domain, QType::A, targetAddr.toString()); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com + 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral) + 1 query for A */ + BOOST_CHECK_EQUAL(queriesCount, 7); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 7); +} + + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) { + /* + Direct DS query: + - parent is secure, zone is secure: DS should be secure + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) { + /* + Direct DS query: + - parent is secure, zone is insecure: DS denial should be secure + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.sub.powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + if (domain == DNSName("sub.powerdns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + return 1; + } + else if (domain == DNSName("www.sub.powerdns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, DNSName("sub.powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("www.sub.powerdns.com.")) { + addRecordToLW(res, DNSName("sub.powerdns.com"), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + } + else if (domain == DNSName("sub.powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + } + else if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + } + } else { + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 9); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 9); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("www.sub.powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + /* No key material for .com */ + /* But TA for sub.powerdns.com. */ + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + if (domain == DNSName("www.sub.powerdns.com")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, DNSName("sub.powerdns.com"), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300); + } + else { + setLWResult(res, 0, false, false, true); + + if (domain == DNSName("com.")) { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("."), 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + } + } + return 1; + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com."); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + else if (domain.isPartOf(DNSName("powerdns.com."))) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("www.sub.powerdns.com.")) { + addRecordToLW(res, DNSName("sub.powerdns.com"), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300); + } + else if (domain == DNSName("sub.powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300); + } + else if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + } + } + else if (domain == DNSName("www.sub.powerdns.com.")) { + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 7); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 7); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + if (domain == target) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + /* 4 NS (com from root, com from com, powerdns.com from com, + powerdns.com from powerdns.com) + 2 DNSKEY (. and com., none for powerdns.com because no DS) + 1 query for A + */ + BOOST_CHECK_EQUAL(queriesCount, 7); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 7); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const DNSName targetCName("power-dns.com."); + const ComboAddress targetCNameAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + if (domain == targetCName) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, false, false, true); + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + if (domain == DNSName("powerdns.com.")) { + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + } + else if (domain == targetCName) { + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + } + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + if (domain == DNSName("powerdns.com.")) { + addRRSIG(keys, res->d_records, domain, 300); + } + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + if (domain == DNSName("powerdns.com.")) { + addRRSIG(keys, res->d_records, domain, 300); + } + } + else { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::CNAME, targetCName.toString()); + addRRSIG(keys, res->d_records, domain, 300); + } + else if (domain == targetCName) { + addRecordToLW(res, domain, QType::A, targetCNameAddr.toString()); + } + } + + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const DNSName targetCName1("cname.sub.powerdns.com."); + const DNSName targetCName2("cname2.sub.powerdns.com."); + const ComboAddress targetCName2Addr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetCName1,targetCName2,targetCName2Addr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == DNSName("sub.powerdns.com")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, false, false, true); + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + if (domain == DNSName("powerdns.com.")) { + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + } + else if (domain == DNSName("sub.powerdns.com")) { + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + } + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + if (domain == DNSName("powerdns.com.")) { + addRRSIG(keys, res->d_records, domain, 300); + } + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + if (domain == DNSName("powerdns.com.")) { + addRRSIG(keys, res->d_records, domain, 300); + } + } + else { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::CNAME, targetCName1.toString()); + addRRSIG(keys, res->d_records, domain, 300); + /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */ + addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString()); + addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString()); + } + else if (domain == targetCName1) { + addRecordToLW(res, domain, QType::CNAME, targetCName2.toString()); + } + else if (domain == targetCName2) { + addRecordToLW(res, domain, QType::A, targetCName2Addr.toString()); + } + } + + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 11); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 11); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("power-dns.com."); + const DNSName targetCName("powerdns.com."); + const ComboAddress targetCNameAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + if (domain == DNSName("power-dns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + if (domain == targetCName) { + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + } + else if (domain == target) { + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + } + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + if (domain == DNSName("powerdns.com.")) { + addRRSIG(keys, res->d_records, domain, 300); + } + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + if (domain == DNSName("powerdns.com.")) { + addRRSIG(keys, res->d_records, domain, 300); + } + } + else { + if (domain == target) { + addRecordToLW(res, domain, QType::CNAME, targetCName.toString()); + } + else if (domain == targetCName) { + addRecordToLW(res, domain, QType::A, targetCNameAddr.toString()); + addRRSIG(keys, res->d_records, domain, 300); + } + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("power-dns.com."); + const DNSName targetCName("powerdns.com."); + const ComboAddress targetCNameAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName(domain), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + if (domain == target) { + addRecordToLW(res, domain, QType::CNAME, targetCName.toString()); + /* No RRSIG, leading to bogus */ + } + else if (domain == targetCName) { + addRecordToLW(res, domain, QType::A, targetCNameAddr.toString()); + addRRSIG(keys, res->d_records, domain, 300); + } + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("power-dns.com."); + const DNSName targetCName("powerdns.com."); + const ComboAddress targetCNameAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName(domain), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + if (domain == target) { + addRecordToLW(res, domain, QType::CNAME, targetCName.toString()); + addRRSIG(keys, res->d_records, domain, 300); + } + else if (domain == targetCName) { + addRecordToLW(res, domain, QType::A, targetCNameAddr.toString()); + /* No RRSIG, leading to bogus */ + } + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 3); + BOOST_CHECK_EQUAL(queriesCount, 11); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("power-dns.com."); + const DNSName targetCName("powerdns.com."); + const ComboAddress targetCNameAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName(domain), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + if (domain == target) { + addRecordToLW(res, domain, QType::CNAME, targetCName.toString()); + addRRSIG(keys, res->d_records, domain, 300); + } + else if (domain == targetCName) { + addRecordToLW(res, domain, QType::A, targetCNameAddr.toString()); + addRRSIG(keys, res->d_records, domain, 300); + } + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 12); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 12); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const DNSName targetCName("power-dns.com."); + const ComboAddress targetCNameAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS) { + if (domain == DNSName("power-dns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + if (domain == DNSName("powerdns.com.")) { + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + } + else if (domain == targetCName) { + addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); + } + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + else { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::CNAME, targetCName.toString()); + /* No RRSIG -> Bogus */ + } + else if (domain == targetCName) { + addRecordToLW(res, domain, QType::A, targetCNameAddr.toString()); + } + } + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* no RRSIG to show */ + BOOST_CHECK_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 10); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_CHECK_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 10); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + /* No key material for .com */ + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + luaconfsCopy.dsAnchors[target].insert(keys[target].second); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else if (domain == DNSName("com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (target == domain) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + else if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + } + else { + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + } + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + /* should be insecure but we have a TA for powerdns.com. */ + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + /* We got a RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 5); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 5); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + /* No key material for .com */ + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + luaconfsCopy.dsAnchors[target].insert(keys[target].second); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return 1; + } + else if (domain == DNSName("com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + } + else { + if (target.isPartOf(domain) && isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + if (target == domain) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + else if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + } + return 1; + } + else if (domain == target && ip == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + } + else { + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + } + /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/ + return 1; + } + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */ + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* No RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK(ret[0].d_type == QType::A); + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_nta) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + /* Add a NTA for "." */ + luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root"; + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + /* No DNSKEY */ + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 1); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + /* Remove the root DS */ + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + setLWResult(res, 0, true, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + /* 13 NS + 0 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 13); + BOOST_CHECK_EQUAL(queriesCount, 1); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 13); + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + else { + + setLWResult(res, 0, true, false, true); + return 1; + } + + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 0); + /* com|NS, powerdns.com|NS, powerdns.com|A */ + BOOST_CHECK_EQUAL(queriesCount, 3); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 0); + /* we don't store empty results */ + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + No wrap test case: + a.example.org. -> d.example.org. denies the existence of b.example.org. + */ + addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("example.org."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair; + + /* add wildcard denial */ + recordContents.clear(); + signatureContents.clear(); + addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("example.org."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + pair.records = recordContents; + pair.signatures = signatureContents; + denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair; + + dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NXDOMAIN); + + denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false); + /* let's check that d.example.org. is not denied by this proof */ + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + Wrap case 1 test case: + z.example.org. -> b.example.org. denies the existence of a.example.org. + */ + addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("example.org."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair; + + dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NXDOMAIN); + + denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false); + /* let's check that d.example.org. is not denied by this proof */ + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + Wrap case 2 test case: + y.example.org. -> a.example.org. denies the existence of z.example.org. + */ + addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("example.org."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair; + + dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NXDOMAIN); + + denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false); + /* let's check that d.example.org. is not denied by this proof */ + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + Only one NSEC in the whole zone test case: + a.example.org. -> a.example.org. denies the existence of b.example.org. + */ + addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("example.org."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair; + + dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NXDOMAIN); + + denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false); + /* let's check that d.example.org. is not denied by this proof */ + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + The RRSIG from "." denies the existence of anything between a. and c., + including b. + */ + addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair; + + /* add wildcard denial */ + recordContents.clear(); + signatureContents.clear(); + addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + pair.records = recordContents; + pair.signatures = signatureContents; + denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair; + + dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NXDOMAIN); +} + +BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + The RRSIG from "." denies the existence of any type except NS at a. + However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear, + signer field that is shorter than the owner name of the NSEC RR) it can't + be used to deny anything except the whole name or a DS. + */ + addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair; + + /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs": + Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume + nonexistence of any RRs below that zone cut, which include all RRs at + that (original) owner name other than DS RRs, and all RRs below that + owner name regardless of type. + */ + + dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false); + /* no data means the qname/qtype is not denied, because an ancestor + delegation NSEC can only deny the DS */ + BOOST_CHECK_EQUAL(denialState, NODATA); + + /* it can not be used to deny any RRs below that owner name either */ + denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NODATA); + + denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); + BOOST_CHECK_EQUAL(denialState, NXQTYPE); +} + +BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + * RFC 5155 section 8.9: + * If there is an NSEC3 RR present in the response that matches the + * delegation name, then the validator MUST ensure that the NS bit is + * set and that the DS bit is not set in the Type Bit Maps field of the + * NSEC3 RR. + */ + /* + The RRSIG from "." denies the existence of any type at a. + NS should be set if it was proving an insecure delegation, let's check that + we correctly detect that it's not. + */ + addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair; + + /* Insecure because the NS is not set, so while it does + denies the DS, it can't prove an insecure delegation */ + dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair; + + /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */ + dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true); + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + records.clear(); + + /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */ + dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true); + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair; + + dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + + /* Add NSEC3 for the closest encloser */ + recordContents.clear(); + signatureContents.clear(); + records.clear(); + addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + + pair.records = recordContents; + pair.signatures = signatureContents; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + + dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false); + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair; + + /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that + it is an ENT */ + dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true); + BOOST_CHECK_EQUAL(denialState, NXQTYPE); + + /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com, + it could prove a NXDOMAIN if it had an additional wildcard denial */ + denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true); + BOOST_CHECK_EQUAL(denialState, NODATA); + + /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */ + denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true); + BOOST_CHECK_EQUAL(denialState, NODATA); + + /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */ + recordContents.clear(); + signatureContents.clear(); + addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + pair.records = recordContents; + pair.signatures = signatureContents; + denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair; + + denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false); + BOOST_CHECK_EQUAL(denialState, NXDOMAIN); +} + +BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + The RRSIG from "." denies the existence of any type except NS at a. + However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear, + signer field that is shorter than the owner name of the NSEC RR) it can't + be used to deny anything except the whole name or a DS. + */ + addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + records.clear(); + + /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs": + Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume + nonexistence of any RRs below that zone cut, which include all RRs at + that (original) owner name other than DS RRs, and all RRs below that + owner name regardless of type. + */ + + dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true); + /* no data means the qname/qtype is not denied, because an ancestor + delegation NSEC3 can only deny the DS */ + BOOST_CHECK_EQUAL(denialState, NODATA); + + denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); + BOOST_CHECK_EQUAL(denialState, NXQTYPE); + + /* it can not be used to deny any RRs below that owner name either */ + /* Add NSEC3 for the next closer */ + recordContents.clear(); + signatureContents.clear(); + records.clear(); + addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + + pair.records = recordContents; + pair.signatures = signatureContents; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + + /* add wildcard denial */ + recordContents.clear(); + signatureContents.clear(); + records.clear(); + addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + + pair.records = recordContents; + pair.signatures = signatureContents; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + + denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true); + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* adding a NSEC3 with more iterations that we support */ + addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + records.clear(); + + dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true); + /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */ + BOOST_CHECK_EQUAL(denialState, INSECURE); +} + +BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + /* + * RFC 5155 section 8.9: + * If there is an NSEC3 RR present in the response that matches the + * delegation name, then the validator MUST ensure that the NS bit is + * set and that the DS bit is not set in the Type Bit Maps field of the + * NSEC3 RR. + */ + /* + The RRSIG from "." denies the existence of any type at a. + NS should be set if it was proving an insecure delegation, let's check that + we correctly detect that it's not. + */ + addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("."), 300); + signatureContents.push_back(getRR(records.at(1))); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair; + records.clear(); + + /* Insecure because the NS is not set, so while it does + denies the DS, it can't prove an insecure delegation */ + dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); + BOOST_CHECK_EQUAL(denialState, NODATA); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + auth.chopOff(); + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, domain, 300); + addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, domain, 1); + return 1; + } + + return 0; + }); + + const time_t now = sr->getNow().tv_sec; + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* check that the entry has not been negatively cached for longer than the RRSIG validity */ + NegCache::NegCacheEntry ne; + BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); + BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); + BOOST_CHECK_EQUAL(ne.d_ttd, now + 1); + BOOST_CHECK_EQUAL(ne.d_validationState, Secure); + BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); + BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + auth.chopOff(); + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, domain, 1); + return 1; + } + + return 0; + }); + + const time_t now = sr->getNow().tv_sec; + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 4); + + /* check that the entry has not been cached for longer than the RRSIG validity */ + const ComboAddress who; + vector cached; + vector> signatures; + BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1); + BOOST_REQUIRE_EQUAL(cached.size(), 1); + BOOST_REQUIRE_EQUAL(signatures.size(), 1); + BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is cached as Indeterminate. + The second query asks for validation, answer should be marked as + Secure. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + else { + if (domain == target && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::A, "192.0.2.1"); + addRRSIG(keys, res->d_records, DNSName("."), 300); + return 1; + } + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 1); + + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 3); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is cached as Indeterminate. + The second query asks for validation, answer should be marked as + Insecure. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + else { + if (domain == target && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::A, "192.0.2.1"); + return 1; + } + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 1); + + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is cached as Indeterminate. + The second query asks for validation, answer should be marked as + Bogus. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + else { + if (domain == target && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::A, "192.0.2.1"); + /* no RRSIG */ + return 1; + } + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 1); + + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 3); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is cached as Indeterminate. + The second query asks for validation, answer should be marked as + Secure. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + const DNSName cnameTarget("cname-com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + else { + if (domain == target && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::CNAME, cnameTarget.toString()); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1"); + addRRSIG(keys, res->d_records, DNSName("."), 300); + return 1; + } else if (domain == cnameTarget && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1"); + addRRSIG(keys, res->d_records, DNSName("."), 300); + return 1; + } + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 2); + + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG); + } + BOOST_CHECK_EQUAL(queriesCount, 5); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is cached as Indeterminate. + The second query asks for validation, answer should be marked as + Insecure. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + const DNSName cnameTarget("cname-com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + else { + if (domain == target && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::CNAME, cnameTarget.toString()); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1"); + return 1; + } else if (domain == cnameTarget && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1"); + return 1; + } + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 2); + + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 2); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is cached as Indeterminate. + The second query asks for validation, answer should be marked as + Bogus. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + const DNSName cnameTarget("cname-com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + else { + if (domain == target && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::CNAME, cnameTarget.toString()); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1"); + /* no RRSIG */ + return 1; + } else if (domain == cnameTarget && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1"); + /* no RRSIG */ + return 1; + } + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 2); + + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 5); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) { + /* + We get a record from a secure zone in the additional section, without + the corresponding RRSIG. The record should not be marked as authoritative + and should be correctly validated. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + const DNSName addTarget("nsX.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,addTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == addTarget) { + DNSName auth(domain); + /* no DS for com, auth will be . */ + auth.chopOff(); + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false); + } + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + else { + if (domain == target && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::A, "192.0.2.1"); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL); + /* no RRSIG for the additional record */ + return 1; + } else if (domain == addTarget && type == QType::A) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, addTarget, QType::A, "192.0.2.42"); + addRRSIG(keys, res->d_records, DNSName("."), 300); + return 1; + } + } + + return 0; + }); + + vector ret; + /* first query for target/A, will pick up the additional record as non-auth / unvalidated */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_CHECK_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 1); + + ret.clear(); + /* ask for the additional record directly, we should not use + the non-auth one and issue a new query, properly validated */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_CHECK_EQUAL(ret.size(), 2); + for (const auto& record : ret) { + BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A); + } + BOOST_CHECK_EQUAL(queriesCount, 5); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is negatively cached as Indeterminate. + The second query asks for validation, answer should be marked as + Secure. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + auth.chopOff(); + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, domain, 300); + addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, domain, 1); + return 1; + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 1); + /* check that the entry has not been negatively cached */ + NegCache::NegCacheEntry ne; + BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); + BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); + BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate); + BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); + BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1); + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 4); + BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); + BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); + BOOST_CHECK_EQUAL(ne.d_validationState, Secure); + BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); + BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is negatively cached as Indeterminate. + The second query asks for validation, answer should be marked as + Secure. + The difference with test_dnssec_validation_from_negcache_secure is + that have one more level here, so we are going to look for the proof + that the DS does not exist for the last level. Since there is no cut, + we should accept the fact that the NSEC denies DS and NS both. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("www.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + /* there is no cut */ + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); + } + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 1); + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4); + BOOST_CHECK_EQUAL(queriesCount, 4); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is negatively cached as Indeterminate. + The second query asks for validation, answer should be marked as + Insecure. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + auth.chopOff(); + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return 1; + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 1); + /* check that the entry has not been negatively cached */ + NegCache::NegCacheEntry ne; + BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); + BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); + BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate); + BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); + BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0); + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 1); + BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); + BOOST_CHECK_EQUAL(ne.d_validationState, Insecure); + BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); + BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) { + /* + Validation is optional, and the first query does not ask for it, + so the answer is negatively cached as Indeterminate. + The second query asks for validation, answer should be marked as + Bogus. + */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::Process); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + DNSName auth = domain; + auth.chopOff(); + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, domain, 300); + /* no denial */ + return 1; + } + + return 0; + }); + + vector ret; + /* first query does not require validation */ + sr->setDNSSECValidationRequested(false); + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 1); + NegCache::NegCacheEntry ne; + BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); + BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); + BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate); + BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); + BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0); + + ret.clear(); + /* second one _does_ require validation */ + sr->setDNSSECValidationRequested(true); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(queriesCount, 4); + BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); + BOOST_CHECK_EQUAL(ne.d_validationState, Bogus); + BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); + BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0); + BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) { + g_lowercaseOutgoing = true; + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + vector sentOutQnames; + + const DNSName target("WWW.POWERDNS.COM"); + const DNSName cname("WWW.PowerDNS.org"); + + sr->setAsyncCallback([target, cname, &sentOutQnames](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + + sentOutQnames.push_back(domain); + + if (isRootServer(ip)) { + if (domain == target) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + if (domain == cname) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + } else if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == target) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, cname.toString()); + return 1; + } + } else if (ip == ComboAddress("192.0.2.2:53")) { + if (domain == cname) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "127.0.0.1"); + return 1; + } + } + return 0; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + + BOOST_CHECK_EQUAL(res, RCode::NoError); + + BOOST_REQUIRE_EQUAL(ret.size(), 2); + BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString()); + + BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4); + BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString()); + BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString()); + BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString()); + BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString()); + + g_lowercaseOutgoing = false; +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2, keys3; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3); + // But add the existing root key otherwise no RRSIG can be created + keys3.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2, keys3; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3); + // But add the existing root key otherwise no RRSIG can be created + keys3.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 2); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256); + } +} + +#ifdef HAVE_BOTAN +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res, bool* chained) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST); + } +} +#endif // HAVE_BOTAN110 + +/* +// cerr<<"asyncresolve called to ask "< + +#include "dnssecinfra.hh" +#include "dnswriter.hh" +#include "misc.hh" +#include "tsigverifier.hh" + +BOOST_AUTO_TEST_SUITE(tsig) + +static vector generateTSIGQuery(const DNSName& qname, const DNSName& tsigName, const DNSName& tsigAlgo, const string& tsigSecret, uint16_t fudge=300, time_t tsigTime=time(nullptr)) +{ + vector packet; + DNSPacketWriter pw(packet, qname, QType::A); + pw.getHeader()->qr=0; + pw.getHeader()->rd=0; + pw.getHeader()->id=42; + pw.startRecord(qname, QType::A); + pw.xfr32BitInt(0x01020304); + pw.addOpt(512, 0, 0); + pw.commit(); + + TSIGTriplet tt; + tt.name = tsigName; + tt.algo = tsigAlgo; + tt.secret = tsigSecret; + + TSIGHashEnum the; + BOOST_REQUIRE(getTSIGHashEnum(tt.algo, the)); + + TSIGRecordContent trc; + trc.d_algoName = getTSIGAlgoName(the); + trc.d_time = tsigTime; + trc.d_fudge = fudge; + trc.d_origID = ntohs(pw.getHeader()->id); + trc.d_eRcode = 0; + + addTSIG(pw, trc, tt.name, tt.secret, "", false); + return packet; +} + +static void checkTSIG(const DNSName& tsigName, const DNSName& tsigAlgo, const string& tsigSecret, const vector& packet, const string* overrideMac=nullptr, uint16_t* overrideExtendedRCode=nullptr, uint16_t* overrideOrigID=nullptr) +{ + string packetStr(reinterpret_cast(packet.data()), packet.size()); + MOADNSParser mdp(true, packetStr); + + bool tsigFound = false; + string theirMac; + DNSName keyName; + TSIGRecordContent trc; + + for(const auto& answer: mdp.d_answers) { + if(answer.first.d_type == QType::TSIG) { + BOOST_CHECK_EQUAL(answer.first.d_place, DNSResourceRecord::ADDITIONAL); + BOOST_CHECK_EQUAL(answer.first.d_class, QClass::ANY); + BOOST_CHECK_EQUAL(answer.first.d_ttl, 0); + BOOST_CHECK_EQUAL(tsigFound, false); + + shared_ptr rectrc = getRR(answer.first); + if (rectrc) { + trc = *rectrc; + theirMac = rectrc->d_mac; + keyName = answer.first.d_name; + tsigFound = true; + } + } + } + + if (overrideMac) { + theirMac = *overrideMac; + } + + if (overrideOrigID) { + trc.d_origID = *overrideOrigID; + } + + if (overrideExtendedRCode) { + trc.d_eRcode = *overrideExtendedRCode; + } + + BOOST_REQUIRE(tsigFound); + TSIGTriplet tt; + tt.name = tsigName; + tt.algo = tsigAlgo; + tt.secret = tsigSecret; + + BOOST_CHECK(validateTSIG(packetStr, mdp.getTSIGPos(), tt, trc, "", theirMac, false)); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_valid) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + checkTSIG(tsigName, tsigAlgo, tsigSecret, packet);} + + +BOOST_AUTO_TEST_CASE(test_TSIG_different_case_algo) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + checkTSIG(tsigName, tsigAlgo.makeLowerCase(), tsigSecret, packet); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_different_name_same_algo) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + checkTSIG(tsigName, DNSName("hmac-md5."), tsigSecret, packet); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_bad_key_name) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + BOOST_CHECK_THROW(checkTSIG(DNSName("another.tsig.key.name"), tsigAlgo, tsigSecret, packet), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_bad_algo) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + BOOST_CHECK_THROW(checkTSIG(tsigName, DNSName("hmac-sha512."), tsigSecret, packet), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_bad_secret) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + BOOST_CHECK_THROW(checkTSIG(tsigName, tsigAlgo, "bad secret", packet), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_bad_ercode) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + uint16_t badERcode = 1; + + BOOST_CHECK_THROW(checkTSIG(tsigName, tsigAlgo, tsigSecret, packet, nullptr, &badERcode), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_bad_origID) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + uint16_t badOrigID = 1; + + BOOST_CHECK_THROW(checkTSIG(tsigName, tsigAlgo, tsigSecret, packet, nullptr, nullptr, &badOrigID), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_bad_mac) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + string badMac = "badmac"; + BOOST_CHECK_THROW(checkTSIG(tsigName, tsigAlgo, tsigSecret, packet, &badMac), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_signature_expired) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret, 5, time(nullptr) - 10); + + BOOST_CHECK_THROW(checkTSIG(tsigName, tsigAlgo, tsigSecret, packet), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(test_TSIG_signature_too_far_in_the_future) { + DNSName tsigName("tsig.name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret, 5, time(nullptr) + 20); + + BOOST_CHECK_THROW(checkTSIG(tsigName, tsigAlgo, tsigSecret, packet), std::runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/test_libcrypto b/test_libcrypto new file mode 100755 index 0000000..91af04f --- /dev/null +++ b/test_libcrypto @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ $(ldd pdns_recursor | grep -c libcrypto) -gt 1 ]; then + echo "Error! pdns_recursor is linked against multiple OpenSSL versions!" + echo "This happens when one dependency is linked to OpenSSL 1.0, while" + echo "pdns_recursor is linked against OpenSSL 1.1. Please set --with-libcrypto" + echo "to the directory of the dependency's OpenSSL or drop the dependency." + echo "" + echo "On Debian Stretch, this error is most likely caused by attempting to" + echo "link in net-snmp." + exit 1; +fi diff --git a/testrunner.cc b/testrunner.cc new file mode 100644 index 0000000..b6a6852 --- /dev/null +++ b/testrunner.cc @@ -0,0 +1,31 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MAIN +#define BOOST_TEST_MODULE unit + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include + + diff --git a/tsigverifier.cc b/tsigverifier.cc new file mode 100644 index 0000000..ce01c43 --- /dev/null +++ b/tsigverifier.cc @@ -0,0 +1,74 @@ + +#include "tsigverifier.hh" +#include "dnssecinfra.hh" +#include "gss_context.hh" + +bool TSIGTCPVerifier::check(const string& data, const MOADNSParser& mdp) +{ + if(d_tt.name.empty()) { // TSIG verify message + return true; + } + + string theirMac; + bool checkTSIG = false; + // If we have multiple messages, we need to concatenate them together. We also need to make sure we know the location of + // the TSIG record so we can remove it in makeTSIGMessageFromTSIGPacket + d_signData.append(data); + if (mdp.getTSIGPos() == 0) { + d_tsigPos += data.size(); + } + else { + d_tsigPos += mdp.getTSIGPos(); + } + + for(const auto& answer : mdp.d_answers) { + if (answer.first.d_type == QType::SOA) { + // A SOA is either the first or the last record. We need to check TSIG if that's the case. + checkTSIG = true; + } + + if(answer.first.d_type == QType::TSIG) { + shared_ptr trc = getRR(answer.first); + if(trc) { + theirMac = trc->d_mac; + d_trc.d_time = trc->d_time; + d_trc.d_fudge = trc->d_fudge; + d_trc.d_eRcode = trc->d_eRcode; + d_trc.d_origID = trc->d_origID; + checkTSIG = true; + } + } + } + + if(!checkTSIG && d_nonSignedMessages > 99) { // We're allowed to get 100 digest without a TSIG. + throw std::runtime_error("No TSIG message received in last 100 messages of AXFR transfer."); + } + + if (checkTSIG) { + if (theirMac.empty()) { + throw std::runtime_error("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tt.name.toString()+"'"); + } + + try { + if (!d_prevMac.empty()) { + validateTSIG(d_signData, d_tsigPos, d_tt, d_trc, d_prevMac, theirMac, true, d_signData.size()-data.size()); + } + else { + validateTSIG(d_signData, d_tsigPos, d_tt, d_trc, d_trc.d_mac, theirMac, false); + } + } + catch(const std::runtime_error& err) { + throw std::runtime_error("Error while validating TSIG signature on AXFR response from "+d_remote.toStringWithPort()+":"+err.what()); + } + + // Reset and store some values for the next chunks. + d_prevMac = theirMac; + d_nonSignedMessages = 0; + d_signData.clear(); + d_tsigPos = 0; + } + else + d_nonSignedMessages++; + + return true; +} diff --git a/tsigverifier.hh b/tsigverifier.hh new file mode 100644 index 0000000..84b87eb --- /dev/null +++ b/tsigverifier.hh @@ -0,0 +1,22 @@ + +#pragma once + +#include "dnsrecords.hh" +#include "iputils.hh" + +class TSIGTCPVerifier +{ +public: + TSIGTCPVerifier(const TSIGTriplet& tt, const ComboAddress& remote, TSIGRecordContent& trc): d_tt(tt), d_remote(remote), d_trc(trc) + { + } + bool check(const string& data, const MOADNSParser& mdp); +private: + const TSIGTriplet& d_tt; + const ComboAddress& d_remote; + TSIGRecordContent& d_trc; + string d_prevMac; // RFC2845 4.4 + string d_signData; + size_t d_tsigPos{0}; + uint8_t d_nonSignedMessages{0}; // RFC2845 4.4 +}; diff --git a/ueberbackend.hh b/ueberbackend.hh new file mode 100644 index 0000000..63729d4 --- /dev/null +++ b/ueberbackend.hh @@ -0,0 +1,165 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 UEBERBACKEND_HH +#define UEBERBACKEND_HH + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "dnspacket.hh" +#include "dnsbackend.hh" + +#include "namespaces.hh" + +/** This is a very magic backend that allows us to load modules dynamically, + and query them in order. This is persistent over all UeberBackend instantiations + across multiple threads. + + The UeberBackend is transparent for exceptions, which should fall straight through. +*/ + +class UeberBackend : public boost::noncopyable +{ +public: + UeberBackend(const string &pname="default"); + ~UeberBackend(); + + bool superMasterBackend(const string &ip, const DNSName &domain, const vector&nsset, string *nameserver, string *account, DNSBackend **db); + + /** Tracks all created UeberBackend instances for us. We use this vector to notify + existing threads of new modules + */ + static vectorinstances; + static pthread_mutex_t instances_lock; + + static bool loadmodule(const string &name); + + static void go(void); + + /** This contains all registered backends. The DynListener modifies this list for us when + new modules are loaded */ + vector backends; + + void cleanup(); + + //! the very magic handle for UeberBackend questions + class handle + { + public: + bool get(DNSZoneRecord &dr); + handle(); + ~handle(); + + //! The UeberBackend class where this handle belongs to + UeberBackend *parent; + //! The current real backend, which is answering questions + DNSBackend *d_hinterBackend; + + //! DNSPacket who asked this question + DNSPacket *pkt_p; + DNSName qname; + + //! Index of the current backend within the backends vector + unsigned int i; + QType qtype; + + private: + + static AtomicCounter instances; + }; + + void lookup(const QType &, const DNSName &qdomain, DNSPacket *pkt_p=0, int zoneId=-1); + + /** Determines if we are authoritative for a zone, and at what level */ + bool getAuth(const DNSName &target, const QType &qtype, SOAData* sd, bool cachedOk=true); + bool getSOA(const DNSName &domain, SOAData &sd); + bool getSOAUncached(const DNSName &domain, SOAData &sd); // same, but ignores cache + bool get(DNSZoneRecord &r); + void getAllDomains(vector *domains, bool include_disabled=false); + + void getUnfreshSlaveInfos(vector* domains); + void getUpdatedMasters(vector* domains); + bool getDomainInfo(const DNSName &domain, DomainInfo &di); + bool createDomain(const DNSName &domain); + + bool doesDNSSEC(); + bool addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& id); + bool getDomainKeys(const DNSName& name, std::vector& keys); + bool getAllDomainMetadata(const DNSName& name, std::map >& meta); + bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector& meta); + bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector& meta); + + bool removeDomainKey(const DNSName& name, unsigned int id); + bool activateDomainKey(const DNSName& name, unsigned int id); + bool deactivateDomainKey(const DNSName& name, unsigned int id); + + bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content); + bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content); + bool deleteTSIGKey(const DNSName& name); + bool getTSIGKeys(std::vector< struct TSIGKey > &keys); + + void alsoNotifies(const DNSName &domain, set *ips); + void rediscover(string* status=0); + void reload(); + bool searchRecords(const string &pattern, int maxResults, vector& result); + bool searchComments(const string &pattern, int maxResults, vector& result); +private: + pthread_t d_tid; + handle d_handle; + vector d_answers; + vector::const_iterator d_cachehandleiter; + + static pthread_mutex_t d_mut; + static pthread_cond_t d_cond; + + struct Question + { + DNSName qname; + int zoneId; + QType qtype; + }d_question; + + unsigned int d_cache_ttl, d_negcache_ttl; + int d_domain_id; + int d_ancount; + + bool d_negcached; + bool d_cached; + static bool d_go; + bool d_stale; + + int cacheHas(const Question &q, vector &rrs); + void addNegCache(const Question &q); + void addCache(const Question &q, const vector &rrs); + +}; + +#endif diff --git a/unix_utility.cc b/unix_utility.cc new file mode 100644 index 0000000..5f5bb82 --- /dev/null +++ b/unix_utility.cc @@ -0,0 +1,306 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "utility.hh" +#include +#include +#include +#include +#include "pdnsexception.hh" +#include "logger.hh" +#include "misc.hh" +#include +#include +#include +#include + +#ifdef NEED_INET_NTOP_PROTO +extern "C" { +const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); +} +#endif + + +#include "namespaces.hh" + + +// Connects to socket with timeout +int Utility::timed_connect( Utility::sock_t sock, + const sockaddr *addr, + Utility::socklen_t sockaddr_size, + int timeout_sec, + int timeout_usec ) +{ + fd_set set; + struct timeval timeout; + int ret; + + timeout.tv_sec = timeout_sec; + timeout.tv_usec = timeout_usec; + + FD_ZERO(&set); + FD_SET(sock, &set); + + setNonBlocking(sock); + + if ((ret = connect (sock, addr, sockaddr_size)) < 0) { + if (errno != EINPROGRESS) + return ret; + } + + ret = select(sock + 1, NULL, &set, NULL, &timeout); + setBlocking(sock); + + return ret; +} + + + +void Utility::setBindAny(int af, sock_t sock) +{ + const int one = 1; + + (void) one; // avoids 'unused var' warning on systems that have none of the defines checked below +#ifdef IP_FREEBIND + if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) + theL()<pw_name, gid)<0) { + theL()<gr_gid; + } + return newgid; +} + + +// Retrieves an uid using a username. +int Utility::makeUidNumeric(const string &username) +{ + int newuid; + if(!(newuid=atoi(username.c_str()))) { + struct passwd *pw=getpwnam(username.c_str()); + if(!pw) { + theL()<pw_uid; + } + return newuid; +} + + +// Returns a random number. +long int Utility::random( void ) +{ + return rand(); +} + +// Sets the random seed. +void Utility::srandom( unsigned int seed ) +{ + ::srandom(seed); +} + + +// Writes a vector. +int Utility::writev(int socket, const iovec *vector, size_t count ) +{ + return ::writev(socket,vector,count); +} + +/* this is cut and pasted from dietlibc, gratefully copied! */ +static int isleap(int year) { + /* every fourth year is a leap year except for century years that are + * not divisible by 400. */ + return (!(year%4) && ((year%100) || !(year%400))); +} + +time_t Utility::timegm(struct tm *const t) +{ + const static short spm[13] = /* days per month -- nonleap! */ + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + (31+28+31+30+31+30+31+31+30+31+30+31), + }; + + time_t day; + time_t i; + time_t years = t->tm_year - 70; + + if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; } + if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; } + if (t->tm_hour>60) { t->tm_mday += t->tm_hour/60; t->tm_hour%=60; } + if (t->tm_mon>11) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; } + + while (t->tm_mday>spm[1+t->tm_mon]) { + if (t->tm_mon==1 && isleap(t->tm_year+1900)) { + if (t->tm_mon==31+29) break; + --t->tm_mday; + } + t->tm_mday-=spm[t->tm_mon]; + ++t->tm_mon; + if (t->tm_mon>11) { t->tm_mon=0; ++t->tm_year; } + } + + if (t->tm_year < 70) + return (time_t) -1; + /* Days since 1970 is 365 * number of years + number of leap years since 1970 */ + day = years * 365 + (years + 1) / 4; + + /* After 2100 we have to subtract 3 leap years for every 400 years + This is not intuitive. Most mktime implementations do not support + dates after 2059, anyway, so we might leave this out for its + bloat. */ + if ((years -= 131) >= 0) { + years /= 100; + day -= (years >> 2) * 3 + 1; + if ((years &= 3) == 3) years--; + day -= years; + } + + day += t->tm_yday = spm [t->tm_mon] + t->tm_mday-1 + ( isleap (t->tm_year+1900) & (t->tm_mon > 1) ); + + /* day is now the number of days since 'Jan 1 1970' */ + i = 7; + t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */ + + i = 24; + day *= i; + i = 60; + return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec; +} + diff --git a/utility.hh b/utility.hh new file mode 100644 index 0000000..d197c7c --- /dev/null +++ b/utility.hh @@ -0,0 +1,155 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +// Utility class specification. + +#ifndef UTILITY_HH +#define UTILITY_HH + +#ifdef NEED_POSIX_TYPEDEF +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "namespaces.hh" + +//! A semaphore class. +class Semaphore +{ +private: + typedef int sem_value_t; + +#if defined(_AIX) || defined(__APPLE__) + uint32_t m_magic; + pthread_mutex_t m_lock; + pthread_cond_t m_gtzero; + sem_value_t m_count; + uint32_t m_nwaiters; +#else + sem_t *m_pSemaphore; +#endif + +protected: +public: + //! Default constructor. + Semaphore( unsigned int value = 0 ); + + //! Destructor. + ~Semaphore( void ); + + //! Posts to a semaphore. + int post( void ); + + //! Waits for a semaphore. + int wait( void ); + + //! Tries to wait for a semaphore. + int tryWait( void ); + + //! Retrieves the semaphore value. + int getValue( Semaphore::sem_value_t *sval ); +}; + +//! This is a utility class used for platform independent abstraction. +class Utility +{ +public: + typedef ::iovec iovec; + typedef ::pid_t pid_t; + typedef int sock_t; + typedef ::socklen_t socklen_t; + + //! Connect with timeout + // Returns: + // > 0 on success + // -1 on error + // 0 on timeout + static int timed_connect(sock_t sock, + const sockaddr *addr, + socklen_t sockaddr_size, + int timeout_sec, + int timeout_usec); + + //! Returns the process id of the current process. + static pid_t getpid( void ); + + //! Gets the current time. + static int gettimeofday( struct timeval *tv, void *tz = NULL ); + + //! Converts an address from dot and numbers format to binary data. + static int inet_aton( const char *cp, struct in_addr *inp ); + + //! Converts an address from presentation format to network format. + static int inet_pton( int af, const char *src, void *dst ); + + //! The inet_ntop() function converts an address from network format (usually a struct in_addr or some other binary form, in network byte order) to presentation format. + static const char *inet_ntop( int af, const char *src, char *dst, size_t size ); + + //! Retrieves a gid using a groupname. + static int makeGidNumeric( const string & group ); + + //! Retrieves an uid using an username. + static int makeUidNumeric( const string & username ); + + //! Writes a vector. + static int writev( Utility::sock_t socket, const iovec *vector, size_t count ); + //! Returns a random number. + static long int random( void ); + + //! Sets the random seed. + static void srandom( unsigned int seed ); + + //! Drops the program's group privileges. + static void dropGroupPrivs( int uid, int gid ); + + //! Drops the program's user privileges. + static void dropUserPrivs( int uid ); + + //! Sets the socket into Bind-any mode + static void setBindAny ( int af, Utility::sock_t socket ); + + //! Sleeps for a number of seconds. + static unsigned int sleep( unsigned int seconds ); + + //! Sleeps for a number of microseconds. + static void usleep( unsigned long usec ); + + static time_t timegm(struct tm *tm); + +}; + + +#endif // UTILITY_HH diff --git a/validate-recursor.cc b/validate-recursor.cc new file mode 100644 index 0000000..a870c2e --- /dev/null +++ b/validate-recursor.cc @@ -0,0 +1,26 @@ +#include "syncres.hh" +#include "validate.hh" +#include "validate-recursor.hh" +#include "logger.hh" + +DNSSECMode g_dnssecmode{DNSSECMode::ProcessNoValidate}; +bool g_dnssecLogBogus; + +bool checkDNSSECDisabled() { + return warnIfDNSSECDisabled(""); +} + +bool warnIfDNSSECDisabled(const string& msg) { + if(g_dnssecmode == DNSSECMode::Off) { + if (!msg.empty()) + L< servfail +*/ + +enum class DNSSECMode { Off, Process, ProcessNoValidate, ValidateForLog, ValidateAll }; +extern DNSSECMode g_dnssecmode; +extern bool g_dnssecLogBogus; + +bool checkDNSSECDisabled(); +bool warnIfDNSSECDisabled(const string& msg); +vState increaseDNSSECStateCounter(const vState& state); diff --git a/validate.cc b/validate.cc new file mode 100644 index 0000000..00afcd7 --- /dev/null +++ b/validate.cc @@ -0,0 +1,1133 @@ +#include "validate.hh" +#include "misc.hh" +#include "dnssecinfra.hh" +#include "dnsseckeeper.hh" +#include "rec-lua-conf.hh" +#include "base32.hh" +#include "logger.hh" +bool g_dnssecLOG{false}; +uint16_t g_maxNSEC3Iterations{0}; + +#define LOG(x) if(g_dnssecLOG) { L < > getByTag(const skeyset_t& keys, uint16_t tag, uint8_t algorithm) +{ + vector> ret; + for(const auto& key : keys) + if(key->d_protocol == 3 && key->getTag() == tag && key->d_algorithm == algorithm) + ret.push_back(key); + return ret; +} + +static bool isCoveredByNSEC3Hash(const std::string& h, const std::string& beginHash, const std::string& nextHash) +{ + return ((beginHash < h && h < nextHash) || // no wrap BEGINNING --- HASH -- END + (nextHash > h && beginHash > nextHash) || // wrap HASH --- END --- BEGINNING + (nextHash < beginHash && beginHash < h) || // wrap other case END --- BEGINNING --- HASH + (beginHash == nextHash && h != beginHash)); // "we have only 1 NSEC3 record, LOL!" +} + +static bool isCoveredByNSEC(const DNSName& name, const DNSName& begin, const DNSName& next) +{ + return ((begin.canonCompare(name) && name.canonCompare(next)) || // no wrap BEGINNING --- NAME --- NEXT + (name.canonCompare(next) && next.canonCompare(begin)) || // wrap NAME --- NEXT --- BEGINNING + (next.canonCompare(begin) && begin.canonCompare(name)) || // wrap other case NEXT --- BEGINNING --- NAME + (begin == next && name != begin)); // "we have only 1 NSEC record, LOL!" +} + +static bool nsecProvesENT(const DNSName& name, const DNSName& begin, const DNSName& next) +{ + /* if name is an ENT: + - begin < name + - next is a child of name + */ + return begin.canonCompare(name) && next != name && next.isPartOf(name); +} + +static std::string getHashFromNSEC3(const DNSName& qname, const std::shared_ptr nsec3) +{ + std::string result; + + if (g_maxNSEC3Iterations && nsec3->d_iterations > g_maxNSEC3Iterations) { + return result; + } + + return hashQNameWithSalt(nsec3->d_salt, nsec3->d_iterations, qname); +} + +/* There is no delegation at this exact point if: + - the name exists but the NS type is not set + - the name does not exist + One exception, if the name is covered by an opt-out NSEC3 + it doesn't prove that an insecure delegation doesn't exist. +*/ +bool denialProvesNoDelegation(const DNSName& zone, const std::vector& dsrecords) +{ + for (const auto& record : dsrecords) { + if (record.d_type == QType::NSEC) { + const auto nsec = getRR(record); + if (!nsec) { + continue; + } + + if (record.d_name == zone) { + return !nsec->d_set.count(QType::NS); + } + + if (isCoveredByNSEC(zone, record.d_name, nsec->d_next)) { + return true; + } + } + else if (record.d_type == QType::NSEC3) { + const auto nsec3 = getRR(record); + if (!nsec3) { + continue; + } + + const string h = getHashFromNSEC3(zone, nsec3); + if (h.empty()) { + return false; + } + + const string beginHash = fromBase32Hex(record.d_name.getRawLabels()[0]); + if (beginHash == h) { + return !nsec3->d_set.count(QType::NS); + } + + if (isCoveredByNSEC3Hash(h, beginHash, nsec3->d_nexthash)) { + return !(nsec3->d_flags & 1); + } + } + } + + return false; +} + +/* RFC 4035 section-5.3.4: + "If the number of labels in an RRset's owner name is greater than the + Labels field of the covering RRSIG RR, then the RRset and its + covering RRSIG RR were created as a result of wildcard expansion." +*/ +static bool isWildcardExpanded(const DNSName& owner, const std::vector >& signatures) +{ + if (signatures.empty()) { + return false; + } + + const auto& sign = signatures.at(0); + unsigned int labelsCount = owner.countLabels(); + if (sign && sign->d_labels < labelsCount) { + return true; + } + + return false; +} + +/* if this is a wildcard NSEC, the owner name has been modified + to match the name. Make sure we use the original '*' form. */ +static DNSName getNSECOwnerName(const DNSName& initialOwner, const std::vector >& signatures) +{ + DNSName result = initialOwner; + + if (signatures.empty()) { + return result; + } + + const auto& sign = signatures.at(0); + unsigned int labelsCount = initialOwner.countLabels(); + if (sign && sign->d_labels < labelsCount) { + do { + result.chopOff(); + labelsCount--; + } + while (sign->d_labels < labelsCount); + + result = g_wildcarddnsname + result; + } + + return result; +} + +static bool isNSECAncestorDelegation(const DNSName& signer, const DNSName& owner, const std::shared_ptr nsec) +{ + return nsec->d_set.count(QType::NS) && + !nsec->d_set.count(QType::SOA) && + signer.countLabels() < owner.countLabels(); +} + +static bool isNSEC3AncestorDelegation(const DNSName& signer, const DNSName& owner, const std::shared_ptr nsec3) +{ + return nsec3->d_set.count(QType::NS) && + !nsec3->d_set.count(QType::SOA) && + signer.countLabels() < owner.countLabels(); +} + +static bool provesNoDataWildCard(const DNSName& qname, const uint16_t qtype, const cspmap_t& validrrsets) +{ + LOG("Trying to prove that there is no data in wildcard for "<getZoneRepresentation()<(r); + if (!nsec) { + continue; + } + + if (!v.first.first.isWildcard()) { + continue; + } + DNSName wildcard = getNSECOwnerName(v.first.first, v.second.signatures); + if (qname.countLabels() < wildcard.countLabels()) { + continue; + } + + wildcard.chopOff(); + + if (qname.isPartOf(wildcard)) { + LOG("\tWildcard matches"); + if (qtype == 0 || !nsec->d_set.count(qtype)) { + LOG(" and proves that the type did not exist"<getZoneRepresentation()<(r); + if (!nsec) { + continue; + } + + const DNSName owner = getNSECOwnerName(v.first.first, v.second.signatures); + /* + A NSEC can only prove the non-existence of a wildcard with at least the same + number of labels than the intersection of its owner name and next name. + */ + const DNSName commonLabels = owner.getCommonLabels(nsec->d_next); + unsigned int commonLabelsCount = commonLabels.countLabels(); + + DNSName wildcard(qname); + unsigned int wildcardLabelsCount = wildcard.countLabels(); + while (wildcard.chopOff() && wildcardLabelsCount >= commonLabelsCount) { + DNSName target = g_wildcarddnsname + wildcard; + + LOG("Comparing owner: "<d_next)) { + LOG("\tWildcard is covered"<getZoneRepresentation()<(r); + if (!nsec3) { + continue; + } + + const DNSName signer = getSigner(v.second.signatures); + if (!v.first.first.isPartOf(signer)) + continue; + + string h = getHashFromNSEC3(wildcard, nsec3); + if (h.empty()) { + return false; + } + LOG("\tWildcard hash: "< "<d_nexthash)<d_set.count(qtype)) { + LOG(" and proves that the type did not exist"<d_nexthash)) { + LOG("\tWildcard hash is covered"<getZoneRepresentation()<(r); + if(!nsec) + continue; + + const DNSName signer = getSigner(v.second.signatures); + if (!v.first.first.isPartOf(signer)) + continue; + + const DNSName owner = getNSECOwnerName(v.first.first, v.second.signatures); + /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs": + Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume + nonexistence of any RRs below that zone cut, which include all RRs at + that (original) owner name other than DS RRs, and all RRs below that + owner name regardless of type. + */ + if (qtype != QType::DS && (qname == owner || qname.isPartOf(owner)) && isNSECAncestorDelegation(signer, owner, nsec)) { + LOG("type is "<d_set.count(QType::NS))<<", SOA is "<d_set.count(QType::SOA))<<", signer is "<d_set.count(qtype)) { + LOG("Does _not_ deny existence of type "<d_set.count(QType::CNAME)) { + LOG("However a CNAME exists"<d_set.count(QType::NS)) { + LOG("However, no NS record exists at this level!"<d_next)) { + /* if the name is an ENT and we received a NODATA answer, + we are fine with a NSEC proving that the name does not exist. */ + if (wantsNoDataProof && nsecProvesENT(qname, owner, nsec->d_next)) { + LOG("Denies existence of type "<d_set.count(qtype)<<", next: "<d_next<getZoneRepresentation()<(r); + if(!nsec3) + continue; + + const DNSName signer = getSigner(v.second.signatures); + if (!v.first.first.isPartOf(signer)) { + LOG("Owner "<d_salt.length()<<", iterations: "<d_iterations<<", hashed: "<d_set.count(QType::NS))<<", SOA is "<d_set.count(QType::SOA))<<", signer is "<d_set.count(qtype)) { + LOG("Does _not_ deny existence of type "<d_set.count(QType::CNAME)) { + LOG("However a CNAME exists"<d_set.count(QType::NS)) { + LOG("However, no NS record exists at this level!"<getZoneRepresentation()<(r); + if(!nsec3) + continue; + + const DNSName signer = getSigner(v.second.signatures); + if (!v.first.first.isPartOf(signer)) { + LOG("Owner "< 0 && closestEncloserLabelsCount > wildcardLabelsCount) { + closestEncloser.chopOff(); + closestEncloserLabelsCount--; + } + } + + bool nextCloserFound = false; + bool isOptOut = false; + + if (found == true) { + /* now that we have found the closest (provable) encloser, + we can construct the next closer (FRC7129 section-5.5) name + and look for a NSEC3 RR covering it */ + unsigned int labelIdx = qname.countLabels() - closestEncloser.countLabels(); + if (labelIdx >= 1) { + DNSName nextCloser(closestEncloser); + nextCloser.prependRawLabel(qname.getRawLabel(labelIdx - 1)); + LOG("Looking for a NSEC3 covering the next closer name "<getZoneRepresentation()<(r); + if(!nsec3) + continue; + + string h = getHashFromNSEC3(nextCloser, nsec3); + if (h.empty()) { + return INSECURE; + } + + string beginHash=fromBase32Hex(v.first.first.getRawLabels()[0]); + + LOG("Comparing "< "<d_nexthash)<d_nexthash)) { + LOG("Denies existence of name "<d_flags & 1) { + LOG(" but is opt-out!"); + isOptOut = true; + } + LOG(endl); + break; + } + LOG("Did not cover us ("< getZoneCuts(const DNSName& begin, const DNSName& end, DNSRecordOracle& dro) +{ + vector ret; + if(!begin.isPartOf(end)) + throw PDNSException(end.toLogString() + "is not part of " + begin.toString()); + + DNSName qname(end); + vector labelsToAdd = begin.makeRelative(end).getRawLabels(); + + // The shortest name is assumed to a zone cut + ret.push_back(qname); + while(qname != begin) { + bool foundCut = false; + if (labelsToAdd.empty()) + break; + + qname.prependRawLabel(labelsToAdd.back()); + labelsToAdd.pop_back(); + auto records = dro.get(qname, (uint16_t)QType::NS); + for (const auto record : records) { + if(record.d_type != QType::NS || record.d_name != qname) + continue; + foundCut = true; + break; + } + if (foundCut) + ret.push_back(qname); + } + return ret; +} + +bool isRRSIGNotExpired(const time_t now, const shared_ptr sig) +{ + return sig->d_siginception <= now && sig->d_sigexpire >= now; +} + +static bool checkSignatureWithKey(time_t now, const shared_ptr sig, const shared_ptr key, const std::string& msg) +{ + bool result = false; + try { + /* rfc4035: + - The validator's notion of the current time MUST be less than or equal to the time listed in the RRSIG RR's Expiration field. + - The validator's notion of the current time MUST be greater than or equal to the time listed in the RRSIG RR's Inception field. + */ + if(isRRSIGNotExpired(now, sig)) { + std::shared_ptr dke = shared_ptr(DNSCryptoKeyEngine::makeFromPublicKeyString(key->d_algorithm, key->d_key)); + result = dke->verify(msg, sig->d_signature); + LOG("signature by key with tag "<d_tag<<" and algorithm "<d_algorithm)<<" was " << (result ? "" : "NOT ")<<"valid"<d_siginception > now) ? "not yet valid" : "expired")<<" (inception: "<d_siginception<<", expiration: "<d_sigexpire<<", now: "< >& records, const vector >& signatures, const skeyset_t& keys, bool validateAllSigs) +{ + bool isValid = false; + + for(const auto& signature : signatures) { + unsigned int labelCount = name.countLabels(); + if (signature->d_labels > labelCount) { + LOG(name<<": Discarding invalid RRSIG whose label count is "<d_labels<<" while the RRset owner name has only "< > toSign = records; + + auto r = getByTag(keys, signature->d_tag, signature->d_algorithm); + + if(r.empty()) { + LOG("No key provided for "<d_tag<<" and algorithm "<d_algorithm)<d_type)<first.first<<"/"<<)<d_type != QType::DNSKEY) { + dotEdge(signature->d_signer, + "DNSKEY", signature->d_signer, std::to_string(signature->d_tag), + DNSRecordContent::NumberToType(signature->d_type), name, "", signIsValid ? "green" : "red"); + } + if (signIsValid && !validateAllSigs) { + return true; + } + } + } + + return isValid; +} + +void validateWithKeySet(const cspmap_t& rrsets, cspmap_t& validated, const skeyset_t& keys) +{ + validated.clear(); + /* cerr<<"Validating an rrset with following keys: "<getTag()<<" -> "<getZoneRepresentation()<first.first)<<"/"<first.second)<<" with "<second.signatures.size()<<" sigs"<first.first, i->second.records, i->second.signatures, keys, true)) { + validated[i->first] = i->second; + } + } +} + +// returns vState +// should return vState, zone cut and validated keyset +// i.e. www.7bits.nl -> insecure/7bits.nl/[] +// www.powerdnssec.org -> secure/powerdnssec.org/[keys] +// www.dnssec-failed.org -> bogus/dnssec-failed.org/[] + +cspmap_t harvestCSPFromRecs(const vector& recs) +{ + cspmap_t cspmap; + for(const auto& rec : recs) { + // cerr<<"res "<(rec); + if (rrc) { + cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc); + } + } + else { + cspmap[{rec.d_name, rec.d_type}].records.push_back(rec.d_content); + } + } + return cspmap; +} + +bool getTrustAnchor(const map& anchors, const DNSName& zone, dsmap_t &res) +{ + const auto& it = anchors.find(zone); + + if (it == anchors.cend()) { + return false; + } + + res = it->second; + return true; +} + +bool haveNegativeTrustAnchor(const map& negAnchors, const DNSName& zone, std::string& reason) +{ + const auto& it = negAnchors.find(zone); + + if (it == negAnchors.cend()) { + return false; + } + + reason = it->second; + return true; +} + +void validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, vector >& toSign, const vector >& sigs, skeyset_t& validkeys) +{ + /* + * Check all DNSKEY records against all DS records and place all DNSKEY records + * that have DS records (that we support the algo for) in the tentative key storage + */ + for(auto const& dsrc : dsmap) + { + auto r = getByTag(tkeys, dsrc.d_tag, dsrc.d_algorithm); + // cerr<<"looking at DS with tag "<(dsrc.d_digesttype) % static_cast(dsrc.d_algorithm)).str()); + } + else { + if (dsCreated) { + LOG("DNSKEY did not match the DS, parent DS: "< "<(dsrc.d_digesttype)<<"\" ]; label = \"zone: "<getTag()), isValid ? "green" : "red"); + // dotNode("DNSKEY", zone, (boost::format("tag=%d, algo=%d") % drc->getTag() % static_cast(drc->d_algorithm)).str()); + } + } + + vector toSignTags; + for (const auto& key : tkeys) { + toSignTags.push_back(key->getTag()); + } + + // cerr<<"got "<d_tag<<" matching "<d_tag).size()<<" keys of which "<d_tag).size()<<" valid"<d_tag, sig->d_algorithm); + + if (bytag.empty()) { + continue; + } + + string msg = getMessageForRRSET(zone, *sig, toSign); + for(const auto& key : bytag) { + // cerr<<"validating : "; + bool signIsValid = checkSignatureWithKey(now, sig, key, msg); + + for(uint16_t tag : toSignTags) { + dotEdge(zone, + "DNSKEY", zone, std::to_string(sig->d_tag), + "DNSKEY", zone, std::to_string(tag), signIsValid ? "green" : "red"); + } + + if(signIsValid) + { + LOG("validation succeeded - whole DNSKEY set is valid"<d_signer))<<" -> "<dsAnchors; + if (anchors.empty()) // Nothing to do here + return Insecure; + + // Determine the lowest (i.e. with the most labels) Trust Anchor for zone + DNSName lowestTA("."); + for (auto const &anchor : anchors) + if (zone.isPartOf(anchor.first) && lowestTA.countLabels() < anchor.first.countLabels()) + lowestTA = anchor.first; + + // Before searching for the keys, see if we have a Negative Trust Anchor. If + // so, test if the NTA is valid and return an NTA state + const auto negAnchors = luaLocal->negAnchors; + + if (!negAnchors.empty()) { + DNSName lowestNTA; + + for (auto const &negAnchor : negAnchors) + if (zone.isPartOf(negAnchor.first) && lowestNTA.countLabels() <= negAnchor.first.countLabels()) + lowestNTA = negAnchor.first; + + if(!lowestNTA.empty()) { + LOG("Found a Negative Trust Anchor for "< "< > sigs; + vector > toSign; + + skeyset_t tkeys; // tentative keys + validkeys.clear(); + + // cerr<<"got DS for ["< (rec); + if(rrc) { + LOG("Got signature: "<getZoneRepresentation()<<" with tag "<d_tag<<", for type "<d_type)<d_type != QType::DNSKEY) + continue; + sigs.push_back(rrc); + } + } + else if(rec.d_type == QType::DNSKEY) + { + auto drc=getRR (rec); + if(drc) { + tkeys.insert(drc); + LOG("Inserting key with tag "<getTag()<<" and algorithm "<d_algorithm)<<": "<getZoneRepresentation()<getTag()), (boost::format("tag=%d, algo=%d") % drc->getTag() % static_cast(drc->d_algorithm)).str()); + + toSign.push_back(rec.d_content); + } + } + } + LOG("got "<second.records.cbegin(); j!=cspiter->second.records.cend(); j++) + { + const auto dsrc=std::dynamic_pointer_cast(*j); + if(dsrc) { + dsmap.insert(*dsrc); + // dotEdge(key*(zoneCutIter+1), + // "DNSKEY", key*(zoneCutIter+1), , + // "DS", *(zoneCutIter+1), std::to_string(dsrc.d_tag)); + // cout<<" "< "< >& signatures) +{ + for (const auto sig : signatures) { + if (sig) { + return sig->d_signer; + } + } + + return DNSName(); +} + +string dotEscape(string name) +{ + return "\"" + boost::replace_all_copy(name, "\"", "\\\"") + "\""; +} + +string dotName(string type, DNSName name, string tag) +{ + if(tag == "") + return type+" "+name.toString(); + else + return type+" "+name.toString()+"/"+tag; +} +void dotNode(string type, DNSName name, string tag, string content) +{ +#ifdef GRAPHVIZ + cout<<" " + < " + < +#include "namespaces.hh" +#include "dnsrecords.hh" + +extern bool g_dnssecLOG; +extern uint16_t g_maxNSEC3Iterations; + +// 4033 5 +enum vState { Indeterminate, Bogus, Insecure, Secure, NTA, TA }; +extern const char *vStates[]; + +// NSEC(3) results +enum dState { NODATA, NXDOMAIN, NXQTYPE, ENT, INSECURE, OPTOUT}; +extern const char *dStates[]; + +class DNSRecordOracle +{ +public: + virtual std::vector get(const DNSName& qname, uint16_t qtype)=0; +}; + + +struct ContentSigPair +{ + vector> records; + vector> signatures; + // ponder adding a validate method that accepts a key +}; +typedef map, ContentSigPair> cspmap_t; +typedef std::set dsmap_t; + +struct sharedDNSKeyRecordContentCompare +{ + bool operator() (const shared_ptr& a, const shared_ptr& b) const + { + return *a < *b; + } +}; + +typedef set, sharedDNSKeyRecordContentCompare > skeyset_t; + +bool validateWithKeySet(time_t now, const DNSName& name, const vector >& records, const vector >& signatures, const skeyset_t& keys, bool validateAllSigs=true); +void validateWithKeySet(const cspmap_t& rrsets, cspmap_t& validated, const skeyset_t& keys); +cspmap_t harvestCSPFromRecs(const vector& recs); +vState getKeysFor(DNSRecordOracle& dro, const DNSName& zone, skeyset_t& keyset); +bool getTrustAnchor(const map& anchors, const DNSName& zone, dsmap_t &res); +bool haveNegativeTrustAnchor(const map& negAnchors, const DNSName& zone, std::string& reason); +void validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, vector >& toSign, const vector >& sigs, skeyset_t& validkeys); +dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof, bool needsWildcardProof=true, unsigned int wildcardLabelsCount=0); +bool isSupportedDS(const DSRecordContent& ds); +DNSName getSigner(const std::vector >& signatures); +bool denialProvesNoDelegation(const DNSName& zone, const std::vector& dsrecords); +bool isRRSIGNotExpired(const time_t now, const shared_ptr sig); diff --git a/version.cc b/version.cc new file mode 100644 index 0000000..8dbb9f3 --- /dev/null +++ b/version.cc @@ -0,0 +1,147 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "logger.hh" +#include "version.hh" + +#ifdef HAVE_BOTAN +#include +#endif /* HAVE_BOTAN */ + +static ProductType productType; + +string compilerVersion() +{ +#if defined(__clang__) + return string("clang " __clang_version__ ); +#elif defined(__GNUC__) + return string("gcc " __VERSION__ ); +#else // add other compilers here + return string("Unknown compiler"); +#endif +} + +// Human-readable product name +string productName() { + switch (productType) { + case ProductAuthoritative: + return "PowerDNS Authoritative Server"; + case ProductRecursor: + return "PowerDNS Recursor"; + }; + return "Unknown"; +} + +string getPDNSVersion() +{ + return VERSION; +} + +// REST API product type +string productTypeApiType() { + switch (productType) { + case ProductAuthoritative: + return "authoritative"; + case ProductRecursor: + return "recursor"; + }; + return "unknown"; +} + +void showProductVersion() +{ + theL()< +#include +#include "logger.hh" +#include +#include "dns.hh" +#include "base64.hh" +#include "json.hh" +#include "arguments.hh" +#include + +json11::Json HttpRequest::json() +{ + string err; + if(this->body.empty()) { + L<body, err); + if (doc.is_null()) { + L<second).find("basic ") == 0) { + string cookie = header->second.substr(6); + + string plain; + B64Decode(cookie, plain); + + vector cparts; + stringtok(cparts, plain, ":"); + + // this gets rid of terminating zeros + auth_ok = (cparts.size()==2 && (0==strcmp(cparts[1].c_str(), expected_password.c_str()))); + } + return auth_ok; +} + +bool HttpRequest::compareHeader(const string &header_name, const string &expected_value) +{ + YaHTTP::strstr_map_t::iterator header = headers.find(header_name); + if (header == headers.end()) + return false; + + // this gets rid of terminating zeros + return (0==strcmp(header->second.c_str(), expected_value.c_str())); +} + + +void HttpResponse::setBody(const json11::Json& document) +{ + document.dump(this->body); +} + +void HttpResponse::setErrorResult(const std::string& message, const int status_) +{ + setBody(json11::Json::object { { "error", message } }); + this->status = status_; +} + +void HttpResponse::setSuccessResult(const std::string& message, const int status_) +{ + setBody(json11::Json::object { { "result", message } }); + this->status = status_; +} + +static void bareHandlerWrapper(WebServer::HandlerFunction handler, YaHTTP::Request* req, YaHTTP::Response* resp) +{ + // wrapper to convert from YaHTTP::* to our subclasses + handler(static_cast(req), static_cast(resp)); +} + +void WebServer::registerBareHandler(const string& url, HandlerFunction handler) +{ + YaHTTP::THandlerFunction f = boost::bind(&bareHandlerWrapper, handler, _1, _2); + YaHTTP::Router::Any(url, f); +} + +static bool optionsHandler(HttpRequest* req, HttpResponse* resp) { + if (req->method == "OPTIONS") { + resp->headers["access-control-allow-origin"] = "*"; + resp->headers["access-control-allow-headers"] = "Content-Type, X-API-Key"; + resp->headers["access-control-allow-methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"; + resp->headers["access-control-max-age"] = "3600"; + resp->status = 200; + resp->headers["content-type"]= "text/plain"; + resp->body = ""; + return true; + } + return false; +} + +static void apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) { + const string& api_key = arg()["api-key"]; + + if (optionsHandler(req, resp)) return; + + resp->headers["access-control-allow-origin"] = "*"; + + if (api_key.empty()) { + L<url.path << "\": Authentication failed, API Key missing in config" << endl; + throw HttpUnauthorizedException("X-API-Key"); + } + bool auth_ok = req->compareHeader("x-api-key", api_key) || req->getvars["api-key"]==api_key; + + if (!auth_ok) { + L<url.path << "\": Authentication by API Key failed" << endl; + throw HttpUnauthorizedException("X-API-Key"); + } + + resp->headers["Content-Type"] = "application/json"; + + // security headers + resp->headers["X-Content-Type-Options"] = "nosniff"; + resp->headers["X-Frame-Options"] = "deny"; + resp->headers["X-Permitted-Cross-Domain-Policies"] = "none"; + resp->headers["X-XSS-Protection"] = "1; mode=block"; + resp->headers["Content-Security-Policy"] = "default-src 'self'; style-src 'self' 'unsafe-inline'"; + + req->getvars.erase("_"); // jQuery cache buster + + try { + resp->status = 200; + handler(req, resp); + } catch (ApiException &e) { + resp->setErrorResult(e.what(), 422); + return; + } catch (JsonException &e) { + resp->setErrorResult(e.what(), 422); + return; + } + + if (resp->status == 204) { + // No Content -> no Content-Type. + resp->headers.erase("Content-Type"); + } +} + +void WebServer::registerApiHandler(const string& url, HandlerFunction handler) { + HandlerFunction f = boost::bind(&apiWrapper, handler, _1, _2); + registerBareHandler(url, f); +} + +static void webWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) { + const string& web_password = arg()["webserver-password"]; + + if (!web_password.empty()) { + bool auth_ok = req->compareAuthorization(web_password); + if (!auth_ok) { + L<url.path << "\": Web Authentication failed" << endl; + throw HttpUnauthorizedException("Basic"); + } + } + + handler(req, resp); +} + +void WebServer::registerWebHandler(const string& url, HandlerFunction handler) { + HandlerFunction f = boost::bind(&webWrapper, handler, _1, _2); + registerBareHandler(url, f); +} + +static void *WebServerConnectionThreadStart(const WebServer* webServer, std::shared_ptr client) { + webServer->serveConnection(client); + return nullptr; +} + +void WebServer::handleRequest(HttpRequest& req, HttpResponse& resp) const +{ + // set default headers + resp.headers["Content-Type"] = "text/html; charset=utf-8"; + + try { + if (!req.complete) { + L<second.find("application/json") != std::string::npos) { + req.accept_json = true; + } else if (header->second.find("text/html") != std::string::npos) { + req.accept_html = true; + } + } + + YaHTTP::THandlerFunction handler; + if (!YaHTTP::Router::Route(&req, handler)) { + L<

" + what + "

"; + } else if (req.accept_json) { + resp.headers["Content-Type"] = "application/json"; + resp.setErrorResult(what, resp.status); + } else { + resp.headers["Content-Type"] = "text/plain; charset=utf-8"; + resp.body = what; + } + } + + // always set these headers + resp.headers["Server"] = "PowerDNS/" VERSION; + resp.headers["Connection"] = "close"; + + if (req.method == "HEAD") { + resp.body = ""; + } else { + resp.headers["Content-Length"] = std::to_string(resp.body.size()); + } +} + +void WebServer::serveConnection(std::shared_ptr client) const +try { + HttpRequest req; + YaHTTP::AsyncRequestLoader yarl; + yarl.initialize(&req); + int timeout = 5; + client->setNonBlocking(); + + try { + while(!req.complete) { + int bytes; + char buf[1024]; + bytes = client->readWithTimeout(buf, sizeof(buf), timeout); + if (bytes > 0) { + string data = string(buf, bytes); + req.complete = yarl.feed(data); + } else { + // read error OR EOF + break; + } + } + yarl.finalize(); + } catch (YaHTTP::ParseError &e) { + // request stays incomplete + } + + HttpResponse resp; + WebServer::handleRequest(req, resp); + ostringstream ss; + resp.write(ss); + string reply = ss.str(); + + client->writenWithTimeout(reply.c_str(), reply.size(), timeout); +} +catch(PDNSException &e) { + L<d_local.toStringWithPort()<accept(); + if (!client) { + continue; + } + if (client->acl(acl)) { + std::thread webHandler(WebServerConnectionThreadStart, this, client); + webHandler.detach(); + } else { + ComboAddress remote; + if (client->getRemote(remote)) + L< +#include +#include +#include +#include +#include "json11.hpp" +#include "namespaces.hh" +#include "sstuff.hh" + +class WebServer; + +class HttpRequest : public YaHTTP::Request { +public: + HttpRequest() : YaHTTP::Request(), accept_json(false), accept_html(false), complete(false) { }; + + bool accept_json; + bool accept_html; + bool complete; + json11::Json json(); + + // checks password _only_. + bool compareAuthorization(const string &expected_password); + bool compareHeader(const string &header_name, const string &expected_value); +}; + +class HttpResponse: public YaHTTP::Response { +public: + HttpResponse() : YaHTTP::Response() { }; + HttpResponse(const YaHTTP::Response &resp) : YaHTTP::Response(resp) { }; + + void setBody(const json11::Json& document); + void setErrorResult(const std::string& message, const int status); + void setSuccessResult(const std::string& message, const int status = 200); +}; + + +class HttpException +{ +public: + HttpException(int status) : d_response() + { + d_response.status = status; + }; + + HttpResponse response() + { + return d_response; + } + +protected: + HttpResponse d_response; +}; + +class HttpBadRequestException : public HttpException { +public: + HttpBadRequestException() : HttpException(400) { }; +}; + +class HttpUnauthorizedException : public HttpException { +public: + HttpUnauthorizedException(string const &scheme) : HttpException(401) + { + d_response.headers["WWW-Authenticate"] = scheme + " realm=\"PowerDNS\""; + } +}; + +class HttpForbiddenException : public HttpException { +public: + HttpForbiddenException() : HttpException(403) { }; +}; + +class HttpNotFoundException : public HttpException { +public: + HttpNotFoundException() : HttpException(404) { }; +}; + +class HttpMethodNotAllowedException : public HttpException { +public: + HttpMethodNotAllowedException() : HttpException(405) { }; +}; + +class HttpInternalServerErrorException : public HttpException { +public: + HttpInternalServerErrorException() : HttpException(500) { }; +}; + +class ApiException : public runtime_error +{ +public: + ApiException(const string& what) : runtime_error(what) { + } +}; + +class Server +{ +public: + Server(const string &localaddress, int port) : d_local(localaddress.empty() ? "0.0.0.0" : localaddress, port), d_server_socket(d_local.sin4.sin_family, SOCK_STREAM, 0) { + d_server_socket.setReuseAddr(); + d_server_socket.bind(d_local); + d_server_socket.listen(); + } + virtual ~Server() { }; + + ComboAddress d_local; + + std::shared_ptr accept() { + return std::shared_ptr(d_server_socket.accept()); + } + +protected: + Socket d_server_socket; +}; + +class WebServer : public boost::noncopyable +{ +public: + WebServer(const string &listenaddress, int port); + virtual ~WebServer() { }; + void bind(); + void go(); + + void serveConnection(std::shared_ptr client) const; + void handleRequest(HttpRequest& request, HttpResponse& resp) const; + + typedef boost::function HandlerFunction; + void registerApiHandler(const string& url, HandlerFunction handler); + void registerWebHandler(const string& url, HandlerFunction handler); + +protected: + void registerBareHandler(const string& url, HandlerFunction handler); + + virtual std::shared_ptr createServer() { + return std::make_shared(d_listenaddress, d_port); + } + + string d_listenaddress; + int d_port; + string d_password; + std::shared_ptr d_server; +}; + +#endif /* WEBSERVER_HH */ diff --git a/ws-api.cc b/ws-api.cc new file mode 100644 index 0000000..4258f3d --- /dev/null +++ b/ws-api.cc @@ -0,0 +1,311 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "namespaces.hh" +#include "ws-api.hh" +#include "json.hh" +#include "version.hh" +#include "arguments.hh" +#include +#include +#include +#include +#include + +extern string s_programname; +using json11::Json; + +#ifndef HAVE_STRCASESTR + +/* + * strcasestr() locates the first occurrence in the string s1 of the + * sequence of characters (excluding the terminating null character) + * in the string s2, ignoring case. strcasestr() returns a pointer + * to the located string, or a null pointer if the string is not found. + * If s2 is empty, the function returns s1. + */ + +static char * +strcasestr(const char *s1, const char *s2) +{ + int *cm = __trans_lower; + const uchar_t *us1 = (const uchar_t *)s1; + const uchar_t *us2 = (const uchar_t *)s2; + const uchar_t *tptr; + int c; + + if (us2 == NULL || *us2 == '\0') + return ((char *)us1); + + c = cm[*us2]; + while (*us1 != '\0') { + if (c == cm[*us1++]) { + tptr = us1; + while (cm[c = *++us2] == cm[*us1++] && c != '\0') + continue; + if (c == '\0') + return ((char *)tptr - 1); + us1 = tptr; + us2 = (const uchar_t *)s2; + c = cm[*us2]; + } + } + + return (NULL); +} + +#endif // HAVE_STRCASESTR + +static Json getServerDetail() { + return Json::object { + { "type", "Server" }, + { "id", "localhost" }, + { "url", "/api/v1/servers/localhost" }, + { "daemon_type", productTypeApiType() }, + { "version", getPDNSVersion() }, + { "config_url", "/api/v1/servers/localhost/config{/config_setting}" }, + { "zones_url", "/api/v1/servers/localhost/zones{/zone}" } + }; +} + +/* Return information about the supported API versions. + * The format of this MUST NEVER CHANGE at it's not versioned. + */ +void apiDiscovery(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + Json version1 = Json::object { + { "version", 1 }, + { "url", "/api/v1" } + }; + Json doc = Json::array { version1 }; + + resp->setBody(doc); +} + +void apiServer(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + Json doc = Json::array {getServerDetail()}; + resp->setBody(doc); +} + +void apiServerDetail(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + resp->setBody(getServerDetail()); +} + +void apiServerConfig(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + vector items = ::arg().list(); + string value; + Json::array doc; + for(const string& item : items) { + if(item.find("password") != string::npos || item.find("api-key") != string::npos) + value = "***"; + else + value = ::arg()[item]; + + doc.push_back(Json::object { + { "type", "ConfigSetting" }, + { "name", item }, + { "value", value }, + }); + } + resp->setBody(doc); +} + +static Json logGrep(const string& q, const string& fname, const string& prefix) +{ + FILE* ptr = fopen(fname.c_str(), "r"); + if(!ptr) { + throw ApiException("Opening \"" + fname + "\" failed: " + stringerror()); + } + std::shared_ptr fp(ptr, fclose); + + string line; + string needle = q; + trim_right(needle); + + boost::replace_all(needle, "%20", " "); + boost::replace_all(needle, "%22", "\""); + + boost::tokenizer > t(needle, boost::escaped_list_separator("\\", " ", "\"")); + vector matches(t.begin(), t.end()); + matches.push_back(prefix); + + boost::circular_buffer lines(200); + while(stringfgets(fp.get(), line)) { + vector::const_iterator iter; + for(iter = matches.begin(); iter != matches.end(); ++iter) { + if(!strcasestr(line.c_str(), iter->c_str())) + break; + } + if(iter == matches.end()) { + trim_right(line); + lines.push_front(line); + } + } + + Json::array items; + for(const string& iline : lines) { + items.push_back(iline); + } + return items; +} + +void apiServerSearchLog(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + string prefix = " " + s_programname + "["; + resp->setBody(logGrep(req->getvars["q"], ::arg()["api-logfile"], prefix)); +} + +void apiServerStatistics(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + map items; + productServerStatisticsFetch(items); + + Json::array doc; + typedef map items_t; + for(const items_t::value_type& item : items) { + doc.push_back(Json::object { + { "type", "StatisticItem" }, + { "name", item.first }, + { "value", item.second }, + }); + } + + resp->setBody(doc); +} + +DNSName apiNameToDNSName(const string& name) { + if (!isCanonical(name)) { + throw ApiException("DNS Name '" + name + "' is not canonical"); + } + try { + return DNSName(name); + } catch (...) { + throw ApiException("Unable to parse DNS Name '" + name + "'"); + } +} + +DNSName apiZoneIdToName(const string& id) { + string zonename; + ostringstream ss; + + if(id.empty()) + throw HttpBadRequestException(); + + std::size_t lastpos = 0, pos = 0; + while ((pos = id.find('=', lastpos)) != string::npos) { + ss << id.substr(lastpos, pos-lastpos); + char c; + // decode tens + if (id[pos+1] >= '0' && id[pos+1] <= '9') { + c = id[pos+1] - '0'; + } else if (id[pos+1] >= 'A' && id[pos+1] <= 'F') { + c = id[pos+1] - 'A' + 10; + } else { + throw HttpBadRequestException(); + } + c = c * 16; + + // decode unit place + if (id[pos+2] >= '0' && id[pos+2] <= '9') { + c += id[pos+2] - '0'; + } else if (id[pos+2] >= 'A' && id[pos+2] <= 'F') { + c += id[pos+2] - 'A' + 10; + } else { + throw HttpBadRequestException(); + } + + ss << c; + + lastpos = pos+3; + } + if (lastpos < pos) { + ss << id.substr(lastpos, pos-lastpos); + } + + zonename = ss.str(); + + try { + return DNSName(zonename); + } catch (...) { + throw ApiException("Unable to parse DNS Name '" + zonename + "'"); + } +} + +string apiZoneNameToId(const DNSName& dname) { + string name=dname.toString(); + ostringstream ss; + + for(string::const_iterator iter = name.begin(); iter != name.end(); ++iter) { + if ((*iter >= 'A' && *iter <= 'Z') || + (*iter >= 'a' && *iter <= 'z') || + (*iter >= '0' && *iter <= '9') || + (*iter == '.') || (*iter == '-')) { + ss << *iter; + } else { + ss << (boost::format("=%02X") % (int)(*iter)); + } + } + + string id = ss.str(); + + // add trailing dot + if (id.size() == 0 || id.substr(id.size()-1) != ".") { + id += "."; + } + + // special handling for the root zone, as a dot on it's own doesn't work + // everywhere. + if (id == ".") { + id = (boost::format("=%02X") % (int)('.')).str(); + } + return id; +} + +void apiCheckNameAllowedCharacters(const string& name) { + if (name.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_/.-") != std::string::npos) + throw ApiException("Name '"+name+"' contains unsupported characters"); +} + +void apiCheckQNameAllowedCharacters(const string& qname) { + if (qname.compare(0, 2, "*.") == 0) apiCheckNameAllowedCharacters(qname.substr(2)); + else apiCheckNameAllowedCharacters(qname); +} diff --git a/ws-api.hh b/ws-api.hh new file mode 100644 index 0000000..1bbd6b5 --- /dev/null +++ b/ws-api.hh @@ -0,0 +1,46 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_WSAPI_HH +#define PDNS_WSAPI_HH + +#include +#include "webserver.hh" + +void apiDiscovery(HttpRequest* req, HttpResponse* resp); +void apiServer(HttpRequest* req, HttpResponse* resp); +void apiServerDetail(HttpRequest* req, HttpResponse* resp); +void apiServerConfig(HttpRequest* req, HttpResponse* resp); +void apiServerSearchLog(HttpRequest* req, HttpResponse* resp); +void apiServerStatistics(HttpRequest* req, HttpResponse* resp); + +// helpers +DNSName apiZoneIdToName(const string& id); +string apiZoneNameToId(const DNSName& name); +void apiCheckNameAllowedCharacters(const string& name); +void apiCheckQNameAllowedCharacters(const string& name); +DNSName apiNameToDNSName(const string& name); + +// To be provided by product code. +void productServerStatisticsFetch(std::map& out); + +#endif /* PDNS_WSAPI_HH */ diff --git a/ws-recursor.cc b/ws-recursor.cc new file mode 100644 index 0000000..dbe1c07 --- /dev/null +++ b/ws-recursor.cc @@ -0,0 +1,663 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "syncres.hh" +#include "ws-recursor.hh" +#include "json.hh" + +#include +#include "namespaces.hh" +#include +#include "iputils.hh" +#include "rec_channel.hh" +#include "arguments.hh" +#include "misc.hh" +#include "dnsparser.hh" +#include "json11.hpp" +#include "webserver.hh" +#include "ws-api.hh" +#include "logger.hh" +#include "ext/incbin/incbin.h" +#include "rec-lua-conf.hh" +#include "rpzloader.hh" + +extern thread_local FDMultiplexer* t_fdm; + +using json11::Json; + +void productServerStatisticsFetch(map& out) +{ + map stats = getAllStatsMap(); + out.swap(stats); +} + +static void apiWriteConfigFile(const string& filebasename, const string& content) +{ + if (::arg()["api-config-dir"].empty()) { + throw ApiException("Config Option \"api-config-dir\" must be set"); + } + + string filename = ::arg()["api-config-dir"] + "/" + filebasename + ".conf"; + ofstream ofconf(filename.c_str()); + if (!ofconf) { + throw ApiException("Could not open config fragment file '"+filename+"' for writing: "+stringerror()); + } + ofconf << "# Generated by pdns-recursor REST API, DO NOT EDIT" << endl; + ofconf << content << endl; + ofconf.close(); +} + +static void apiServerConfigAllowFrom(HttpRequest* req, HttpResponse* resp) +{ + if (req->method == "PUT" && !::arg().mustDo("api-readonly")) { + Json document = req->json(); + + auto jlist = document["value"]; + if (!jlist.is_array()) { + throw ApiException("'value' must be an array"); + } + + NetmaskGroup nmg; + for (auto value : jlist.array_items()) { + try { + nmg.addMask(value.string_value()); + } catch (const NetmaskException &e) { + throw ApiException(e.reason); + } + } + + ostringstream ss; + + // Clear allow-from-file if set, so our changes take effect + ss << "allow-from-file=" << endl; + + // Clear allow-from, and provide a "parent" value + ss << "allow-from=" << endl; + ss << "allow-from+=" << nmg.toString() << endl; + + apiWriteConfigFile("allow-from", ss.str()); + + parseACLs(); + + // fall through to GET + } else if (req->method != "GET") { + throw HttpMethodNotAllowedException(); + } + + // Return currently configured ACLs + vector entries; + t_allowFrom->toStringVector(&entries); + + resp->setBody(Json::object { + { "name", "allow-from" }, + { "value", entries }, + }); +} + +static void fillZone(const DNSName& zonename, HttpResponse* resp) +{ + auto iter = SyncRes::t_sstorage.domainmap->find(zonename); + if (iter == SyncRes::t_sstorage.domainmap->end()) + throw ApiException("Could not find domain '"+zonename.toString()+"'"); + + const SyncRes::AuthDomain& zone = iter->second; + + Json::array servers; + for(const ComboAddress& server : zone.d_servers) { + servers.push_back(server.toStringWithPort()); + } + + Json::array records; + for(const SyncRes::AuthDomain::records_t::value_type& dr : zone.d_records) { + records.push_back(Json::object { + { "name", dr.d_name.toString() }, + { "type", DNSRecordContent::NumberToType(dr.d_type) }, + { "ttl", (double)dr.d_ttl }, + { "content", dr.d_content->getZoneRepresentation() } + }); + } + + // id is the canonical lookup key, which doesn't actually match the name (in some cases) + string zoneId = apiZoneNameToId(iter->first); + Json::object doc = { + { "id", zoneId }, + { "url", "/api/v1/servers/localhost/zones/" + zoneId }, + { "name", iter->first.toString() }, + { "kind", zone.d_servers.empty() ? "Native" : "Forwarded" }, + { "servers", servers }, + { "recursion_desired", zone.d_servers.empty() ? false : zone.d_rdForward }, + { "records", records } + }; + + resp->setBody(doc); +} + +static void doCreateZone(const Json document) +{ + if (::arg()["api-config-dir"].empty()) { + throw ApiException("Config Option \"api-config-dir\" must be set"); + } + + DNSName zonename = apiNameToDNSName(stringFromJson(document, "name")); + apiCheckNameAllowedCharacters(zonename.toString()); + + string singleIPTarget = document["single_target_ip"].string_value(); + string kind = toUpper(stringFromJson(document, "kind")); + bool rd = boolFromJson(document, "recursion_desired"); + string confbasename = "zone-" + apiZoneNameToId(zonename); + + if (kind == "NATIVE") { + if (rd) + throw ApiException("kind=Native and recursion_desired are mutually exclusive"); + if(!singleIPTarget.empty()) { + try { + ComboAddress rem(singleIPTarget); + if(rem.sin4.sin_family != AF_INET) + throw ApiException(""); + singleIPTarget = rem.toString(); + } + catch(...) { + throw ApiException("Single IP target '"+singleIPTarget+"' is invalid"); + } + } + string zonefilename = ::arg()["api-config-dir"] + "/" + confbasename + ".zone"; + ofstream ofzone(zonefilename.c_str()); + if (!ofzone) { + throw ApiException("Could not open '"+zonefilename+"' for writing: "+stringerror()); + } + ofzone << "; Generated by pdns-recursor REST API, DO NOT EDIT" << endl; + ofzone << zonename << "\tIN\tSOA\tlocal.zone.\thostmaster."<method == "POST" && !::arg().mustDo("api-readonly")) { + if (::arg()["api-config-dir"].empty()) { + throw ApiException("Config Option \"api-config-dir\" must be set"); + } + + Json document = req->json(); + + DNSName zonename = apiNameToDNSName(stringFromJson(document, "name")); + + auto iter = SyncRes::t_sstorage.domainmap->find(zonename); + if (iter != SyncRes::t_sstorage.domainmap->end()) + throw ApiException("Zone already exists"); + + doCreateZone(document); + reloadAuthAndForwards(); + fillZone(zonename, resp); + resp->status = 201; + return; + } + + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + Json::array doc; + for(const SyncRes::domainmap_t::value_type& val : *SyncRes::t_sstorage.domainmap) { + const SyncRes::AuthDomain& zone = val.second; + Json::array servers; + for(const ComboAddress& server : zone.d_servers) { + servers.push_back(server.toStringWithPort()); + } + // id is the canonical lookup key, which doesn't actually match the name (in some cases) + string zoneId = apiZoneNameToId(val.first); + doc.push_back(Json::object { + { "id", zoneId }, + { "url", "/api/v1/servers/localhost/zones/" + zoneId }, + { "name", val.first.toString() }, + { "kind", zone.d_servers.empty() ? "Native" : "Forwarded" }, + { "servers", servers }, + { "recursion_desired", zone.d_servers.empty() ? false : zone.d_rdForward } + }); + } + resp->setBody(doc); +} + +static void apiServerZoneDetail(HttpRequest* req, HttpResponse* resp) +{ + DNSName zonename = apiZoneIdToName(req->parameters["id"]); + + SyncRes::domainmap_t::const_iterator iter = SyncRes::t_sstorage.domainmap->find(zonename); + if (iter == SyncRes::t_sstorage.domainmap->end()) + throw ApiException("Could not find domain '"+zonename.toString()+"'"); + + if(req->method == "PUT" && !::arg().mustDo("api-readonly")) { + Json document = req->json(); + + doDeleteZone(zonename); + doCreateZone(document); + reloadAuthAndForwards(); + resp->body = ""; + resp->status = 204; // No Content, but indicate success + } + else if(req->method == "DELETE" && !::arg().mustDo("api-readonly")) { + if (!doDeleteZone(zonename)) { + throw ApiException("Deleting domain failed"); + } + + reloadAuthAndForwards(); + // empty body on success + resp->body = ""; + resp->status = 204; // No Content: declare that the zone is gone now + } else if(req->method == "GET") { + fillZone(zonename, resp); + } else { + throw HttpMethodNotAllowedException(); + } +} + +static void apiServerSearchData(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + string q = req->getvars["q"]; + if (q.empty()) + throw ApiException("Query q can't be blank"); + + Json::array doc; + for(const SyncRes::domainmap_t::value_type& val : *SyncRes::t_sstorage.domainmap) { + string zoneId = apiZoneNameToId(val.first); + string zoneName = val.first.toString(); + if (pdns_ci_find(zoneName, q) != string::npos) { + doc.push_back(Json::object { + { "type", "zone" }, + { "zone_id", zoneId }, + { "name", zoneName } + }); + } + + // if zone name is an exact match, don't bother with returning all records/comments in it + if (val.first == DNSName(q)) { + continue; + } + + const SyncRes::AuthDomain& zone = val.second; + + for(const SyncRes::AuthDomain::records_t::value_type& rr : zone.d_records) { + if (pdns_ci_find(rr.d_name.toString(), q) == string::npos && pdns_ci_find(rr.d_content->getZoneRepresentation(), q) == string::npos) + continue; + + doc.push_back(Json::object { + { "type", "record" }, + { "zone_id", zoneId }, + { "zone_name", zoneName }, + { "name", rr.d_name.toString() }, + { "content", rr.d_content->getZoneRepresentation() } + }); + } + } + resp->setBody(doc); +} + +static void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp) { + if(req->method != "PUT") + throw HttpMethodNotAllowedException(); + + DNSName canon = apiNameToDNSName(req->getvars["domain"]); + bool subtree = (req->getvars.count("subtree") > 0 && req->getvars["subtree"].compare("true") == 0); + + int count = broadcastAccFunction(boost::bind(pleaseWipeCache, canon, subtree)); + count += broadcastAccFunction(boost::bind(pleaseWipePacketCache, canon, subtree)); + count += broadcastAccFunction(boost::bind(pleaseWipeAndCountNegCache, canon, subtree)); + resp->setBody(Json::object { + { "count", count }, + { "result", "Flushed cache." } + }); +} + +static void apiServerRPZStats(HttpRequest* req, HttpResponse* resp) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + auto luaconf = g_luaconfs.getLocal(); + auto numZones = luaconf->dfe.size(); + + Json::object ret; + + for (size_t i=0; i < numZones; i++) { + auto zone = luaconf->dfe.getZone(i); + if (zone == nullptr) + continue; + auto name = zone->getName(); + auto stats = getRPZZoneStats(*name); + if (stats == nullptr) + continue; + Json::object zoneInfo = { + {"transfers_failed", (double)stats->d_failedTransfers}, + {"transfers_success", (double)stats->d_successfulTransfers}, + {"transfers_full", (double)stats->d_fullTransfers}, + {"records", (double)stats->d_numberOfRecords}, + {"last_update", (double)stats->d_lastUpdate}, + {"serial", (double)stats->d_serial}, + }; + ret[*name] = zoneInfo; + } + resp->setBody(ret); +} + +#include "htmlfiles.h" + +static void serveStuff(HttpRequest* req, HttpResponse* resp) +{ + resp->headers["Cache-Control"] = "max-age=86400"; + + if(req->url.path == "/") + req->url.path = "/index.html"; + + const string charset = "; charset=utf-8"; + if(boost::ends_with(req->url.path, ".html")) + resp->headers["Content-Type"] = "text/html" + charset; + else if(boost::ends_with(req->url.path, ".css")) + resp->headers["Content-Type"] = "text/css" + charset; + else if(boost::ends_with(req->url.path,".js")) + resp->headers["Content-Type"] = "application/javascript" + charset; + else if(boost::ends_with(req->url.path, ".png")) + resp->headers["Content-Type"] = "image/png"; + + resp->headers["X-Content-Type-Options"] = "nosniff"; + resp->headers["X-Frame-Options"] = "deny"; + resp->headers["X-Permitted-Cross-Domain-Policies"] = "none"; + + resp->headers["X-XSS-Protection"] = "1; mode=block"; + // resp->headers["Content-Security-Policy"] = "default-src 'self'; style-src 'self' 'unsafe-inline'"; + + resp->body = g_urlmap[req->url.path.c_str()+1]; + resp->status = 200; +} + + +RecursorWebServer::RecursorWebServer(FDMultiplexer* fdm) +{ + registerAllStats(); + + d_ws = new AsyncWebServer(fdm, arg()["webserver-address"], arg().asNum("webserver-port")); + d_ws->bind(); + + // legacy dispatch + d_ws->registerApiHandler("/jsonstat", boost::bind(&RecursorWebServer::jsonstat, this, _1, _2)); + d_ws->registerApiHandler("/api/v1/servers/localhost/cache/flush", &apiServerCacheFlush); + d_ws->registerApiHandler("/api/v1/servers/localhost/config/allow-from", &apiServerConfigAllowFrom); + d_ws->registerApiHandler("/api/v1/servers/localhost/config", &apiServerConfig); + d_ws->registerApiHandler("/api/v1/servers/localhost/rpzstatistics", &apiServerRPZStats); + d_ws->registerApiHandler("/api/v1/servers/localhost/search-log", &apiServerSearchLog); + d_ws->registerApiHandler("/api/v1/servers/localhost/search-data", &apiServerSearchData); + d_ws->registerApiHandler("/api/v1/servers/localhost/statistics", &apiServerStatistics); + d_ws->registerApiHandler("/api/v1/servers/localhost/zones/", &apiServerZoneDetail); + d_ws->registerApiHandler("/api/v1/servers/localhost/zones", &apiServerZones); + d_ws->registerApiHandler("/api/v1/servers/localhost", &apiServerDetail); + d_ws->registerApiHandler("/api/v1/servers", &apiServer); + d_ws->registerApiHandler("/api", &apiDiscovery); + + for(const auto& u : g_urlmap) + d_ws->registerWebHandler("/"+u.first, serveStuff); + d_ws->registerWebHandler("/", serveStuff); + d_ws->go(); +} + +void RecursorWebServer::jsonstat(HttpRequest* req, HttpResponse *resp) +{ + string command; + + if(req->getvars.count("command")) { + command = req->getvars["command"]; + req->getvars.erase("command"); + } + + map stats; + if(command == "get-query-ring") { + typedef pair query_t; + vector queries; + bool filter=!req->getvars["public-filtered"].empty(); + + if(req->getvars["name"]=="servfail-queries") + queries=broadcastAccFunction >(pleaseGetServfailQueryRing); + else if(req->getvars["name"]=="queries") + queries=broadcastAccFunction >(pleaseGetQueryRing); + + typedef map counts_t; + counts_t counts; + unsigned int total=0; + for(const query_t& q : queries) { + total++; + if(filter) + counts[make_pair(getRegisteredName(q.first), q.second)]++; + else + counts[make_pair(q.first, q.second)]++; + } + + typedef std::multimap rcounts_t; + rcounts_t rcounts; + + for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i) + rcounts.insert(make_pair(-i->second, i->first)); + + Json::array entries; + unsigned int tot=0, totIncluded=0; + for(const rcounts_t::value_type& q : rcounts) { + totIncluded-=q.first; + entries.push_back(Json::array { + -q.first, q.second.first.toString(), DNSRecordContent::NumberToType(q.second.second) + }); + if(tot++>=100) + break; + } + if(queries.size() != totIncluded) { + entries.push_back(Json::array { + (int)(queries.size() - totIncluded), "", "" + }); + } + resp->setBody(Json::object { { "entries", entries } }); + return; + } + else if(command == "get-remote-ring") { + vector queries; + if(req->getvars["name"]=="remotes") + queries=broadcastAccFunction >(pleaseGetRemotes); + else if(req->getvars["name"]=="servfail-remotes") + queries=broadcastAccFunction >(pleaseGetServfailRemotes); + else if(req->getvars["name"]=="large-answer-remotes") + queries=broadcastAccFunction >(pleaseGetLargeAnswerRemotes); + + typedef map counts_t; + counts_t counts; + unsigned int total=0; + for(const ComboAddress& q : queries) { + total++; + counts[q]++; + } + + typedef std::multimap rcounts_t; + rcounts_t rcounts; + + for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i) + rcounts.insert(make_pair(-i->second, i->first)); + + Json::array entries; + unsigned int tot=0, totIncluded=0; + for(const rcounts_t::value_type& q : rcounts) { + totIncluded-=q.first; + entries.push_back(Json::array { + -q.first, q.second.toString() + }); + if(tot++>=100) + break; + } + if(queries.size() != totIncluded) { + entries.push_back(Json::array { + (int)(queries.size() - totIncluded), "" + }); + } + + resp->setBody(Json::object { { "entries", entries } }); + return; + } else { + resp->setErrorResult("Command '"+command+"' not found", 404); + } +} + + +void AsyncServerNewConnectionMT(void *p) { + AsyncServer *server = (AsyncServer*)p; + + try { + auto socket = server->accept(); // this is actually a shared_ptr + if (socket) { + server->d_asyncNewConnectionCallback(socket); + } + } catch (NetworkError &e) { + // we're running in a shared process/thread, so can't just terminate/abort. + L<addReadFD(d_server_socket.getHandle(), boost::bind(&AsyncServer::newConnection, this)); +} + +void AsyncServer::newConnection() +{ + getMT()->makeThread(&AsyncServerNewConnectionMT, this); +} + +// This is an entry point from FDM, so it needs to catch everything. +void AsyncWebServer::serveConnection(std::shared_ptr client) const +try { + HttpRequest req; + YaHTTP::AsyncRequestLoader yarl; + yarl.initialize(&req); + client->setNonBlocking(); + + string data; + try { + while(!req.complete) { + int bytes = arecvtcp(data, 16384, client.get(), true); + if (bytes > 0) { + req.complete = yarl.feed(data); + } else { + // read error OR EOF + break; + } + } + yarl.finalize(); + } catch (YaHTTP::ParseError &e) { + // request stays incomplete + } + + HttpResponse resp; + handleRequest(req, resp); + ostringstream ss; + resp.write(ss); + data = ss.str(); + + // now send the reply + if (asendtcp(data, client.get()) == -1 || data.empty()) { + L<(d_server); + if (!server) + return; + server->asyncWaitForConnections(d_fdm, boost::bind(&AsyncWebServer::serveConnection, this, _1)); +} diff --git a/ws-recursor.hh b/ws-recursor.hh new file mode 100644 index 0000000..9df3a81 --- /dev/null +++ b/ws-recursor.hh @@ -0,0 +1,75 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_WSRECURSOR_HH +#define PDNS_WSRECURSOR_HH + +#include +#include "namespaces.hh" +#include "mplexer.hh" +#include "webserver.hh" + +class HttpRequest; +class HttpResponse; + +class AsyncServer : public Server { +public: + AsyncServer(const string &localaddress, int port) : Server(localaddress, port) { }; + + friend void AsyncServerNewConnectionMT(void *p); + + typedef boost::function< void(std::shared_ptr) > newconnectioncb_t; + void asyncWaitForConnections(FDMultiplexer* fdm, const newconnectioncb_t& callback); + +private: + void newConnection(); + + newconnectioncb_t d_asyncNewConnectionCallback; +}; + +class AsyncWebServer : public WebServer +{ +public: + AsyncWebServer(FDMultiplexer* fdm, const string &listenaddress, int port) : + WebServer(listenaddress, port), d_fdm(fdm) { }; + void go(); + +private: + FDMultiplexer* d_fdm; + void serveConnection(std::shared_ptr socket) const; + +protected: + virtual std::shared_ptr createServer() override { + return std::make_shared(d_listenaddress, d_port); + }; +}; + +class RecursorWebServer : public boost::noncopyable +{ +public: + explicit RecursorWebServer(FDMultiplexer* fdm); + void jsonstat(HttpRequest* req, HttpResponse *resp); + +private: + AsyncWebServer* d_ws; +}; + +#endif /* PDNS_WSRECURSOR_HH */ diff --git a/zoneparser-tng.cc b/zoneparser-tng.cc new file mode 100644 index 0000000..913063c --- /dev/null +++ b/zoneparser-tng.cc @@ -0,0 +1,537 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ascii.hh" +#include "dnsparser.hh" +#include "sstuff.hh" +#include "misc.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" +#include "misc.hh" +#include +#include "dns.hh" +#include "zoneparser-tng.hh" +#include +#include +#include + +static string g_INstr("IN"); + +ZoneParserTNG::ZoneParserTNG(const string& fname, const DNSName& zname, const string& reldir) : d_reldir(reldir), + d_zonename(zname), d_defaultttl(3600), + d_templatecounter(0), d_templatestop(0), + d_templatestep(0), d_havedollarttl(false){ + stackFile(fname); +} + +ZoneParserTNG::ZoneParserTNG(const vector zonedata, const DNSName& zname): + d_zonename(zname), d_defaultttl(3600), + d_templatecounter(0), d_templatestop(0), + d_templatestep(0), d_havedollarttl(false) +{ + d_zonedata = zonedata; + d_zonedataline = d_zonedata.begin(); + d_fromfile = false; +} + +void ZoneParserTNG::stackFile(const std::string& fname) +{ + FILE *fp=fopen(fname.c_str(), "r"); + if(!fp) { + std::error_code ec (errno,std::generic_category()); + throw std::system_error(ec, "Unable to open file '"+fname+"': "+stringerror()); + } + + filestate fs(fp, fname); + d_filestates.push(fs); + d_fromfile = true; +} + +ZoneParserTNG::~ZoneParserTNG() +{ + while(!d_filestates.empty()) { + fclose(d_filestates.top().d_fp); + d_filestates.pop(); + } +} + +static string makeString(const string& line, const pair& range) +{ + return string(line.c_str() + range.first, range.second - range.first); +} + +static bool isTimeSpec(const string& nextpart) +{ + if(nextpart.empty()) + return false; + for(string::const_iterator iter = nextpart.begin(); iter != nextpart.end(); ++iter) { + if(isdigit(*iter)) + continue; + if(iter+1 != nextpart.end()) + return false; + char c=tolower(*iter); + return (c=='s' || c=='m' || c=='h' || c=='d' || c=='w' || c=='y'); + } + return true; +} + + +unsigned int ZoneParserTNG::makeTTLFromZone(const string& str) +{ + if(str.empty()) + return 0; + + unsigned int val; + try { + val=pdns_stou(str); + } + catch (const std::out_of_range& oor) { + throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile()); + } + + char lc=dns_tolower(str[str.length()-1]); + if(!isdigit(lc)) + switch(lc) { + case 's': + break; + case 'm': + val*=60; // minutes, not months! + break; + case 'h': + val*=3600; + break; + case 'd': + val*=3600*24; + break; + case 'w': + val*=3600*24*7; + break; + case 'y': // ? :-) + val*=3600*24*365; + break; + + default: + throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile()); + } + return val; +} + +bool ZoneParserTNG::getTemplateLine() +{ + if(d_templateparts.empty() || d_templatecounter > d_templatestop) // no template, or done with + return false; + + string retline; + for(parts_t::const_iterator iter = d_templateparts.begin() ; iter != d_templateparts.end(); ++iter) { + if(iter != d_templateparts.begin()) + retline+=" "; + + string part=makeString(d_templateline, *iter); + + /* a part can contain a 'naked' $, an escaped $ (\$), or ${offset,width,radix}, with width defaulting to 0, + and radix being 'd', 'o', 'x' or 'X', defaulting to 'd'. + + The width is zero-padded, so if the counter is at 1, the offset is 15, with is 3, and the radix is 'x', + output will be '010', from the input of ${15,3,x} + */ + + string outpart; + outpart.reserve(part.size()+5); + bool inescape=false; + + for(string::size_type pos = 0; pos < part.size() ; ++pos) { + char c=part[pos]; + if(inescape) { + outpart.append(1, c); + inescape=false; + continue; + } + + if(part[pos]=='\\') { + inescape=true; + continue; + } + if(c=='$') { + if(pos + 1 == part.size() || part[pos+1]!='{') { // a trailing $, or not followed by { + outpart.append(std::to_string(d_templatecounter)); + continue; + } + + // need to deal with { case + + pos+=2; + string::size_type startPos=pos; + for(; pos < part.size() && part[pos]!='}' ; ++pos) + ; + + if(pos == part.size()) // partial spec + break; + + // we are on the '}' + + string spec(part.c_str() + startPos, part.c_str() + pos); + int offset=0, width=0; + char radix='d'; + sscanf(spec.c_str(), "%d,%d,%c", &offset, &width, &radix); // parse format specifier + + char sformat[12]; + snprintf(sformat, sizeof(sformat) - 1, "%%0%d%c", width, radix); // make into printf-style format + + char tmp[80]; + snprintf(tmp, sizeof(tmp)-1, sformat, d_templatecounter + offset); // and do the actual printing + outpart+=tmp; + } + else + outpart.append(1, c); + } + retline+=outpart; + } + d_templatecounter+=d_templatestep; + + d_line = retline; + return true; +} + +void chopComment(string& line) +{ + if(line.find(';')==string::npos) + return; + string::size_type pos, len = line.length(); + bool inQuote=false; + for(pos = 0 ; pos < len; ++pos) { + if(line[pos]=='\\') + pos++; + else if(line[pos]=='"') + inQuote=!inQuote; + else if(line[pos]==';' && !inQuote) + break; + } + if(pos != len) + line.resize(pos); +} + +bool findAndElide(string& line, char c) +{ + string::size_type pos, len = line.length(); + bool inQuote=false; + for(pos = 0 ; pos < len; ++pos) { + if(line[pos]=='\\') + pos++; + else if(line[pos]=='"') + inQuote=!inQuote; + else if(line[pos]==c && !inQuote) + break; + } + if(pos != len) { + line.erase(pos, 1); + return true; + } + return false; +} + +DNSName ZoneParserTNG::getZoneName() +{ + return d_zonename; +} + +string ZoneParserTNG::getLineOfFile() +{ + if (d_zonedata.size() > 0) + return "on line "+std::to_string(std::distance(d_zonedata.begin(), d_zonedataline))+" of given string"; + + if (d_filestates.empty()) + return ""; + + return "on line "+std::to_string(d_filestates.top().d_lineno)+" of file '"+d_filestates.top().d_filename+"'"; +} + +pair ZoneParserTNG::getLineNumAndFile() +{ + return {d_filestates.top().d_filename, d_filestates.top().d_lineno}; +} + +bool ZoneParserTNG::get(DNSResourceRecord& rr, std::string* comment) +{ + retry:; + if(!getTemplateLine() && !getLine()) + return false; + + boost::trim_right_if(d_line, is_any_of(" \t\r\n\x1a")); + if(comment) + comment->clear(); + if(comment && d_line.find(';') != string::npos) + *comment = d_line.substr(d_line.find(';')); + parts_t parts; + vstringtok(parts, d_line); + + if(parts.empty()) + goto retry; + + if(parts[0].first != parts[0].second && d_line[parts[0].first]==';') // line consisting of nothing but comments + goto retry; + + if(d_line[0]=='$') { + string command=makeString(d_line, parts[0]); + if(pdns_iequals(command,"$TTL") && parts.size() > 1) { + d_defaultttl=makeTTLFromZone(trim_right_copy_if(makeString(d_line, parts[1]), is_any_of(";"))); + d_havedollarttl=true; + } + else if(pdns_iequals(command,"$INCLUDE") && parts.size() > 1 && d_fromfile) { + string fname=unquotify(makeString(d_line, parts[1])); + if(!fname.empty() && fname[0]!='/' && !d_reldir.empty()) + fname=d_reldir+"/"+fname; + stackFile(fname); + } + else if(pdns_iequals(command, "$ORIGIN") && parts.size() > 1) { + d_zonename = DNSName(makeString(d_line, parts[1])); + } + else if(pdns_iequals(command, "$GENERATE") && parts.size() > 2) { + // $GENERATE 1-127 $ CNAME $.0 + string range=makeString(d_line, parts[1]); + d_templatestep=1; + d_templatestop=0; + sscanf(range.c_str(),"%d-%d/%d", &d_templatecounter, &d_templatestop, &d_templatestep); + d_templateline=d_line; + parts.pop_front(); + parts.pop_front(); + + d_templateparts=parts; + goto retry; + } + else + throw exception("Can't parse zone line '"+d_line+"' "+getLineOfFile()); + goto retry; + } + + bool prevqname=false; + string qname = makeString(d_line, parts[0]); // Don't use DNSName here! + if(dns_isspace(d_line[0])) { + rr.qname=d_prevqname; + prevqname=true; + }else { + rr.qname=DNSName(qname); + parts.pop_front(); + if(qname.empty() || qname[0]==';') + goto retry; + } + if(qname=="@") + rr.qname=d_zonename; + else if(!prevqname && !isCanonical(qname)) + rr.qname += d_zonename; + d_prevqname=rr.qname; + + if(parts.empty()) + throw exception("Line with too little parts "+getLineOfFile()); + + string nextpart; + + rr.ttl=d_defaultttl; + bool haveTTL=0, haveQTYPE=0; + pair range; + + while(!parts.empty()) { + range=parts.front(); + parts.pop_front(); + nextpart=makeString(d_line, range); + if(nextpart.empty()) + break; + + if(nextpart.find(';')!=string::npos) { + break; + } + + // cout<<"Next part: '"< recparts; + switch(rr.qtype.getCode()) { + case QType::MX: + stringtok(recparts, rr.content); + if(recparts.size()==2) { + if (recparts[1]!=".") { + try { + recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot(); + } catch (std::exception &e) { + throw PDNSException("Error in record '" + rr.qname.toString() + " " + rr.qtype.getName() + "': " + e.what()); + } + } + rr.content=recparts[0]+" "+recparts[1]; + } + break; + + case QType::RP: + stringtok(recparts, rr.content); + if(recparts.size()==2) { + recparts[0] = toCanonic(d_zonename, recparts[0]).toStringRootDot(); + recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot(); + rr.content=recparts[0]+" "+recparts[1]; + } + break; + + case QType::SRV: + stringtok(recparts, rr.content); + if(recparts.size()==4) { + if(recparts[3]!=".") { + try { + recparts[3] = toCanonic(d_zonename, recparts[3]).toStringRootDot(); + } catch (std::exception &e) { + throw PDNSException("Error in record '" + rr.qname.toString() + " " + rr.qtype.getName() + "': " + e.what()); + } + } + rr.content=recparts[0]+" "+recparts[1]+" "+recparts[2]+" "+recparts[3]; + } + break; + + + case QType::NS: + case QType::CNAME: + case QType::DNAME: + case QType::PTR: + try { + rr.content = toCanonic(d_zonename, rr.content).toStringRootDot(); + } catch (std::exception &e) { + throw PDNSException("Error in record '" + rr.qname.toString() + " " + rr.qtype.getName() + "': " + e.what()); + } + break; + case QType::AFSDB: + stringtok(recparts, rr.content); + if(recparts.size() == 2) { + try { + recparts[1]=toCanonic(d_zonename, recparts[1]).toStringRootDot(); + } catch (std::exception &e) { + throw PDNSException("Error in record '" + rr.qname.toString() + " " + rr.qtype.getName() + "': " + e.what()); + } + } else { + throw PDNSException("AFSDB record for "+rr.qname.toString()+" invalid"); + } + rr.content.clear(); + for(string::size_type n = 0; n < recparts.size(); ++n) { + if(n) + rr.content.append(1,' '); + + rr.content+=recparts[n]; + } + break; + case QType::SOA: + stringtok(recparts, rr.content); + if(recparts.size() > 7) + throw PDNSException("SOA record contents for "+rr.qname.toString()+" contains too many parts"); + if(recparts.size() > 1) { + try { + recparts[0]=toCanonic(d_zonename, recparts[0]).toStringRootDot(); + recparts[1]=toCanonic(d_zonename, recparts[1]).toStringRootDot(); + } catch (std::exception &e) { + throw PDNSException("Error in record '" + rr.qname.toString() + " " + rr.qtype.getName() + "': " + e.what()); + } + } + rr.content.clear(); + for(string::size_type n = 0; n < recparts.size(); ++n) { + if(n) + rr.content.append(1,' '); + + if(n > 1) + rr.content+=std::to_string(makeTTLFromZone(recparts[n])); + else + rr.content+=recparts[n]; + } + break; + default:; + } + return true; +} + + +bool ZoneParserTNG::getLine() +{ + if (d_zonedata.size() > 0) { + if (d_zonedataline != d_zonedata.end()) { + d_line = *d_zonedataline; + d_zonedataline++; + return true; + } + return false; + } + while(!d_filestates.empty()) { + if(stringfgets(d_filestates.top().d_fp, d_line)) { + d_filestates.top().d_lineno++; + return true; + } + fclose(d_filestates.top().d_fp); + d_filestates.pop(); + } + return false; +} diff --git a/zoneparser-tng.hh b/zoneparser-tng.hh new file mode 100644 index 0000000..36d58f9 --- /dev/null +++ b/zoneparser-tng.hh @@ -0,0 +1,72 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * 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 PDNS_ZONEPARSER_TNG +#define PDNS_ZONEPARSER_TNG +#include +#include +#include +#include + +#include "namespaces.hh" + +class ZoneParserTNG +{ +public: + ZoneParserTNG(const string& fname, const DNSName& zname=DNSName("."), const string& reldir=""); + ZoneParserTNG(const vector zonedata, const DNSName& zname); + + ~ZoneParserTNG(); + bool get(DNSResourceRecord& rr, std::string* comment=0); + typedef runtime_error exception; + typedef deque > parts_t; + DNSName getZoneName(); + string getLineOfFile(); // for error reporting purposes + pair getLineNumAndFile(); // idem +private: + bool getLine(); + bool getTemplateLine(); + void stackFile(const std::string& fname); + unsigned makeTTLFromZone(const std::string& str); + + struct filestate { + filestate(FILE* fp, string filename) : d_fp(fp), d_filename(filename), d_lineno(0){} + FILE *d_fp; + string d_filename; + int d_lineno; + }; + + string d_reldir; + string d_line; + DNSName d_prevqname; + DNSName d_zonename; + string d_templateline; + vector d_zonedata; + vector::iterator d_zonedataline; + std::stack d_filestates; + parts_t d_templateparts; + int d_defaultttl; + uint32_t d_templatecounter, d_templatestop, d_templatestep; + bool d_havedollarttl; + bool d_fromfile; +}; + +#endif