diff options
305 files changed, 133445 insertions, 0 deletions
@@ -0,0 +1,5 @@ +Ľuboš Slovák <lubos.slovak@nic.cz> +Marek Vavruša <marek.vavrusa@nic.cz> +Jan Kadlec <jan.kadlec@nic.cz> +Ondřej Surý <ondrej.sury@nic.cz> +Ondřej Filip <ondrej.filip@nic.cz> @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ChangeLog diff --git a/CodingStyle b/CodingStyle new file mode 100644 index 0000000..986417c --- /dev/null +++ b/CodingStyle @@ -0,0 +1,77 @@ +Coding style +============ +* Indentation: TAB (8 spaces width) +* Braces: K&R, 1TBS +* Max line width: 80 chars +* Pointer asterisk attached to the name of the variable +* Own structures/types: _t suffix (f.e. nameserver_t) +* Header guard format: _KNOTD__HEADER_H_ +* Spaces around binary operators +* Space between keyword and bracket (f.e. "if (predicate)") +* No space between variable and typecast (f.e. "return (int)val;") + +To sum it up, Linux KNF is used, see [1]. + +[1] Linux Coding Style: + http://kerneltrap.org/files/Jeremy/CodingStyle.txt + +AStyle command format +===================== +astyle --style=1tbs -t8 -w -p -H -U -j --align-pointer=name + +Doxygen +======= +* Format: Qt-style + * "\brief", not "@brief" + * "/*!", not "/**" +* Order of sections + * brief description + * long description + * notes + * warnings + * parameters + * return values + * todos +* Always use \brief (no autobrief) +* Indent text (using spaces only) in multiple-line sections +* In multi-line comments, opening line (/*!) should be empty +* One empty line between two consecutive sections +* Struct and union members documented on the same line if the comment fits +* Use \retval (or more of them) instead of \return + if the function returns some distinct values + (such as 0 for no error, -1 for something else, etc.) + +Example +======= +/*! + * \brief Some structure. + * + * Longer description. + */ + struct some_struct { + /*! + * \brief This comment does not fit on the same line as the member + * as it is rather large. + */ + int fd; + int flags; /*!< Flags. */ + }; + +/*! + * \brief Brief description of some function. + * + * Longer description. + * + * \note This function is deprecated. + * + * \warning Do not use this function! + * + * \param param1 Some parameter. + * \param param2 Other parameter. This one has rather large comment, + * so its next line is indented for better readability. + * + * \retval 0 on success. + * \retval -1 if some error occured. + * + * \todo Remove (deprecated). + */ diff --git a/Doxy.page.h b/Doxy.page.h new file mode 100644 index 0000000..4d0704c --- /dev/null +++ b/Doxy.page.h @@ -0,0 +1,88 @@ +/*! + +\defgroup server Server control module. +\defgroup threading Threading API. +\defgroup network Socket API. +\defgroup query_processing DNS query processing. +\defgroup utils Utilities, constants and macros. +\defgroup debugging Server debugging API. +\defgroup logging Server logging API. +\defgroup statistics Statistics module (optional). +\defgroup dnslib dnslib - Generic DNS library. +\defgroup hashing Hash table and functions. +\defgroup common_lib Common library. +\defgroup alloc Memory allocation. +\defgroup tests Unit tests. +\defgroup zoneparser Zone compiler utility +\defgroup ctl Control utility + +\mainpage Knot API documentation. + +Knot is an open-source, high-performace, purely authoritative DNS server. + +<h2>Requirements</h2> +- liburcu (at least 0.4.5): http://lttng.org/urcu +- automake +- autoconf +- libtool + +<h2>Installation</h2> +Knot uses autotools to generate makefiles. + +\todo Add some more info about usage and requirements. + +\code +$ autoreconf -i +$ ./configure +$ make +\endcode + +<h2>Starting the server</h2> + +When compiled, the following executables are created (in the src/ directory): +- \em knotd - The server +- \em knotc - Control utility +- \em knot-zcompile - Zone compiler +- \em unittests - Unit tests for the server and dnslib +- \em unittests-zcompile - Unit tests for the zone compiler + +1. Add path to knotd and knot-zcompile executables to PATH + +2. Prepare a configuration file. You may copy and edit the one provided with + the server (\em samples/knot.conf.sample). + +2. Compile zone +\code +$ src/knotc -c path-to-config-file compile +\endcode + +3. Run the server +\code +$ src/knotc -c path-to-config-file start +\endcode + +<h2>Server modules</h2> +- \ref server +- \ref threading +- \ref network +- \ref query_processing +- \ref utils +- \ref debugging +- \ref logging +- \ref statistics + +<h2>DNS library</h2> + +- \ref dnslib +- \ref hashing + +<h2>Common library</h2> + +- \ref common_lib +- \ref alloc + +<h2>Other modules</h2> +- \ref tests +- \ref zoneparser +- \ref ctl + */ diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..4966e80 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1634 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Knot + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = \ + src/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 50 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src/ \ + Doxy.page.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/Doxyfile.devel b/Doxyfile.devel new file mode 100644 index 0000000..4b73045 --- /dev/null +++ b/Doxyfile.devel @@ -0,0 +1,1634 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Knot + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc-devel + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = \ + src/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 50 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src/ \ + Doxy.page.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES @@ -0,0 +1,365 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES new file mode 100644 index 0000000..85bb088 --- /dev/null +++ b/KNOWN_ISSUES @@ -0,0 +1,25 @@ +Features not supported +====================== + +Here is a list of the most notable features that are not supported in the +current version of Knot. + +* IXFR +* Dynamic updates +* TSIG +* Slave functionality (AXFR-in). +* RRSet rotation +* Root zone (Knot cannot serve the root zone) +* Other DNS classes than IN (CH, CS, HS) +* Unknown RR types (types in form TYPE1234) + + +Known bugs +========== + +* Certain malformed packets cause the server to crash. +* Some actions may not be fully thread-safe (e.g. removing expired zone). +* If some hashed domain name (NSEC3) contains other data than NSEC3 and RRSIG, + queries for this data will not be responded well (always answers NXDOMAIN). +* Server fails to quit properly on some systems. + diff --git a/Knot.config b/Knot.config new file mode 100644 index 0000000..8cec188 --- /dev/null +++ b/Knot.config @@ -0,0 +1 @@ +// ADD PREDEFINED MACROS HERE! diff --git a/Knot.creator b/Knot.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/Knot.creator @@ -0,0 +1 @@ +[General] diff --git a/Knot.files b/Knot.files new file mode 100644 index 0000000..06fff5e --- /dev/null +++ b/Knot.files @@ -0,0 +1,253 @@ +CodingStyle +Makefile.am +Doxy.page.h +Doxyfile +Doxyfile.devel +configure.ac +KNOWN_ISSUES +README +tests/querytcp.c +libknot/Makefile.am +libknot/libknot.h +libknot/common.h +libknot/dname.h +libknot/dname.c +libknot/rrset.h +libknot/rrset.c +libknot/rdata.h +libknot/rdata.c +libknot/edns.h +libknot/edns.c +libknot/nsec3.h +libknot/nsec3.c +libknot/consts.h +libknot/hash/cuckoo-hash-table.c +libknot/hash/cuckoo-hash-table.h +libknot/hash/hash-functions.c +libknot/hash/hash-functions.h +libknot/hash/universal-system.c +libknot/hash/universal-system.h +libknot/nameserver/name-server.c +libknot/nameserver/name-server.h +libknot/packet/packet.h +libknot/packet/packet.c +libknot/packet/query.h +libknot/packet/query.c +libknot/packet/response.h +libknot/packet/response.c +libknot/updates/changesets.h +libknot/updates/changesets.c +libknot/updates/ddns.h +libknot/updates/ddns.c +libknot/updates/xfr-in.h +libknot/updates/xfr-in.c +libknot/util/wire.h +libknot/util/debug.h +libknot/util/debug.c +libknot/util/tolower.h +libknot/util/tolower.c +libknot/util/utils.h +libknot/util/utils.c +libknot/util/descriptor.h +libknot/util/descriptor.c +libknot/util/error.c +libknot/util/error.h +libknot/zone/zonedb.h +libknot/zone/zonedb.c +libknot/zone/node.h +libknot/zone/node.c +libknot/zone/zone.h +libknot/zone/zone.c +libknot/zone/zone-contents.c +libknot/zone/zone-contents.h +libknot/zone/zone-tree.h +libknot/zone/zone-tree.c +libknot/zone/dname-table.h +libknot/zone/dname-table.c +src/Makefile.am +src/common/slab/malloc.c +src/common/slab/malloc.h +src/common/slab/slab.c +src/common/slab/slab.h +src/common/slab/alloc-common.h +src/common/libtap/tap.c +src/common/libtap/tap.h +src/common/libtap/tap_unit.h +src/common/lists.h +src/common/lists.c +src/common/base32.h +src/common/base32.c +src/common/print.c +src/common/print.h +src/common/latency.c +src/common/latency.h +src/common/dynamic-array.c +src/common/dynamic-array.h +src/common/skip-list.c +src/common/skip-list.h +src/common/tree.h +src/common/base32hex.h +src/common/base32hex.c +src/common/evqueue.c +src/common/evqueue.h +src/common/evsched.c +src/common/evsched.h +src/common/errors.h +src/common/errors.c +src/common/acl.c +src/common/acl.h +src/common/sockaddr.h +src/common/sockaddr.c +src/common/crc.c +src/common/crc.h +src/common/ref.c +src/common/ref.h +src/common/modified_tree.h +src/common/general-tree.h +src/common/general-tree.c +src/common/WELL1024a.c +src/common/WELL1024a.h +src/common/fdset.h +src/common/fdset.c +src/common/fdset_poll.h +src/common/fdset_poll.c +src/common/fdset_epoll.h +src/common/fdset_epoll.c +src/common/fdset_kqueue.h +src/common/fdset_kqueue.c +src/zcompile/parser-descriptor.h +src/zcompile/parser-descriptor.c +src/zcompile/parser-util.h +src/zcompile/parser-util.c +src/zcompile/zcompile.c +src/zcompile/zcompile.h +src/zcompile/zparser.y +src/zcompile/zlexer.l +src/zcompile/zcompile-error.h +src/zcompile/zcompile_main.c +src/knot/common.h +src/knot/main.c +src/knot/ctl/knotc_main.c +src/knot/ctl/process.c +src/knot/ctl/process.h +src/knot/other/debug.h +src/knot/other/log.c +src/knot/other/log.h +src/knot/other/error.c +src/knot/other/error.h +src/knot/stat/gatherer.c +src/knot/stat/gatherer.h +src/knot/stat/stat.h +src/knot/stat/stat.c +src/knot/stat/stat-common.h +src/knot/server/dthreads.c +src/knot/server/dthreads.h +src/knot/server/server.c +src/knot/server/server.h +src/knot/server/socket.c +src/knot/server/socket.h +src/knot/server/tcp-handler.c +src/knot/server/tcp-handler.h +src/knot/server/xfr-handler.c +src/knot/server/xfr-handler.h +src/knot/server/udp-handler.c +src/knot/server/udp-handler.h +src/knot/server/zones.c +src/knot/server/zones.h +src/knot/server/journal.c +src/knot/server/journal.h +src/knot/server/notify.c +src/knot/server/notify.h +src/knot/ctl/process.c +src/knot/ctl/process.h +src/knot/conf/cf-lex.l +src/knot/conf/cf-parse.y +src/knot/conf/conf.c +src/knot/conf/conf.h +src/knot/conf/logconf.c +src/knot/conf/logconf.h +src/knot/zone/zone-dump.c +src/knot/zone/zone-dump.h +src/knot/zone/zone-load.c +src/knot/zone/zone-load.h +src/knot/zone/zone-dump-text.h +src/knot/zone/zone-dump-text.c +src/zcompile/tests/unittests_zp_main.c +src/zcompile/tests/zcompile_tests.c +src/zcompile/zcompile-error.c +src/tests/unittests_main.c +src/tests/common/acl_tests.c +src/tests/common/acl_tests.h +src/tests/common/da_tests.c +src/tests/common/da_tests.h +src/tests/common/events_tests.c +src/tests/common/events_tests.h +src/tests/common/skiplist_tests.c +src/tests/common/skiplist_tests.h +src/tests/common/slab_tests.c +src/tests/common/slab_tests.h +src/tests/common/fdset_tests.c +src/tests/common/fdset_tests.h +src/tests/knot/dthreads_tests.c +src/tests/knot/dthreads_tests.h +src/tests/knot/conf_tests.c +src/tests/knot/conf_tests.h +src/tests/knot/journal_tests.c +src/tests/knot/journal_tests.h +src/tests/knot/server_tests.c +src/tests/knot/server_tests.h +src/tests/libknot/unittests_libknot.c +src/tests/libknot/libknot/dname_tests.c +src/tests/libknot/libknot/dname_tests.h +src/tests/libknot/libknot/edns_tests.c +src/tests/libknot/libknot/edns_tests.h +src/tests/libknot/libknot/node_tests.c +src/tests/libknot/libknot/node_tests.h +src/tests/libknot/libknot/rdata_tests.c +src/tests/libknot/libknot/rdata_tests.h +src/tests/libknot/libknot/response_tests.c +src/tests/libknot/libknot/response_tests.h +src/tests/libknot/libknot/rrset_tests.c +src/tests/libknot/libknot/rrset_tests.h +src/tests/libknot/libknot/zone_tests.c +src/tests/libknot/libknot/zone_tests.h +src/tests/libknot/libknot/zonedb_tests.c +src/tests/libknot/libknot/zonedb_tests.h +src/tests/libknot/libknot/cuckoo_tests.c +src/tests/libknot/libknot/cuckoo_tests.h +src/tests/libknot/libknot/dname_table_tests.h +src/tests/libknot/libknot/dname_table_tests.c +src/tests/libknot/libknot/packet_tests.c +src/tests/libknot/libknot/packet_tests.h +src/tests/libknot/libknot/query_tests.c +src/tests/libknot/libknot/query_tests.h +src/tests/libknot/libknot/nsec3_tests.c +src/tests/libknot/libknot/nsec3_tests.h +src/tests/libknot/realdata/unittests_libknot_realdata.c +src/tests/libknot/realdata/libknot/packet_tests_realdata.c +src/tests/libknot/realdata/libknot/packet_tests_realdata.h +src/tests/libknot/realdata/libknot/dname_tests_realdata.c +src/tests/libknot/realdata/libknot/dname_tests_realdata.h +src/tests/libknot/realdata/libknot/edns_tests_realdata.c +src/tests/libknot/realdata/libknot/edns_tests_realdata.h +src/tests/libknot/realdata/libknot/node_tests_realdata.c +src/tests/libknot/realdata/libknot/node_tests_realdata.h +src/tests/libknot/realdata/libknot/rdata_tests_realdata.c +src/tests/libknot/realdata/libknot/rdata_tests_realdata.h +src/tests/libknot/realdata/libknot/response_tests_realdata.c +src/tests/libknot/realdata/libknot/response_tests_realdata.h +src/tests/libknot/realdata/libknot/rrset_tests_realdata.c +src/tests/libknot/realdata/libknot/rrset_tests_realdata.h +src/tests/libknot/realdata/libknot/zone_tests_realdata.c +src/tests/libknot/realdata/libknot/zone_tests_realdata.h +src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c +src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h +src/tests/libknot/realdata/libknot_tests_loader_realdata.c +src/tests/libknot/realdata/libknot_tests_loader_realdata.h +src/tests/libknot/libknot/zone_tree_tests.c +src/tests/libknot/libknot/zone_tree_tests.h +samples/Makefile.am +libknot/tsig.h +libknot/tsig.c +libknot/tsig-op.c +libknot/tsig-op.h diff --git a/Knot.includes b/Knot.includes new file mode 100644 index 0000000..8184956 --- /dev/null +++ b/Knot.includes @@ -0,0 +1,13 @@ +obj +src/alloc +src/ctl +src/dnslib +src/hash +src/lib +src/other +src/server +src/stat +src/tests/libtap +src/tests +src/zoneparser +src
\ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..30ea215 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src samples diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..e52ea78 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,708 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/configure AUTHORS COPYING \ + ChangeLog INSTALL NEWS config.guess config.sub depcomp \ + install-sh ltmain.sh missing ylwrap +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compiler_flags.m4 \ + $(top_srcdir)/m4/ax_ext.m4 \ + $(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/src/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIMD_FLAGS = @SIMD_FLAGS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src samples +all: all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ + distcheck distclean distclean-generic distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: @@ -0,0 +1,142 @@ +Installation +============ + +The following steps should work (verified in VirtualBox only) +on the distribution/architecture/release combinations as listed bellow. + +---------------------------------------------- +Debian (AMD64, I386) 6.0.2.1 (squeeze) +Ubuntu Server (AMD64, I386) 10.04 LTS +Ubuntu Desktop (AMD64, I386) 10.04 LTS +---------------------------------------------- + +$ # make the system up-to-date +$ +$ sudo apt-get update +$ sudo apt-get upgrade +$ +$ # ensure all prerequisites are installed +$ +$ sudo apt-get install git-core autoconf libtool flex bison libssl-dev +$ +$ # the required version of liburcu is not available in the default package sources. +$ +$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu0_0.5.4-1_amd64.deb +$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu-dev_0.5.4-1_amd64.deb +$ sudo dpkg -i liburcu0_0.5.4-1_amd64.deb +$ sudo dpkg -i liburcu-dev_0.5.4-1_amd64.deb +$ +$ # go for the real thing +$ +$ git clone git://git.nic.cz/knot +$ cd knot +$ autoreconf -if +$ ./configure +$ make +$ sudo make install +$ sudo ldconfig + +Alternative packages for I386: + +$ # the required version of liburcu is not available in the default package sources. +$ +$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu0_0.5.4-1_i386.deb +$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu-dev_0.5.4-1_i386.deb +$ sudo dpkg -i liburcu0_0.5.4-1_i386.deb +$ sudo dpkg -i liburcu-dev_0.5.4-1_i386.deb + +Installation on BSD +=================== + +Not all prerequisites are available as ports on BSD. + +- liburcu must be compiled from sources + - version 0.6.4 compiles on BSD without any source code modifications + - in case of x86_64 build, CFLAGS nad build type has to be set appropriately. + $ CFLAGS=-fPIC ./configure --build amd64 +- flex must be newer version from ports that support reentrant parsers + +Knot DNS requires more recent version of flex from ports, to prevent name clash, specify flex destination. +$ cd <knot sources> +$ autoreconf -if +$ ./configure +$ make && sudo make install + +Installation on OS X +==================== + +Not all prerequisites are preinstalled for OS X. + +- liburcu must be compiled from sources + - liburcu requires gcc-4.6 from MacPorts, as it depends on __thread keyword + $ CC=gcc-mp-4.6 ARCH=x86_64 ./configure + $ make && sudo make install + +Compiling Knot DNS with gcc-mp-4.6 is recommended, but not necessary. + +Running +======= + +First, each server needs configuration file. Please see samples/knot.sample.conf +for reference. Minimal configuration can be found in samples/knot.min.conf +Configuration zone has to specify: +* storage for PID files, compiled zones etc. +* network interfaces +* served zones + +$ cp samples/knot.min.conf myserver.conf +$ vim myserver.conf # or your favourite text editor + +Second, zone files have to be compiled to binary form in order for server to +load them. Binary 'knotc' (controller) offers functionality for everything from zone file +management to controlling server instance. Most important parameter is '-c' that +specifies config file for our server. Compiled zones are saved to storage +defined in 'storage' variable in configuration. + +$ knotc -h # see what it can do +$ knotc -c myserver.conf compile # compile zone files to binary format + +Third, lets load server. You can do this by running 'knotd' directly, or with +'knotc' as well. Server is able to run in daemonized or interactive mode. +Lets start our server in interactive mode (parameter '-i') to see if it runs. + +$ knotc -c myserver.conf -i start # start server in interactive mode + +Running as daemon +================= + +Controller runs server in daemonized mode as default. Disadvantage is, that +it closes stdout/stderr so you need to set up either syslog or logging to +own files in the configuration. Controller parameter '-w' waits for the operation +to finish. Let's test server functionality. + +$ knotc -c myserver.conf -w start # start server +$ dig @$ADDR -p $PORT example.com # issue a query and see result +$ ... +$ knotc -c myserver.conf -w stop # stop server + +Also, keep in mind that zone files have to be compiled before they are loaded +to server. Workflow is as follows: + +$ knotc -c myserver.conf -w start +$ <edit zonefile> +$ knotc -c myserver.conf compile # compile zones to binary format +$ knotc -c myserver.conf reload # reconfigures server on-the-fly +$ dig @$ADDR -p $PORT example.com # issue a query and see result +$ ... +$ knotc -c myserver.conf stop + +Supported features +================== + +DNS functions: +* AXFR (master) +* EDNS0 +* DNSSEC +* NSEC3 + +Server features: +* Adding/removing zones on-the-fly +* Reconfiguring server instance on-the-fly +* IPv6 support +* Semantic checks of loaded zone diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..2b546eb --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1020 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],, +[m4_warning([this file was generated for autoconf 2.67. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_PROG_LEX +# ----------- +# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a +# "missing" invocation, for better error output. +AC_DEFUN([AM_PROG_LEX], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AM_MISSING_HAS_RUN])dnl +AC_REQUIRE([AC_PROG_LEX])dnl +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/ax_check_compiler_flags.m4]) +m4_include([m4/ax_ext.m4]) +m4_include([m4/ax_gcc_x86_cpuid.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..c2246a4 --- /dev/null +++ b/config.guess @@ -0,0 +1,1502 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +# Free Software Foundation, Inc. + +timestamp='2009-12-30' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to <config-patches@gnu.org> and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free +Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +and + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..c2d1257 --- /dev/null +++ b/config.sub @@ -0,0 +1,1714 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +# Free Software Foundation, Inc. + +timestamp='2010-01-22' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free +Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile-* | tilegx-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + # This must be matched before tile*. + tilegx*) + basic_machine=tilegx-unknown + os=-linux-gnu + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..5ee05a9 --- /dev/null +++ b/configure @@ -0,0 +1,15763 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.67 for knot 0.8. +# +# Report bugs to <knot-dns@labs.nic.cz>. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: knot-dns@labs.nic.cz about your system, including any +$0: error possibly output before this message. Then install +$0: a modern shell, or manually run the script under such a +$0: shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +$* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='knot' +PACKAGE_TARNAME='knot' +PACKAGE_VERSION='0.8' +PACKAGE_STRING='knot 0.8' +PACKAGE_BUGREPORT='knot-dns@labs.nic.cz' +PACKAGE_URL='' + +ac_unique_file="src/knot/main.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_header_list= +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +YFLAGS +YACC +LEXLIB +LEX_OUTPUT_ROOT +LEX +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +lt_ECHO +RANLIB +AR +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +SIMD_FLAGS +EGREP +GREP +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_dependency_tracking +enable_maintainer_mode +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +enable_ldns +enable_debug +enable_recvmmsg +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +YACC +YFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures knot 0.8 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/knot] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of knot 0.8:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --disable-maintainer-mode disable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-ldns=yes|no Enable tests with ldns [default=no] + --enable-debug=brief|verbose|details + enable given debug level [default=disabled] + --enable-recvmmsg=yes|no + enable recvmmsg() network API under Linux (kernel + support required) (set to 'no' if you have trouble + running server under valgrind) [default=yes] + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + YACC The `Yet Another C Compiler' implementation to use. Defaults to + the first program found out of: `bison -y', `byacc', `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to <knot-dns@labs.nic.cz>. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +knot configure 0.8 +generated by GNU Autoconf 2.67 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval "test \"\${$3+set}\"" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## ----------------------------------- ## +## Report this to knot-dns@labs.nic.cz ## +## ----------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_type + +# ac_fn_c_find_intX_t LINENO BITS VAR +# ----------------------------------- +# Finds a signed integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_intX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 +$as_echo_n "checking for int$2_t... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in int$2_t 'int' 'long int' \ + 'long long int' 'short int' 'signed char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) + < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + case $ac_type in #( + int$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_find_intX_t + +# ac_fn_c_find_uintX_t LINENO BITS VAR +# ------------------------------------ +# Finds an unsigned integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_uintX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 +$as_echo_n "checking for uint$2_t... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + case $ac_type in #( + uint$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_find_uintX_t +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by knot $as_me 0.8, which was +generated by GNU Autoconf 2.67. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5 ; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +as_fn_append ac_header_list " stdlib.h" +as_fn_append ac_header_list " unistd.h" +as_fn_append ac_header_list " sys/param.h" +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +am__api_version='1.11' + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5 ;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5 ;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='knot' + VERSION='0.8' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +ac_config_headers="$ac_config_headers src/config.h" + + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5 ; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5 ; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5 ; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = x""yes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid output" >&5 +$as_echo_n "checking for x86 cpuid output... " >&6; } +if test "${ax_cv_gcc_x86_cpuid_+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ax_cv_gcc_x86_cpuid_=unknown +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ + + int op = , eax, ebx, ecx, edx; + FILE *f; +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) + __asm__("push %%rbx\n\t" + "cpuid\n\t" + "pop %%rbx" + : "=a" (eax), "=c" (ecx), "=d" (edx) + : "a" (op)); + __asm__("push %%rbx\n\t" + "cpuid\n\t" + "mov %%rbx, %%rax\n\t" + "pop %%rbx" + : "=a" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op)); +#else + __asm__("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx" + : "=a" (eax), "=c" (ecx), "=d" (edx) + : "a" (op)); + __asm__("push %%ebx\n\t" + "cpuid\n\t" + "mov %%ebx, %%eax\n\t" + "pop %%ebx" + : "=a" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op)); +#endif + f = fopen("conftest_cpuid", "w"); if (!f) return 1; + fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); + fclose(f); + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ax_cv_gcc_x86_cpuid_=`cat conftest_cpuid`; rm -f conftest_cpuid +else + ax_cv_gcc_x86_cpuid_=unknown; rm -f conftest_cpuid +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_" >&5 +$as_echo "$ax_cv_gcc_x86_cpuid_" >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid 0x00000001 output" >&5 +$as_echo_n "checking for x86 cpuid 0x00000001 output... " >&6; } +if test "${ax_cv_gcc_x86_cpuid_0x00000001+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ax_cv_gcc_x86_cpuid_0x00000001=unknown +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ + + int op = 0x00000001, eax, ebx, ecx, edx; + FILE *f; +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) + __asm__("push %%rbx\n\t" + "cpuid\n\t" + "pop %%rbx" + : "=a" (eax), "=c" (ecx), "=d" (edx) + : "a" (op)); + __asm__("push %%rbx\n\t" + "cpuid\n\t" + "mov %%rbx, %%rax\n\t" + "pop %%rbx" + : "=a" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op)); +#else + __asm__("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx" + : "=a" (eax), "=c" (ecx), "=d" (edx) + : "a" (op)); + __asm__("push %%ebx\n\t" + "cpuid\n\t" + "mov %%ebx, %%eax\n\t" + "pop %%ebx" + : "=a" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op)); +#endif + f = fopen("conftest_cpuid", "w"); if (!f) return 1; + fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); + fclose(f); + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ax_cv_gcc_x86_cpuid_0x00000001=`cat conftest_cpuid`; rm -f conftest_cpuid +else + ax_cv_gcc_x86_cpuid_0x00000001=unknown; rm -f conftest_cpuid +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_0x00000001" >&5 +$as_echo "$ax_cv_gcc_x86_cpuid_0x00000001" >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + ecx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 3` + edx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 4` + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmx is supported" >&5 +$as_echo_n "checking whether mmx is supported... " >&6; } +if test "${ax_cv_have_mmx_ext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_cv_have_mmx_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$edx>>23&0x01))" = 1; then + ax_cv_have_mmx_ext=yes + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_mmx_ext" >&5 +$as_echo "$ax_cv_have_mmx_ext" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sse is supported" >&5 +$as_echo_n "checking whether sse is supported... " >&6; } +if test "${ax_cv_have_sse_ext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_cv_have_sse_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$edx>>25&0x01))" = 1; then + ax_cv_have_sse_ext=yes + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_sse_ext" >&5 +$as_echo "$ax_cv_have_sse_ext" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sse2 is supported" >&5 +$as_echo_n "checking whether sse2 is supported... " >&6; } +if test "${ax_cv_have_sse2_ext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_cv_have_sse2_ext=no + if test "$((0x$edx>>26&0x01))" = 1; then + ax_cv_have_sse2_ext=yes + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_sse2_ext" >&5 +$as_echo "$ax_cv_have_sse2_ext" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sse3 is supported" >&5 +$as_echo_n "checking whether sse3 is supported... " >&6; } +if test "${ax_cv_have_sse3_ext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_cv_have_sse3_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$ecx&0x01))" = 1; then + ax_cv_have_sse3_ext=yes + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_sse3_ext" >&5 +$as_echo "$ax_cv_have_sse3_ext" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ssse3 is supported" >&5 +$as_echo_n "checking whether ssse3 is supported... " >&6; } +if test "${ax_cv_have_ssse3_ext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_cv_have_ssse3_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$ecx>>9&0x01))" = 1; then + ax_cv_have_ssse3_ext=yes + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_ssse3_ext" >&5 +$as_echo "$ax_cv_have_ssse3_ext" >&6; } + + if test "$ax_cv_have_mmx_ext" = yes; then + +$as_echo "#define HAVE_MMX /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -mmmx" >&5 +$as_echo_n "checking whether C compiler accepts -mmmx... " >&6; } +if test "${ax_cv_c_flags__mmmx+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_save_FLAGS=$CFLAGS + CFLAGS="-mmmx" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_c_flags__mmmx=yes +else + ax_cv_c_flags__mmmx=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_save_FLAGS +fi + +eval ax_check_compiler_flags=$ax_cv_c_flags__mmmx +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5 +$as_echo "$ax_check_compiler_flags" >&6; } +if test "x$ax_check_compiler_flags" = xyes; then + SIMD_FLAGS="$SIMD_FLAGS -mmmx" +else + : +fi + + fi + + if test "$ax_cv_have_sse_ext" = yes; then + +$as_echo "#define HAVE_SSE /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse" >&5 +$as_echo_n "checking whether C compiler accepts -msse... " >&6; } +if test "${ax_cv_c_flags__msse+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_save_FLAGS=$CFLAGS + CFLAGS="-msse" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_c_flags__msse=yes +else + ax_cv_c_flags__msse=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_save_FLAGS +fi + +eval ax_check_compiler_flags=$ax_cv_c_flags__msse +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5 +$as_echo "$ax_check_compiler_flags" >&6; } +if test "x$ax_check_compiler_flags" = xyes; then + SIMD_FLAGS="$SIMD_FLAGS -msse" +else + : +fi + + fi + + if test "$ax_cv_have_sse2_ext" = yes; then + +$as_echo "#define HAVE_SSE2 /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse2" >&5 +$as_echo_n "checking whether C compiler accepts -msse2... " >&6; } +if test "${ax_cv_c_flags__msse2+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_save_FLAGS=$CFLAGS + CFLAGS="-msse2" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_c_flags__msse2=yes +else + ax_cv_c_flags__msse2=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_save_FLAGS +fi + +eval ax_check_compiler_flags=$ax_cv_c_flags__msse2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5 +$as_echo "$ax_check_compiler_flags" >&6; } +if test "x$ax_check_compiler_flags" = xyes; then + SIMD_FLAGS="$SIMD_FLAGS -msse2" +else + : +fi + + fi + + if test "$ax_cv_have_sse3_ext" = yes; then + +$as_echo "#define HAVE_SSE3 /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse3" >&5 +$as_echo_n "checking whether C compiler accepts -msse3... " >&6; } +if test "${ax_cv_c_flags__msse3+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ax_save_FLAGS=$CFLAGS + CFLAGS="-msse3" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_c_flags__msse3=yes +else + ax_cv_c_flags__msse3=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_save_FLAGS +fi + +eval ax_check_compiler_flags=$ax_cv_c_flags__msse3 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5 +$as_echo "$ax_check_compiler_flags" >&6; } +if test "x$ax_check_compiler_flags" = xyes; then + SIMD_FLAGS="$SIMD_FLAGS -msse3" +else + : +fi + + fi + + if test "$ax_cv_have_ssse3_ext" = yes; then + +$as_echo "#define HAVE_SSSE3 /**/" >>confdefs.h + + fi + + + + +# Enable maintainer mode by default for development + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to disable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to disable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +# Initialize libtool +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.6b' +macro_revision='1.3017' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if test "${ac_cv_path_SED+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if test "${ac_cv_path_FGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test "${lt_cv_path_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$ac_tool_prefix"; then + for ac_prog in "dumpbin -symbols" "link -dump -symbols" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in "dumpbin -symbols" "link -dump -symbols" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if test "${lt_cv_nm_interface+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:5468: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:5471: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:5474: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 6679 "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if test "${lt_cv_objdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + + + + + + + + + + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7941: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7945: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:8280: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:8284: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:8385: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:8389: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:8440: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:8444: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + link_all_deplibs=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 +$as_echo "$archive_cmds_need_lc" >&6; } + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10824 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10920 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for reentrant lex" >&5 +$as_echo_n "checking for reentrant lex... " >&6; } +if test "${ac_cv_path_LEX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LEX"; then + ac_path_LEX_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in $LEX flex gflex; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_LEX="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_LEX" && $as_test_x "$ac_path_LEX"; } || continue +cat >conftest.l <<_ACEOF +%{ +%} + +%option reentrant +%option bison-bridge +%option noinput +%option nounput +%option noreject + +BLANK \t\n + +%% +<<EOF>> return 0; +%% +_ACEOF +{ { ac_try="$ac_path_LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_path_LEX conftest.l") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +test $ac_status -eq 0 && ac_cv_path_LEX=$ac_path_LEX ac_path_LEX_found=true +rm -f conftest.l lexyy.c lex.yy.c + + $ac_path_LEX_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_LEX"; then + as_fn_error $? "could not find lex that supports reentrant parsers" "$LINENO" 5 + fi +else + ac_cv_path_LEX=$LEX +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_LEX" >&5 +$as_echo "$ac_cv_path_LEX" >&6; } +LEX=$ac_cv_path_LEX + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LEX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LEX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +$as_echo "$LEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { yyless (input () != 0); } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +main (void) +{ + return ! yylex () + ! yywrap (); +} +_ACEOF +{ { ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 +$as_echo_n "checking lex output file root... " >&6; } +if test "${ac_cv_prog_lex_root+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +$as_echo "$ac_cv_prog_lex_root" >&6; } +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test -z "${LEXLIB+set}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 +$as_echo_n "checking lex library... " >&6; } +if test "${ac_cv_lib_lex+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS=$LIBS + ac_cv_lib_lex='none needed' + for ac_lib in '' -lfl -ll; do + LIBS="$ac_lib $ac_save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_lex=$ac_lib +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + test "$ac_cv_lib_lex" != 'none needed' && break + done + LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +$as_echo "$ac_cv_lib_lex" >&6; } + test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +$as_echo_n "checking whether yytext is a pointer... " >&6; } +if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +ac_save_LIBS=$LIBS +LIBS="$LEXLIB $ac_save_LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_prog_lex_yytext_pointer=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi + +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_YACC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +YACC_BISON=`bison --version | awk '{print $1;exit}'` +if test "$YACC_BISON" != "bison"; then + as_fn_error $? "GNU bison needed for reentrant parsers, set the \$YACC variable before running configure" "$LINENO" 5 +fi + + +# Set compiler compatibility flags +ac_c_preproc_warn_flag=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 +$as_echo_n "checking for $CC option to accept ISO C99... " >&6; } +if test "${ac_cv_prog_cc_c99+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <wchar.h> +#include <stdio.h> + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +#define debug(...) fprintf (stderr, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + your preprocessor is broken; +#endif +#if BIG_OK +#else + your preprocessor is broken; +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\0'; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static void +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str; + int number; + float fnumber; + + while (*format) + { + switch (*format++) + { + case 's': // string + str = va_arg (args_copy, const char *); + break; + case 'd': // int + number = va_arg (args_copy, int); + break; + case 'f': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); +} + +int +main () +{ + + // Check bool. + _Bool success = false; + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + test_varargs ("s, d' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' + || dynamic_array[ni.number - 1] != 543); + + ; + return 0; +} +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c99" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c99" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +$as_echo "$ac_cv_prog_cc_c99" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c99" != xno; then : + +fi + + + +# Check whether --enable-ldns was given. +if test "${enable_ldns+set}" = set; then : + enableval=$enable_ldns; case "${enableval}" in + yes) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ldns_rr_list_pop_rrset" >&5 +$as_echo_n "checking for library containing ldns_rr_list_pop_rrset... " >&6; } +if test "${ac_cv_search_ldns_rr_list_pop_rrset+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ldns_rr_list_pop_rrset (); +int +main () +{ +return ldns_rr_list_pop_rrset (); + ; + return 0; +} +_ACEOF +for ac_lib in '' ldns; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_ldns_rr_list_pop_rrset=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_ldns_rr_list_pop_rrset+set}" = set; then : + break +fi +done +if test "${ac_cv_search_ldns_rr_list_pop_rrset+set}" = set; then : + +else + ac_cv_search_ldns_rr_list_pop_rrset=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ldns_rr_list_pop_rrset" >&5 +$as_echo "$ac_cv_search_ldns_rr_list_pop_rrset" >&6; } +ac_res=$ac_cv_search_ldns_rr_list_pop_rrset +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define HAVE_LDNS 1" >>confdefs.h + +else + as_fn_error $? "ldns not found" "$LINENO" 5 +fi + ;; + no) ldns=false ;; + *) as_fn_error $? "bad value ${enableval} for --enable-ldns" "$LINENO" 5 ;; + esac +else + ldns=false +fi + + +# Debug level +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then : + enableval=$enable_debug; # Not all shells support fall-through with ;& so I have to duplicate + case "x${enableval}" in + xdetails) + +$as_echo "#define DEBUG_ENABLE_DETAILS 1" >>confdefs.h + + +$as_echo "#define DEBUG_ENABLE_VERBOSE 1" >>confdefs.h + + +$as_echo "#define DEBUG_ENABLE_BRIEF 1" >>confdefs.h + + ;; + xverbose) + +$as_echo "#define DEBUG_ENABLE_VERBOSE 1" >>confdefs.h + + +$as_echo "#define DEBUG_ENABLE_BRIEF 1" >>confdefs.h + + ;; + xbrief) + +$as_echo "#define DEBUG_ENABLE_BRIEF 1" >>confdefs.h + + ;; + esac +fi + + +# recvmmsg() (valgrind doesn't support it, so disable for debugging) +# Check whether --enable-recvmmsg was given. +if test "${enable_recvmmsg+set}" = set; then : + enableval=$enable_recvmmsg; case "${enableval}" in + yes) + +$as_echo "#define ENABLE_RECVMMSG 1" >>confdefs.h + + ;; + no) + recvmmsg=false + ;; + *) + as_fn_error $? "bad value ${enableval} for --enable-recvmmsg" "$LINENO" 5 + ;; + esac +else + + +$as_echo "#define ENABLE_RECVMMSG 1" >>confdefs.h + + recvmmsg=true + +fi + + +# Checks for libraries. +# FIXME: Replace `main' with a function in `-lm': +# TODO: check if paths exist before appending +CFLAGS="$CFLAGS -I/usr/local/include" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pow" >&5 +$as_echo_n "checking for library containing pow... " >&6; } +if test "${ac_cv_search_pow+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pow (); +int +main () +{ +return pow (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_pow=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_pow+set}" = set; then : + break +fi +done +if test "${ac_cv_search_pow+set}" = set; then : + +else + ac_cv_search_pow=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pow" >&5 +$as_echo "$ac_cv_search_pow" >&6; } +ac_res=$ac_cv_search_pow +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 +$as_echo_n "checking for library containing pthread_create... " >&6; } +if test "${ac_cv_search_pthread_create+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +for ac_lib in '' pthread; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_pthread_create=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_pthread_create+set}" = set; then : + break +fi +done +if test "${ac_cv_search_pthread_create+set}" = set; then : + +else + ac_cv_search_pthread_create=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 +$as_echo "$ac_cv_search_pthread_create" >&6; } +ac_res=$ac_cv_search_pthread_create +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +else + as_fn_error $? "pthreads not found" "$LINENO" 5 +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing rcu_set_pointer_sym" >&5 +$as_echo_n "checking for library containing rcu_set_pointer_sym... " >&6; } +if test "${ac_cv_search_rcu_set_pointer_sym+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char rcu_set_pointer_sym (); +int +main () +{ +return rcu_set_pointer_sym (); + ; + return 0; +} +_ACEOF +for ac_lib in '' urcu; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_rcu_set_pointer_sym=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_rcu_set_pointer_sym+set}" = set; then : + break +fi +done +if test "${ac_cv_search_rcu_set_pointer_sym+set}" = set; then : + +else + ac_cv_search_rcu_set_pointer_sym=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rcu_set_pointer_sym" >&5 +$as_echo "$ac_cv_search_rcu_set_pointer_sym" >&6; } +ac_res=$ac_cv_search_rcu_set_pointer_sym +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +else + as_fn_error $? "liburcu not found" "$LINENO" 5 +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if test "${ac_cv_search_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dlopen=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_dlopen+set}" = set; then : + break +fi +done +if test "${ac_cv_search_dlopen+set}" = set; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +#AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([librt not found])]) +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing OpenSSL_add_all_digests" >&5 +$as_echo_n "checking for library containing OpenSSL_add_all_digests... " >&6; } +if test "${ac_cv_search_OpenSSL_add_all_digests+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char OpenSSL_add_all_digests (); +int +main () +{ +return OpenSSL_add_all_digests (); + ; + return 0; +} +_ACEOF +for ac_lib in '' crypto; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_OpenSSL_add_all_digests=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_OpenSSL_add_all_digests+set}" = set; then : + break +fi +done +if test "${ac_cv_search_OpenSSL_add_all_digests+set}" = set; then : + +else + ac_cv_search_OpenSSL_add_all_digests=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_OpenSSL_add_all_digests" >&5 +$as_echo "$ac_cv_search_OpenSSL_add_all_digests" >&6; } +ac_res=$ac_cv_search_OpenSSL_add_all_digests +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +else + as_fn_error $? "libcrypto not found" "$LINENO" 5 +fi + +#AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [], [AC_MSG_ERROR([libldns not found])]) + +# Checks for header files. +for ac_header in sys/types.h netinet/in.h arpa/nameser.h netdb.h resolv.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> /* inet_ functions / structs */ +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> /* DNS HEADER struct */ +#endif +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/socket.h sys/time.h syslog.h unistd.h urcu.h ev.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 +$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } +if test "${ac_cv_header_stdbool_h+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include <stdbool.h> +#ifndef bool + "error: bool is not defined" +#endif +#ifndef false + "error: false is not defined" +#endif +#if false + "error: false is not 0" +#endif +#ifndef true + "error: true is not defined" +#endif +#if true != 1 + "error: true is not 1" +#endif +#ifndef __bool_true_false_are_defined + "error: __bool_true_false_are_defined is not defined" +#endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) 0.5 == true ? 1 : -1]; + bool e = &s; + char f[(_Bool) 0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + enum { j = false, k = true, l = false * true, m = true * 256 }; + /* The following fails for + HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ + _Bool n[m]; + char o[sizeof n == m * sizeof n[0] ? 1 : -1]; + char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; +# if defined __xlc__ || defined __GNUC__ + /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0 + reported by James Lemley on 2005-10-05; see + http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html + This test is not quite right, since xlc is allowed to + reject this program, as the initializer for xlcbug is + not one of the forms that C requires support for. + However, doing the test right would require a runtime + test, and that would make cross-compilation harder. + Let us hope that IBM fixes the xlc bug, and also adds + support for this kind of constant expression. In the + meantime, this test will reject xlc, which is OK, since + our stdbool.h substitute should suffice. We also test + this with GCC, where it should work, to detect more + quickly whether someone messes up the test in the + future. */ + char digs[] = "0123456789"; + int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1); +# endif + /* Catch a bug in an HP-UX C compiler. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + */ + _Bool q = true; + _Bool *pq = &q; + +int +main () +{ + + *pq |= q; + *pq |= ! q; + /* Refer to every declared value, to avoid compiler optimizations. */ + return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + + !m + !n + !o + !p + !q + !pq); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdbool_h=yes +else + ac_cv_header_stdbool_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 +$as_echo "$ac_cv_header_stdbool_h" >&6; } +ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" +if test "x$ac_cv_type__Bool" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 +_ACEOF + + +fi + +if test $ac_cv_header_stdbool_h = yes; then + +$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if test "${ac_cv_c_inline+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" +case $ac_cv_c_int64_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int64_t $ac_cv_c_int64_t +_ACEOF +;; +esac + +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + +ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" +case $ac_cv_c_uint16_t in #( + no|yes) ;; #( + *) + + +cat >>confdefs.h <<_ACEOF +#define uint16_t $ac_cv_c_uint16_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" +case $ac_cv_c_uint32_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT32_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint32_t $ac_cv_c_uint32_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" +case $ac_cv_c_uint64_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT64_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint64_t $ac_cv_c_uint64_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" +case $ac_cv_c_uint8_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT8_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint8_t $ac_cv_c_uint8_t +_ACEOF +;; + esac + + +# Checks for library functions. +for ac_header in vfork.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" +if test "x$ac_cv_header_vfork_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VFORK_H 1 +_ACEOF + +fi + +done + +for ac_func in fork vfork +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +if test "x$ac_cv_func_fork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 +$as_echo_n "checking for working fork... " >&6; } +if test "${ac_cv_func_fork_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_fork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* By Ruediger Kuhlmann. */ + return fork () < 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_fork_works=yes +else + ac_cv_func_fork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 +$as_echo "$ac_cv_func_fork_works" >&6; } + +else + ac_cv_func_fork_works=$ac_cv_func_fork +fi +if test "x$ac_cv_func_fork_works" = xcross; then + case $host in + *-*-amigaos* | *-*-msdosdjgpp*) + # Override, as these systems have only a dummy fork() stub + ac_cv_func_fork_works=no + ;; + *) + ac_cv_func_fork_works=yes + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} +fi +ac_cv_func_vfork_works=$ac_cv_func_vfork +if test "x$ac_cv_func_vfork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 +$as_echo_n "checking for working vfork... " >&6; } +if test "${ac_cv_func_vfork_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_vfork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Thanks to Paul Eggert for this test. */ +$ac_includes_default +#include <sys/wait.h> +#ifdef HAVE_VFORK_H +# include <vfork.h> +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. The compiler + is told about this with #include <vfork.h>, but some compilers + (e.g. gcc -O) don't grok <vfork.h>. Test for this by using a + static variable whose address is put into a register that is + clobbered by the vfork. */ +static void +#ifdef __cplusplus +sparc_address_test (int arg) +# else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} + +int +main () +{ + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (0); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. This + test uses lots of local variables, at least as many local + variables as main has allocated so far including compiler + temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris + 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should + reuse the register of parent for one of the local variables, + since it will think that parent can't possibly be used any more + in this routine. Assigning to the local variable will thus + munge parent in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent + from child file descriptors. If the child closes a descriptor + before it execs or exits, this munges the parent's descriptor + as well. Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + return ( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_vfork_works=yes +else + ac_cv_func_vfork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 +$as_echo "$ac_cv_func_vfork_works" >&6; } + +fi; +if test "x$ac_cv_func_fork_works" = xcross; then + ac_cv_func_vfork_works=$ac_cv_func_vfork + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} +fi + +if test "x$ac_cv_func_vfork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h + +else + +$as_echo "#define vfork fork" >>confdefs.h + +fi +if test "x$ac_cv_func_fork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h + +fi + + + + + for ac_header in $ac_header_list +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + +for ac_func in getpagesize +do : + ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" +if test "x$ac_cv_func_getpagesize" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETPAGESIZE 1 +_ACEOF + +fi +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 +$as_echo_n "checking for working mmap... " >&6; } +if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_mmap_fixed_mapped=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +/* malloc might have been renamed as rpl_malloc. */ +#undef malloc + +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the file system buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propagated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ + +#include <fcntl.h> +#include <sys/mman.h> + +#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H +char *malloc (); +#endif + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +int +main () +{ + char *data, *data2, *data3; + const char *cdata2; + int i, pagesize; + int fd, fd2; + + pagesize = getpagesize (); + + /* First, make a file with some known garbage in it. */ + data = (char *) malloc (pagesize); + if (!data) + return 1; + for (i = 0; i < pagesize; ++i) + *(data + i) = rand (); + umask (0); + fd = creat ("conftest.mmap", 0600); + if (fd < 0) + return 2; + if (write (fd, data, pagesize) != pagesize) + return 3; + close (fd); + + /* Next, check that the tail of a page is zero-filled. File must have + non-zero length, otherwise we risk SIGBUS for entire page. */ + fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd2 < 0) + return 4; + cdata2 = ""; + if (write (fd2, cdata2, 1) != 1) + return 5; + data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); + if (data2 == MAP_FAILED) + return 6; + for (i = 0; i < pagesize; ++i) + if (*(data2 + i)) + return 7; + close (fd2); + if (munmap (data2, pagesize)) + return 8; + + /* Next, try to mmap the file at a fixed address which already has + something else allocated at it. If we can, also make sure that + we see the same garbage. */ + fd = open ("conftest.mmap", O_RDWR); + if (fd < 0) + return 9; + if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + return 10; + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + return 11; + + /* Finally, make sure that changes to the mapped area do not + percolate back to the file as seen by read(). (This is a bug on + some variants of i386 svr4.0.) */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = (char *) malloc (pagesize); + if (!data3) + return 12; + if (read (fd, data3, pagesize) != pagesize) + return 13; + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + return 14; + close (fd); + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_mmap_fixed_mapped=yes +else + ac_cv_func_mmap_fixed_mapped=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 +$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } +if test $ac_cv_func_mmap_fixed_mapped = yes; then + +$as_echo "#define HAVE_MMAP 1" >>confdefs.h + +fi +rm -f conftest.mmap conftest.txt + +for ac_func in gethostbyname gettimeofday memmove memset munmap regcomp select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +ac_config_files="$ac_config_files Makefile samples/Makefile src/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by knot $as_me 0.8, which was +generated by GNU Autoconf 2.67. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to <knot-dns@labs.nic.cz>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +knot config.status 0.8 +configured by $0, generated by GNU Autoconf 2.67, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' +macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' +enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' +pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' +host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' +host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' +host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' +build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' +build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' +build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' +SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' +Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' +GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' +EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' +FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' +LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' +NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' +LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' +ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' +exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' +lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' +reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' +AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' +STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' +RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' +compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' +GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' +SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' +ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' +need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' +LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' +libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' +version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' +runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' +libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' +soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' +old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' +striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +SHELL \ +ECHO \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` + ;; +esac + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "samples/Makefile") CONFIG_FILES="$CONFIG_FILES samples/Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="" + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that does not interpret backslashes. +ECHO=$lt_ECHO + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..b824a43 --- /dev/null +++ b/configure.ac @@ -0,0 +1,141 @@ +# -*- Autoconf -*- + +AC_PREREQ([2.65]) +AC_INIT([knot], [0.8], [knot-dns@labs.nic.cz]) +AM_INIT_AUTOMAKE([gnu -Wall -Werror]) +AC_CONFIG_SRCDIR([src/knot/main.c]) +AC_CONFIG_HEADERS([src/config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_USE_SYSTEM_EXTENSIONS([_GNU_SOURCE]) +AX_EXT + +# Enable maintainer mode by default for development +AM_MAINTAINER_MODE([enable]) + +# Initialize libtool +LT_INIT + +# Checks for programs. +AC_PROG_CC + +AC_CACHE_CHECK([for reentrant lex], [ac_cv_path_LEX], + [AC_PATH_PROGS_FEATURE_CHECK([LEX], [$LEX flex gflex], + [cat >conftest.l <<_ACEOF +%{ +%} + +%option reentrant +%option bison-bridge +%option noinput +%option nounput +%option noreject + +BLANK [ \t\n] + +%% +<<EOF>> return 0; +%% +_ACEOF +_AC_DO_VAR(ac_path_LEX conftest.l) +test $ac_status -eq 0 && ac_cv_path_LEX=$ac_path_LEX ac_path_LEX_found=true +rm -f conftest.l lexyy.c lex.yy.c +], +[AC_MSG_ERROR([could not find lex that supports reentrant parsers])])]) +AC_SUBST([LEX], [$ac_cv_path_LEX]) +AM_PROG_LEX + +AC_PROG_YACC +YACC_BISON=`bison --version | awk '{print $1;exit}'` +if test "$YACC_BISON" != "bison"; then + AC_MSG_ERROR([GNU bison needed for reentrant parsers, set the \$YACC variable before running configure]) +fi +AC_PROG_INSTALL + +# Set compiler compatibility flags +AC_PROG_CPP_WERROR +AC_PROG_CC_C99 + +AC_ARG_ENABLE([ldns], + AC_HELP_STRING([--enable-ldns=yes|no], [Enable tests with ldns [default=no]]), + [case "${enableval}" in + yes) AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [AC_DEFINE([HAVE_LDNS], [1], [ldns present])], + AC_MSG_ERROR([ldns not found])) ;; + no) ldns=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-ldns]) ;; + esac],[ldns=false]) + +# Debug level +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug=brief|verbose|details], [enable given debug level [default=disabled]]), + # Not all shells support fall-through with ;& so I have to duplicate + [case "x${enableval}" in + xdetails) + AC_DEFINE([DEBUG_ENABLE_DETAILS], [1], [Enable details debugging messages.]) + AC_DEFINE([DEBUG_ENABLE_VERBOSE], [1], [Enable verbose debugging messages.]) + AC_DEFINE([DEBUG_ENABLE_BRIEF], [1], [Enable brief debugging messages.]) + ;; + xverbose) + AC_DEFINE([DEBUG_ENABLE_VERBOSE], [1], [Enable verbose debugging messages.]) + AC_DEFINE([DEBUG_ENABLE_BRIEF], [1], [Enable brief debugging messages.]) + ;; + xbrief) + AC_DEFINE([DEBUG_ENABLE_BRIEF], [1], [Enable brief debugging messages.]) + ;; + esac], []) + +# recvmmsg() (valgrind doesn't support it, so disable for debugging) +AC_ARG_ENABLE([recvmmsg], + AS_HELP_STRING([--enable-recvmmsg=yes|no], [enable recvmmsg() network API under Linux (kernel support required) (set to 'no' if you have trouble running server under valgrind) [default=yes]]), + [case "${enableval}" in + yes) + AC_DEFINE([ENABLE_RECVMMSG], [1], [recvmmsg enabled]) + ;; + no) + recvmmsg=false + ;; + *) + AC_MSG_ERROR([bad value ${enableval} for --enable-recvmmsg]) + ;; + esac], [ + AC_DEFINE([ENABLE_RECVMMSG], [1], [recvmmsg enabled]) + recvmmsg=true + ]) + +# Checks for libraries. +# FIXME: Replace `main' with a function in `-lm': +# TODO: check if paths exist before appending +CFLAGS="$CFLAGS -I/usr/local/include" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +AC_SEARCH_LIBS([pow], [m]) +AC_SEARCH_LIBS([pthread_create], [pthread], [], [AC_MSG_ERROR([pthreads not found])]) +AC_SEARCH_LIBS([rcu_set_pointer_sym], [urcu], [], [AC_MSG_ERROR([liburcu not found])]) +AC_SEARCH_LIBS([dlopen], [dl]) +#AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([librt not found])]) +AC_SEARCH_LIBS([OpenSSL_add_all_digests], [crypto],[], [AC_MSG_ERROR([libcrypto not found])]) +#AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [], [AC_MSG_ERROR([libldns not found])]) + +# Checks for header files. +AC_HEADER_RESOLV +AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/socket.h sys/time.h syslog.h unistd.h urcu.h ev.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_INLINE +AC_TYPE_INT64_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_FORK +AC_FUNC_MMAP +AC_CHECK_FUNCS([gethostbyname gettimeofday memmove memset munmap regcomp select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue]) + +AC_CONFIG_FILES([Makefile + samples/Makefile + src/Makefile]) +AC_OUTPUT @@ -0,0 +1,630 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free +# Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u="sed s,\\\\\\\\,/,g" + depmode=msvisualcpp +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..6781b98 --- /dev/null +++ b/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/knot.sample.conf.in b/knot.sample.conf.in new file mode 100644 index 0000000..db5c587 --- /dev/null +++ b/knot.sample.conf.in @@ -0,0 +1,18 @@ +system { + identity "@package@ @version@"; + storage "@localstatedir@/@package@"; +} + +interfaces { + ipv4 { address 127.0.0.1@53; } +} + +zones { + example.com { + file "@sysconfdir@/example.com.zone"; + } +} + +log { + syslog { any warning, error, notice; } +} diff --git a/ltmain.sh b/ltmain.sh new file mode 100755 index 0000000..d88da2c --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,8413 @@ +# Generated from ltmain.m4sh. + +# ltmain.sh (GNU libtool) 2.2.6b +# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print informational messages (default) +# --version print version information +# -h, --help print short or long help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to <bug-libtool@gnu.org>. + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="2.2.6b Debian-2.2.6b-2" +TIMESTAMP="" +package_revision=1.3017 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + +: ${CP="cp -f"} +: ${ECHO="echo"} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +# Generated shell functions inserted here. + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +# In the unlikely event $progname began with a '-', it would play havoc with +# func_echo (imagine progname=-n), so we prepend ./ in that case: +func_dirname_and_basename "$progpath" +progname=$func_basename_result +case $progname in + -*) progname=./$progname ;; +esac + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + done + my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "X$my_tmpdir" | $Xsed +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "X$1" | $Xsed \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/# -h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + $ECHO + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help +# Echo long help message to standard output and exit. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + exit $? +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + +# Check that we have a working $ECHO. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell, and then maybe $ECHO will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +$* +EOF + exit $EXIT_SUCCESS +fi + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +# $mode is unset +nonopt= +execute_dlfiles= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +opt_dry_run=false +opt_duplicate_deps=false +opt_silent=false +opt_debug=: + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + $ECHO "host: $host" + if test "$build_libtool_libs" = yes; then + $ECHO "enable shared libraries" + else + $ECHO "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $ECHO "enable static libraries" + else + $ECHO "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case "$@ " in + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <<EOF +# $write_libobj - a libtool object file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object=$write_lobj + +# Name of the non-PIC object +non_pic_object=$write_oldobj + +EOF + $MV "${write_libobj}T" "${write_libobj}" + } +} + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + pie_flag="$pie_flag $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_quote_for_eval "$arg" + lastarg="$lastarg $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_quote_for_eval "$lastarg" + base_compile="$base_compile $func_quote_for_eval_result" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.obj | *.sx) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { +test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + $ECHO + $ECHO "Try \`$progname --help' for more information about other modes." + + exit $? +} + + # Now that we've collected a possible --mode arg, show help if necessary + $opt_help && func_mode_help + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + $ECHO "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + $ECHO "X----------------------------------------------------------------------" | $Xsed + $ECHO "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + $ECHO + $ECHO "If you ever happen to want to link against installed libraries" + $ECHO "in a given directory, LIBDIR, you must either use libtool, and" + $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" + $ECHO "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" + $ECHO " during execution" + fi + if test -n "$runpath_var"; then + $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" + $ECHO " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $ECHO + + $ECHO "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" + $ECHO "pages." + ;; + *) + $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + $ECHO "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 </dev/null >/dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + $ECHO >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + $ECHO >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + $ECHO >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + $ECHO >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + + +# func_emit_wrapper_part1 [arg=no] +# +# Emit the first part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part1 () +{ + func_emit_wrapper_part1_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part1_arg1=$1 + fi + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + ECHO=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$ECHO works! + : + else + # Restart under the correct shell, and then maybe \$ECHO will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $ECHO "\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done +" +} +# end: func_emit_wrapper_part1 + +# func_emit_wrapper_part2 [arg=no] +# +# Emit the second part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part2 () +{ + func_emit_wrapper_part2_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part2_arg1=$1 + fi + + $ECHO "\ + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} +# end: func_emit_wrapper_part2 + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=no + if test -n "$1" ; then + func_emit_wrapper_arg1=$1 + fi + + # split this up so that func_emit_cwrapperexe_src + # can call each part independently. + func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" + func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_path_tmp1=`( cmd //c echo "$1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_tmp1=`cygpath -w "$1"` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result="" + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_to_host_pathlist_tmp2="$1" + # Once set for this call, this variable should not be + # reassigned. It is used in tha fallback case. + func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e 's|^:*||' -e 's|:*$||'` + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" + fi + fi + fi + IFS=: + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result" ; then + func_error "Could not determine the host path(s) corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat <<EOF + +/* $cwrappersource - temporary wrapper executable for $objdir/$outputname + Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION + + The $output program cannot be directly executed until all the libtool + libraries that it depends on are installed. + + This wrapper executable should never be moved out of the build directory. + If it is, it will not operate correctly. + + Currently, it simply execs the wrapper *script* "$SHELL $output", + but could eventually absorb all of the scripts functionality and + exec $objdir/$outputname directly. +*/ +EOF + cat <<"EOF" +#include <stdio.h> +#include <stdlib.h> +#ifdef _MSC_VER +# include <direct.h> +# include <process.h> +# include <io.h> +# define setmode _setmode +#else +# include <unistd.h> +# include <stdint.h> +# ifdef __CYGWIN__ +# include <io.h> +# define HAVE_SETENV +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +# endif +#endif +#include <malloc.h> +#include <stdarg.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +#ifdef _MSC_VER +# define S_IXUSR _S_IEXEC +# define stat _stat +# ifndef _INTPTR_T_DEFINED +# define intptr_t int +# endif +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifdef __CYGWIN__ +# define FOPEN_WB "wb" +#endif + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_opt_process_env_set (const char *arg); +void lt_opt_process_env_prepend (const char *arg); +void lt_opt_process_env_append (const char *arg); +int lt_split_name_value (const char *arg, char** name, char** value); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); + +static const char *script_text_part1 = +EOF + + func_emit_wrapper_part1 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + cat <<EOF + +static const char *script_text_part2 = +EOF + func_emit_wrapper_part2 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + + cat <<EOF +const char * MAGIC_EXE = "$magic_exe"; +const char * LIB_PATH_VARNAME = "$shlibpath_var"; +EOF + + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + func_to_host_pathlist "$temp_rpath" + cat <<EOF +const char * LIB_PATH_VALUE = "$func_to_host_pathlist_result"; +EOF + else + cat <<"EOF" +const char * LIB_PATH_VALUE = ""; +EOF + fi + + if test -n "$dllsearchpath"; then + func_to_host_pathlist "$dllsearchpath:" + cat <<EOF +const char * EXE_PATH_VARNAME = "PATH"; +const char * EXE_PATH_VALUE = "$func_to_host_pathlist_result"; +EOF + else + cat <<"EOF" +const char * EXE_PATH_VARNAME = ""; +const char * EXE_PATH_VALUE = ""; +EOF + fi + + if test "$fast_install" = yes; then + cat <<EOF +const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */ +EOF + else + cat <<EOF +const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */ +EOF + fi + + + cat <<"EOF" + +#define LTWRAPPER_OPTION_PREFIX "--lt-" +#define LTWRAPPER_OPTION_PREFIX_LENGTH 5 + +static const size_t opt_prefix_len = LTWRAPPER_OPTION_PREFIX_LENGTH; +static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX; + +static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script"; + +static const size_t env_set_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 7; +static const char *env_set_opt = LTWRAPPER_OPTION_PREFIX "env-set"; + /* argument is putenv-style "foo=bar", value of foo is set to bar */ + +static const size_t env_prepend_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 11; +static const char *env_prepend_opt = LTWRAPPER_OPTION_PREFIX "env-prepend"; + /* argument is putenv-style "foo=bar", new value of foo is bar${foo} */ + +static const size_t env_append_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 10; +static const char *env_append_opt = LTWRAPPER_OPTION_PREFIX "env-append"; + /* argument is putenv-style "foo=bar", new value of foo is ${foo}bar */ + +int +main (int argc, char *argv[]) +{ + char **newargz; + int newargc; + char *tmp_pathspec; + char *actual_cwrapper_path; + char *actual_cwrapper_name; + char *target_name; + char *lt_argv_zero; + intptr_t rval = 127; + + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + LTWRAPPER_DEBUGPRINTF (("(main) argv[0] : %s\n", argv[0])); + LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name)); + + /* very simple arg parsing; don't want to rely on getopt */ + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], dumpscript_opt) == 0) + { +EOF + case "$host" in + *mingw* | *cygwin* ) + # make stdout use "unix" line endings + echo " setmode(1,_O_BINARY);" + ;; + esac + + cat <<"EOF" + printf ("%s", script_text_part1); + printf ("%s", script_text_part2); + return 0; + } + } + + newargz = XMALLOC (char *, argc + 1); + tmp_pathspec = find_executable (argv[0]); + if (tmp_pathspec == NULL) + lt_fatal ("Couldn't find %s", argv[0]); + LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n", + tmp_pathspec)); + + actual_cwrapper_path = chase_symlinks (tmp_pathspec); + LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n", + actual_cwrapper_path)); + XFREE (tmp_pathspec); + + actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path)); + strendzap (actual_cwrapper_path, actual_cwrapper_name); + + /* wrapper name transforms */ + strendzap (actual_cwrapper_name, ".exe"); + tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1); + XFREE (actual_cwrapper_name); + actual_cwrapper_name = tmp_pathspec; + tmp_pathspec = 0; + + /* target_name transforms -- use actual target program name; might have lt- prefix */ + target_name = xstrdup (base_name (TARGET_PROGRAM_NAME)); + strendzap (target_name, ".exe"); + tmp_pathspec = lt_extend_str (target_name, ".exe", 1); + XFREE (target_name); + target_name = tmp_pathspec; + tmp_pathspec = 0; + + LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n", + target_name)); +EOF + + cat <<EOF + newargz[0] = + XMALLOC (char, (strlen (actual_cwrapper_path) + + strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1)); + strcpy (newargz[0], actual_cwrapper_path); + strcat (newargz[0], "$objdir"); + strcat (newargz[0], "/"); +EOF + + cat <<"EOF" + /* stop here, and copy so we don't have to do this twice */ + tmp_pathspec = xstrdup (newargz[0]); + + /* do NOT want the lt- prefix here, so use actual_cwrapper_name */ + strcat (newargz[0], actual_cwrapper_name); + + /* DO want the lt- prefix here if it exists, so use target_name */ + lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1); + XFREE (tmp_pathspec); + tmp_pathspec = NULL; +EOF + + case $host_os in + mingw*) + cat <<"EOF" + { + char* p; + while ((p = strchr (newargz[0], '\\')) != NULL) + { + *p = '/'; + } + while ((p = strchr (lt_argv_zero, '\\')) != NULL) + { + *p = '/'; + } + } +EOF + ;; + esac + + cat <<"EOF" + XFREE (target_name); + XFREE (actual_cwrapper_path); + XFREE (actual_cwrapper_name); + + lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */ + lt_setenv ("DUALCASE", "1"); /* for MSK sh */ + lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE); + lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE); + + newargc=0; + for (i = 1; i < argc; i++) + { + if (strncmp (argv[i], env_set_opt, env_set_opt_len) == 0) + { + if (argv[i][env_set_opt_len] == '=') + { + const char *p = argv[i] + env_set_opt_len + 1; + lt_opt_process_env_set (p); + } + else if (argv[i][env_set_opt_len] == '\0' && i + 1 < argc) + { + lt_opt_process_env_set (argv[++i]); /* don't copy */ + } + else + lt_fatal ("%s missing required argument", env_set_opt); + continue; + } + if (strncmp (argv[i], env_prepend_opt, env_prepend_opt_len) == 0) + { + if (argv[i][env_prepend_opt_len] == '=') + { + const char *p = argv[i] + env_prepend_opt_len + 1; + lt_opt_process_env_prepend (p); + } + else if (argv[i][env_prepend_opt_len] == '\0' && i + 1 < argc) + { + lt_opt_process_env_prepend (argv[++i]); /* don't copy */ + } + else + lt_fatal ("%s missing required argument", env_prepend_opt); + continue; + } + if (strncmp (argv[i], env_append_opt, env_append_opt_len) == 0) + { + if (argv[i][env_append_opt_len] == '=') + { + const char *p = argv[i] + env_append_opt_len + 1; + lt_opt_process_env_append (p); + } + else if (argv[i][env_append_opt_len] == '\0' && i + 1 < argc) + { + lt_opt_process_env_append (argv[++i]); /* don't copy */ + } + else + lt_fatal ("%s missing required argument", env_append_opt); + continue; + } + if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0) + { + /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX + namespace, but it is not one of the ones we know about and + have already dealt with, above (inluding dump-script), then + report an error. Otherwise, targets might begin to believe + they are allowed to use options in the LTWRAPPER_OPTION_PREFIX + namespace. The first time any user complains about this, we'll + need to make LTWRAPPER_OPTION_PREFIX a configure-time option + or a configure.ac-settable value. + */ + lt_fatal ("Unrecognized option in %s namespace: '%s'", + ltwrapper_option_prefix, argv[i]); + } + /* otherwise ... */ + newargz[++newargc] = xstrdup (argv[i]); + } + newargz[++newargc] = NULL; + + LTWRAPPER_DEBUGPRINTF (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>"))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : "<NULL>"), + (value ? value : "<NULL>"))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +int +lt_split_name_value (const char *arg, char** name, char** value) +{ + const char *p; + int len; + if (!arg || !*arg) + return 1; + + p = strchr (arg, (int)'='); + + if (!p) + return 1; + + *value = xstrdup (++p); + + len = strlen (arg) - strlen (*value); + *name = XMALLOC (char, len); + strncpy (*name, arg, len-1); + (*name)[len - 1] = '\0'; + + return 0; +} + +void +lt_opt_process_env_set (const char *arg) +{ + char *name = NULL; + char *value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); + } + + lt_setenv (name, value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_prepend (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_append (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 1); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : "<NULL>"), + (value ? value : "<NULL>"))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : "<NULL>"), + (value ? value : "<NULL>"))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + + +EOF +} +# end: func_emit_cwrapperexe_src + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $ECHO + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because the file extensions .$libext of this argument makes me believe" + $ECHO "*** that it is just a static archive that I should not use here." + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + $ECHO + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $ECHO + $ECHO "*** And there doesn't seem to be a static archive available" + $ECHO "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $ECHO + $ECHO "*** Warning: This system can not link to static lib archive $lib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $ECHO "*** But as you try to build a module library, libtool will still create " + $ECHO "*** a static module, that should work as long as the dlopening application" + $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` + # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` + # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then + ldd_output=`ldd conftest` + for i in $deplibs; do + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + deplib_matches=`eval "\\$ECHO \"$library_names_spec\""` + set dummy $deplib_matches; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $ECHO + $ECHO "*** Warning: dynamic linker does not accept needed library $i." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which I believe you do not have" + $ECHO "*** because a test_compile did reveal that the linker did not use it for" + $ECHO "*** its dynamic dependency list that programs get resolved with at runtime." + fi + fi + ;; + *) + newdeplibs="$newdeplibs $i" + ;; + esac + done + else + # Error occurred in the first compile. Let's try to salvage + # the situation: Compile a separate program for each library. + for i in $deplibs; do + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $i; then + ldd_output=`ldd conftest` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + deplib_matches=`eval "\\$ECHO \"$library_names_spec\""` + set dummy $deplib_matches; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $ECHO + $ECHO "*** Warning: dynamic linker does not accept needed library $i." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because a test_compile did reveal that the linker did not use this one" + $ECHO "*** as a dynamic dependency that programs can get resolved with at runtime." + fi + fi + else + droppeddeps=yes + $ECHO + $ECHO "*** Warning! Library $i is needed by this library but I was not able to" + $ECHO "*** make it link in! You will probably need to install it or some" + $ECHO "*** library that it depends on before this library will be fully" + $ECHO "*** functional. Installing it before continuing would be even better." + fi + ;; + *) + newdeplibs="$newdeplibs $i" + ;; + esac + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method; shift + file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ + -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + done + fi + if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | + $GREP . >/dev/null; then + $ECHO + if test "X$deplibs_check_method" = "Xnone"; then + $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + else + $ECHO "*** Warning: inter-library dependencies are not known to be supported." + fi + $ECHO "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $ECHO + $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + $ECHO "*** a static module, that should work as long as the dlopening" + $ECHO "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $ECHO "*** The inter-library dependencies that have been dropped here will be" + $ECHO "*** automatically added whenever a program is linked with this library" + $ECHO "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $ECHO + $ECHO "*** Since this library must not contain undefined symbols," + $ECHO "*** because either the platform does not support them or" + $ECHO "*** it was explicitly requested with -no-undefined," + $ECHO "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + $ECHO 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + $ECHO ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *cegcc) + # Disable wrappers for cegcc, we are cross compiling anyway. + wrappers_required=no + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $ECHO for shipping. + if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $ECHO "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/m4/ax_check_compiler_flags.m4 b/m4/ax_check_compiler_flags.m4 new file mode 100644 index 0000000..05e5c3b --- /dev/null +++ b/m4/ax_check_compiler_flags.m4 @@ -0,0 +1,78 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_check_compiler_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE]) +# +# DESCRIPTION +# +# Check whether the given compiler FLAGS work with the current language's +# compiler, or whether they give an error. (Warnings, however, are +# ignored.) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu> +# Copyright (c) 2008 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see <http://www.gnu.org/licenses/>. +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_CHECK_COMPILER_FLAGS], +[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX +AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1]) +dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: +AS_LITERAL_IF([$1], + [AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1), [ + ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes, + AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no) + _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])], + [ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes, + eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no) + _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS]) +eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1) +AC_MSG_RESULT($ax_check_compiler_flags) +if test "x$ax_check_compiler_flags" = xyes; then + m4_default([$2], :) +else + m4_default([$3], :) +fi +])dnl AX_CHECK_COMPILER_FLAGS diff --git a/m4/ax_ext.m4 b/m4/ax_ext.m4 new file mode 100644 index 0000000..41536f7 --- /dev/null +++ b/m4/ax_ext.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_ext.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_EXT +# +# DESCRIPTION +# +# Find supported SIMD extensions by requesting cpuid. When an SIMD +# extension is found, the -m"simdextensionname" is added to SIMD_FLAGS +# (only if compilator support it) (ie : if "sse2" is available "-msse2" is +# added to SIMD_FLAGS) +# +# This macro calls: +# +# AC_SUBST(SIMD_FLAGS) +# +# And defines: +# +# HAVE_MMX / HAVE_SSE / HAVE_SSE2 / HAVE_SSE3 / HAVE_SSSE3 +# +# LAST MODIFICATION +# +# 2008-04-12 +# 2009-04-23 Mark Asbach <markasbach@users.sourceforge.net< +# Renamed cache variables so they adhere naming convention +# Corrected M4 quoting for AX_CHECK_COMPILER_FLAGS +# +# COPYLEFT +# +# Copyright (c) 2008 Christophe Tournayre <turn3r@users.sourceforge.net> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AX_EXT], +[ + AC_REQUIRE([AX_GCC_X86_CPUID]) + + AX_GCC_X86_CPUID([0x00000001]) + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + ecx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 3` + edx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 4` + fi + + AC_CACHE_CHECK([whether mmx is supported], [ax_cv_have_mmx_ext], + [ + ax_cv_have_mmx_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$edx>>23&0x01))" = 1; then + ax_cv_have_mmx_ext=yes + fi + fi + ]) + + AC_CACHE_CHECK([whether sse is supported], [ax_cv_have_sse_ext], + [ + ax_cv_have_sse_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$edx>>25&0x01))" = 1; then + ax_cv_have_sse_ext=yes + fi + fi + ]) + + AC_CACHE_CHECK([whether sse2 is supported], [ax_cv_have_sse2_ext], + [ + ax_cv_have_sse2_ext=no + if test "$((0x$edx>>26&0x01))" = 1; then + ax_cv_have_sse2_ext=yes + fi + ]) + + AC_CACHE_CHECK([whether sse3 is supported], [ax_cv_have_sse3_ext], + [ + ax_cv_have_sse3_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$ecx&0x01))" = 1; then + ax_cv_have_sse3_ext=yes + fi + fi + ]) + + AC_CACHE_CHECK([whether ssse3 is supported], [ax_cv_have_ssse3_ext], + [ + ax_cv_have_ssse3_ext=no + if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then + if test "$((0x$ecx>>9&0x01))" = 1; then + ax_cv_have_ssse3_ext=yes + fi + fi + ]) + + if test "$ax_cv_have_mmx_ext" = yes; then + AC_DEFINE(HAVE_MMX,,[Support mmx instructions]) + AX_CHECK_COMPILER_FLAGS([-mmmx], [SIMD_FLAGS="$SIMD_FLAGS -mmmx"], []) + fi + + if test "$ax_cv_have_sse_ext" = yes; then + AC_DEFINE(HAVE_SSE,,[Support SSE (Streaming SIMD Extensions) instructions]) + AX_CHECK_COMPILER_FLAGS([-msse], [SIMD_FLAGS="$SIMD_FLAGS -msse"], []) + fi + + if test "$ax_cv_have_sse2_ext" = yes; then + AC_DEFINE(HAVE_SSE2,,[Support SSE2 (Streaming SIMD Extensions 2) instructions]) + AX_CHECK_COMPILER_FLAGS([-msse2], [SIMD_FLAGS="$SIMD_FLAGS -msse2"], []) + fi + + if test "$ax_cv_have_sse3_ext" = yes; then + AC_DEFINE(HAVE_SSE3,,[Support SSE3 (Streaming SIMD Extensions 3) instructions]) + AX_CHECK_COMPILER_FLAGS([-msse3], [SIMD_FLAGS="$SIMD_FLAGS -msse3"], []) + fi + + if test "$ax_cv_have_ssse3_ext" = yes; then + AC_DEFINE(HAVE_SSSE3,,[Support SSSE3 (Supplemental Streaming SIMD Extensions 3) instructions]) + fi + + AC_SUBST(SIMD_FLAGS) +]) diff --git a/m4/ax_gcc_x86_cpuid.m4 b/m4/ax_gcc_x86_cpuid.m4 new file mode 100644 index 0000000..e9231b8 --- /dev/null +++ b/m4/ax_gcc_x86_cpuid.m4 @@ -0,0 +1,65 @@ +dnl @synopsis AX_GCC_X86_CPUID(OP) +dnl @summary run x86 cpuid instruction OP using gcc inline assembler +dnl @category Misc +dnl +dnl On Pentium and later x86 processors, with gcc or a compiler that +dnl has a compatible syntax for inline assembly instructions, run +dnl a small program that executes the cpuid instruction with +dnl input OP. This can be used to detect the CPU type. +dnl +dnl On output, the values of the eax, ebx, ecx, and edx registers +dnl are stored as hexadecimal strings as "eax:ebx:ecx:edx" in +dnl the cache variable ax_cv_gcc_x86_cpuid_OP. +dnl +dnl If the cpuid instruction fails (because you are running a cross-compiler, +dnl or because you are not using gcc, or because you are on a processor +dnl that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP is set +dnl to the string "unknown". +dnl +dnl This macro mainly exists to be used in AX_GCC_ARCHFLAG. +dnl +dnl @version 2008-12-06 +dnl @license GPLWithACException +dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Matteo Frigo. +AC_DEFUN([AX_GCC_X86_CPUID], +[AC_REQUIRE([AC_PROG_CC]) +AC_LANG_PUSH([C]) +AC_CACHE_CHECK([for x86 cpuid $1 output], [ax_cv_gcc_x86_cpuid_$1], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>], [ + int op = $1, eax, ebx, ecx, edx; + FILE *f; +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) + __asm__("push %%rbx\n\t" + "cpuid\n\t" + "pop %%rbx" + : "=a" (eax), "=c" (ecx), "=d" (edx) + : "a" (op)); + __asm__("push %%rbx\n\t" + "cpuid\n\t" + "mov %%rbx, %%rax\n\t" + "pop %%rbx" + : "=a" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op)); +#else + __asm__("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx" + : "=a" (eax), "=c" (ecx), "=d" (edx) + : "a" (op)); + __asm__("push %%ebx\n\t" + "cpuid\n\t" + "mov %%ebx, %%eax\n\t" + "pop %%ebx" + : "=a" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op)); +#endif + f = fopen("conftest_cpuid", "w"); if (!f) return 1; + fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); + fclose(f); + return 0; +])], + [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], + [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], + [ax_cv_gcc_x86_cpuid_$1=unknown])]) +AC_LANG_POP([C]) +]) diff --git a/m4/libtool.m4 b/m4/libtool.m4 new file mode 100644 index 0000000..a3fee53 --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,7377 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to <bug-libtool@gnu.org>." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +_LT_PATH_LD_GNU +AC_SUBST([LD]) + +_LT_TAGDECL([], [LD], [1], [The linker used to build libraries]) +])# LT_PATH_LD + +# Old names: +AU_ALIAS([AM_PROG_LD], [LT_PATH_LD]) +AU_ALIAS([AC_PROG_LD], [LT_PATH_LD]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_LD], []) +dnl AC_DEFUN([AC_PROG_LD], []) + + +# _LT_PATH_LD_GNU +#- -------------- +m4_defun([_LT_PATH_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac]) +with_gnu_ld=$lt_cv_prog_gnu_ld +])# _LT_PATH_LD_GNU + + +# _LT_CMD_RELOAD +# -------------- +# find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +m4_defun([_LT_CMD_RELOAD], +[AC_CACHE_CHECK([for $LD option to reload object files], + lt_cv_ld_reload_flag, + [lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac +_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl +_LT_DECL([], [reload_cmds], [2])dnl +])# _LT_CMD_RELOAD + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +AC_CACHE_CHECK([how to recognize dependent libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[[4-9]]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[[45]]*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 0000000..34151a3 --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,368 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 new file mode 100644 index 0000000..9000a05 --- /dev/null +++ b/m4/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 new file mode 100644 index 0000000..f3c5309 --- /dev/null +++ b/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 new file mode 100644 index 0000000..637bb20 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,92 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) @@ -0,0 +1,376 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to <bug-automake@gnu.org>." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + tar*) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar*) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/resource.sh b/resource.sh new file mode 100755 index 0000000..c73d681 --- /dev/null +++ b/resource.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# This script generates resource files. +# Usage: ./resource.sh <file> +# Resource file is printed to stdout. +# Usable variables (<file> is stripped from path and extension): +# const char *<file>_rc; // File content in binary format +# const unsigned <file_rc_size; // File size +# Examples: +# (file: dumps/test.out content: "ahoj") +# ./resource.sh dumps/test.out +# static const unsigned test_rc_size = 4; +# static const char test_rc[] = { 'a', 'h', 'o', 'j', '\0' }; + +hd="hexdump -v -e" +fmt="\"0\" \"x\" 1/1 \"%02X\" \", \"" + +# Preparse source file name +header="${1%.*}_rc" +header=`basename ${header}` + +# Get file size and dump content +size=`wc -c ${1} | awk '{print $1}' 2>/dev/null` +dump=`${hd} "${fmt}" ${1} 2>/dev/null` + +# Format file size variable +echo "static const unsigned ${header}_size = ${size};" + +# Format file content dump +echo "static const char ${header}[] = { " +echo "${dump}0x00 };" diff --git a/samples/Makefile.am b/samples/Makefile.am new file mode 100644 index 0000000..5ac505b --- /dev/null +++ b/samples/Makefile.am @@ -0,0 +1,24 @@ +edit = sed \ + -e 's|@version[@]|$(PACKAGE_VERSION)|g' \ + -e 's|@package[@]|$(PACKAGE_NAME)|g' \ + -e 's|@localstatedir[@]|$(localstatedir)|g' \ + -e 's|@prefix[@]|$(prefix)|g' \ + -e 's|@sysconfdir[@]|$(sysconfdir)|g' + +knot.sample.conf: Makefile + rm -f $@ $@.tmp + srcdir=''; \ + test -f ./$@.in || srcdir=$(srcdir)/; \ + $(edit) $${srcdir}$@.in >$@.tmp + mv $@.tmp $@ + +knot.sample.conf: knot.sample.conf.in + +install-data-local: knot.sample.conf + [ -d $(sysconfdir) ] || \ + $(INSTALL) -d $(sysconfdir) + [ -f $(sysconfdir)/knot.sample.conf ] || \ + $(INSTALL_DATA) knot.sample.conf example.com.zone $(sysconfdir) + +clean-local: + rm -f knot.sample.conf diff --git a/samples/Makefile.in b/samples/Makefile.in new file mode 100644 index 0000000..a992c4c --- /dev/null +++ b/samples/Makefile.in @@ -0,0 +1,385 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = samples +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compiler_flags.m4 \ + $(top_srcdir)/m4/ax_ext.m4 \ + $(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/src/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIMD_FLAGS = @SIMD_FLAGS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +edit = sed \ + -e 's|@version[@]|$(PACKAGE_VERSION)|g' \ + -e 's|@package[@]|$(PACKAGE_NAME)|g' \ + -e 's|@localstatedir[@]|$(localstatedir)|g' \ + -e 's|@prefix[@]|$(prefix)|g' \ + -e 's|@sysconfdir[@]|$(sysconfdir)|g' + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu samples/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu samples/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local distclean distclean-generic distclean-libtool \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-data-local \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am uninstall uninstall-am + + +knot.sample.conf: Makefile + rm -f $@ $@.tmp + srcdir=''; \ + test -f ./$@.in || srcdir=$(srcdir)/; \ + $(edit) $${srcdir}$@.in >$@.tmp + mv $@.tmp $@ + +knot.sample.conf: knot.sample.conf.in + +install-data-local: knot.sample.conf + [ -d $(sysconfdir) ] || \ + $(INSTALL) -d $(sysconfdir) + [ -f $(sysconfdir)/knot.sample.conf ] || \ + $(INSTALL_DATA) knot.sample.conf example.com.zone $(sysconfdir) + +clean-local: + rm -f knot.sample.conf + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/samples/bogus25.com.zone b/samples/bogus25.com.zone new file mode 100644 index 0000000..5260270 --- /dev/null +++ b/samples/bogus25.com.zone @@ -0,0 +1,16 @@ +$TTL 3600 +bogus25.com. IN SOA ns1.bogus25.com. support.bogus25.com. ( + 20010923; Serial + 10800 ; Refresh after 3hrs + 3600 ; Retry after 1 hr + 604800 ; Expire in 1 week + 86400 ) ; Minimum ttl 1 day + +@ IN NS ns1.bogus25.com. +@ IN NS ns2.bogus25.com. +@ IN MX 10 mail +bogus25.com. IN A 72.96.52.127 +www IN CNAME bogus25.com. +ftp IN CNAME bogus25.com. +mail IN A 72.96.52.127 + diff --git a/samples/example.com.zone b/samples/example.com.zone new file mode 100644 index 0000000..a1e3aef --- /dev/null +++ b/samples/example.com.zone @@ -0,0 +1,69 @@ +$TTL 1h ; The default expiration time of a resource record without its own TTL value +$ORIGIN example.com. +@ IN SOA ns.example.com. username.example.com. ( + 2007120713 ; serial number of this zone file + 10 ; slave refresh (1 day) + 30 ; slave retry time in case of a problem (1 day) + 4w ; slave expiration time (4 weeks) + 1h ; minimum caching time in case of failed lookups (1 hour) + ) + NS ns ; ns.example.com is the nameserver for example.com + NS ns.somewhere.com. ; ns.somewhere.com is a backup nameserver for example.com + MX 10 mail.example.com. ; mail.example.com is the mailserver for example.com + MX 20 mail2.example.com. ; Similar to above line, but using "@" to say "use $ORIGIN" + MX 50 mail3 ; Similar to above line, but using a host within this domain + A 10.0.0.1 ; ip address for "example.com" +ns A 10.0.0.2 ; ip address for "ns.example.com". Since there is no "." after ns, $ORIGIN is attached +www CNAME ns ; "www.example.com" is an alias for "ns.example.com" +wwwtest CNAME www ; "wwwtest.example.com" is another alias for "www.example.com" +mail A 10.0.0.3 ; ip address for "mail.example.com", any MX record host must be +ns.sub A 10.1.0.1 ; glue + +;ns.sub TYPE23444 \# abcedfg + +a A 10.0.0.4 +*.a A 10.0.0.5 + +c CNAME c.a.example.com. +@ NS ns2 +ns2 A 10.0.0.6 +@ NS c.a.example.com. + +sub2 NS ns.sub2.example.com. +*.sub2 A 10.2.0.1 + +_foobar._tcp SRV 0 1 9 old-slow-box.example.com. + SRV 0 3 9 new-fast-box.example.com. +; if neither old-slow-box or new-fast-box is up, switch to +; using the sysdmin's box and the server + SRV 1 0 9 sysadmins-box.example.com. + SRV 1 0 9 server.example.com. +server A 172.30.79.10 +old-slow-box A 172.30.79.11 +sysadmins-box A 172.30.79.12 +new-fast-box A 172.30.79.13 +; NO other services are supported +*._tcp SRV 0 0 0 . +*._udp SRV 0 0 0 . + +sub3 NS ns.sub2.example.com. +sub4 NS ns.example.com. + +d CNAME non-existing.example.com. +e DNAME bogus25.com. +f CNAME e.example.com. +g CNAME www.bogus25.com. + +f.g A 10.0.0.20 +h.i.j.k A 10.0.0.21 +*.j.k A 10.0.0.22 + +sub5 CNAME sub3 +*.l CNAME c.example.com. +;*.m NS ns.sub2.example.com. +*.n DNAME bogus25.com. +o CNAME a.e.example.com. +p CNAME a.sub.example.com. +r CNAME a.l.example.com. +*.s CNAME s +s A 10.1.1.1 diff --git a/samples/example.com.zone.nsec3 b/samples/example.com.zone.nsec3 new file mode 100644 index 0000000..f5bf984 --- /dev/null +++ b/samples/example.com.zone.nsec3 @@ -0,0 +1,635 @@ +; File written on Tue Mar 1 10:45:24 2011 +; dnssec_signzone version 9.7.1-P2 +example.com. 3600 IN SOA ns.example.com. username.example.com. ( + 2007120712 ; serial + 86400 ; refresh (1 day) + 86400 ; retry (1 day) + 2419200 ; expire (4 weeks) + 3600 ; minimum (1 hour) + ) + 3600 RRSIG SOA 8 2 3600 20110331084524 ( + 20110301084524 28635 example.com. + 6G4Hpl8WFCTVZN292HX+NaS1K8+oLaXK+2gr + tIp53Y1MI/A8qAD2HZ+bECnbedU+mP5PIJ8I + 4Q6STbZE3HpiaTMP8D87sJwgD6tUexHhBNgf + CPZQBdF2Gw/hP+yqeY89ZcoeJVimy6h56X+V + 7KM+JqRQ6KlGo8vLJTn/lo3pOq8= ) + 3600 NS c.a.example.com. + 3600 NS ns.example.com. + 3600 NS ns.somewhere.com. + 3600 NS ns2.example.com. + 3600 RRSIG NS 8 2 3600 20110331084524 ( + 20110301084524 28635 example.com. + 3VqU2AvI720W9frpY+jz5U6a25115tUmkC57 + tr/fvZS2CEAYhWVEpSSFWKRApb70JmQeYgvt + pvdmOriyChzq4y6phVJxChYrFeTqVYS0AvE1 + ldZ1k5xL6I0hIL6UXgMoz6nRZQ6T1qh/7G2o + Ge9Taqu0KroITTLGfn4HlyMViq4= ) + 3600 A 10.0.0.1 + 3600 RRSIG A 8 2 3600 20110331084524 ( + 20110301084524 28635 example.com. + 5tOtdUUMjX0T7QWL/YgYga+HuJOLOh8O3to8 + 3fWUvS5hmrR5/hWV1TRXSHCS0HKIaPBJCn24 + DCHM91uTPNASrpdyWlIAXTJBDqm62C0tXOKD + zn/50P0cgqHJXa7f69FQc5V+oA/OGcOb2xpV + e/ig/L8xLcRTGFoYScNMObq9tlg= ) + 3600 MX 10 mail.example.com. + 3600 MX 20 mail2.example.com. + 3600 MX 50 mail3.example.com. + 3600 RRSIG MX 8 2 3600 20110331084524 ( + 20110301084524 28635 example.com. + yX8xQLpUeZCX3Q4Aq0PTsjEO+5HUrXTWSH1k + LQ6qozQqWW/SAvnYGkjL/MILnqtTFl07DyrY + 1y++Ifh2vW5wR11lrIUiftpa0QmSUIj4eJlJ + fc78wZa3D1g6ni1VDsRClEk3Gx3sfmf2ryjN + QVa3s++ZszKolUR4WjGGJuwmbFI= ) + 3600 DNSKEY 256 3 8 ( + AwEAAdtkxsfkpMv9P3oa4FGDr+zbs5T28hC2 + G7zRsgHHSP1r3AS9JW8I3yCXI/DWJu5M0Iv3 + UuOc5Q/lNoxmiMKipIP0UZZ97sRyVIK4RWfB + quVV0GKQ08exwUvUwkej9Uu5Ub0YcWkQXAg5 + xVNpWZ5WxlVhcDVwXG/geikMJPyk6j2N + ) ; key id = 25581 + 3600 DNSKEY 256 3 8 ( + AwEAAesA9XFmAudDuFARUUn4fcYdwbPfSRYU + DVC792SMtnEl6dZBLujInZbbQiqW+OyVlo6v + kyjyQBDuS6aebN4sxO7UYz4vHxxJVuP/+H0n + /+UAyz11XYT8Rbsmpgzu3PMq5mB13jCjzZ9y + 3JBJjp5Lrk/jRjFcZapDpX/yXu0UsuuV + ) ; key id = 28635 + 3600 DNSKEY 257 3 8 ( + AwEAAddbawR+0U7Bz/2lbX1iwMGmAoYOHmb8 + sQF5Jp8gI1tEtpsDD42fW4EM1i1tx7Cyca/9 + u9MSFB14BapX+dxMMj1xJJg0RNTiswjw4DC+ + 7idLwmQHDUMhZLJBqdGkSDcgfsXm9xNEdRrs + u10wxWpmqMUFxyGStSdGneqdchSRDgr6fihu + NExHeXp884kXUPuAXSYu02xtYOLLAAhqLeEL + tQAoyi901FwmmYhyu4eYK2aWqy+ld7JCZZbQ + j4/9zdecIGETI+NbvQVoO5lSGt6GY7cKaf8m + 17L++dj2R2rTER/R3gwnjAGQ1GL/djhqbgMi + vhrxqAQ9R9Ko+6kaeqA6a60= + ) ; key id = 6190 + 3600 RRSIG DNSKEY 8 2 3600 20110331084524 ( + 20110301084524 6190 example.com. + qRB0bNPGgy4p2kGBNKbjK/03dowH3zx4fLyP + 6wv4VmJinbqe2hxqLNLGTdA1toT/82iaLJEA + Nh0GKnYRVW1rmX/YsvArYH5Z8ikrZbTYSu7Z + TVTJHHXOGIbddpx3BaEPeNJyJHf7UF5yDKkv + wM8KhkMw7zRWnuLw5dWYTqmegMVHkNekIHrH + kW389rY7gbNsZexusmsKURhl3/LhRJlZd/hP + IlAUIhEV0DZ2xmFEkCOa7QRD/PMUwuiEykxd + 0ffGm1aCzBUUWdVP7tbYbsePa9f380473m6U + xDSgNmU5/NjFRYw79/QopE68OU+7F+xTX+6S + U6bBtAvTPoG+RIBUAQ== ) + 3600 RRSIG DNSKEY 8 2 3600 20110331084524 ( + 20110301084524 28635 example.com. + MD75IQDQQtrDQTUHJV/F2cYfd49e6YkSWT7O + BuJUnTvyuYyxpqJg7Rj1H552078yrUQiNSCC + fqo9yoW6QrpxXgAsPW8wd4vT/bXRayvqZTRJ + 6ht4FMvOe1dI0cMEOEGfOnve1r4faaHBYPIo + P5sJQIkoYpQ/0FOnOLz1dIiFZpI= ) + 0 NSEC3PARAM 1 0 100 8B3F579FA62A6CE6 + 0 RRSIG NSEC3PARAM 8 2 0 20110331084524 ( + 20110301084524 28635 example.com. + Go3s7HQ1n+WLlECouJi/2P0h0F7buRYP7zSE + UcjBgBDczSucB8ZdfSI+Z9gZpJrOL+hpnhU5 + UB0xVUldoWzO3KK/Zu0YEoBNf/z1eSA8Lrt0 + kWtxDlppfYk9rMRJIBEkY4nNKJz/IlPppZ8j + TY361bbHGhoHmjJeozrdMGc6/Ls= ) +_foobar._tcp.example.com. 3600 IN SRV 0 1 9 old-slow-box.example.com. + 3600 IN SRV 0 3 9 new-fast-box.example.com. + 3600 IN SRV 1 0 9 server.example.com. + 3600 IN SRV 1 0 9 sysadmins-box.example.com. + 3600 RRSIG SRV 8 4 3600 20110331084524 ( + 20110301084524 28635 example.com. + 45kpyR6Avac84Ycv/EpLT3ScICeNpLFgQq7P + peNgEpboXrJTc7uYUtoxswq19m9czMNQNcoZ + nFKw3unQGrsfr/B38Vz6uOc9ILF/4WQbC002 + F+VGlgGvPVc9RficEYg3Wwzly7m27d4hPwk4 + pnQQaVenubmXgVHKQ+kl1c8Bqu4= ) +*._udp.example.com. 3600 IN SRV 0 0 0 . + 3600 RRSIG SRV 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + zxu5UR7j0cgvdw8q1L8eD2AvsvhkhbSvuFQH + C8a0pYCmM0OoDEiLoHj5F9Mk7LI4Mc7sESfr + roKEOQC4y6xwsuQxCjuG+V2s4xnxLbSrZwee + JqaI3e8X/gVfd3VoKycY3MqDC1432Qc8VSZC + Lz9mb68ulNEK1VrEbbA3/jTGGOM= ) +a.example.com. 3600 IN A 10.0.0.4 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + x30rkJBwLV+aiDao0J1N/FbiUWROwBqkl6lK + V3z4zHfkcEgORa7o2kNkHANPCUJj7bQSSlPD + I99dyszDxYW4bgnlNlYw9h3D+6+sK9ehREDa + IMvV1Xuup+oo6LccJhZTlEFrGFU4oUF9VXj+ + g4TDzCyCGMHnVj3SFc/+5xUXGsg= ) +c.example.com. 3600 IN CNAME c.a.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + 1sHLDUiGyabatbzRknYdhwu4CQXH+bb6+9x0 + yW/173FMudGOGowiPdfMkUFOP0Igqb/4FqVj + bg+jDdu4zFCszLQ5MC4Q6mrLL0nfUJ4JL2J9 + kScZN12/t9+P0dnLb5YYXKV8E0GtlKd4ZVr5 + 9fRJvve/OsV29Xj02vX1+sXNjoE= ) +d.example.com. 3600 IN CNAME non-existing.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + Or6i4+ez4nkhodwJC8OWJaj9TyvxJ1i6HC3u + /xjwF/kStCkTaX/Cg8d36KhVGev6z6LyT++s + SKiQ0wdPzhgfv2d386W7XUSCje7/OCRUUZwp + taQvzJsfKCBy2hYz00Anai2qk1pldKEYI3aN + P3qnSItISO9zbOcKtV2ug6B304Y= ) +e.example.com. 3600 IN DNAME bogus25.com. + 3600 RRSIG DNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + sbrGVq24p55ke3GGXkr/7IPu3fNO67SUABQW + 67VKrfL1AF5qWN7UdcEb5FZQ5302s28/mePb + c4Ubn2bpQrmHdMZm1W370J0fDQ/PBT9lKnQS + tZpAx6xPMRmLG+qvrOtGFDeuCVDqmRlK13wJ + ryCGvI2eJcfrOU7Kx98ZLgDTzbQ= ) +*._tcp.example.com. 3600 IN SRV 0 0 0 . + 3600 RRSIG SRV 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + k9YqgNDYkvF4tqiPjw0FCsL675BQ6V0mztXc + +Vfcd/bSbpD3HiMDbkmBeW68TH7g2rkqTzS2 + yjXGdVsxo7jDWdfPiGDdAUueYbPzxEF1eY3q + v7oquG86sfTrbosYFPfihLXZrnGhVDIlHmgi + L428BtZbXTINKm9XwjFwv+pZ66s= ) +g.example.com. 3600 IN CNAME www.bogus25.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + gwENYoTmnyn38R4sIb1wJ/uKXPNQnKOu2gfa + sWW91lrkcwQYF59XZIDme+XST4fiscDJfjPH + 9xHXs86j771L/2shVZkfh161qXMv2xWVKP14 + tXXfjcQyz/YZ4S6S6MWkUl1w5ujqJCq4PLv0 + +BucVmtjQkcxG9yR0P8F5hMZBsA= ) +*.j.k.example.com. 3600 IN A 10.0.0.22 + 3600 RRSIG A 8 4 3600 20110331084524 ( + 20110301084524 28635 example.com. + MI/Q/zFqnUrlIQmPjy4Kpq8lQ38PAi15cidP + C1ZutJUXV7aiYpJJcpmkDNRA96L+/cApfW06 + /ahv+IYrxI3qWd8agOxDXTR/bclrxWJs8Zdq + aQeM+uvhtVCua6tRcdJf1UCHwEFpqoEg6xcs + 3vR13IuPLlJrfe/AMrw1FvROfBg= ) +f.example.com. 3600 IN CNAME e.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + cvQbg2jKGDrL6dyOXSY++SaEzo31OKDPRXWe + l4pVWsJdK9YmjQ0zXdAVtqiYFdKsfS4ep5FG + VPFF3xuHF0cPzzozwQ3cyn6BRq6EVDohn5Ct + oyqSQ9jWuwDNdLxG6yCFK+R6bdlc5fxE3Jkn + qQ8hK6z7XHpHL7ZySVufRtGhMrA= ) +h.i.j.k.example.com. 3600 IN A 10.0.0.21 + 3600 RRSIG A 8 6 3600 20110331084524 ( + 20110301084524 28635 example.com. + m+FuNt4WmfnICukl82DSunja8nfoy68u+oBU + MX3nzp5AjwbqWyZTvQRaZpDa0Rsa90oHbCuv + hOYiK4tVdZjk0yd0Fx6XX/zFqD29BEI/oLu4 + u8CPLvSC9vWB8bFScOjeoCUM+hmnoLVuZ/rq + XFHz/CQmYX+mpU3u7pKSpFyQDAw= ) +mail.example.com. 3600 IN A 10.0.0.3 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + HPK9q98C16xCURI5wxP3lxUGdJr1X1TeRZ2L + tnf2s5Izmt28Y3SIbVI83prKO/m4PrpfeV7T + Ji3ErMMUe7k6Q096YaGStBHL5GWeymJCAzC8 + pJPnyzExDRZeGeknEg4bn0+WJHJz+hlVzYQx + LRaqA4O021aZf9U/sdDZhGBR0Hw= ) +*.a.example.com. 3600 IN A 10.0.0.5 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + fXOfzPtCYPPyxtw5ivLn7Kq3JlK+LR8BbYLp + Z6f/Nir3R00GURfsUM6NVbPnMOpnPE513yz7 + 1sAAO/rsOFXPZUSJF4G4zMA6O4OirjGh68bX + Ei/yrdllyPiTgtHI693MpsDvAFNIaO+pkgS6 + zt+Mk1MEau+78saWxyZVbBWCqT4= ) +*.n.example.com. 3600 IN DNAME bogus25.com. + 3600 RRSIG DNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + s/gyETQ20pNXEbhwRhTIPTMOQYMW8KhhHaSN + uOYX57dabeGuYgfXFRfNIB+Y1m3kTlxmacMS + dNIep2b4SF59/T7Ww06/I4P/qQiOosdyeBSY + X4mQeMrUh8kqxh9C4cQh5yPiiz4w/0Ui+SLP + J/7Z0AKgYKh7t+pVQfiDAKGQJXo= ) +ns.example.com. 3600 IN A 10.0.0.2 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + aPAigU/glISbY2VM8F8JpfElQ+xab12ZO7el + 5Cl3t1qiU/3iirBmaKTj7g6IhBduPx+iBgOy + 5v32FyrfHi2El6nJZxEgi52/Z/4Ohvju3jVA + hUJLGoREc20FUXOiICCftEauQp7uPM1RAQ17 + Q0pykRRQ50bn+jApSRLL696e+EY= ) +f.g.example.com. 3600 IN A 10.0.0.20 + 3600 RRSIG A 8 4 3600 20110331084524 ( + 20110301084524 28635 example.com. + EfjVvHQ/IEPdP10B+dEDfyHpCRNpmf0dV7Pb + Ia/gRDuoRg6FUbL04oycNQSMjafInBpinmx/ + WSDMenEf5HUtP3fyzZ9Fywg2QDZqm6/TJXBk + 8q+uOxPKfMlcn9Skg1k8XJGbJkAovmyCS+DA + LC2Ewp7yVUwEliZBkKzUblWE5ig= ) +ns2.example.com. 3600 IN A 10.0.0.6 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + hgX7gI1GpJeuQtTnVDCHS4esc1wRQk6zAP/8 + st6cILlYbOQkwfRVpB88Y4LDCYuWLkplKBjp + cOhL/gU+zvR8QQQHmdksUlYSK0SFEdvcpvIm + uD4KosW3wJSAPS8M3bxI2yA/CPdY6SalClbY + jM/OpPfynAqS1UdNo8vNu4pBYks= ) +o.example.com. 3600 IN CNAME a.e.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + RMRnQd17zWB6vxGUl6L+zKWchPD9XyNMaK6W + v0MfpY5E9hqSMvNp5BKf+1Fsk5aWs9aWga/a + AVFUTObelpdG4IE4oyGSUB3wCN9ZTxJ9rKqd + NVG48X2+iAb2k3tGcUQaYH20gBIezPwi2AWc + k+CHI2FTi10evykIeVJo+Paro7I= ) +old-slow-box.example.com. 3600 IN A 172.30.79.11 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + LfF5v3pRRomTjLMLqCyEqK9J9m7dbBs1V0zS + bEu9T+MPOdW4swoObFBPv/FLqr50Y6OGlovK + J0lSGo+plLw6gPMW9bzJNGeIP19TgcEmF626 + 7+hRibwn6fZvoK4qBQSDQKmNBoST1u+ZhWa6 + xpdY5bdosyQ0oM1Q6eHZsEGELvs= ) +*.l.example.com. 3600 IN CNAME c.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + l+p7hZxP1VakVXtcDE2dN+DCK9tAdZpT8i0i + IoUdRUgeTv2DcViVsK2tNjv0HIZcffhEatwi + pM7IAvqkbS22PduU+dxb3OMzcj6n/dQBcxoW + vfk56RpQcDrqPJVYn7AqVH6KXFg6oRrIYzw1 + O9uTLaHt+futcIEDvRVMTODe9os= ) +sub.example.com. 3600 IN NS ns.sub.example.com. +ns.sub.example.com. 3600 IN A 10.1.0.1 +sub2.example.com. 3600 IN NS ns.sub2.example.com. +*.sub2.example.com. 3600 IN A 10.2.0.1 +sub3.example.com. 3600 IN NS ns.sub2.example.com. +sub4.example.com. 3600 IN NS ns.example.com. +server.example.com. 3600 IN A 172.30.79.10 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + zWLeUhLq/2lU0KwPFxzJaFIiOSqwA4xQ+mwh + UYSa27N1t58m3L+XeOwj/zSE69sWl8Lbm3pV + B+4FNVVPkGzBhocJRf/7a0xc0IlQSI1hgZ3p + meFlPC/kMTmxK1p9un/dF5r35FsnnAN8ECnR + 2imbaQLIrjhHshK9bBIVCwK92Ws= ) +sysadmins-box.example.com. 3600 IN A 172.30.79.12 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + WUp7V4gH7JMyvtKURuvrNmW7rVMI1aSMZU9U + xukVAmQDaQTYXsD5XC3j7X+9gAhQJWA/JNga + pXT7wzBJpqVrJHqAfRYZFMQ9WI0rJzKJnFPI + WOlVerQMEwUpyJsX/GlJglldK5kKM0bbPjW8 + s6Vqmq3rfyjGY94HNS9jX+uqCwk= ) +new-fast-box.example.com. 3600 IN A 172.30.79.13 + 3600 RRSIG A 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + qK9x7sS736Go3vdVfYhtuEnFLOhl6djWpXVC + l4+kvvPpkAJTkfHmTcAsWbChSolB8X4UPt/P + KTnImnF4uhc2qLOhvToKqx9tVExEIWDBKA7F + JPPBYG0c6n/50j2bVmzrkhyzaLLuhsbbfm5o + eZDwwO+vuoMBvj8Z/mt0Di9rh/w= ) +www.example.com. 3600 IN CNAME ns.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + LPrX8sh5xYUfW+wKpQRg50qkf67maJRcN6tH + R+H3OwL4u9JhdK6RpdRvs4nAF8HmrUZZYtxo + 80+RMbFhynqPYWlnXd/ZH6taQN2qJYdVLdnd + dhyLajAkxJqpOWVLezr2KOPj6YzJzu15ngXD + nHnkSKsTlziq3ifLd5oJLy9UJAk= ) +0J3ID6U2GQUPOADI9B867SGMROP8U4Q0.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 18DGVBOD0NE6AJ2OV3MV9QGNBTJ39V2U SRV RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + BStj/PbAk78rRKdCf4eCvtGKYGco/i7fg54U + mlIGY/ToQwsB4f9NuDpuajdt+30QnL6w1m5u + /Hku6cZAV7PEr5S286TWtIHu1GSUfjQ2ObKC + sF9PYoQrARTNYceY8ZKPNwTk1DgfBNM1WcdW + 5zJLbQ/DfP/O1c9ZiaR5jokbRnE= ) +18DGVBOD0NE6AJ2OV3MV9QGNBTJ39V2U.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 28CVPDQCRQARAVE71745J8C1C9RR9U6A NS + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + LeQC7vW1322QqG/X08ZQ3hokSMIDB0rmGxk/ + JsmrNt6o1hmpwfz9ET1GM6LDf+SLd12SdnYa + vRZxVVeUv7KloxZI77aaZabqKYWCX+LmkoJk + LAinY3wQ6vZD3vSP/BxUZL4Ojs0GNpWqGNzs + ZOkU9EOOE/mwQFlU6GamBJoy2nU= ) +sub5.example.com. 3600 IN CNAME sub3.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + qIPaS9aKJASzy2ncqcnlyLW4npkwBW12Udvc + zGyjk/bO8Q58eKm3uBfJ3LtQVCznkBhAksXK + AXGnN1TRtaxeVBWZNqlRtHV2hgmXQsTWxoVz + Qc8Qz2LvnzfgRTjt0H1n/5aDQ3FeZ25XuwLB + W5fFHwvOmQDd3lvZhOJVfSvEKNM= ) +28CVPDQCRQARAVE71745J8C1C9RR9U6A.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2BMOOQEUMB3KGE328CJ7B2Q65OPJM8DJ CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + i2K6FAon2wyZnGTH35mMmjWth+czEC1cdoyL + hk6Xd3iGrN5tjPAqkMtuKDuG2boGjDP02npj + Ytv59m5IK5vSNgeOekR6TRNWdJ/S3XM9VSlv + 9R07P9WjJVjO4viGtAfvbKVNOYyLPe6+e/Na + lIjYv87EAAlV3Hot7Pzff1duRSM= ) +2BMOOQEUMB3KGE328CJ7B2Q65OPJM8DJ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2CIJJH4RBMAISUSA1TH02A2RAN03THDQ CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + HWSQYMuhCxYWm6DVKRwnik/PYwQmdZhOHMmb + P+Map173RzL0kzCqGzpokaDmZBs8zZohgvMs + UYbQss8jnXJuAcyRF0dSc0IVVeJLUAaipJpi + kmzyIy/+ANxsaSeRgKvkGecFT8dnl5xNQ6F3 + vbBwGNQ34VQHNx6S4a3Qa/vBwS8= ) +wwwtest.example.com. 3600 IN CNAME www.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + 2kfR8e8X0LNbTyPg9fe7vlOknc63ksjBRECm + pCKNFqSMXJ9gd4gbB2DKHTQLarAQx1KOy3lA + OezcuJS3WKxF/ucZDqkOaiN/YGJqC5GZ1jcW + zcCahY8FAM/eJfjbZpdn8YowVQy9f/1m+agl + vsHMD00nflPUyFiRmoik1DAWoVU= ) +2CIJJH4RBMAISUSA1TH02A2RAN03THDQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2E74KFMC0MPQFVMLM1UD7O7HCEUV01TQ A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + f6Gj3qbdYjC27HqDBLv3Ip5Gf/j/GJNVko3G + XIVrebHqTPUssOy81/CRElLstM1l1WzX/KTz + 9Pzu5e1qmlYk4Ym20mMAyihWON3/IJk2GI8x + TDR4tJ3DBWk37l1S4eMhjv43OSms98GlKfZl + soYKgv6hwPyX7si1FEL9gWTJjio= ) +2FIB35726VOBGISOGPQLFO6O5IRN3M0G.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 3JL9UEM86R2IO5RMPACMSD92NTVGRPNG SRV RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + xmeQ5RA8LUt1UDtfFhKdTCq6ean35+UdK0fP + OIb7XeWcp63YVS28l0uoud3+HjsB8VSF/FXi + PpJnN/kG6Xk/+sdTDGuObtqlAI1W6/dXgDcP + VdbGNo4uPcJsdkQdCgrQs0oxZCwpW2Q69LWH + yKLTVO6avq/V9DiNOPjTSG7Ix8c= ) +3JL9UEM86R2IO5RMPACMSD92NTVGRPNG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 4F4ISAF7SLHE2FVS6IH2N1HHOCVUTMTN A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + JbwLpP6KcZ4UbuR7vmjRozuL2uoyp6U1HP9L + tRu6CH5CJwMa0crXBM6cCg7zm4PkSxyQBMSV + lt+T3lThVSx6HzxGoDAblj5SiPF/SA79zZW6 + g9qFAlLQ4doeC0CesjeOPu9bL37wtWJIZY5P + 3LhYhNN67PYAwGFl+s+3kVrLiTE= ) +p.example.com. 3600 IN CNAME a.sub.example.com. + 3600 RRSIG CNAME 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + eXmvtean3kAh6cJGtMWPfzVlOC6cjaF4IgIC + UnJruUTcL61mR57nQKxBD6Fc6/BQoVMOvP2n + Q19akZQoDvgt/p/Koo3vUozrCzLvkj1n4oSd + R0fSl7PCBl8Rf1TMuvw+7XvQeIfLq2c8INL1 + PONXmm/lkgqbYw2BJxzx5tKffcE= ) +6A3ESFQICSC9TLOHO0P20QB3T0H8DHNT.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 6T8FEOHJ6MH3O1N4B0H6AES9842FDUSS A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + kUhsVZbbmfkCczTv/wMzX8sbPn+5VbR1r+xE + x8YvzZ42zof62wIvS2JcwXCR2GvSi9LVKBQE + 3y1g548Y8n9moXC13MP4F84h+5U/VAhyaPpw + e2TJpBnMLCDjvMUXP3XQKQzkdiV3UaLFn0aP + khwT6nh+TTPYeREjcSLuyhWs8Hk= ) +74EBGC37NAC14CAFDT47M48A5JSFFSL2.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 75DLOF6I4571LIKU0GLDE5T49QMEN8IG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + MtZCtVby4Hprx3spzSglrUqmPvvreRDrKXhc + 0xaWh27f81oGsnek+jDYvaw9JIdDcOAQbonT + 2nVy6s6Jmrjt+7pWSGPkuFGPgybBrH1l0Rh3 + QmODDmVDueyTMSdEpfe+Nw7+zlq7BI1qXe3T + fBoESwb73RXgOQ4VztK0/XXk1wQ= ) +75DLOF6I4571LIKU0GLDE5T49QMEN8IG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 7GD2384TAD22TQJ5ULAC03C93FO12QF0 A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + zukfY1bN+D7H/q3QKmPz+rRRxofgC1ECjbxL + ZdG0NBT/w2QL3wRLe5CDmy4hNsU0Iq3xxeel + 7B4f/CMkY+F7WXBbFwsi0cLf0gfN+VOMcFR9 + 700/L99AUw8ofRkH7sWNj0sfHB/CHSC38980 + u+n453MvcT31Svt6GwBVtt75ZOc= ) +7GD2384TAD22TQJ5ULAC03C93FO12QF0.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 7NS0GBBS9N6L1E3OM48637F6HOKCOLQB + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + 4nqxLigxKw86DpZ0KAo/k0507oWoind1FOCV + GDJvF+YejkSuvJFpAtfVSUrw690XZ7+zyuoV + 05e7BH07rcJV9TeSTgWe86nIGegDr+yzZBEZ + 3eGsbCwHxrR9ROieVBxNpWnfkVrA6MFqHZj1 + trAY6ajLrb/+kQEBaBdPC668tJE= ) +6T8FEOHJ6MH3O1N4B0H6AES9842FDUSS.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 74EBGC37NAC14CAFDT47M48A5JSFFSL2 DNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + i0z9WCo2snvGjQJvl2ZOkzg0PwCBuCPlDZ2U + NTbw3k/P4N90yVYu7IuJVEOuwPNaKHzBnz1u + 2vzYxM/fJHkWi4FljRFGGHC2ViBKJS+li5FK + KVUXwqZCHWlEc5tZ6lrpFTv5Q7h0zC6M3gSt + kBl8r8CZY75Yls/xGk7NZDd40R0= ) +7NS0GBBS9N6L1E3OM48637F6HOKCOLQB.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 80I3RRJLHHEFK8HQHD2A8O6VBHGKBSJ7 + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + VXcnf/ptpsoJgahBd0QYFkxBqyBE7ZOPNFJO + jT/fh6syVGIuV/FVSPY5c24RTs0pU59FPW1e + Ce1bDLWR30pyZfXBrwLmvjwn6XA+RhYtlBu2 + vE31i9zr8pSnZ3GU553zE/30J3ggO+WLQy6f + sLMmPynGnACOMz8hwvAuqATLswA= ) +9LF5T2M8139TAUL9LBR53N1RLU9BLIFG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 9T92PKASBK46QUITTDHH5T7U73HFLO9A + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + vJJLcMmUHJIKxBS1a33EljJpocAmudNOZJ1k + KKpoHIfhN2U4b2GbaAQRbPIttDW14dmwuqZg + pi//Vm5krSx1PrVWoaCwvyn/9Fey3PcY4zWX + Rj5m/zgMrqnK8mVdnCVTcSVwlgpcJrpiYxxA + 5/Lj2MsiY9vf2Gk9kcYqyg09iqg= ) +4F4ISAF7SLHE2FVS6IH2N1HHOCVUTMTN.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 6A3ESFQICSC9TLOHO0P20QB3T0H8DHNT CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + QO6x9M8tKx9nEwTGTLOmWJm2ReQWdDJq/s8x + CyLc8W1v38iqMgP/X0e+un2MicXkG9Xx6bn/ + KBCMVx16q9MFfpdyQaxvc3w0ZvRliAupP9iH + pFS5igBe/BAnUS7O6jjAaY03frbz+JaAmNUU + qbyEm+nfWWDWmPpVgU9qMTh4Iz8= ) +9T92PKASBK46QUITTDHH5T7U73HFLO9A.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 B939IPLCHDGHKH64CLV0F799P2QFKODM DNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + b08XgQYnvasffMbun6yS0gohnuJL2TklNPf8 + AA+2g036YcXQeLTHHMgzgxrpUTKVAnBP8G4U + gWD+xRwsys2q4Ws14oG9SAos+YEcus8AGs+7 + AFtHyOyBmRwOgP90Iu4W27bpIYf8D0mTC/vL + JDFkAVYzcL5DW7Rx+pr2F8bqY3I= ) +C8BNH0HKUBJF5F9Q6TV3BLVDP2H05C7D.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 DB9UE21NARLOFV0U06U8CMVKP4GNC10K NS + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + bxfqIBTAIogKzXbyqPnlv+MFIyoYlIT6knm7 + F6BZp9Q0VXNgVM6dEU0THhIzPvaMszn55Tg/ + lEohKrDuFWgbEbWpA9CQEm3LFLVg9QYuYl4j + 3Glym7TdGl3PDGagEpmHvLHx4gKbnqZWtN6J + uudu2UAlp8EUP4BWwsCsbnzLk2g= ) +80I3RRJLHHEFK8HQHD2A8O6VBHGKBSJ7.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 9LF5T2M8139TAUL9LBR53N1RLU9BLIFG CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + A2sU+74sIE4X4Ai2pzJPngzssUG9q6FTrBA2 + ZcvOZtkzS1hY9OafSHoyKonqlRC9A+tX8Ny0 + by2M66eX4NvlinGyBJWdC5Ekj1b5cMy6Pcig + zcMAGsj91MZOqA8gwKiJ8xRGF/LUf1YdlQAb + qD2MLj83BSzg2m5lXl9EVMLmQwg= ) +DB9UE21NARLOFV0U06U8CMVKP4GNC10K.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 DE3D7U7081COUA3PSVT8MLFDGNGNMUTN A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + VPzYwah96Z+CrgO1cgRHzAe6DCDbn0wxGvfS + X7suIoXVhz71+PCksxmBzXCjEX8hkta8bfgy + KEweSDw/PAGeBq/gktmx4XravfhSrvcdxfyC + jaJQDfKvf//iJKujR4sP1crWnTNKXNLNO4io + AKiecOcs5L7FFLf/mG/tkRrZD4g= ) +2E74KFMC0MPQFVMLM1UD7O7HCEUV01TQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2FIB35726VOBGISOGPQLFO6O5IRN3M0G A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + k4LLw681oD7qIr/GUupQFuOlbUJe0XkH5YHB + hG19hIy4BXPGYI0UEaxLnPcLsvhLgb+sdWTG + JL1JrRcCMRne0zNMY28sAzO1npbtN9pd9oK5 + ZYe5OK6wXpIvziGdJ/2eUVEmV+NrSJREgPbO + krsX8SxFss/S5i3C+UoWHQd9LoU= ) +EE6P9GRHC60PKN1E34GP2GFODTK9ABNL.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 ER30P5E30F7PBIBO9JHDUD2ATC20OKNQ NS + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + N1IBfELSSlFUJwA9WBo0CtNHwvsWrDnVTUGv + Cdfz3mp4H1CIUtKx36zX4CJeVXtwc+zWgKki + WZvpc00L+uvP6tIyMwGeshjd4etY5DqbnIuH + mCbIxGpVqgjhcAahCogG0kHBnNWkHYD37SZ7 + 9J/uwMoNHUGqpEKiy9PeIHfX3zw= ) +GDU5SE9F3JUO6HF8AONHIVJI53NAE301.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 GJPHM3J2JR55KMCICU1NPT84KMP1C4UU CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + 1M5Lz9VF7zkSQWN+uUUHAvCIzj54/eRvqkkV + XLjviMkQ3G90qrS7Ro3FN35fbVdgn1sets/r + R87yO3TpgNwWjcBejT0KQXr3VI8me/Jr/yID + HlXpfkJZi7YfOs7Us7pKwlzXz6Ox90qtC0ce + 8WXbjdjrmdpiLAsdZxo1miQXTZA= ) +ER30P5E30F7PBIBO9JHDUD2ATC20OKNQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 GDU5SE9F3JUO6HF8AONHIVJI53NAE301 NS + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + TKkytnNfTi8pvoqjXO6V7CY20Zr9oosNb1/z + 3X7s5UBDZh5KR1aSDjFxt1FrY6+SJkTGHfC/ + 3pNerSIecbMJ5Y2crLJReXFt8zafrL6SLI/a + 2QwFVuqVWzacwN+0rSxCqcz1tUPcztv0KSv4 + 87yK39umtsKCQ76PaucVtj6DNYk= ) +GJPHM3J2JR55KMCICU1NPT84KMP1C4UU.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 HOJ16G88JKIIDO9ML2CJFV5SNJ8BFVEI A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + QYhzXTmXhrSEsN6ue8c0NgSTaLXVyauv8cTW + WA/Wa9MDa3+OzaI/X5VnDZOumbnAbX4p1EC3 + yHDrXC+QnQrgr6/Gj9rqCaNzyXKtmBYIGUvV + DZ4ZRayXeYc/18GgWrCx1gBTUsjsqy1ON/1K + i8R/aZhwzcUvWbqr1FlaTLSvk78= ) +HOJ16G88JKIIDO9ML2CJFV5SNJ8BFVEI.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 J2A0018O0QCSI08D608LDVJOLPTB3G96 CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + bnvyEDA/snJUVw5jBhdMZ0ajEE4kcfiXVSM/ + P/cKiCEMgR+xhDrz4sUSWitQHz75QXLybgSj + cjU1XrjGP53kWGb3YEtWaM+JaqV/1yZEdCDH + ny+zyxcI0foYPu/4r9uqTWB9VLIRHCQol7kJ + XHu88kXYdu44hdiqQf5E0+VSdfQ= ) +J2A0018O0QCSI08D608LDVJOLPTB3G96.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 K3MJD76QQQ6H0RKERHB88S6LHEHOMJRV + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + jIknVULnzmGn8B3LoTKcuU6ELNYyRLagrI37 + XrnvlLjxWcqNk8W5aiNcVMhfEjlu6F2zLGLU + 4K4KLV1efxNfJpcp5Ki0lNS+i3HB0rkg8dP2 + j+UCsQ9wHbwzZNSbDli3/kQzEwnHvuuy9f5t + WCEXC1dwVt0QDrVu9yNVgXuW5SI= ) +N9INKG4137UMU0NL0U8V5FOTD66UJQIN.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 OBT94VQ2BVN9NBPVL65OCARNBQ92R9NS A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + P0xnjLy1AbyOUDyM1lbApfQxQILKU9m3lVIR + 6a419fA3jkFcBoB3A5ReXWFUW+lYuVGAL7cX + na/QB4J+skak7oEUz03Hoctc3eCR/ud7vobY + QULzq+cHzFsDUFC3b8ie0NWMZH8GNRGeHS0T + FtlHk4mQofYwQkF9Dbzdwn327iE= ) +OBT94VQ2BVN9NBPVL65OCARNBQ92R9NS.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 ONKAPQRU8HJED18U7QPRPJA8GGKP5RCQ CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + uhM8yr7khK1/Ii3buLO+oHUY38t23CcSApyP + RUefb87LREQVtcNh26Oymd741/NfhvZmhop7 + Uvx0CxSICmjdV+u8Pm7/fbFK1Ha5m0/UvrUo + 0M4QNEGS8Jbs+xsshr8RbaBCpUStTCxz5og0 + E4lFekJEXuqT7wa/0TVBRyzWIQc= ) +DE3D7U7081COUA3PSVT8MLFDGNGNMUTN.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 EE6P9GRHC60PKN1E34GP2GFODTK9ABNL CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + onPGqq1wHK4TnzDM0stR93s5SsCWFMQh0l0u + 3lVmvEh8T93G7OpfSEhRoQ9td9o5NxHSR6V0 + 4xxgDxvnjgMMbvDvgyeHLtnmRaaJhC6xL6jy + 0UQYb0Dz5S5aGocR6tvgDu8vmDgEmTx7zMV7 + 8vdwz2epzT40MX0hGAw9YhYdQGk= ) +B939IPLCHDGHKH64CLV0F799P2QFKODM.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 C8BNH0HKUBJF5F9Q6TV3BLVDP2H05C7D A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + nUn1EpD0cHWC8C9RnfBt4wBepa+DGQFU3nKU + 2+75RSeL1ltptxuuUmhmiBindtODFY10rdtP + TecPL4dsG5CXIZzx1zO0OMJalYFyN3MAnZXS + ENv/K7bWTal6OqVjxsYfrCqCcEmYW+8+0b+1 + vUhfqqaIAdCgVGYrzXMDoQ80m0A= ) +ONKAPQRU8HJED18U7QPRPJA8GGKP5RCQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 PO4K5TL8FC932CHVR1339QMSVCG8TFE5 SRV RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + d+sbaGrwmTVOfTajPdsD9NHEUpLXjjJ94Rpp + 9HIvdJozkwPOP4nUt2lc3lZiJ1OhK/GbMkHZ + wFlkPKmGeBPoa6FARpYuFj1DtDZhWCd+mTH/ + VMSzGiX8InCQGoTTiufT1G4aSP21oY+UtduF + KHJYikaPULyWgWjbqOpoO0OxFtM= ) +Q373J0K0LKK0NE6QLDMCDUMUS4D7N9DF.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 Q89JNCJ55KEMLN012BN386RRG5V35MGG CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + ESQkjbD7LTon4QDSN6tZwU4ZaPopzvIXfJ5d + 3UorybWbBVrctR0AR4mvjuaY8jPuxjcn3awh + B/RwtlQ2oWrquPfFdinx60v6hmbhFJRSzIM7 + ob6tJObd6Be775r8M9N/aEi0ghtL7qv4BO0F + 3aoN1TKFHrFB58uyjmtNUBYtE2A= ) +Q89JNCJ55KEMLN012BN386RRG5V35MGG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 S6102U94KPK3HL2EEB1KU341JC2EMML8 + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + s9GsCDhpCzdFG/lnYS1EXxD1yqW1Rs8NFsZi + ht7zt0qu+AlxFXZ5Y9rC3joPYzoVgMH6f0h5 + WItWvGHQ8gBQgjel7ZAKVSAdinYcyvXyh/g5 + XQ2xwbDHi/Gx736y3SNW3Ivr3vRRNQ/ORJgt + SQ0ECCQbhRryNCz25SlDDAxbs6w= ) +PO4K5TL8FC932CHVR1339QMSVCG8TFE5.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 Q373J0K0LKK0NE6QLDMCDUMUS4D7N9DF A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + cz7WE3bqo5gy7MGC+CCp5rQq2OmWp1T0fb4z + SA3kxsMIEh8CDG9B3ETauKSvBokyLHT+WVC1 + z96F1BiIM+ZDey0IYRDc3EGYhNBgdNGGan7N + GvyGpzTlwhBZAZNvn0Ledn9W6dI8DLBWEIbl + LFaBFwOGseR2VUp2u7yla73QTP0= ) +SEF41HBES71QEAB5G8DV253ODMLDJS10.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 VCVTKD7HV5II9DCBRH6O7O0FL9NV6O88 A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + SWIZLy2XlDbDRqN7UPOrWMxnc5MHzfw12I8A + VKGdUlXhOVcVEwVVAk4A3bXihVMP5gG5Z6WU + sLYFe5TOBmz66OjRmGNVODQNHpacdHeDvjQo + f3KcbWbl8CGH+uLxjGGkTpZ8MhJ8vm9w9cBq + urAsJbO1zFHDJi8zi9dQknmfJcQ= ) +VEK49TJCDQQ7AFSAH0A8MMF4EPP0LVFE.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 0J3ID6U2GQUPOADI9B867SGMROP8U4Q0 + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + bSvFoFDIForjpYjxvmq7au1hq0oyL5mSC5zl + V/4WXGT9lAYk7wOZUA/8jsp0BGha9deH0G64 + fTAfxt0OOuwibgqjXOEL9ioJ+xjk0ut1YQqc + lLenWNE7986fNLKihLk6CTIzXDRORqOp1cS/ + 1ZmeKTA5zT8oM7FUwGmxPYLjozc= ) +S6102U94KPK3HL2EEB1KU341JC2EMML8.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 SEF41HBES71QEAB5G8DV253ODMLDJS10 CNAME RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + LMpezs03lkHxNunfHXUIqt5nOhUVclymGgvM + JCqFIDuUyhi6pcOPm4lxK5uPjxl4H5rdBRQ8 + k0H3Ms3a4u0/wCFVgoZxsmxRBKuuYg8Hy2DY + 1wA8xshYi//tMqpSfaPn1qWOQ4H3Lmk1QQ9d + 7oS5xbj8LbxgRy2nHIMq2Tu/PLA= ) +VCVTKD7HV5II9DCBRH6O7O0FL9NV6O88.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 VEK49TJCDQQ7AFSAH0A8MMF4EPP0LVFE A NS SOA MX RRSIG DNSKEY NSEC3PARAM + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + KtSNurYbgzIR4o419h/wdNPJmiCe/N6V8Qpn + lL5L/ZE5JqnAq2MKdybxHpSwojGR2pTGehMc + GV5NEWqyK2TPN8f9stwJ0bH6N1/ab5iXe6Kt + F8zHjWXMDt/dwtKspsTt1crkXaI4qduta4Rp + IKoL0b5PqVr3vA4hvwAwqgYe/Zk= ) +K3MJD76QQQ6H0RKERHB88S6LHEHOMJRV.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 N9INKG4137UMU0NL0U8V5FOTD66UJQIN A RRSIG + 3600 RRSIG NSEC3 8 3 3600 20110331084524 ( + 20110301084524 28635 example.com. + zyqm5HgDE1CUqpY2D/UcceQ7GmJZvyZn2uWd + 9S9/As+NIp/Pf90E6bnhpPu5Hn6H34xubnKk + G7qH3IE8JcohHw4zRIv1kW4u0CLikBbNq+1d + rDkWz/FDjsV5QR+nxLlaGwkO12wgDQYSZwNw + ja5DoRdcCKz2T1jKcQ+NNr0j0Cg= ) diff --git a/samples/example.com.zone.signed b/samples/example.com.zone.signed new file mode 100644 index 0000000..851cc13 --- /dev/null +++ b/samples/example.com.zone.signed @@ -0,0 +1,571 @@ +; File written on Thu Feb 17 11:19:57 2011 +; dnssec_signzone version 9.7.1-P2 +example.com. 3600 IN SOA ns.example.com. username.example.com. ( + 2007120711 ; serial + 86400 ; refresh (1 day) + 86400 ; retry (1 day) + 2419200 ; expire (4 weeks) + 3600 ; minimum (1 hour) + ) + 3600 RRSIG SOA 8 2 3600 20110319091957 ( + 20110217091957 20058 example.com. + T8PgPaLsdbkEfZvPHPvYV08y73yoEGqQuLOl + db4jvv48AUqt/Q/6dLMcWz6lpFDCEyf/9aCl + XVBhS+PAo3ex8lXye8MIyGvh5/yGFUveDHRM + TvigNYz3iJnJj6aK8nkSM29DUe92pkx2m76O + sT97uSoh+8FX8Vz4qRRBD6NwVIQ= ) + 3600 NS c.a.example.com. + 3600 NS ns.example.com. + 3600 NS ns.somewhere.com. + 3600 NS ns2.example.com. + 3600 RRSIG NS 8 2 3600 20110319091957 ( + 20110217091957 20058 example.com. + U8RogXPsS5rAUPbG0d8Wcvdk2NJ5ccvK4pda + jEfvIXXgZIib3T+gR+PwDuK4sMV2rQxsmcrr + qz3Vc15SQhyt+DAXVsrTojT8iu0NJXEZSr/H + ntPu2/BfVcHbq2wTu01QW1g9/ub0yUltbkcv + Mt8ZGiIyF5AoChy04SmZVlmuHSI= ) + 3600 A 10.0.0.1 + 3600 RRSIG A 8 2 3600 20110319091957 ( + 20110217091957 20058 example.com. + RXbKPkFlSJLiKoliNUC+tlPKru2UZfdksz63 + Jdla5qf+prYU5HZlvMLD/Fs3dSmK7vx5S6gh + 4pzWAtI0NZ7NoHSsxk/aztoASeal0On55yCt + 9lXRQ+Avzl7Z41fyFTTdu3GF+tOfAoPuTegL + qDLokpWQTRfABy8zFIQvVvLWAHY= ) + 3600 MX 10 mail.example.com. + 3600 MX 20 mail2.example.com. + 3600 MX 50 mail3.example.com. + 3600 RRSIG MX 8 2 3600 20110319091957 ( + 20110217091957 20058 example.com. + Skb7nbpNawsKpBZBC/4vVXUxioxbrPggr+Pv + EZzxrVcZN4PNL1vLQxWLKaZf9p0VWjFUh6Y7 + pyup5y8kL/y5PBM75jTIx+L95FlnB+Cef24c + z4f5eqGTteWxqBhp25ZNGNxs5lI6wWJkIObU + 2PHjtoZyXEGcYYQHtC5LQVQndbI= ) + 3600 NSEC *._tcp.example.com. A NS SOA MX RRSIG NSEC DNSKEY + 3600 RRSIG NSEC 8 2 3600 20110319091957 ( + 20110217091957 20058 example.com. + cM0Oa8GL61RYfdbLp3P6dH0gU2Yp1hsPvpkw + IBCcJ+0MNbZRxCTBnMBxt6VyBBAu9PPsTkgN + 1TdFmu1kD0fBP2bYAHrVg7xul7n9xoCKhWhx + x5Kj3bQCKlWL1AfhdH0fkXGyY4D8ufe4yItK + svm1y0TsIHnXO8aUrh+DOxyp4rE= ) + 3600 DNSKEY 256 3 8 ( + AwEAAbns20HerHdgnwqTXVG1a3764I7hVAzp + ahf9AF2dq+f+/aC8CWwow9BxU2uUSxDGj33c + 6LQLaJm9gx1y1o5lB/0iM4Oui6/xfx4xi5vR + SRE4fWPnWexH8SeHQgQOaq8ALUQGwIQ1l1bP + lWNKDg8AL1ohQERLQf0Skpgi9psrkPNR + ) ; key id = 46476 + 3600 DNSKEY 256 3 8 ( + AwEAAdC9GxD5zDPcTe6UdoZp+rm9EdFnV0mI + z/zFz8qRop9mLq/QBFaYsjpQdOahHQgk5FtH + OUywUaDKCorZuw8dH4iWpt/OqW79l8KMCNzd + xTV9Qky/ZRwO7Le/LbhsYgzw6eSE8d1xOUrb + 3w9PL8Zn5/059TE4yjmO8W73AZakgMtL + ) ; key id = 20058 + 3600 DNSKEY 257 3 8 ( + AwEAAdA0zDQsBM+2/OI8I1lAmAvdf8cB5jiS + wyyrjRjpWHlMQYiNXNTigb7fZdTx1SfX05Vf + yERfWy9ACRcssjf47rQLvmvE+sRAP7mOaRIY + 7CjD1kQCTYf3TybqAX5/MXZbl5OibvS4hpjj + SYO1lg/tITefq/Z1JpNUnyzwiuzQbu2MUytv + qqnkrVIBp0AmPenomFmaJ7chi3s9TMrkiBvc + 58S5a3jEvQR/U/B6hw1ruCP6EOhBg/KHApPn + eVHeMCtv7LLf1+xNQ2j6k3N5sCXQ89EooLO/ + WNsrCmbQE3zpwZsa7pCC8LW7YQowTtbjOIhZ + DsatvWPhGGUaCemoTt2ceH0= + ) ; key id = 49540 + 3600 RRSIG DNSKEY 8 2 3600 20110319091957 ( + 20110217091957 20058 example.com. + RW5kvcZuCmlM8DEb8teYpTRv8BCT87cvrlv2 + eJHlnIT03wjUVJx5pLr9gYrL1fjua4zGPLc6 + 8MjssdVoiHbYt7pZ9JVnGgrfTSMW5emkyu3+ + FazMDmCpMhy8GN6QyUADS9c12JkanNR+ugwW + i2IuR6VSZbBEbgK7wizdmu3yt58= ) + 3600 RRSIG DNSKEY 8 2 3600 20110319091957 ( + 20110217091957 49540 example.com. + AFg593dFrLP8EWKnKVQCpt+/rufL8mCTe/Ks + NozsesatF/B0LXkztK41wEFczeciTJOMlqcp + tbuaTUyiC0Lnz8yzAt1PRRxxZrjr8CVbwHDn + SodKElpfRA9MEFHEvphD7s8gnzCEVCQEw2zo + 8IbDapCNAADx8pDE976/ixKWca1XNbXGUUwv + LSKZ/pbNd4FCd8DqG3B7vcmVv8k5bGcJXdlU + v8OlI2rJXr9yVs4Tb/LgncLcDHOHg4TCKE5e + ssQ3qnAwC+PtJGMl+UF2Ar5Ue2JZXijkcgxx + fYYqB3yFaoxfn7neRE5CdALY+kMwv9ySkXWz + 1+D0NCjZGKIdnZCAcg== ) +*._tcp.example.com. 3600 IN SRV 0 0 0 . + 3600 RRSIG SRV 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + SZqwbOWOrGh0PB0st0OwVICwishDYIwM/VE1 + 3yp3/WboQFWESfrpv9QOfPD19yet97Zi17C/ + vQ7YifNWm/pKHOfvlgAMd5Y+Vku0Y7W85M5j + SsqjfDoiS6jPWKtHswVq8MRHIpRrCyLY7ZTM + fGp2A9SRGTa/vFyCgbvu76ampbs= ) + 3600 NSEC _foobar._tcp.example.com. SRV RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + B7lFuz7YrWCvuTs5wb0dA7a+FaKhzQnOYSAr + 4myC1mVFpRtTsk50n/NkUBTSDBoHjfDdlYU9 + DRBBct0PZTmRRv5EX0Eiw1BVs4mDa7WlYfFq + Xkc9nhY2jjOFbt8HTLsOdAahXV7VxQBHn8/w + ewrh0BvaM2Z/r4OHUqc2DVsgr2U= ) +a.example.com. 3600 IN A 10.0.0.4 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + KMwO1EvPdjDW7LJaKY85TPtUogFWA4IWQPvw + SKNX2aADOanzu/gnY2tVOhDq7mWJ9tQXlMtx + TwsAzcp+1PdEKCUjEBC53YQI/L1s3opKBl4S + HTLgGCKw5KhcALeWKGVJp4bbuuDFzmkpP3dw + DX41E74bR1qFeVofwcjuvQw45hw= ) + 3600 NSEC *.a.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + p09gsGkMo8QSE1ujTblgmpKqaOk6X5RXsIsi + 8oiOgpNiMfBIMAYNd4T8OqyAEoygvkqw4h/U + GuRSlSI1vFUzcsua+lVd9/WfbQ0gjWw9zzGL + rfku6PS+skQZPfZhkTh+a7TnUwoHb3K1sY5l + tM8Cph4mXhHJbiqxdAiQqjlSj7k= ) +*._udp.example.com. 3600 IN SRV 0 0 0 . + 3600 RRSIG SRV 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + IG3bi+NqZUHgSG0qyASuEc56z9HVV1/TMCUM + dMTBMfsMzG3LqI3qonhRGPelb9ELDlowKnXC + joMXetqLNPpsFsc6tO97yxmkDfAskAFpWmUu + UQ5lG5crlwJ+6PiVANXtrNNZnsMp/jiDFOoV + b7FrF48gfkt/8E6Mzq1nYKFn67I= ) + 3600 NSEC a.example.com. SRV RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + mQxN2DLH/YEO2bHnvKaHqhfJYkx3HHgqD8JM + fRbcRX/YDNY0oy0b7VNfN1J+4FYdCZ8r60eb + 39dFigjiSEXNXmi3SJ6X6irqv4ZOXwoxtjtk + CzQV5GsKXnERFcQ5SsCwSbFNik2R3gb3kYuW + qqvYpqPSVA+ScJ4cdNXODvL9zag= ) +_foobar._tcp.example.com. 3600 IN SRV 0 1 9 old-slow-box.example.com. + 3600 IN SRV 0 3 9 new-fast-box.example.com. + 3600 IN SRV 1 0 9 server.example.com. + 3600 IN SRV 1 0 9 sysadmins-box.example.com. + 3600 RRSIG SRV 8 4 3600 20110319091957 ( + 20110217091957 20058 example.com. + jIA+72DXdYMsWQ45Sv2MBg0rI3rv/7oEqoA0 + rJ9X4la9o/ozwca7CJE8HKP6l43gzns1pfZ7 + +QsYW5BJOOB8ov+cCEVBW9XY37naNa8fKUsK + Mpzo35gaQ1zi9+FnseAwZ0WAicl4+766p4iJ + MzDEZA9VXvSMq36i/v8c+VMxFP4= ) + 3600 NSEC *._udp.example.com. SRV RRSIG NSEC + 3600 RRSIG NSEC 8 4 3600 20110319091957 ( + 20110217091957 20058 example.com. + npUQV7MbigckrB6D4jshTkGpOvZY4XTulYP1 + EUjN7Ttr8i56UEon3zzVY2ZUK4McyNrkzWqg + KPoFNG8xwf4bI2+WxdJeYo45PPZsy6bDTbMu + lYc68hQ35r3ok32SPG4GMuV53iuSJBCNrM9o + Rat/FL4Qoqzy+sVk1+tnz2ShzqI= ) +*.a.example.com. 3600 IN A 10.0.0.5 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + iHMA40EdVEV0HIxDKbxcOe74roa7X3Vi+lpr + XGJWx0gbVVhMsGdXi8YycbWAyHvwxImiU/VT + ZcDiDExzH89XZbzmEtP5vjAOBaf9rQu7cFzC + mAekgEEccVYSt6QLJTxcdk97CDRNkbU1kd02 + J09lSSyQL8ATADXIlWFUfMC8Fx4= ) + 3600 NSEC c.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + NKYN+2bmtp/2Bfic6vBqWAC/ouTz4qEUgdw9 + a153VST6W3UpROG/xiKV/STmURt8oYIzHy42 + UDRp8DmuVRMgeP7CCCYDmFq1+hSHv7iia79k + bvrSqdEbfaAjBkHMPlJyd3VjqKz0L+Q7sOKP + pWKItsBruF9UTJMP0Y4WLCvsD1Y= ) +d.example.com. 3600 IN CNAME non-existing.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + KFfbRqMSwZOtr3plXJ2E9uKvEZjop9wpmq57 + EXq4Pus6pBhdPXXgwDo9/tDsTj6woScdlWyk + BsDYRIVfcu+jBbyTdFYSg2Em2A3XwtTxHD+s + wL3cRc7uKHs/FsWDVldxvrKy/ljX/kdmkiHN + xiRCWZsPa6kxB3/KtDRjYO6pkCM= ) + 3600 NSEC e.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + HbB+j61LK2AzrGmeLtVFRI4Ee+9dkh01xY44 + AHWKIEqqxRA95yOxWYDwVXXC4F1cO/UN0nAs + pTZekW8qb3vGrBUytno3mYZST+RHN8KcrWwL + n0nXsidEekA+ZGxRw7eltu8ECYX71C56bqp/ + DIilbcD1+bIyGxFHlYN77l+nVUw= ) +e.example.com. 3600 IN DNAME bogus25.com. + 3600 RRSIG DNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + SKLwv2FArbnNXXjaRxHsw3YcqYBxPNL/EETi + 6rKHVHHOgLN/IwQ6wLtmXZfRSV3Avw0pYmgt + 6hVda0mnJ8M4BPRal3z2cf9+PVX/f9kJWUNM + h1A/ibKKIwrhcdh4Z9s7QXGioE6WiEViG3zP + pfkajBllmOrE0pEH0YX1rWValCE= ) + 3600 NSEC f.example.com. DNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + swVPAYAboz3U8Y2Jcil1R6jUIAHggZlrs8I8 + ky7EAQTFYDRhLBC4UeGO+6DpkHAKCGepd2E7 + yojy/wttp4VhBxcaDGidc94z59Km/wuxF9Yk + cCYv7Ip6qLpk8L4CJOJvkFAGWTpkOYkA1qDR + tQ1IMSOsc6s1xaY9pd4vxmZkS4o= ) +c.example.com. 3600 IN CNAME c.a.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + hlO9jq8fIGbacLj9oYvwwyz65+z6ttWGg0Dh + wel26v08PEEJ19wVcZsXwiZi5ey9xaNG0OfC + z0xeH4XCOYaFGtKjSAqpT1FLGmcFOqhbGP2+ + 4pxICNlMonG+w/p7YePr5jyDILbTbUmp62Hc + ZoV+MVNvjFpDbxgHvCpFoGZguqs= ) + 3600 NSEC d.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + yTCDrpHhmnrwD8HxGPwPAXCmCik9aFyfESjW + 7bqrVgo8/pH57JJxGw1FVdoP46+ba1E0XRmo + zBdKKjum19SJBV5rzTFsJ58TDxsIeXWgwZgB + +RKY/peVIEfhuBHfLhdPocWB7rrk0dCDsLmN + FbmhtNkmXs9CKLYv/ucsXnEEyYU= ) +g.example.com. 3600 IN CNAME www.bogus25.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + PCl2njNFV8UQjnI5C5QUOE4IPETqM3orSN/e + B0WhX8QRvYRqJgayP07tjgaslUIzpAWo4t/J + +R1bjfkj4w0Kxk+eABUgyHBq4Cd1EO82L88L + DVvrDAXxg7Uw1dkeeN8y5ZuJ0tK71AE7XJ7u + YdTpbi7cfwcJuhRY45NbZDVtLd8= ) + 3600 NSEC f.g.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + zVhwl4EzpNuLNvPr5y5m8hIZyjhMzHSMNPQz + gMqljABxOeeNw3r5y9NZzm+6vczJVuJstrzr + n99bHnis0CX9QHZ9JMyZM2+qDLqvFccjAqTF + TwZBRhYODrI6u61DiRPCum8J2sIiEwIOVW8a + cDosel0Kz5cckjLJmyvew+vI2Hg= ) +f.example.com. 3600 IN CNAME e.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + QLcICtoOCD6eqtqDlawijBoRkruFxtOY2lv5 + nrkQoZa0zarM4Y8Zs05PPjMnFYd1kVgDgzNq + 4RU3jd0bMM6vdFBDfg/HV1OK98nvA9upuFOy + Mn4Ll98aSkZ9rBW2nHMK0gxClGZBRSU0983v + +vcSrrwK/Xr5MLYzJPCyMzmZjt0= ) + 3600 NSEC g.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + zWPwHGblevq/icAJ2PEB/Vrexdk78ZqkQ4fb + sfKxqHXoXlXvXSTgMd+8jD83rpCwS9ju3W1c + XF0qcrw7kWVDsjuZB4ynustAWXFa61+S93Tz + clXNNb0zRFFt/pfhMi/6MG8VL3lPZ3seRUAH + sNqUj9cD8J3ViCJ6S2tD0EaWdqI= ) +*.j.k.example.com. 3600 IN A 10.0.0.22 + 3600 RRSIG A 8 4 3600 20110319091957 ( + 20110217091957 20058 example.com. + AhY44yY5dbyJvWFfEjxhksL0Jr2hGy7LAwFS + nM1+xeU40Z4+xB+6NEiwu+aa52ylbHkGyp7W + seQ0+8DG9biYIFm4QiEud/jQQIDEqYk/oVVX + +aJmTYsJbZFVmffWK5oG+/ncP/xfLcnPQ7Zp + GAvKgnnxSr0B+FNsFGwFrAJpyy8= ) + 3600 NSEC h.i.j.k.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 4 3600 20110319091957 ( + 20110217091957 20058 example.com. + aS+Z3vh9yrxVIk5w2t5SfuSjY52ylTaKCFoq + QP5WiZ+Ce9K9E5kenfU3ugmKxU2Ocwl7491G + 7mYW9ZxfBRnqoA4WZtszDL5g/qGNS0UQm2q7 + 1tVkBQlMt5vXQO7e0mK0upZ2Y+6mllgvv5/x + EfICd8LbiJuD8PqrixsiTZRGzXk= ) +f.g.example.com. 3600 IN A 10.0.0.20 + 3600 RRSIG A 8 4 3600 20110319091957 ( + 20110217091957 20058 example.com. + EEOBQ2O31vmGHuj86oLBL5AmFAV7nVVxPjxI + +Xvru2Evbm2HJdZalcB8YwrFEdFGMpoxLpXo + FKevq2mGL0CfwifSfN6Z+lU6/m3JZQ5ugzXz + c6PFm/KDtCJtWkNIYtHGC4flj2rpMNlJ4ERm + /U/lfDy0PwPQ0QvYXZE8imXQsjw= ) + 3600 NSEC *.j.k.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 4 3600 20110319091957 ( + 20110217091957 20058 example.com. + knCwO1mKW8GKZr+jq0zT2FwlPwoK58GgvyGt + wvJmotKlu0pyYvVXeibowOxacDRx1SZA/Zue + nkA3dF83GWygxg36WjH3lyN+yaIFkuXtKYFH + nb/F6tIT6C26gnBJfMBKxm5mh6DqncIMFIad + p7ohHb/HKjj0CbGP55T6NV6OJdY= ) +*.l.example.com. 3600 IN CNAME c.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + bj2qkiCFVKzkmLafxnS70+gzkTErQgsJK1sl + SAxObFbBfG9eLGktw64k5XNSX1gK8cswj4Q0 + d/XkITXMf//rVgyRSXFkIRdalhW9VlkqNHll + muF5PQF3bqz1ec3aVYJoQJurnjKj9YIyCzNm + Y5gjwqB69xzc08hUM57WwS5PrYc= ) + 3600 NSEC mail.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + W5qj7ZHUIii8CR3sHkLc6ivln+AFK4SmxpjD + tgYUCWaUd8Y/ahldOzgCjzFY+I+hrUCifd1G + YLr0WtlNe/LgF9JhbiuIFg+SViBnLJzJAPR/ + yTr9qENKWQABvhmd5CfCsUAW/r8q5d+q4/9d + P7DfCX7FosksTkOuO5qSWFHiPAg= ) +h.i.j.k.example.com. 3600 IN A 10.0.0.21 + 3600 RRSIG A 8 6 3600 20110319091957 ( + 20110217091957 20058 example.com. + IfqXe0py5ug/bM3n+L8vIjgyEF+DPCkWZ1xj + LmHAYjBHW8fBnByoYNwSBayXJDzpVPrlGiGB + u7FC78yTqNeeGKgH72D7JgNybpEELpHY72+A + uYKOgizlOQn+172h5pmQcSNZjfRPVtK5wR3t + /ZOsz44siyNR3+TQEuDTnZnS59A= ) + 3600 NSEC *.l.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 6 3600 20110319091957 ( + 20110217091957 20058 example.com. + nTUAjiYPw6Gj+V+uz7gW27lYidi7Jgu1rTRY + 7GGZZHZRaFtoeM7ymSxZmlOdKrJxsjIhpXOC + ltU9dR0PJo1OnXKCQPrLjK3nIkNfGVcJU5Xj + MfNcdW6T1ursO2uZ7lrTOgBhSTxNNqiXln1d + HLwy1lHgTqNGg8QvdsbT1ixR3uE= ) +*.n.example.com. 3600 IN DNAME bogus25.com. + 3600 RRSIG DNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + gcuk3osH5dCvM2GgfVEogCuSNIQgQFAc+hY1 + igrm4uTT9Q+xrwRTKVqyaIZs/TovhKUS3npB + 4noVLbGJIlguztNvIgaB9wnam61NaFnBZRdW + 1guOnkExhSe/dTBupdEKVAw0WOrAOLlt06Fu + TFAAOBNo6384KB3aZ1RrKUu4Cqs= ) + 3600 NSEC new-fast-box.example.com. DNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + wMenqM3A9lWwZSHJz+7t0hBfTsB1JGK9qV9F + kGtJRNl0SuZA28bFRL0J5vSKj9tuB8EjCRdW + 2l885yaKKGSTF3aFzDnF2YW9mV6BadNGwdkC + +mYguk/tkPNW2TMdrYJC7StXKh8dOQIpT6/K + oc+ShVBYtQJocRy89hk9M4Ex9EA= ) +mail.example.com. 3600 IN A 10.0.0.3 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + ah9IQBB/moRnqRL9mug+9cEE6Pz1YbJMQkUg + yzTeh/09bh3POMn9eZqo5bBx6vlDsFgUbw6e + IclZY4rV4mUeIWz2kEW/ZHc2tADDYVHRTQAy + 4sy3g+tF3d8OxMQZ0v6J2MTN9DlpVCaxbjPp + sd0xjJ2uBmn81DKbaZ8UKA5ND1E= ) + 3600 NSEC *.n.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + oJMJsjzzNWihix6CeVihqCI/ByqU0qm+hDWX + mvgss0U8VXQ1o6oUJ2kXB9agzhRtzo+Z/5jU + 6zFYajcnzuwD62jmLbz5NAzcyZX+ejyHtt+d + /wlkYGrumY1B4qB0YGRji66Wo68BK11VZ+a4 + hjsW6qRyHsQeKus3BfdQ2DRHU2s= ) +ns.example.com. 3600 IN A 10.0.0.2 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + Lx5lSuiEjsbXrLW6PVIkoojgWfRTxIxdbVDv + 8lC5bUziKm41NQ0AVduIY/c08fBshJ83ylM1 + GqsZKwfqSszMIlHu3u5pONkMsYs7lxxYBdES + NZqEsTsaEmgnMlv6BM5cvstiJKVX7+z43y9j + XohTZ3G9UOv3B0uObMzabqweSfw= ) + 3600 NSEC ns2.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + rqlsD5SHTL9sXqlqBU/ZcAxn9pkKFZoRjAiB + kgdU8vExku+wGRbBB+c0toFbmPjJv1E4z9ae + fN3dfxCmIg049UspJUP0AqWOrtbQqqN2d3dl + ycJRw5Cpf7qOpp41EGJ/ujPzeIq6t0nW/m2P + JGkE9arlL8J802tFJKWn2aUc78Y= ) +o.example.com. 3600 IN CNAME a.e.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + fjrWtwXBv82jZ6BWeYlfxLqxOvaZNONWqiIF + 6p3NM4Nwv7O1BvI+Jr9MzxAkk3CkTynGIFQc + 2wFDrAlT6XnBjJmvNiGf45utlhkifEYOR2Vw + qR1O3o3x4XMc+gVrmhdMaYAabZnD6YYPEybM + 6dLzSDMg5K6GjLJglmimT0wfTcI= ) + 3600 NSEC old-slow-box.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + RwVHMNAd0Qdcu85znEzuhPF47UmoEZ0uBo0M + jd8ySEH07eV0lg9JOpzvdo3gUD6zyYs3xC1S + CO/RcTGIhEAfvkhV1N4/S5eQzUn3Cc5iaXUG + WQNpYuE2JKaLr3m3iGmxO2JqkE8YqTyK2WEf + rAL2SunFcKua1KHX959yNFGtou0= ) +new-fast-box.example.com. 3600 IN A 172.30.79.13 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + aeEl9FNzWG3QAPjDjCTZNMpO108nKfRqB8oW + Sw/e6Hynq4XKQuBBKNCvRBujuyrPMSuJdV1Z + xc1MGKMbSD1ZGyROhW+F1pTyRho1f3V4gmyI + 318iZuKxy+IbOVimYxXggM2xgkBgROOVI7r8 + slU5+SqZ3c/DfJn3cVHuevAI+wo= ) + 3600 NSEC ns.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + KF7gy4yC2SLwJvhCr/wBiNDWO68ypNu6EyBo + SyFnP3BsoZxsZvz3PYnG+slYAfMYqxfZAnEX + p8qMUQeWuZEzZLqmDw4/yrRupzjLDFE581vp + LVjUxYANKjOvYPbn+bPsuLKG2BuCcpyjLeEb + 4GrR1PBI6tRPfIyeUo1AUjXzlW8= ) +ns2.example.com. 3600 IN A 10.0.0.6 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + EjnIln97zP0GlFiF8J9HUuGBohcqvaAnCZUf + u9RuM4YhAijthrv+1vYJj9IKLE7JGXesVXcW + 6iLsddK05EA9UWcKhyOWrSIz2NmBBo0lj8uK + 7K/0zAvJ4uiSU+/CiGJBmzXxAQzC/gH4mU8k + vdpB7AufVUaKGDkB8203wk7LeiU= ) + 3600 NSEC o.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + cOxEjb/Aje8DI82rY7qNowoJ2VIiPOZIhlfr + MJMNDEiXBfbw+x53ewEj+YpnwwAAFWPrATtj + C/pEyxGCqwxEYkUCCTaM6YjhAKR0yPVJVkjY + GM1frct0/uOUuowalGf1SppZsxBKqv5cGq8o + x8GlBRNWt02ElyO2Wyy9k2TjKR4= ) +old-slow-box.example.com. 3600 IN A 172.30.79.11 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + ON91+7dJR8dAN2SUBZclVbrhRX8BOU5HLRYx + J8Iy4kiaPMNdLEHqXF2tK5FqSLKkZV9S6k1p + 5Hl1TUGYxVFq1+OxXpYzgk+Wy6QCW/sxWNky + ZpZ2X0ZzicI733kJ2YTZS8F7GaU053tCwOmY + wmLMKa6qd+FNh/xGLpUFrG6xRmo= ) + 3600 NSEC p.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + LFwXMS6XtokUOkda4DcVgSTNpuO2dhzUMbiu + LhfiYQ+nXn3Qwx0gORJZNdcMmUn3/j8dV/MN + Mfdil66OwG12ZNfi6LvLlj8DdMsBie/vHDLR + oUJUXdeQe5sM1rU+QoHfPCBXMWv5Bp6ZV8Wo + Bw1ASybab+P0JXWzlnKkfzgBUsg= ) +ns.sub.example.com. 3600 IN A 10.1.0.1 +sub.example.com. 3600 IN NS ns.sub.example.com. + 3600 NSEC sub2.example.com. NS RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + HjalhqyrN25GoPU0znzhzh58b7nM8N4mLKsE + bB+edEZOkM15enAhMeKzYWtUau9DTWwUC3Ip + DeLUT5XKEm91Ln0UnK7GKWfSPfVyTrpNOpKi + EnCUpk9yVC3OKkYt5jCTlP5HjuLRh7IJLpfd + RPtrJqJJSNmHt2vFoSdMw54Z1Xk= ) +*.sub2.example.com. 3600 IN A 10.2.0.1 +sub2.example.com. 3600 IN NS ns.sub2.example.com. + 3600 NSEC sub3.example.com. NS RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + NdI/fYvlY5BQsIU98z37XRUtoYL+3d6NJBMn + erxI0rDgqceMFVI52Hl2POzqanYoqK9QEyWS + 9rnt6pKzCG3vZv7XcdyqFkP/sIoMNcevZw5/ + JJ172wyrfYRepkbQ20CL9KUGOyQaPJQs61wR + 1L/78YmA8QD+zduli61hwDRjN4Y= ) +p.example.com. 3600 IN CNAME a.sub.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + DQQ5JhXp1OUOTm6+Rtsb3idf0iO9PvuASLwU + 9tzKExU9piaTE7FQN95fq48Kv40iH3W7513p + JKbojGbZui2OR4l4V0gqDzP4MU0fhMi+kmt8 + oKhEY7FlOx09Ei9jS0wWYBnPAxIm5N1NSTbP + g5tQ7MWYtBNtyyrN9mSdicAaCvw= ) + 3600 NSEC server.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + LcvgnVSYj2bojkEPkHopvuwg097SLoVYVzDe + N9M4GbHYkPILrdevgmmNIhDw7FS5XJI4zVo9 + xvE+bUMK056uT+DmPSCJh36q9gt2bteSxbqb + yus9zWldGoUoQzwuvtWcjHwPtSnquL/16xUJ + 3FPwtqNGKw4Vx6zw5PXdY+jRTcs= ) +sub3.example.com. 3600 IN NS ns.sub2.example.com. + 3600 NSEC sub4.example.com. NS RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + QKnEmC9rfdkdEkLLKxcnm0EkAyW1QI56AuTG + +Mf2CoD+JHgf9dFKm9EOinM+pHcrlT6/XmUW + H2IKnWcoqs2B9Vrh9CeC9qXCnFxaNxgMG9hu + zg4H6LCW0pSKOoq8/KPCrtGGJTn6k8ck+qhP + hoz2O63tHuIpAtO6jcFL0B5jk7k= ) +sub4.example.com. 3600 IN NS ns.example.com. + 3600 NSEC sub5.example.com. NS RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + pFTM518iEalVbWIisYeXX0mfel5D3EeKL2tV + e547nz5STOOKeqhaFpwiEkBnvBvbUJLDpNJH + bTpR98BDLnLPhSuhdQy1uBhONl6vaI6o0+P1 + 2cDaDQWat7Qc0bt2FOjWfhwzEJznqUvHFW1E + 3umsEPEXcHR4fmdPNnpvCnuCYv8= ) +server.example.com. 3600 IN A 172.30.79.10 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + ptyuguf9rHSyP8q4a+ob+kNl4ns3ZNzOT2NZ + +9lZsqpbbe6D15/6AVZyEz7NjLsLbSTbmUxI + MKacxVRUbJS1vQ7pztP/Lms4W+LsmnXafH0d + Pyj1OpArqckA/zeX05RXizUfqmsWq5thTZZ8 + VMsCFImGqpi+p3wr6FFc6NkuvEE= ) + 3600 NSEC sub.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + Tv46nHdkqO+SBiFf3RtDnIbyom2qGJ8w+ftJ + EYNfIdIghrR45az4sE5Ax2OzbIDzDycJhu8i + dSaLEgWASatClQZvzysdqoVmM2ajD+MgKTpv + Djr5BRpLSQc/qfEINM5lus1Gy1UNruhYc7XV + ah4fr1LXSrPGoo3bPk5r9Sy2VKI= ) +sub5.example.com. 3600 IN CNAME sub3.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + AP1MAgDTW5UYOQGZe1kW9qJGNComeMgBtQtK + PzsIU9y2TyrcSbU4wB8JRFJ1hMZk5wlkUe5M + yhvKe55wvknSlWOR1AU0vks0kSzhoPxHPxEM + NpMBV/Dv7NCGivh7LMxr0ra7EENNr4Ojv1Bl + bUAj8VMuLir8xqv5z3LzWTEVQ/g= ) + 3600 NSEC sysadmins-box.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + u+ulC7UqLA754CiYgKQHXquGhHHHoF3SifcC + lVHj9OTLXomfJMDJX5UG5K3yODlokaYVWOZS + MDus3B0LdAVv0+rEEPNxVBZ+t6P5/4JufESK + JFvxL3pSIU1bIlUZ4VDzgg5h6rBnA/oFavCc + a8xgf6FDwRNWVxdWcSfH/dStCSk= ) +wwwtest.example.com. 3600 IN CNAME www.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + GNh/COVeSULHxFcEBE66wv56YHNAWsPuSF7C + Cl2rc0JXlOCDhUqKy7ZKFTbXMZi++upiHpwI + BBbYLb7mhpLr/zEaOJH8QdiHsE7+hkY7oe2e + Gz1rvDyjx4XSugVXHr97RhZI7UA4opECDrIv + 5p3nqGLutSWju/grR6+keppEfFk= ) + 3600 NSEC example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + sRklHhLmH7i22GH8W3j5N6qMrG0rEmUb2+d9 + QJVcnQCgwyeiO38DMN2Vvy8jqVgXN+C5uRHV + XcvUhJjyJ7x7zaxVKvncwlRBQkGj5hNmVCoJ + 4gpVzD3aerZ8fwwMUf+ETqBtbkBajsfayEXq + kpITfSd4Pi5IyVbIr420IconoPc= ) +sysadmins-box.example.com. 3600 IN A 172.30.79.12 + 3600 RRSIG A 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + ztrXayS9OAxxKPP2U6DxtU3VNQ+aauZXNB+l + lxhXm2j/dFo6j6eR1hnRfGx6UeauQAdeKQA3 + OKeNaar6KbH9rw/iwnZbErWQurdUNVYvxEHD + fRRBa1b6d/zkwPcbdT+pSIZVoRzt9LrWQuEd + 2Gk5cBl6RP2oKxulDeP5XWXpQN8= ) + 3600 NSEC www.example.com. A RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + D03U27J/Yoan06O1qYHavUBHZZapO/f0GR5j + OfNHxpEvsiQmekeJNtYD/pm3aQhXjn8GDh57 + yrN6TBmo4tleL9M0w5BTT4Bm7yHdg69T+DgW + cVvgqv2Vgq/zbIYJuBd21doDh2LrkHcMbTas + FSYHA6OV8p6DzkbkXL9oykq/LCo= ) +www.example.com. 3600 IN CNAME ns.example.com. + 3600 RRSIG CNAME 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + ElzpT92LMJmKZq37lHmE6tOFDjh3RBdW3wRF + M63YsLhlP0OFNsbFefBA9H6qQdlV/OlP9QYD + FRn6hWPkuoelvDjyNdVFPc6CZrns4+eU34Yg + aGPZoKVszovHu22Lr4soJnDFwRAJ/DXcHMCJ + EHMSQpTYIg7AuDaBg9j+LqCVKZs= ) + 3600 NSEC wwwtest.example.com. CNAME RRSIG NSEC + 3600 RRSIG NSEC 8 3 3600 20110319091957 ( + 20110217091957 20058 example.com. + ycFBDZT3AHzyCklFxMheOfRyehNZNZsXHJei + h6Fi9AChB05oLVsM1MZqVQj0LPfZC7bJENtJ + XNwNz/wOJIjX4OUSGQQvEBLa+bzMvBg9i3L1 + YduNOH1xHGYbYKvxUd5b84XsIu1VQdffWDoK + hkFCBPGlL+A8/5qPva1FFdk3s6Q= ) diff --git a/samples/knot.full.conf b/samples/knot.full.conf new file mode 100644 index 0000000..04fbe09 --- /dev/null +++ b/samples/knot.full.conf @@ -0,0 +1,250 @@ +# +# knot.sample.conf +# +# This is a sample configuration file for Knot DNS server. +# + +# This is a comment. + +# +# There are 4 main sections of this config file: +# system, zones, interfaces and log +# + +# Section 'system' contains general options for the server +system { + + # Identity of the server (see RFC 4892). Not used yet. + identity "I have no mouth and must scream"; + + # Version of the server (see RFC 4892). Not used yet. + version "0.1"; + + # Working directory of the server + # Used to store compiled zones and PID file + storage "/tmp/knot-sample"; + + # Number of workers per interface + # This option is used to force number of threads used per interface + # Default: unset (auto-estimates optimal value from the number of online CPUs) + workers 1; +} + +# Section 'keys' contains list of TSIG keys +keys { + + # TSIG key + # + # format: name key-type "<key>"; + # where key-type may be one of the following: + # hmac-md5 + # hmac-sha1 + # hmac-sha224 + # hmac-sha256 + # hmac-sha384 + # hmac-sha512 + # and <key> is the private key + key0.server0 hmac-md5 "Wg=="; + + # TSIG key for zone + key0.example.com hmac-md5 "==gW"; +} + +# Section 'interfaces' contains definitions of listening interfaces. +interfaces { + + # Interface entry + # + # Format 1: <name> { address <address>; [port <port>;] } + ipv4 { # <name> is an arbitrary symbolic name + address 127.0.0.1; # <address> may be ither IPv4 or IPv6 address + port 53531; # port is required for XFR/IN and NOTIFY/OUT + } + + # Format 2: <name> { address <address>@<port>; } + # shortipv4 { + # address 127.0.0.1@53532; + #} + + # Format 1 (IPv6 interface) + # ipv6 { + # address ::1@53533; + # } + + # Format 2 (IPv6 interface) + # ipv6b { + # address [::1]@53534; + # } + +} + +# Section 'remotes' contains symbolic names for remote servers. +# Syntax for 'remotes' is the same as for 'interfaces'. +remotes { + + # Remote entry + # + # Format 1: <name> { address <address>; [port <port>;] } + server0 { # <name> is an arbitrary symbolic name + address 127.0.0.1; # <address> may be ither IPv4 or IPv6 address + port 53531; # port is optional (default: 53) + key key0.server0; # (optional) specification of TSIG key associated for this remote + } + + # Format 2: <name> { address <address>@<port>; } + server1 { + address 127.0.0.1@53001; + } +} + +# Section 'zones' contains information about zones to be served. +zones { + + # Shared options for all listed zones + # + + # Enable semantic checks for all zones (if 'on') + # Possible values: on|off + # Default value: off + semantic-checks off; + + # NOTIFY response timeout + # Possible values: <1,...> (seconds) + # Default value: 60 + notify-timeout 60; + + # Number of retries for NOTIFY + # Possible values: <1,...> + # Default value: 5 + notify-retries 5; + + # Timeout for syncing changes from zone database to zonefile + # Possible values: <1..INT_MAX> (seconds) + # Default value: 1h (1 hour) + # It is also possible to suffix with unit size [s/m/h/d] + # f.e. 1s = 1 day, 1m = 1 minute, 1h = 1 hour, 1d = 1 day + zonefile-sync 1h; + + # File size limit for IXFR journal + # Possible values: <1..INT_MAX> + # Default value: N/A (infinite) + # It is also possible to suffix with unit size [k/M/G] + # f.e. 1k, 100M, 2G + ixfr-fslimit 1G; + + # Zone entry + # + # Format: <zone-name> { file "<path-to-zone-file>"; } + example.com { # <zone-name> is the DNS name of the zone (zone root) + # <path-to-zone-file> may be either absolute or relative, in which case + # it is considered relative to the current directory from which the server + # was started. + file "samples/example.com.zone"; + + # Enable zone semantic checks + # Possible values: on|off + # Default value: off + semantic-checks on; + + # NOTIFY response timeout (specific for current zone) + # Possible values: <1,...> (seconds) + # Default value: 60 + notify-timeout 60; + + # Number of retries for NOTIFY (specific for current zone) + # Possible values: <1,...> + # Default value: 5 + notify-retries 5; + + # Timeout for syncing changes from zone database to zonefile + # Possible values: <1..INT_MAX> (seconds) + # Default value: inherited from zones.zonefile-sync + # It is also possible to suffix with unit size [s/m/h/d] + # f.e. 1s = 1 day, 1m = 1 minute, 1h = 1 hour, 1d = 1 day + zonefile-sync 1h; + + # XFR master server + xfr-in server0; + + # ACL list of XFR slaves + xfr-out server0, server1; + + # ACL list of servers allowed to send NOTIFY queries + notify-in server0; + + # List of servers to send NOTIFY to + notify-out server0, server1; + } +} + +# Section 'log' configures logging of server messages. +# +# Logging recognizes 3 symbolic names of log devices: +# stdout - Standard output +# stderr - Standard error output +# syslog - Syslog +# +# In addition, arbitrary number of log files may be specified (see below). +# +# Log messages are characterized by severity and category. +# Supported severities: +# debug - Debug messages. Must be turned on at compile time. +# info - Informational messages. +# notice - Notices and hints. +# warning - Warnings. An action from the operator may be required. +# error - Recoverable error. Some action should be taken. +# fatal - Non-recoverable errors resulting in server shutdown. +# (Not supported yet.) +# all - All severities. +# +# Categories designate the source of the log message and roughly correspond +# to server modules +# Supported categories: +# server - Messages related to general operation of the server. +# zone - Messages related to zones, zone parsing and loading. +# answering - Messages regarding query processing and response creation. +# any - All categories +# +# More severities (separated by commas) may be listed for each category. +# All applicable severities must be listed. +# (I.e. specifying 'error' severity does mean: 'log error messages', +# and NOT 'log all messages of severity error and above'.) +# +# Default settings (in case there are no entries in 'log' section or the section +# is missing at all): +# +# stderr { any error; } +# syslog { any error; } +log { + + # Log entry + # + # Format 1: + # <log> { + # <category1> <severity1> [, <severity2> ...]; + # <category2> <severity1> [, <severity2> ...]; + # ... + # } + syslog { # <log> is a symbolic name of a log device (see above) + # log errors of any category + any error; # for <category> and <severity> see above + # log also warnings and notices from category 'zone' + zone warning, notice; + # log info from server + server info; + } + + # Log fatal, warnings and errors to stderr + stderr { + any error, warning; + } + + # Format 2: + # file <path> { + # <category1> <severity1> [, <severity2> ...]; + # <category2> <severity1> [, <severity2> ...]; + # } + file "/tmp/knot-sample/knotd.debug" { # <path> is absolute or relative path to log file + server debug; + } +} diff --git a/samples/knot.min.conf b/samples/knot.min.conf new file mode 100644 index 0000000..f9bc29c --- /dev/null +++ b/samples/knot.min.conf @@ -0,0 +1,30 @@ +# +# knot.min.conf +# +# This is a sample of a minimal configuration file for Knot DNS. +# +# For exhaustive list of all options see samples/knot.full.conf +# in the source directory. +# + +system { + identity "Knot DNS minimal configuration"; + storage "/tmp/knot-minimal"; +} + +interfaces { + ipv4 { address 127.0.0.1@53533; } +} + +zones { + example.com { + file "samples/example.com.zone"; + } +} + +log { + stdout { any info, notice; } + stderr { any debug, warning, error; } + syslog {} + file "/tmp/knot-minimal/knotd.log" { any all; } +} diff --git a/samples/knot.sample.conf.in b/samples/knot.sample.conf.in new file mode 100644 index 0000000..7084595 --- /dev/null +++ b/samples/knot.sample.conf.in @@ -0,0 +1,18 @@ +system { + identity "@package@ @version@"; + storage "@localstatedir@/@package@"; +} + +interfaces { + my-iface { address 127.0.0.1@5353; } +} + +zones { + example.com { + file "@sysconfdir@/example.com.zone"; + } +} + +log { + syslog { any warning, error; } +} diff --git a/scripts/parse_dump.py b/scripts/parse_dump.py new file mode 100755 index 0000000..d9cc44b --- /dev/null +++ b/scripts/parse_dump.py @@ -0,0 +1,145 @@ +#!/usr/bin/python +from scapy.all import * +from binascii import * +import base64 +import sys +import dns.rdata +import dns.rrset +from struct import * + +fr = open(sys.argv[1] + ".raw_data", 'wb') +fp = open(sys.argv[1] + ".parsed_data", 'wb') + +def chop_and_write_rr_query(rr): + name = dns.name.from_text(rr.qname) +# print rr.qname + + wire = name.to_wire() + fp.write(pack('B', len(wire))) +# print len(wire) + fp.write(wire) + fp.write(pack('H', rr.qtype)) + fp.write(pack('H', rr.qclass)) + +def chop_and_write_rr_response(rr): + name = dns.name.from_text(rr.rrname) +# print rr.rrname + + wire = name.to_wire() + fp.write(pack('B', len(wire))) + fp.write(wire) + fp.write(pack('H', rr.type)) + fp.write(pack('H', rr.rclass)) + fp.write(pack('L', rr.ttl)) + + try: + rdata = dns.rdata.from_wire(rr.rclass, rr.type, rr.rdata, 0, len(rr.rdata)) + fp.write(pack('H', len(rr.rdata))) +# print "type ", rr.type, "length ", len(rr.rdata) +# OPT has length 0 - it should have no rdata + rdata.to_wire(fp) + except: + + try: +# if rr.rdata[0] != '\#': + rdata = dns.rdata.from_text(rr.rclass, rr.type, rr.rdata) + try: + fp.write(pack('H', len(rdata))) + except: + # no length - no way to know wire length + try: +# print "unknown length for type", rr.type +# if rr.type == 2: +# fp.seek(1, 1) +# old = fp.tell() +# rdata.to_wire(fp) +# size = fp.tell() - old +# fp.seek(-(size + 1), 1) +# fp.write(pack('B', size)) +# fp.seek(0, 2) +# else: + rdata.to_wire(fp) + except Exception as e: + print 'Error, exiting: ', e + sys.exit(-1) + except Exception as e: + print 'Error,', e + print 'could not parse rdata type: ', rr.type + print 'dumping directly (hopefully it is SOA)' +# i need to do some kind of rollback here... + fp.write(pack('H', len(rr.rdata))) + fp.write(rr.rdata) + + + if rr.type == 50: + f = open('nsec3debug', 'wb') + rdata.to_wire(f) + f.close() + +def chop_and_write_section_response(section): + if section == None: + return + i = 0 + rr = section.getlayer(i); + while rr != None: + chop_and_write_rr_response(rr) + i += 1 + rr = section.getlayer(i) + +def chop_and_write_section_query(section): + if section == None: + return + i = 0 + rr = section.getlayer(i); + while rr != None: + chop_and_write_rr_query(rr) + i += 1 + rr = section.getlayer(i) + +def chop_and_write_packet(packet): + fp.write(pack('H', packet.id)) +# fp.write(pack('H', packet.qr)) +# fp.write(pack('H', packet.opcode)) +# fp.write(pack('H', packet.aa)) #TODO these are not uint16_t +# fp.write(pack('H', packet.rcode)) + fp.write(pack('H', packet.qdcount)) + fp.write(pack('H', packet.ancount)) + fp.write(pack('H', packet.nscount)) + fp.write(pack('H', packet.arcount)) + +#write query flag + fp.write(pack('H', packet.qr)) + + chop_and_write_section_query(packet.qd) + chop_and_write_section_response(packet.an) + chop_and_write_section_response(packet.ns) + chop_and_write_section_response(packet.ar) + +packets = rdpcap(sys.argv[1]) + +total_length = len(packets) + +fr.write(pack('L', total_length)) +fp.write(pack('L', total_length)) + +for packet in packets: + try: + data = a2b_hex(str(packet['DNS']).encode('hex')) + fr.write(pack('H', packet.qr)) + fr.write(pack('H', len(data))) + fr.write(data) + chop_and_write_packet(packet['DNS']) + except IndexError: + print 'non-DNS packet' + total_length -= 1 + +fr.seek(0) +fp.seek(0) + +fr.write(pack('L', total_length)) +fp.write(pack('L', total_length)) + +print 'written ', total_length, 'packets' + +fr.close() +fp.close() diff --git a/scripts/pcap2dnsp.py b/scripts/pcap2dnsp.py new file mode 100755 index 0000000..305f8bb --- /dev/null +++ b/scripts/pcap2dnsp.py @@ -0,0 +1,17 @@ +#!/usr/bin/python +from scapy.all import * +import sys + +nstypes = { 0:"ANY", 255:"ALL",1:"A", 2:"NS", 3:"MD", 4:"MD", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG", 9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT", 17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME"} + +a=rdpcap(sys.argv[1]); + +f=open(sys.argv[2], 'w'); + +for i in a: + try: + f.write(i[3].qname+' '+nstypes[i[3].qtype]+'\n') + except: + continue + +f.close() diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..3f65566 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,336 @@ +ACLOCAL_AMFLAGS = -I ../m4 +libexec_PROGRAMS = knot-zcompile unittests unittests-zcompile unittests-libknot-realdata unittests-libknot +sbin_PROGRAMS = knotc knotd +MANPAGES = knotc.8 knotd.8 +man8_MANS = knotc.8 knotd.8 +EXTRA_DIST = $(man8_MANS) + +# $(YACC) will generate header file +AM_CFLAGS = -Wall -Ilibknot -DLIBEXECDIR='"$(libexecdir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DSBINDIR='"$(sbindir)"' +AM_YFLAGS = -d +libknotd_la_YFLAGS = -pcf_ -d +libknotd_la_LFLAGS = # TODO: reentrant parser, prefix + +BUILT_SOURCES = \ + tests/libknot/parsed_data.rc \ + tests/libknot/realdata/parsed_data.rc \ + tests/libknot/raw_data_queries.rc \ + tests/libknot/raw_data.rc \ + tests/libknot/realdata/raw_data.rc \ + tests/libknot/parsed_data_queries.rc \ + tests/sample_conf.rc \ + zparser.h \ + zparser.c \ + zlexer.c \ + libknotd_la-cf-lex.c \ + libknotd_la-cf-parse.c \ + libknotd_la-cf-parse.h + +CLEANFILES = \ + tests/libknot/parsed_data.rc \ + tests/libknot/realdata/parsed_data.rc \ + tests/libknot/raw_data_queries.rc \ + tests/libknot/raw_data.rc \ + tests/libknot/realdata/raw_data.rc \ + tests/libknot/parsed_data_queries.rc \ + tests/sample_conf.rc \ + zparser.h \ + zparser.c \ + zlexer.c \ + libknotd_la-cf-lex.c \ + libknotd_la-cf-parse.c \ + libknotd_la-cf-parse.h + +knotc_SOURCES = \ + knot/ctl/knotc_main.c + +knot_zcompile_SOURCES = \ + zcompile/zcompile_main.c \ + zcompile/zcompile-error.c \ + zcompile/parser-util.h \ + zcompile/parser-descriptor.h \ + zcompile/zparser.y \ + zcompile/zlexer.l \ + zcompile/zcompile.c \ + zcompile/parser-util.c \ + zcompile/parser-descriptor.c + +unittests_SOURCES = \ + tests/common/acl_tests.c \ + tests/common/acl_tests.h \ + tests/common/da_tests.c \ + tests/common/da_tests.h \ + tests/common/events_tests.c \ + tests/common/events_tests.h \ + tests/common/skiplist_tests.c \ + tests/common/skiplist_tests.h \ + tests/common/slab_tests.c \ + tests/common/slab_tests.h \ + tests/common/fdset_tests.c \ + tests/common/fdset_tests.h \ + tests/knot/conf_tests.c \ + tests/knot/conf_tests.h \ + tests/knot/dthreads_tests.c \ + tests/knot/dthreads_tests.h \ + tests/knot/journal_tests.c \ + tests/knot/journal_tests.h \ + tests/knot/server_tests.c \ + tests/knot/server_tests.h \ + tests/unittests_main.c + +unittests_libknot_realdata_SOURCES = \ + tests/libknot/realdata/libknot/dname_tests_realdata.c \ + tests/libknot/realdata/libknot/response_tests_realdata.c \ + tests/libknot/realdata/libknot/edns_tests_realdata.c \ + tests/libknot/realdata/libknot/node_tests_realdata.c \ + tests/libknot/realdata/libknot/rdata_tests_realdata.c \ + tests/libknot/realdata/libknot/rrset_tests_realdata.c \ + tests/libknot/realdata/libknot/zone_tests_realdata.c \ + tests/libknot/realdata/libknot/zonedb_tests_realdata.c \ + tests/libknot/realdata/libknot/packet_tests_realdata.h \ + tests/libknot/realdata/libknot/packet_tests_realdata.c \ + tests/libknot/realdata/libknot_tests_loader_realdata.h \ + tests/libknot/realdata/libknot_tests_loader_realdata.c \ + tests/libknot/realdata/unittests_libknot_realdata.c + +unittests_libknot_SOURCES = \ + tests/libknot/libknot/cuckoo_tests.c \ + tests/libknot/libknot/cuckoo_tests.h \ + tests/libknot/libknot/response_tests.h \ + tests/libknot/libknot/response_tests.c \ + tests/libknot/libknot/dname_tests.c \ + tests/libknot/libknot/dname_tests.h \ + tests/libknot/libknot/dname_table_tests.h \ + tests/libknot/libknot/dname_table_tests.c \ + tests/libknot/libknot/nsec3_tests.h \ + tests/libknot/libknot/nsec3_tests.c \ + tests/libknot/libknot/packet_tests.h \ + tests/libknot/libknot/packet_tests.c \ + tests/libknot/libknot/query_tests.h \ + tests/libknot/libknot/query_tests.c \ + tests/libknot/libknot/edns_tests.c \ + tests/libknot/libknot/edns_tests.h \ + tests/libknot/libknot/node_tests.c \ + tests/libknot/libknot/node_tests.h \ + tests/libknot/libknot/rdata_tests.c \ + tests/libknot/libknot/rdata_tests.h \ + tests/libknot/libknot/rrset_tests.c \ + tests/libknot/libknot/rrset_tests.h \ + tests/libknot/libknot/zone_tests.c \ + tests/libknot/libknot/zone_tests.h \ + tests/libknot/libknot/zone_tree_tests.h\ + tests/libknot/libknot/zone_tree_tests.c \ + tests/libknot/libknot/zonedb_tests.c \ + tests/libknot/libknot/zonedb_tests.h \ + tests/libknot/unittests_libknot.c + +unittests_zcompile_SOURCES = \ + zcompile/parser-util.h \ + zcompile/parser-descriptor.h \ + zcompile/zcompile-error.c \ + zcompile/zparser.y \ + zcompile/zlexer.l \ + zcompile/zcompile.c \ + zcompile/parser-util.c \ + zcompile/parser-descriptor.c \ + zcompile/tests/unittests_zp_main.c + +nodist_unittests_SOURCES = \ + tests/libknot/parsed_data.rc \ + tests/libknot/raw_data_queries.rc \ + tests/libknot/raw_data.rc \ + tests/libknot/parsed_data_queries.rc \ + tests/sample_conf.rc + +knotd_SOURCES = \ + knot/main.c + +noinst_LTLIBRARIES = libknot.la libknotd.la libknots.la + +libknot_la_SOURCES = \ + libknot/util/libknot_error.c \ + libknot/util/utils.c \ + libknot/util/debug.c \ + libknot/util/debug.h \ + libknot/util/utils.h \ + libknot/util/descriptor.c \ + libknot/util/tolower.h \ + libknot/util/tolower.c \ + libknot/util/descriptor.h \ + libknot/util/wire.h \ + libknot/packet/query.c \ + libknot/packet/response.c \ + libknot/packet/packet.c \ + libknot/packet/packet.h \ + libknot/packet/query.h \ + libknot/packet/response.h \ + libknot/zone/zone.c \ + libknot/zone/zone-contents.c \ + libknot/zone/zone-tree.c \ + libknot/zone/zone-tree.h \ + libknot/zone/node.h \ + libknot/zone/zone.h \ + libknot/zone/zone-contents.h \ + libknot/zone/zonedb.c \ + libknot/zone/zonedb.h \ + libknot/zone/node.c \ + libknot/zone/dname-table.h \ + libknot/zone/dname-table.c \ + libknot/hash/hash-functions.c \ + libknot/hash/cuckoo-hash-table.c \ + libknot/hash/universal-system.c \ + libknot/hash/universal-system.h \ + libknot/hash/cuckoo-hash-table.h \ + libknot/hash/hash-functions.h \ + libknot/nameserver/name-server.h \ + libknot/nameserver/name-server.c \ + libknot/updates/changesets.h \ + libknot/updates/changesets.c \ + libknot/updates/xfr-in.h \ + libknot/updates/xfr-in.c \ + libknot/updates/ddns.h \ + libknot/updates/ddns.c \ + libknot/edns.c \ + libknot/rrset.c \ + libknot/dname.c \ + libknot/rdata.c \ + libknot/nsec3.c \ + libknot/consts.h \ + libknot/edns.h \ + libknot/rdata.h \ + libknot/libknot.h \ + libknot/dname.h \ + libknot/rrset.h \ + libknot/nsec3.h \ + libknot/tsig.h \ + libknot/tsig.c \ + libknot/tsig-op.h \ + libknot/tsig-op.c + +libknots_la_SOURCES = \ + common/slab/slab.c \ + common/slab/malloc.c \ + common/slab/slab.h \ + common/slab/malloc.h \ + common/libtap/tap.c \ + common/libtap/tap.h \ + common/libtap/tap_unit.h \ + common/lists.c \ + common/base32.c \ + common/lists.h \ + common/base32.h \ + common/print.c \ + common/print.h \ + common/dynamic-array.c \ + common/skip-list.c \ + common/base32hex.c \ + common/skip-list.h \ + common/general-tree.h \ + common/general-tree.c \ + common/dynamic-array.h \ + common/tree.h \ + common/base32hex.h \ + common/evqueue.h \ + common/evqueue.c \ + common/evsched.h \ + common/evsched.c \ + common/acl.h \ + common/acl.c \ + common/sockaddr.h \ + common/sockaddr.c \ + common/crc.h \ + common/crc.c \ + common/ref.h \ + common/ref.c \ + common/errors.h \ + common/errors.c \ + common/WELL1024a.h \ + common/WELL1024a.c \ + common/fdset.h \ + common/fdset.c \ + common/fdset_poll.h \ + common/fdset_poll.c \ + common/fdset_kqueue.h \ + common/fdset_kqueue.c \ + common/fdset_epoll.h \ + common/fdset_epoll.c + +libknotd_la_SOURCES = \ + knot/stat/gatherer.c \ + knot/stat/stat.c \ + knot/stat/gatherer.h \ + knot/stat/stat.h \ + knot/common.h \ + knot/other/log.c \ + knot/other/log.h \ + knot/other/debug.h \ + knot/other/error.h \ + knot/other/error.c \ + knot/conf/cf-parse.y \ + knot/conf/cf-lex.l \ + knot/conf/conf.c \ + knot/conf/logconf.c \ + knot/conf/logconf.h \ + knot/conf/conf.h \ + knot/ctl/process.c \ + knot/ctl/process.h \ + knot/server/dthreads.c \ + knot/server/journal.c \ + knot/server/socket.c \ + knot/server/server.c \ + knot/server/udp-handler.c \ + knot/server/tcp-handler.c \ + knot/server/xfr-handler.c \ + knot/server/zones.c \ + knot/server/socket.h \ + knot/server/udp-handler.h \ + knot/server/tcp-handler.h \ + knot/server/xfr-handler.h \ + knot/server/dthreads.h \ + knot/server/journal.h \ + knot/server/zones.h \ + knot/server/notify.h \ + knot/server/notify.c \ + knot/server/zones.h \ + knot/zone/zone-load.c \ + knot/zone/zone-load.h \ + knot/zone/zone-dump.c \ + knot/zone/zone-dump-text.c \ + knot/zone/zone-dump-text.h \ + knot/zone/zone-dump.h \ + knot/server/server.h + +libknotd_la_LIBADD = ../libknot/libknot.la libknots.la @LIBOBJS@ +libknots_la_LIBADD = @LIBOBJS@ +knotd_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@ +knotc_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@ +knot_zcompile_LDADD = libknots.la ../libknot/libknot.la libknotd.la @LIBOBJS@ +unittests_LDADD = libknotd.la libknots.la @LIBOBJS@ +unittests_zcompile_LDADD = ../libknot/libknot.la libknots.la libknotd.la @LIBOBJS@ +unittests_libknot_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@ +unittests_libknot_realdata_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@ + +# automake complains on % rules: +# `%'-style pattern rules are a GNU make extension + +tests/libknot/parsed_data.rc: tests/libknot/files/parsed_data + ../resource.sh tests/libknot/files/parsed_data >$@ + +tests/libknot/realdata/parsed_data.rc: tests/libknot/realdata/files/parsed_data + ../resource.sh tests/libknot/realdata/files/parsed_data >$@ + +tests/libknot/parsed_data_queries.rc: tests/libknot/files/parsed_data_queries + ../resource.sh tests/libknot/files/parsed_data_queries >$@ + +tests/libknot/raw_data_queries.rc: tests/libknot/files/raw_data_queries + ../resource.sh tests/libknot/files/raw_data_queries >$@ + +tests/libknot/raw_data.rc: tests/libknot/files/raw_data + ../resource.sh tests/libknot/files/raw_data >$@ + +tests/libknot/realdata/raw_data.rc: tests/libknot/realdata/files/raw_data + ../resource.sh tests/libknot/realdata/files/raw_data >$@ + +tests/sample_conf.rc: tests/files/sample_conf + ../resource.sh tests/files/sample_conf >$@ + diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..7811da5 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,2396 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +libexec_PROGRAMS = knot-zcompile$(EXEEXT) unittests$(EXEEXT) \ + unittests-zcompile$(EXEEXT) \ + unittests-libknot-realdata$(EXEEXT) unittests-libknot$(EXEEXT) +sbin_PROGRAMS = knotc$(EXEEXT) knotd$(EXEEXT) +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in libknotd_la-cf-lex.c \ + libknotd_la-cf-parse.c libknotd_la-cf-parse.h zlexer.c \ + zparser.c zparser.h +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compiler_flags.m4 \ + $(top_srcdir)/m4/ax_ext.m4 \ + $(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libknot_la_LIBADD = +am_libknot_la_OBJECTS = libknot_error.lo utils.lo debug.lo \ + descriptor.lo tolower.lo query.lo response.lo packet.lo \ + zone.lo zone-contents.lo zone-tree.lo zonedb.lo node.lo \ + dname-table.lo hash-functions.lo cuckoo-hash-table.lo \ + universal-system.lo name-server.lo changesets.lo xfr-in.lo \ + ddns.lo edns.lo rrset.lo dname.lo rdata.lo nsec3.lo tsig.lo \ + tsig-op.lo +libknot_la_OBJECTS = $(am_libknot_la_OBJECTS) +libknotd_la_DEPENDENCIES = ../libknot/libknot.la libknots.la @LIBOBJS@ +am_libknotd_la_OBJECTS = gatherer.lo stat.lo log.lo error.lo \ + libknotd_la-cf-parse.lo libknotd_la-cf-lex.lo conf.lo \ + logconf.lo process.lo dthreads.lo journal.lo socket.lo \ + server.lo udp-handler.lo tcp-handler.lo xfr-handler.lo \ + zones.lo notify.lo zone-load.lo zone-dump.lo zone-dump-text.lo +libknotd_la_OBJECTS = $(am_libknotd_la_OBJECTS) +libknots_la_DEPENDENCIES = @LIBOBJS@ +am_libknots_la_OBJECTS = slab.lo malloc.lo tap.lo lists.lo base32.lo \ + print.lo dynamic-array.lo skip-list.lo base32hex.lo \ + general-tree.lo evqueue.lo evsched.lo acl.lo sockaddr.lo \ + crc.lo ref.lo errors.lo WELL1024a.lo fdset.lo fdset_poll.lo \ + fdset_kqueue.lo fdset_epoll.lo +libknots_la_OBJECTS = $(am_libknots_la_OBJECTS) +am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ + "$(DESTDIR)$(man8dir)" +PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS) +am_knot_zcompile_OBJECTS = zcompile_main.$(OBJEXT) \ + zcompile-error.$(OBJEXT) zparser.$(OBJEXT) zlexer.$(OBJEXT) \ + zcompile.$(OBJEXT) parser-util.$(OBJEXT) \ + parser-descriptor.$(OBJEXT) +knot_zcompile_OBJECTS = $(am_knot_zcompile_OBJECTS) +knot_zcompile_DEPENDENCIES = libknots.la ../libknot/libknot.la \ + libknotd.la @LIBOBJS@ +am_knotc_OBJECTS = knotc_main.$(OBJEXT) +knotc_OBJECTS = $(am_knotc_OBJECTS) +knotc_DEPENDENCIES = libknotd.la ../libknot/libknot.la libknots.la \ + @LIBOBJS@ $(am__empty) +am_knotd_OBJECTS = main.$(OBJEXT) +knotd_OBJECTS = $(am_knotd_OBJECTS) +knotd_DEPENDENCIES = libknotd.la ../libknot/libknot.la libknots.la \ + @LIBOBJS@ $(am__empty) +am_unittests_OBJECTS = acl_tests.$(OBJEXT) da_tests.$(OBJEXT) \ + events_tests.$(OBJEXT) skiplist_tests.$(OBJEXT) \ + slab_tests.$(OBJEXT) fdset_tests.$(OBJEXT) \ + conf_tests.$(OBJEXT) dthreads_tests.$(OBJEXT) \ + journal_tests.$(OBJEXT) server_tests.$(OBJEXT) \ + unittests_main.$(OBJEXT) +nodist_unittests_OBJECTS = +unittests_OBJECTS = $(am_unittests_OBJECTS) \ + $(nodist_unittests_OBJECTS) +unittests_DEPENDENCIES = libknotd.la libknots.la @LIBOBJS@ +am_unittests_libknot_OBJECTS = cuckoo_tests.$(OBJEXT) \ + response_tests.$(OBJEXT) dname_tests.$(OBJEXT) \ + dname_table_tests.$(OBJEXT) nsec3_tests.$(OBJEXT) \ + packet_tests.$(OBJEXT) query_tests.$(OBJEXT) \ + edns_tests.$(OBJEXT) node_tests.$(OBJEXT) \ + rdata_tests.$(OBJEXT) rrset_tests.$(OBJEXT) \ + zone_tests.$(OBJEXT) zone_tree_tests.$(OBJEXT) \ + zonedb_tests.$(OBJEXT) unittests_libknot.$(OBJEXT) +unittests_libknot_OBJECTS = $(am_unittests_libknot_OBJECTS) +unittests_libknot_DEPENDENCIES = ../libknot/libknot.la libknots.la \ + @LIBOBJS@ $(am__empty) +am_unittests_libknot_realdata_OBJECTS = \ + dname_tests_realdata.$(OBJEXT) \ + response_tests_realdata.$(OBJEXT) \ + edns_tests_realdata.$(OBJEXT) node_tests_realdata.$(OBJEXT) \ + rdata_tests_realdata.$(OBJEXT) rrset_tests_realdata.$(OBJEXT) \ + zone_tests_realdata.$(OBJEXT) zonedb_tests_realdata.$(OBJEXT) \ + packet_tests_realdata.$(OBJEXT) \ + libknot_tests_loader_realdata.$(OBJEXT) \ + unittests_libknot_realdata.$(OBJEXT) +unittests_libknot_realdata_OBJECTS = \ + $(am_unittests_libknot_realdata_OBJECTS) +unittests_libknot_realdata_DEPENDENCIES = ../libknot/libknot.la \ + libknots.la @LIBOBJS@ +am_unittests_zcompile_OBJECTS = zcompile-error.$(OBJEXT) \ + zparser.$(OBJEXT) zlexer.$(OBJEXT) zcompile.$(OBJEXT) \ + parser-util.$(OBJEXT) parser-descriptor.$(OBJEXT) \ + unittests_zp_main.$(OBJEXT) +unittests_zcompile_OBJECTS = $(am_unittests_zcompile_OBJECTS) +unittests_zcompile_DEPENDENCIES = ../libknot/libknot.la libknots.la \ + libknotd.la @LIBOBJS@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ || +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) +LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(LEX) $(LFLAGS) $(AM_LFLAGS) +YLWRAP = $(top_srcdir)/ylwrap +@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ || +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(YACC) $(YFLAGS) $(AM_YFLAGS) +SOURCES = $(libknot_la_SOURCES) $(libknotd_la_SOURCES) \ + $(libknots_la_SOURCES) $(knot_zcompile_SOURCES) \ + $(knotc_SOURCES) $(knotd_SOURCES) $(unittests_SOURCES) \ + $(nodist_unittests_SOURCES) $(unittests_libknot_SOURCES) \ + $(unittests_libknot_realdata_SOURCES) \ + $(unittests_zcompile_SOURCES) +DIST_SOURCES = $(libknot_la_SOURCES) $(libknotd_la_SOURCES) \ + $(libknots_la_SOURCES) $(knot_zcompile_SOURCES) \ + $(knotc_SOURCES) $(knotd_SOURCES) $(unittests_SOURCES) \ + $(unittests_libknot_SOURCES) \ + $(unittests_libknot_realdata_SOURCES) \ + $(unittests_zcompile_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +man8dir = $(mandir)/man8 +NROFF = nroff +MANS = $(man8_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIMD_FLAGS = @SIMD_FLAGS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I ../m4 +MANPAGES = knotc.8 knotd.8 +man8_MANS = knotc.8 knotd.8 +EXTRA_DIST = $(man8_MANS) + +# $(YACC) will generate header file +AM_CFLAGS = -Wall -Ilibknot -DLIBEXECDIR='"$(libexecdir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DSBINDIR='"$(sbindir)"' +AM_YFLAGS = -d +libknotd_la_YFLAGS = -pcf_ -d +libknotd_la_LFLAGS = # TODO: reentrant parser, prefix +BUILT_SOURCES = \ + tests/libknot/parsed_data.rc \ + tests/libknot/realdata/parsed_data.rc \ + tests/libknot/raw_data_queries.rc \ + tests/libknot/raw_data.rc \ + tests/libknot/realdata/raw_data.rc \ + tests/libknot/parsed_data_queries.rc \ + tests/sample_conf.rc \ + zparser.h \ + zparser.c \ + zlexer.c \ + libknotd_la-cf-lex.c \ + libknotd_la-cf-parse.c \ + libknotd_la-cf-parse.h + +CLEANFILES = \ + tests/libknot/parsed_data.rc \ + tests/libknot/realdata/parsed_data.rc \ + tests/libknot/raw_data_queries.rc \ + tests/libknot/raw_data.rc \ + tests/libknot/realdata/raw_data.rc \ + tests/libknot/parsed_data_queries.rc \ + tests/sample_conf.rc \ + zparser.h \ + zparser.c \ + zlexer.c \ + libknotd_la-cf-lex.c \ + libknotd_la-cf-parse.c \ + libknotd_la-cf-parse.h + +knotc_SOURCES = \ + knot/ctl/knotc_main.c + +knot_zcompile_SOURCES = \ + zcompile/zcompile_main.c \ + zcompile/zcompile-error.c \ + zcompile/parser-util.h \ + zcompile/parser-descriptor.h \ + zcompile/zparser.y \ + zcompile/zlexer.l \ + zcompile/zcompile.c \ + zcompile/parser-util.c \ + zcompile/parser-descriptor.c + +unittests_SOURCES = \ + tests/common/acl_tests.c \ + tests/common/acl_tests.h \ + tests/common/da_tests.c \ + tests/common/da_tests.h \ + tests/common/events_tests.c \ + tests/common/events_tests.h \ + tests/common/skiplist_tests.c \ + tests/common/skiplist_tests.h \ + tests/common/slab_tests.c \ + tests/common/slab_tests.h \ + tests/common/fdset_tests.c \ + tests/common/fdset_tests.h \ + tests/knot/conf_tests.c \ + tests/knot/conf_tests.h \ + tests/knot/dthreads_tests.c \ + tests/knot/dthreads_tests.h \ + tests/knot/journal_tests.c \ + tests/knot/journal_tests.h \ + tests/knot/server_tests.c \ + tests/knot/server_tests.h \ + tests/unittests_main.c + +unittests_libknot_realdata_SOURCES = \ + tests/libknot/realdata/libknot/dname_tests_realdata.c \ + tests/libknot/realdata/libknot/response_tests_realdata.c \ + tests/libknot/realdata/libknot/edns_tests_realdata.c \ + tests/libknot/realdata/libknot/node_tests_realdata.c \ + tests/libknot/realdata/libknot/rdata_tests_realdata.c \ + tests/libknot/realdata/libknot/rrset_tests_realdata.c \ + tests/libknot/realdata/libknot/zone_tests_realdata.c \ + tests/libknot/realdata/libknot/zonedb_tests_realdata.c \ + tests/libknot/realdata/libknot/packet_tests_realdata.h \ + tests/libknot/realdata/libknot/packet_tests_realdata.c \ + tests/libknot/realdata/libknot_tests_loader_realdata.h \ + tests/libknot/realdata/libknot_tests_loader_realdata.c \ + tests/libknot/realdata/unittests_libknot_realdata.c + +unittests_libknot_SOURCES = \ + tests/libknot/libknot/cuckoo_tests.c \ + tests/libknot/libknot/cuckoo_tests.h \ + tests/libknot/libknot/response_tests.h \ + tests/libknot/libknot/response_tests.c \ + tests/libknot/libknot/dname_tests.c \ + tests/libknot/libknot/dname_tests.h \ + tests/libknot/libknot/dname_table_tests.h \ + tests/libknot/libknot/dname_table_tests.c \ + tests/libknot/libknot/nsec3_tests.h \ + tests/libknot/libknot/nsec3_tests.c \ + tests/libknot/libknot/packet_tests.h \ + tests/libknot/libknot/packet_tests.c \ + tests/libknot/libknot/query_tests.h \ + tests/libknot/libknot/query_tests.c \ + tests/libknot/libknot/edns_tests.c \ + tests/libknot/libknot/edns_tests.h \ + tests/libknot/libknot/node_tests.c \ + tests/libknot/libknot/node_tests.h \ + tests/libknot/libknot/rdata_tests.c \ + tests/libknot/libknot/rdata_tests.h \ + tests/libknot/libknot/rrset_tests.c \ + tests/libknot/libknot/rrset_tests.h \ + tests/libknot/libknot/zone_tests.c \ + tests/libknot/libknot/zone_tests.h \ + tests/libknot/libknot/zone_tree_tests.h\ + tests/libknot/libknot/zone_tree_tests.c \ + tests/libknot/libknot/zonedb_tests.c \ + tests/libknot/libknot/zonedb_tests.h \ + tests/libknot/unittests_libknot.c + +unittests_zcompile_SOURCES = \ + zcompile/parser-util.h \ + zcompile/parser-descriptor.h \ + zcompile/zcompile-error.c \ + zcompile/zparser.y \ + zcompile/zlexer.l \ + zcompile/zcompile.c \ + zcompile/parser-util.c \ + zcompile/parser-descriptor.c \ + zcompile/tests/unittests_zp_main.c + +nodist_unittests_SOURCES = \ + tests/libknot/parsed_data.rc \ + tests/libknot/raw_data_queries.rc \ + tests/libknot/raw_data.rc \ + tests/libknot/parsed_data_queries.rc \ + tests/sample_conf.rc + +knotd_SOURCES = \ + knot/main.c + +noinst_LTLIBRARIES = libknot.la libknotd.la libknots.la +libknot_la_SOURCES = \ + libknot/util/libknot_error.c \ + libknot/util/utils.c \ + libknot/util/debug.c \ + libknot/util/debug.h \ + libknot/util/utils.h \ + libknot/util/descriptor.c \ + libknot/util/tolower.h \ + libknot/util/tolower.c \ + libknot/util/descriptor.h \ + libknot/util/wire.h \ + libknot/packet/query.c \ + libknot/packet/response.c \ + libknot/packet/packet.c \ + libknot/packet/packet.h \ + libknot/packet/query.h \ + libknot/packet/response.h \ + libknot/zone/zone.c \ + libknot/zone/zone-contents.c \ + libknot/zone/zone-tree.c \ + libknot/zone/zone-tree.h \ + libknot/zone/node.h \ + libknot/zone/zone.h \ + libknot/zone/zone-contents.h \ + libknot/zone/zonedb.c \ + libknot/zone/zonedb.h \ + libknot/zone/node.c \ + libknot/zone/dname-table.h \ + libknot/zone/dname-table.c \ + libknot/hash/hash-functions.c \ + libknot/hash/cuckoo-hash-table.c \ + libknot/hash/universal-system.c \ + libknot/hash/universal-system.h \ + libknot/hash/cuckoo-hash-table.h \ + libknot/hash/hash-functions.h \ + libknot/nameserver/name-server.h \ + libknot/nameserver/name-server.c \ + libknot/updates/changesets.h \ + libknot/updates/changesets.c \ + libknot/updates/xfr-in.h \ + libknot/updates/xfr-in.c \ + libknot/updates/ddns.h \ + libknot/updates/ddns.c \ + libknot/edns.c \ + libknot/rrset.c \ + libknot/dname.c \ + libknot/rdata.c \ + libknot/nsec3.c \ + libknot/consts.h \ + libknot/edns.h \ + libknot/rdata.h \ + libknot/libknot.h \ + libknot/dname.h \ + libknot/rrset.h \ + libknot/nsec3.h \ + libknot/tsig.h \ + libknot/tsig.c \ + libknot/tsig-op.h \ + libknot/tsig-op.c + +libknots_la_SOURCES = \ + common/slab/slab.c \ + common/slab/malloc.c \ + common/slab/slab.h \ + common/slab/malloc.h \ + common/libtap/tap.c \ + common/libtap/tap.h \ + common/libtap/tap_unit.h \ + common/lists.c \ + common/base32.c \ + common/lists.h \ + common/base32.h \ + common/print.c \ + common/print.h \ + common/dynamic-array.c \ + common/skip-list.c \ + common/base32hex.c \ + common/skip-list.h \ + common/general-tree.h \ + common/general-tree.c \ + common/dynamic-array.h \ + common/tree.h \ + common/base32hex.h \ + common/evqueue.h \ + common/evqueue.c \ + common/evsched.h \ + common/evsched.c \ + common/acl.h \ + common/acl.c \ + common/sockaddr.h \ + common/sockaddr.c \ + common/crc.h \ + common/crc.c \ + common/ref.h \ + common/ref.c \ + common/errors.h \ + common/errors.c \ + common/WELL1024a.h \ + common/WELL1024a.c \ + common/fdset.h \ + common/fdset.c \ + common/fdset_poll.h \ + common/fdset_poll.c \ + common/fdset_kqueue.h \ + common/fdset_kqueue.c \ + common/fdset_epoll.h \ + common/fdset_epoll.c + +libknotd_la_SOURCES = \ + knot/stat/gatherer.c \ + knot/stat/stat.c \ + knot/stat/gatherer.h \ + knot/stat/stat.h \ + knot/common.h \ + knot/other/log.c \ + knot/other/log.h \ + knot/other/debug.h \ + knot/other/error.h \ + knot/other/error.c \ + knot/conf/cf-parse.y \ + knot/conf/cf-lex.l \ + knot/conf/conf.c \ + knot/conf/logconf.c \ + knot/conf/logconf.h \ + knot/conf/conf.h \ + knot/ctl/process.c \ + knot/ctl/process.h \ + knot/server/dthreads.c \ + knot/server/journal.c \ + knot/server/socket.c \ + knot/server/server.c \ + knot/server/udp-handler.c \ + knot/server/tcp-handler.c \ + knot/server/xfr-handler.c \ + knot/server/zones.c \ + knot/server/socket.h \ + knot/server/udp-handler.h \ + knot/server/tcp-handler.h \ + knot/server/xfr-handler.h \ + knot/server/dthreads.h \ + knot/server/journal.h \ + knot/server/zones.h \ + knot/server/notify.h \ + knot/server/notify.c \ + knot/server/zones.h \ + knot/zone/zone-load.c \ + knot/zone/zone-load.h \ + knot/zone/zone-dump.c \ + knot/zone/zone-dump-text.c \ + knot/zone/zone-dump-text.h \ + knot/zone/zone-dump.h \ + knot/server/server.h + +libknotd_la_LIBADD = ../libknot/libknot.la libknots.la @LIBOBJS@ +libknots_la_LIBADD = @LIBOBJS@ +knotd_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@ +knotc_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@ +knot_zcompile_LDADD = libknots.la ../libknot/libknot.la libknotd.la @LIBOBJS@ +unittests_LDADD = libknotd.la libknots.la @LIBOBJS@ +unittests_zcompile_LDADD = ../libknot/libknot.la libknots.la libknotd.la @LIBOBJS@ +unittests_libknot_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@ +unittests_libknot_realdata_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@ +all: $(BUILT_SOURCES) config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .l .lo .o .obj .y +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status src/config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libknot.la: $(libknot_la_OBJECTS) $(libknot_la_DEPENDENCIES) + $(LINK) $(libknot_la_OBJECTS) $(libknot_la_LIBADD) $(LIBS) +libknotd_la-cf-parse.h: libknotd_la-cf-parse.c + @if test ! -f $@; then \ + rm -f libknotd_la-cf-parse.c; \ + $(MAKE) $(AM_MAKEFLAGS) libknotd_la-cf-parse.c; \ + else :; fi +libknotd.la: $(libknotd_la_OBJECTS) $(libknotd_la_DEPENDENCIES) + $(LINK) $(libknotd_la_OBJECTS) $(libknotd_la_LIBADD) $(LIBS) +libknots.la: $(libknots_la_OBJECTS) $(libknots_la_DEPENDENCIES) + $(LINK) $(libknots_la_OBJECTS) $(libknots_la_LIBADD) $(LIBS) +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexecdir)" && rm -f $$files + +clean-libexecPROGRAMS: + @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +zparser.h: zparser.c + @if test ! -f $@; then \ + rm -f zparser.c; \ + $(MAKE) $(AM_MAKEFLAGS) zparser.c; \ + else :; fi +knot-zcompile$(EXEEXT): $(knot_zcompile_OBJECTS) $(knot_zcompile_DEPENDENCIES) + @rm -f knot-zcompile$(EXEEXT) + $(LINK) $(knot_zcompile_OBJECTS) $(knot_zcompile_LDADD) $(LIBS) +knotc$(EXEEXT): $(knotc_OBJECTS) $(knotc_DEPENDENCIES) + @rm -f knotc$(EXEEXT) + $(LINK) $(knotc_OBJECTS) $(knotc_LDADD) $(LIBS) +knotd$(EXEEXT): $(knotd_OBJECTS) $(knotd_DEPENDENCIES) + @rm -f knotd$(EXEEXT) + $(LINK) $(knotd_OBJECTS) $(knotd_LDADD) $(LIBS) +unittests$(EXEEXT): $(unittests_OBJECTS) $(unittests_DEPENDENCIES) + @rm -f unittests$(EXEEXT) + $(LINK) $(unittests_OBJECTS) $(unittests_LDADD) $(LIBS) +unittests-libknot$(EXEEXT): $(unittests_libknot_OBJECTS) $(unittests_libknot_DEPENDENCIES) + @rm -f unittests-libknot$(EXEEXT) + $(LINK) $(unittests_libknot_OBJECTS) $(unittests_libknot_LDADD) $(LIBS) +unittests-libknot-realdata$(EXEEXT): $(unittests_libknot_realdata_OBJECTS) $(unittests_libknot_realdata_DEPENDENCIES) + @rm -f unittests-libknot-realdata$(EXEEXT) + $(LINK) $(unittests_libknot_realdata_OBJECTS) $(unittests_libknot_realdata_LDADD) $(LIBS) +unittests-zcompile$(EXEEXT): $(unittests_zcompile_OBJECTS) $(unittests_zcompile_DEPENDENCIES) + @rm -f unittests-zcompile$(EXEEXT) + $(LINK) $(unittests_zcompile_OBJECTS) $(unittests_zcompile_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WELL1024a.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32hex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/changesets.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuckoo-hash-table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuckoo_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/da_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ddns.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname-table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname_table_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dthreads.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dthreads_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynamic-array.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/events_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evqueue.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evsched.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_epoll.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_kqueue.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_poll.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gatherer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/general-tree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-functions.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/journal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/journal_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/knotc_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknot_error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknot_tests_loader_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknotd_la-cf-lex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknotd_la-cf-parse.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lists.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logconf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/name-server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser-descriptor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser-util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdata.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdata_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdata_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ref.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrset.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrset_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrset_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/skip-list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/skiplist_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slab.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slab_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockaddr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcp-handler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tolower.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig-op.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/udp-handler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_libknot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_libknot_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_zp_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/universal-system.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfr-handler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfr-in.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zcompile-error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zcompile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zcompile_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zlexer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-contents.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-dump-text.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-dump.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-load.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-tree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone_tree_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonedb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonedb_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonedb_tests_realdata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zones.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zparser.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libknot_error.lo: libknot/util/libknot_error.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot_error.lo -MD -MP -MF $(DEPDIR)/libknot_error.Tpo -c -o libknot_error.lo `test -f 'libknot/util/libknot_error.c' || echo '$(srcdir)/'`libknot/util/libknot_error.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libknot_error.Tpo $(DEPDIR)/libknot_error.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/libknot_error.c' object='libknot_error.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot_error.lo `test -f 'libknot/util/libknot_error.c' || echo '$(srcdir)/'`libknot/util/libknot_error.c + +utils.lo: libknot/util/utils.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils.lo -MD -MP -MF $(DEPDIR)/utils.Tpo -c -o utils.lo `test -f 'libknot/util/utils.c' || echo '$(srcdir)/'`libknot/util/utils.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/utils.Tpo $(DEPDIR)/utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/utils.c' object='utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils.lo `test -f 'libknot/util/utils.c' || echo '$(srcdir)/'`libknot/util/utils.c + +debug.lo: libknot/util/debug.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT debug.lo -MD -MP -MF $(DEPDIR)/debug.Tpo -c -o debug.lo `test -f 'libknot/util/debug.c' || echo '$(srcdir)/'`libknot/util/debug.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/debug.Tpo $(DEPDIR)/debug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/debug.c' object='debug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o debug.lo `test -f 'libknot/util/debug.c' || echo '$(srcdir)/'`libknot/util/debug.c + +descriptor.lo: libknot/util/descriptor.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT descriptor.lo -MD -MP -MF $(DEPDIR)/descriptor.Tpo -c -o descriptor.lo `test -f 'libknot/util/descriptor.c' || echo '$(srcdir)/'`libknot/util/descriptor.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/descriptor.Tpo $(DEPDIR)/descriptor.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/descriptor.c' object='descriptor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o descriptor.lo `test -f 'libknot/util/descriptor.c' || echo '$(srcdir)/'`libknot/util/descriptor.c + +tolower.lo: libknot/util/tolower.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tolower.lo -MD -MP -MF $(DEPDIR)/tolower.Tpo -c -o tolower.lo `test -f 'libknot/util/tolower.c' || echo '$(srcdir)/'`libknot/util/tolower.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tolower.Tpo $(DEPDIR)/tolower.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/tolower.c' object='tolower.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tolower.lo `test -f 'libknot/util/tolower.c' || echo '$(srcdir)/'`libknot/util/tolower.c + +query.lo: libknot/packet/query.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT query.lo -MD -MP -MF $(DEPDIR)/query.Tpo -c -o query.lo `test -f 'libknot/packet/query.c' || echo '$(srcdir)/'`libknot/packet/query.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/query.Tpo $(DEPDIR)/query.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/packet/query.c' object='query.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o query.lo `test -f 'libknot/packet/query.c' || echo '$(srcdir)/'`libknot/packet/query.c + +response.lo: libknot/packet/response.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response.lo -MD -MP -MF $(DEPDIR)/response.Tpo -c -o response.lo `test -f 'libknot/packet/response.c' || echo '$(srcdir)/'`libknot/packet/response.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response.Tpo $(DEPDIR)/response.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/packet/response.c' object='response.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response.lo `test -f 'libknot/packet/response.c' || echo '$(srcdir)/'`libknot/packet/response.c + +packet.lo: libknot/packet/packet.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet.lo -MD -MP -MF $(DEPDIR)/packet.Tpo -c -o packet.lo `test -f 'libknot/packet/packet.c' || echo '$(srcdir)/'`libknot/packet/packet.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet.Tpo $(DEPDIR)/packet.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/packet/packet.c' object='packet.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet.lo `test -f 'libknot/packet/packet.c' || echo '$(srcdir)/'`libknot/packet/packet.c + +zone.lo: libknot/zone/zone.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone.lo -MD -MP -MF $(DEPDIR)/zone.Tpo -c -o zone.lo `test -f 'libknot/zone/zone.c' || echo '$(srcdir)/'`libknot/zone/zone.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone.Tpo $(DEPDIR)/zone.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zone.c' object='zone.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone.lo `test -f 'libknot/zone/zone.c' || echo '$(srcdir)/'`libknot/zone/zone.c + +zone-contents.lo: libknot/zone/zone-contents.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-contents.lo -MD -MP -MF $(DEPDIR)/zone-contents.Tpo -c -o zone-contents.lo `test -f 'libknot/zone/zone-contents.c' || echo '$(srcdir)/'`libknot/zone/zone-contents.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-contents.Tpo $(DEPDIR)/zone-contents.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zone-contents.c' object='zone-contents.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-contents.lo `test -f 'libknot/zone/zone-contents.c' || echo '$(srcdir)/'`libknot/zone/zone-contents.c + +zone-tree.lo: libknot/zone/zone-tree.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-tree.lo -MD -MP -MF $(DEPDIR)/zone-tree.Tpo -c -o zone-tree.lo `test -f 'libknot/zone/zone-tree.c' || echo '$(srcdir)/'`libknot/zone/zone-tree.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-tree.Tpo $(DEPDIR)/zone-tree.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zone-tree.c' object='zone-tree.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-tree.lo `test -f 'libknot/zone/zone-tree.c' || echo '$(srcdir)/'`libknot/zone/zone-tree.c + +zonedb.lo: libknot/zone/zonedb.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb.lo -MD -MP -MF $(DEPDIR)/zonedb.Tpo -c -o zonedb.lo `test -f 'libknot/zone/zonedb.c' || echo '$(srcdir)/'`libknot/zone/zonedb.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb.Tpo $(DEPDIR)/zonedb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zonedb.c' object='zonedb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb.lo `test -f 'libknot/zone/zonedb.c' || echo '$(srcdir)/'`libknot/zone/zonedb.c + +node.lo: libknot/zone/node.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node.lo -MD -MP -MF $(DEPDIR)/node.Tpo -c -o node.lo `test -f 'libknot/zone/node.c' || echo '$(srcdir)/'`libknot/zone/node.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node.Tpo $(DEPDIR)/node.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/node.c' object='node.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node.lo `test -f 'libknot/zone/node.c' || echo '$(srcdir)/'`libknot/zone/node.c + +dname-table.lo: libknot/zone/dname-table.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname-table.lo -MD -MP -MF $(DEPDIR)/dname-table.Tpo -c -o dname-table.lo `test -f 'libknot/zone/dname-table.c' || echo '$(srcdir)/'`libknot/zone/dname-table.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname-table.Tpo $(DEPDIR)/dname-table.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/dname-table.c' object='dname-table.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname-table.lo `test -f 'libknot/zone/dname-table.c' || echo '$(srcdir)/'`libknot/zone/dname-table.c + +hash-functions.lo: libknot/hash/hash-functions.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hash-functions.lo -MD -MP -MF $(DEPDIR)/hash-functions.Tpo -c -o hash-functions.lo `test -f 'libknot/hash/hash-functions.c' || echo '$(srcdir)/'`libknot/hash/hash-functions.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/hash-functions.Tpo $(DEPDIR)/hash-functions.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/hash/hash-functions.c' object='hash-functions.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hash-functions.lo `test -f 'libknot/hash/hash-functions.c' || echo '$(srcdir)/'`libknot/hash/hash-functions.c + +cuckoo-hash-table.lo: libknot/hash/cuckoo-hash-table.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cuckoo-hash-table.lo -MD -MP -MF $(DEPDIR)/cuckoo-hash-table.Tpo -c -o cuckoo-hash-table.lo `test -f 'libknot/hash/cuckoo-hash-table.c' || echo '$(srcdir)/'`libknot/hash/cuckoo-hash-table.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cuckoo-hash-table.Tpo $(DEPDIR)/cuckoo-hash-table.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/hash/cuckoo-hash-table.c' object='cuckoo-hash-table.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cuckoo-hash-table.lo `test -f 'libknot/hash/cuckoo-hash-table.c' || echo '$(srcdir)/'`libknot/hash/cuckoo-hash-table.c + +universal-system.lo: libknot/hash/universal-system.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT universal-system.lo -MD -MP -MF $(DEPDIR)/universal-system.Tpo -c -o universal-system.lo `test -f 'libknot/hash/universal-system.c' || echo '$(srcdir)/'`libknot/hash/universal-system.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/universal-system.Tpo $(DEPDIR)/universal-system.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/hash/universal-system.c' object='universal-system.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o universal-system.lo `test -f 'libknot/hash/universal-system.c' || echo '$(srcdir)/'`libknot/hash/universal-system.c + +name-server.lo: libknot/nameserver/name-server.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT name-server.lo -MD -MP -MF $(DEPDIR)/name-server.Tpo -c -o name-server.lo `test -f 'libknot/nameserver/name-server.c' || echo '$(srcdir)/'`libknot/nameserver/name-server.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/name-server.Tpo $(DEPDIR)/name-server.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/nameserver/name-server.c' object='name-server.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o name-server.lo `test -f 'libknot/nameserver/name-server.c' || echo '$(srcdir)/'`libknot/nameserver/name-server.c + +changesets.lo: libknot/updates/changesets.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT changesets.lo -MD -MP -MF $(DEPDIR)/changesets.Tpo -c -o changesets.lo `test -f 'libknot/updates/changesets.c' || echo '$(srcdir)/'`libknot/updates/changesets.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/changesets.Tpo $(DEPDIR)/changesets.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/updates/changesets.c' object='changesets.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o changesets.lo `test -f 'libknot/updates/changesets.c' || echo '$(srcdir)/'`libknot/updates/changesets.c + +xfr-in.lo: libknot/updates/xfr-in.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xfr-in.lo -MD -MP -MF $(DEPDIR)/xfr-in.Tpo -c -o xfr-in.lo `test -f 'libknot/updates/xfr-in.c' || echo '$(srcdir)/'`libknot/updates/xfr-in.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xfr-in.Tpo $(DEPDIR)/xfr-in.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/updates/xfr-in.c' object='xfr-in.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xfr-in.lo `test -f 'libknot/updates/xfr-in.c' || echo '$(srcdir)/'`libknot/updates/xfr-in.c + +ddns.lo: libknot/updates/ddns.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ddns.lo -MD -MP -MF $(DEPDIR)/ddns.Tpo -c -o ddns.lo `test -f 'libknot/updates/ddns.c' || echo '$(srcdir)/'`libknot/updates/ddns.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ddns.Tpo $(DEPDIR)/ddns.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/updates/ddns.c' object='ddns.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ddns.lo `test -f 'libknot/updates/ddns.c' || echo '$(srcdir)/'`libknot/updates/ddns.c + +edns.lo: libknot/edns.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns.lo -MD -MP -MF $(DEPDIR)/edns.Tpo -c -o edns.lo `test -f 'libknot/edns.c' || echo '$(srcdir)/'`libknot/edns.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns.Tpo $(DEPDIR)/edns.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/edns.c' object='edns.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns.lo `test -f 'libknot/edns.c' || echo '$(srcdir)/'`libknot/edns.c + +rrset.lo: libknot/rrset.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset.lo -MD -MP -MF $(DEPDIR)/rrset.Tpo -c -o rrset.lo `test -f 'libknot/rrset.c' || echo '$(srcdir)/'`libknot/rrset.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset.Tpo $(DEPDIR)/rrset.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/rrset.c' object='rrset.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset.lo `test -f 'libknot/rrset.c' || echo '$(srcdir)/'`libknot/rrset.c + +dname.lo: libknot/dname.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname.lo -MD -MP -MF $(DEPDIR)/dname.Tpo -c -o dname.lo `test -f 'libknot/dname.c' || echo '$(srcdir)/'`libknot/dname.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname.Tpo $(DEPDIR)/dname.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/dname.c' object='dname.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname.lo `test -f 'libknot/dname.c' || echo '$(srcdir)/'`libknot/dname.c + +rdata.lo: libknot/rdata.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata.lo -MD -MP -MF $(DEPDIR)/rdata.Tpo -c -o rdata.lo `test -f 'libknot/rdata.c' || echo '$(srcdir)/'`libknot/rdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata.Tpo $(DEPDIR)/rdata.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/rdata.c' object='rdata.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata.lo `test -f 'libknot/rdata.c' || echo '$(srcdir)/'`libknot/rdata.c + +nsec3.lo: libknot/nsec3.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nsec3.lo -MD -MP -MF $(DEPDIR)/nsec3.Tpo -c -o nsec3.lo `test -f 'libknot/nsec3.c' || echo '$(srcdir)/'`libknot/nsec3.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nsec3.Tpo $(DEPDIR)/nsec3.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/nsec3.c' object='nsec3.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nsec3.lo `test -f 'libknot/nsec3.c' || echo '$(srcdir)/'`libknot/nsec3.c + +tsig.lo: libknot/tsig.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tsig.lo -MD -MP -MF $(DEPDIR)/tsig.Tpo -c -o tsig.lo `test -f 'libknot/tsig.c' || echo '$(srcdir)/'`libknot/tsig.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tsig.Tpo $(DEPDIR)/tsig.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/tsig.c' object='tsig.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tsig.lo `test -f 'libknot/tsig.c' || echo '$(srcdir)/'`libknot/tsig.c + +tsig-op.lo: libknot/tsig-op.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tsig-op.lo -MD -MP -MF $(DEPDIR)/tsig-op.Tpo -c -o tsig-op.lo `test -f 'libknot/tsig-op.c' || echo '$(srcdir)/'`libknot/tsig-op.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tsig-op.Tpo $(DEPDIR)/tsig-op.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/tsig-op.c' object='tsig-op.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tsig-op.lo `test -f 'libknot/tsig-op.c' || echo '$(srcdir)/'`libknot/tsig-op.c + +gatherer.lo: knot/stat/gatherer.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gatherer.lo -MD -MP -MF $(DEPDIR)/gatherer.Tpo -c -o gatherer.lo `test -f 'knot/stat/gatherer.c' || echo '$(srcdir)/'`knot/stat/gatherer.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/gatherer.Tpo $(DEPDIR)/gatherer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/stat/gatherer.c' object='gatherer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gatherer.lo `test -f 'knot/stat/gatherer.c' || echo '$(srcdir)/'`knot/stat/gatherer.c + +stat.lo: knot/stat/stat.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stat.lo -MD -MP -MF $(DEPDIR)/stat.Tpo -c -o stat.lo `test -f 'knot/stat/stat.c' || echo '$(srcdir)/'`knot/stat/stat.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/stat.Tpo $(DEPDIR)/stat.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/stat/stat.c' object='stat.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stat.lo `test -f 'knot/stat/stat.c' || echo '$(srcdir)/'`knot/stat/stat.c + +log.lo: knot/other/log.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT log.lo -MD -MP -MF $(DEPDIR)/log.Tpo -c -o log.lo `test -f 'knot/other/log.c' || echo '$(srcdir)/'`knot/other/log.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/log.Tpo $(DEPDIR)/log.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/other/log.c' object='log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o log.lo `test -f 'knot/other/log.c' || echo '$(srcdir)/'`knot/other/log.c + +error.lo: knot/other/error.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT error.lo -MD -MP -MF $(DEPDIR)/error.Tpo -c -o error.lo `test -f 'knot/other/error.c' || echo '$(srcdir)/'`knot/other/error.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/error.Tpo $(DEPDIR)/error.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/other/error.c' object='error.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o error.lo `test -f 'knot/other/error.c' || echo '$(srcdir)/'`knot/other/error.c + +conf.lo: knot/conf/conf.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT conf.lo -MD -MP -MF $(DEPDIR)/conf.Tpo -c -o conf.lo `test -f 'knot/conf/conf.c' || echo '$(srcdir)/'`knot/conf/conf.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/conf.Tpo $(DEPDIR)/conf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/conf/conf.c' object='conf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o conf.lo `test -f 'knot/conf/conf.c' || echo '$(srcdir)/'`knot/conf/conf.c + +logconf.lo: knot/conf/logconf.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT logconf.lo -MD -MP -MF $(DEPDIR)/logconf.Tpo -c -o logconf.lo `test -f 'knot/conf/logconf.c' || echo '$(srcdir)/'`knot/conf/logconf.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/logconf.Tpo $(DEPDIR)/logconf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/conf/logconf.c' object='logconf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o logconf.lo `test -f 'knot/conf/logconf.c' || echo '$(srcdir)/'`knot/conf/logconf.c + +process.lo: knot/ctl/process.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT process.lo -MD -MP -MF $(DEPDIR)/process.Tpo -c -o process.lo `test -f 'knot/ctl/process.c' || echo '$(srcdir)/'`knot/ctl/process.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/process.Tpo $(DEPDIR)/process.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/ctl/process.c' object='process.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o process.lo `test -f 'knot/ctl/process.c' || echo '$(srcdir)/'`knot/ctl/process.c + +dthreads.lo: knot/server/dthreads.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dthreads.lo -MD -MP -MF $(DEPDIR)/dthreads.Tpo -c -o dthreads.lo `test -f 'knot/server/dthreads.c' || echo '$(srcdir)/'`knot/server/dthreads.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dthreads.Tpo $(DEPDIR)/dthreads.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/dthreads.c' object='dthreads.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dthreads.lo `test -f 'knot/server/dthreads.c' || echo '$(srcdir)/'`knot/server/dthreads.c + +journal.lo: knot/server/journal.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT journal.lo -MD -MP -MF $(DEPDIR)/journal.Tpo -c -o journal.lo `test -f 'knot/server/journal.c' || echo '$(srcdir)/'`knot/server/journal.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/journal.Tpo $(DEPDIR)/journal.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/journal.c' object='journal.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o journal.lo `test -f 'knot/server/journal.c' || echo '$(srcdir)/'`knot/server/journal.c + +socket.lo: knot/server/socket.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.lo -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.lo `test -f 'knot/server/socket.c' || echo '$(srcdir)/'`knot/server/socket.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/socket.c' object='socket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.lo `test -f 'knot/server/socket.c' || echo '$(srcdir)/'`knot/server/socket.c + +server.lo: knot/server/server.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT server.lo -MD -MP -MF $(DEPDIR)/server.Tpo -c -o server.lo `test -f 'knot/server/server.c' || echo '$(srcdir)/'`knot/server/server.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/server.Tpo $(DEPDIR)/server.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/server.c' object='server.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o server.lo `test -f 'knot/server/server.c' || echo '$(srcdir)/'`knot/server/server.c + +udp-handler.lo: knot/server/udp-handler.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT udp-handler.lo -MD -MP -MF $(DEPDIR)/udp-handler.Tpo -c -o udp-handler.lo `test -f 'knot/server/udp-handler.c' || echo '$(srcdir)/'`knot/server/udp-handler.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/udp-handler.Tpo $(DEPDIR)/udp-handler.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/udp-handler.c' object='udp-handler.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o udp-handler.lo `test -f 'knot/server/udp-handler.c' || echo '$(srcdir)/'`knot/server/udp-handler.c + +tcp-handler.lo: knot/server/tcp-handler.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tcp-handler.lo -MD -MP -MF $(DEPDIR)/tcp-handler.Tpo -c -o tcp-handler.lo `test -f 'knot/server/tcp-handler.c' || echo '$(srcdir)/'`knot/server/tcp-handler.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tcp-handler.Tpo $(DEPDIR)/tcp-handler.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/tcp-handler.c' object='tcp-handler.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tcp-handler.lo `test -f 'knot/server/tcp-handler.c' || echo '$(srcdir)/'`knot/server/tcp-handler.c + +xfr-handler.lo: knot/server/xfr-handler.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xfr-handler.lo -MD -MP -MF $(DEPDIR)/xfr-handler.Tpo -c -o xfr-handler.lo `test -f 'knot/server/xfr-handler.c' || echo '$(srcdir)/'`knot/server/xfr-handler.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xfr-handler.Tpo $(DEPDIR)/xfr-handler.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/xfr-handler.c' object='xfr-handler.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xfr-handler.lo `test -f 'knot/server/xfr-handler.c' || echo '$(srcdir)/'`knot/server/xfr-handler.c + +zones.lo: knot/server/zones.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zones.lo -MD -MP -MF $(DEPDIR)/zones.Tpo -c -o zones.lo `test -f 'knot/server/zones.c' || echo '$(srcdir)/'`knot/server/zones.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zones.Tpo $(DEPDIR)/zones.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/zones.c' object='zones.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zones.lo `test -f 'knot/server/zones.c' || echo '$(srcdir)/'`knot/server/zones.c + +notify.lo: knot/server/notify.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT notify.lo -MD -MP -MF $(DEPDIR)/notify.Tpo -c -o notify.lo `test -f 'knot/server/notify.c' || echo '$(srcdir)/'`knot/server/notify.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/notify.Tpo $(DEPDIR)/notify.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/notify.c' object='notify.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o notify.lo `test -f 'knot/server/notify.c' || echo '$(srcdir)/'`knot/server/notify.c + +zone-load.lo: knot/zone/zone-load.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-load.lo -MD -MP -MF $(DEPDIR)/zone-load.Tpo -c -o zone-load.lo `test -f 'knot/zone/zone-load.c' || echo '$(srcdir)/'`knot/zone/zone-load.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-load.Tpo $(DEPDIR)/zone-load.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/zone/zone-load.c' object='zone-load.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-load.lo `test -f 'knot/zone/zone-load.c' || echo '$(srcdir)/'`knot/zone/zone-load.c + +zone-dump.lo: knot/zone/zone-dump.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-dump.lo -MD -MP -MF $(DEPDIR)/zone-dump.Tpo -c -o zone-dump.lo `test -f 'knot/zone/zone-dump.c' || echo '$(srcdir)/'`knot/zone/zone-dump.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-dump.Tpo $(DEPDIR)/zone-dump.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/zone/zone-dump.c' object='zone-dump.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-dump.lo `test -f 'knot/zone/zone-dump.c' || echo '$(srcdir)/'`knot/zone/zone-dump.c + +zone-dump-text.lo: knot/zone/zone-dump-text.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-dump-text.lo -MD -MP -MF $(DEPDIR)/zone-dump-text.Tpo -c -o zone-dump-text.lo `test -f 'knot/zone/zone-dump-text.c' || echo '$(srcdir)/'`knot/zone/zone-dump-text.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-dump-text.Tpo $(DEPDIR)/zone-dump-text.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/zone/zone-dump-text.c' object='zone-dump-text.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-dump-text.lo `test -f 'knot/zone/zone-dump-text.c' || echo '$(srcdir)/'`knot/zone/zone-dump-text.c + +slab.lo: common/slab/slab.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT slab.lo -MD -MP -MF $(DEPDIR)/slab.Tpo -c -o slab.lo `test -f 'common/slab/slab.c' || echo '$(srcdir)/'`common/slab/slab.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/slab.Tpo $(DEPDIR)/slab.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/slab/slab.c' object='slab.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o slab.lo `test -f 'common/slab/slab.c' || echo '$(srcdir)/'`common/slab/slab.c + +malloc.lo: common/slab/malloc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT malloc.lo -MD -MP -MF $(DEPDIR)/malloc.Tpo -c -o malloc.lo `test -f 'common/slab/malloc.c' || echo '$(srcdir)/'`common/slab/malloc.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/malloc.Tpo $(DEPDIR)/malloc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/slab/malloc.c' object='malloc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o malloc.lo `test -f 'common/slab/malloc.c' || echo '$(srcdir)/'`common/slab/malloc.c + +tap.lo: common/libtap/tap.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tap.lo -MD -MP -MF $(DEPDIR)/tap.Tpo -c -o tap.lo `test -f 'common/libtap/tap.c' || echo '$(srcdir)/'`common/libtap/tap.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tap.Tpo $(DEPDIR)/tap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/libtap/tap.c' object='tap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tap.lo `test -f 'common/libtap/tap.c' || echo '$(srcdir)/'`common/libtap/tap.c + +lists.lo: common/lists.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lists.lo -MD -MP -MF $(DEPDIR)/lists.Tpo -c -o lists.lo `test -f 'common/lists.c' || echo '$(srcdir)/'`common/lists.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lists.Tpo $(DEPDIR)/lists.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/lists.c' object='lists.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lists.lo `test -f 'common/lists.c' || echo '$(srcdir)/'`common/lists.c + +base32.lo: common/base32.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT base32.lo -MD -MP -MF $(DEPDIR)/base32.Tpo -c -o base32.lo `test -f 'common/base32.c' || echo '$(srcdir)/'`common/base32.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/base32.Tpo $(DEPDIR)/base32.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/base32.c' object='base32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o base32.lo `test -f 'common/base32.c' || echo '$(srcdir)/'`common/base32.c + +print.lo: common/print.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT print.lo -MD -MP -MF $(DEPDIR)/print.Tpo -c -o print.lo `test -f 'common/print.c' || echo '$(srcdir)/'`common/print.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/print.Tpo $(DEPDIR)/print.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/print.c' object='print.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o print.lo `test -f 'common/print.c' || echo '$(srcdir)/'`common/print.c + +dynamic-array.lo: common/dynamic-array.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dynamic-array.lo -MD -MP -MF $(DEPDIR)/dynamic-array.Tpo -c -o dynamic-array.lo `test -f 'common/dynamic-array.c' || echo '$(srcdir)/'`common/dynamic-array.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dynamic-array.Tpo $(DEPDIR)/dynamic-array.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/dynamic-array.c' object='dynamic-array.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dynamic-array.lo `test -f 'common/dynamic-array.c' || echo '$(srcdir)/'`common/dynamic-array.c + +skip-list.lo: common/skip-list.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT skip-list.lo -MD -MP -MF $(DEPDIR)/skip-list.Tpo -c -o skip-list.lo `test -f 'common/skip-list.c' || echo '$(srcdir)/'`common/skip-list.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/skip-list.Tpo $(DEPDIR)/skip-list.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/skip-list.c' object='skip-list.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o skip-list.lo `test -f 'common/skip-list.c' || echo '$(srcdir)/'`common/skip-list.c + +base32hex.lo: common/base32hex.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT base32hex.lo -MD -MP -MF $(DEPDIR)/base32hex.Tpo -c -o base32hex.lo `test -f 'common/base32hex.c' || echo '$(srcdir)/'`common/base32hex.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/base32hex.Tpo $(DEPDIR)/base32hex.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/base32hex.c' object='base32hex.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o base32hex.lo `test -f 'common/base32hex.c' || echo '$(srcdir)/'`common/base32hex.c + +general-tree.lo: common/general-tree.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT general-tree.lo -MD -MP -MF $(DEPDIR)/general-tree.Tpo -c -o general-tree.lo `test -f 'common/general-tree.c' || echo '$(srcdir)/'`common/general-tree.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/general-tree.Tpo $(DEPDIR)/general-tree.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/general-tree.c' object='general-tree.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o general-tree.lo `test -f 'common/general-tree.c' || echo '$(srcdir)/'`common/general-tree.c + +evqueue.lo: common/evqueue.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT evqueue.lo -MD -MP -MF $(DEPDIR)/evqueue.Tpo -c -o evqueue.lo `test -f 'common/evqueue.c' || echo '$(srcdir)/'`common/evqueue.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/evqueue.Tpo $(DEPDIR)/evqueue.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/evqueue.c' object='evqueue.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o evqueue.lo `test -f 'common/evqueue.c' || echo '$(srcdir)/'`common/evqueue.c + +evsched.lo: common/evsched.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT evsched.lo -MD -MP -MF $(DEPDIR)/evsched.Tpo -c -o evsched.lo `test -f 'common/evsched.c' || echo '$(srcdir)/'`common/evsched.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/evsched.Tpo $(DEPDIR)/evsched.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/evsched.c' object='evsched.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o evsched.lo `test -f 'common/evsched.c' || echo '$(srcdir)/'`common/evsched.c + +acl.lo: common/acl.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acl.lo -MD -MP -MF $(DEPDIR)/acl.Tpo -c -o acl.lo `test -f 'common/acl.c' || echo '$(srcdir)/'`common/acl.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/acl.Tpo $(DEPDIR)/acl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/acl.c' object='acl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acl.lo `test -f 'common/acl.c' || echo '$(srcdir)/'`common/acl.c + +sockaddr.lo: common/sockaddr.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sockaddr.lo -MD -MP -MF $(DEPDIR)/sockaddr.Tpo -c -o sockaddr.lo `test -f 'common/sockaddr.c' || echo '$(srcdir)/'`common/sockaddr.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/sockaddr.Tpo $(DEPDIR)/sockaddr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/sockaddr.c' object='sockaddr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sockaddr.lo `test -f 'common/sockaddr.c' || echo '$(srcdir)/'`common/sockaddr.c + +crc.lo: common/crc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crc.lo -MD -MP -MF $(DEPDIR)/crc.Tpo -c -o crc.lo `test -f 'common/crc.c' || echo '$(srcdir)/'`common/crc.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/crc.Tpo $(DEPDIR)/crc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/crc.c' object='crc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crc.lo `test -f 'common/crc.c' || echo '$(srcdir)/'`common/crc.c + +ref.lo: common/ref.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ref.lo -MD -MP -MF $(DEPDIR)/ref.Tpo -c -o ref.lo `test -f 'common/ref.c' || echo '$(srcdir)/'`common/ref.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ref.Tpo $(DEPDIR)/ref.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/ref.c' object='ref.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ref.lo `test -f 'common/ref.c' || echo '$(srcdir)/'`common/ref.c + +errors.lo: common/errors.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT errors.lo -MD -MP -MF $(DEPDIR)/errors.Tpo -c -o errors.lo `test -f 'common/errors.c' || echo '$(srcdir)/'`common/errors.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/errors.Tpo $(DEPDIR)/errors.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/errors.c' object='errors.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o errors.lo `test -f 'common/errors.c' || echo '$(srcdir)/'`common/errors.c + +WELL1024a.lo: common/WELL1024a.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT WELL1024a.lo -MD -MP -MF $(DEPDIR)/WELL1024a.Tpo -c -o WELL1024a.lo `test -f 'common/WELL1024a.c' || echo '$(srcdir)/'`common/WELL1024a.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/WELL1024a.Tpo $(DEPDIR)/WELL1024a.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/WELL1024a.c' object='WELL1024a.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o WELL1024a.lo `test -f 'common/WELL1024a.c' || echo '$(srcdir)/'`common/WELL1024a.c + +fdset.lo: common/fdset.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset.lo -MD -MP -MF $(DEPDIR)/fdset.Tpo -c -o fdset.lo `test -f 'common/fdset.c' || echo '$(srcdir)/'`common/fdset.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset.Tpo $(DEPDIR)/fdset.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset.c' object='fdset.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset.lo `test -f 'common/fdset.c' || echo '$(srcdir)/'`common/fdset.c + +fdset_poll.lo: common/fdset_poll.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_poll.lo -MD -MP -MF $(DEPDIR)/fdset_poll.Tpo -c -o fdset_poll.lo `test -f 'common/fdset_poll.c' || echo '$(srcdir)/'`common/fdset_poll.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_poll.Tpo $(DEPDIR)/fdset_poll.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset_poll.c' object='fdset_poll.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_poll.lo `test -f 'common/fdset_poll.c' || echo '$(srcdir)/'`common/fdset_poll.c + +fdset_kqueue.lo: common/fdset_kqueue.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_kqueue.lo -MD -MP -MF $(DEPDIR)/fdset_kqueue.Tpo -c -o fdset_kqueue.lo `test -f 'common/fdset_kqueue.c' || echo '$(srcdir)/'`common/fdset_kqueue.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_kqueue.Tpo $(DEPDIR)/fdset_kqueue.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset_kqueue.c' object='fdset_kqueue.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_kqueue.lo `test -f 'common/fdset_kqueue.c' || echo '$(srcdir)/'`common/fdset_kqueue.c + +fdset_epoll.lo: common/fdset_epoll.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_epoll.lo -MD -MP -MF $(DEPDIR)/fdset_epoll.Tpo -c -o fdset_epoll.lo `test -f 'common/fdset_epoll.c' || echo '$(srcdir)/'`common/fdset_epoll.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_epoll.Tpo $(DEPDIR)/fdset_epoll.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset_epoll.c' object='fdset_epoll.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_epoll.lo `test -f 'common/fdset_epoll.c' || echo '$(srcdir)/'`common/fdset_epoll.c + +zcompile_main.o: zcompile/zcompile_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile_main.o -MD -MP -MF $(DEPDIR)/zcompile_main.Tpo -c -o zcompile_main.o `test -f 'zcompile/zcompile_main.c' || echo '$(srcdir)/'`zcompile/zcompile_main.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile_main.Tpo $(DEPDIR)/zcompile_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile_main.c' object='zcompile_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile_main.o `test -f 'zcompile/zcompile_main.c' || echo '$(srcdir)/'`zcompile/zcompile_main.c + +zcompile_main.obj: zcompile/zcompile_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile_main.obj -MD -MP -MF $(DEPDIR)/zcompile_main.Tpo -c -o zcompile_main.obj `if test -f 'zcompile/zcompile_main.c'; then $(CYGPATH_W) 'zcompile/zcompile_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile_main.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile_main.Tpo $(DEPDIR)/zcompile_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile_main.c' object='zcompile_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile_main.obj `if test -f 'zcompile/zcompile_main.c'; then $(CYGPATH_W) 'zcompile/zcompile_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile_main.c'; fi` + +zcompile-error.o: zcompile/zcompile-error.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile-error.o -MD -MP -MF $(DEPDIR)/zcompile-error.Tpo -c -o zcompile-error.o `test -f 'zcompile/zcompile-error.c' || echo '$(srcdir)/'`zcompile/zcompile-error.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile-error.Tpo $(DEPDIR)/zcompile-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile-error.c' object='zcompile-error.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile-error.o `test -f 'zcompile/zcompile-error.c' || echo '$(srcdir)/'`zcompile/zcompile-error.c + +zcompile-error.obj: zcompile/zcompile-error.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile-error.obj -MD -MP -MF $(DEPDIR)/zcompile-error.Tpo -c -o zcompile-error.obj `if test -f 'zcompile/zcompile-error.c'; then $(CYGPATH_W) 'zcompile/zcompile-error.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile-error.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile-error.Tpo $(DEPDIR)/zcompile-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile-error.c' object='zcompile-error.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile-error.obj `if test -f 'zcompile/zcompile-error.c'; then $(CYGPATH_W) 'zcompile/zcompile-error.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile-error.c'; fi` + +zcompile.o: zcompile/zcompile.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile.o -MD -MP -MF $(DEPDIR)/zcompile.Tpo -c -o zcompile.o `test -f 'zcompile/zcompile.c' || echo '$(srcdir)/'`zcompile/zcompile.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile.Tpo $(DEPDIR)/zcompile.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile.c' object='zcompile.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile.o `test -f 'zcompile/zcompile.c' || echo '$(srcdir)/'`zcompile/zcompile.c + +zcompile.obj: zcompile/zcompile.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile.obj -MD -MP -MF $(DEPDIR)/zcompile.Tpo -c -o zcompile.obj `if test -f 'zcompile/zcompile.c'; then $(CYGPATH_W) 'zcompile/zcompile.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile.Tpo $(DEPDIR)/zcompile.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile.c' object='zcompile.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile.obj `if test -f 'zcompile/zcompile.c'; then $(CYGPATH_W) 'zcompile/zcompile.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile.c'; fi` + +parser-util.o: zcompile/parser-util.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-util.o -MD -MP -MF $(DEPDIR)/parser-util.Tpo -c -o parser-util.o `test -f 'zcompile/parser-util.c' || echo '$(srcdir)/'`zcompile/parser-util.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-util.Tpo $(DEPDIR)/parser-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-util.c' object='parser-util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-util.o `test -f 'zcompile/parser-util.c' || echo '$(srcdir)/'`zcompile/parser-util.c + +parser-util.obj: zcompile/parser-util.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-util.obj -MD -MP -MF $(DEPDIR)/parser-util.Tpo -c -o parser-util.obj `if test -f 'zcompile/parser-util.c'; then $(CYGPATH_W) 'zcompile/parser-util.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-util.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-util.Tpo $(DEPDIR)/parser-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-util.c' object='parser-util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-util.obj `if test -f 'zcompile/parser-util.c'; then $(CYGPATH_W) 'zcompile/parser-util.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-util.c'; fi` + +parser-descriptor.o: zcompile/parser-descriptor.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-descriptor.o -MD -MP -MF $(DEPDIR)/parser-descriptor.Tpo -c -o parser-descriptor.o `test -f 'zcompile/parser-descriptor.c' || echo '$(srcdir)/'`zcompile/parser-descriptor.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-descriptor.Tpo $(DEPDIR)/parser-descriptor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-descriptor.c' object='parser-descriptor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-descriptor.o `test -f 'zcompile/parser-descriptor.c' || echo '$(srcdir)/'`zcompile/parser-descriptor.c + +parser-descriptor.obj: zcompile/parser-descriptor.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-descriptor.obj -MD -MP -MF $(DEPDIR)/parser-descriptor.Tpo -c -o parser-descriptor.obj `if test -f 'zcompile/parser-descriptor.c'; then $(CYGPATH_W) 'zcompile/parser-descriptor.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-descriptor.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-descriptor.Tpo $(DEPDIR)/parser-descriptor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-descriptor.c' object='parser-descriptor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-descriptor.obj `if test -f 'zcompile/parser-descriptor.c'; then $(CYGPATH_W) 'zcompile/parser-descriptor.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-descriptor.c'; fi` + +knotc_main.o: knot/ctl/knotc_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knotc_main.o -MD -MP -MF $(DEPDIR)/knotc_main.Tpo -c -o knotc_main.o `test -f 'knot/ctl/knotc_main.c' || echo '$(srcdir)/'`knot/ctl/knotc_main.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/knotc_main.Tpo $(DEPDIR)/knotc_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/ctl/knotc_main.c' object='knotc_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knotc_main.o `test -f 'knot/ctl/knotc_main.c' || echo '$(srcdir)/'`knot/ctl/knotc_main.c + +knotc_main.obj: knot/ctl/knotc_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knotc_main.obj -MD -MP -MF $(DEPDIR)/knotc_main.Tpo -c -o knotc_main.obj `if test -f 'knot/ctl/knotc_main.c'; then $(CYGPATH_W) 'knot/ctl/knotc_main.c'; else $(CYGPATH_W) '$(srcdir)/knot/ctl/knotc_main.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/knotc_main.Tpo $(DEPDIR)/knotc_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/ctl/knotc_main.c' object='knotc_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knotc_main.obj `if test -f 'knot/ctl/knotc_main.c'; then $(CYGPATH_W) 'knot/ctl/knotc_main.c'; else $(CYGPATH_W) '$(srcdir)/knot/ctl/knotc_main.c'; fi` + +main.o: knot/main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main.o -MD -MP -MF $(DEPDIR)/main.Tpo -c -o main.o `test -f 'knot/main.c' || echo '$(srcdir)/'`knot/main.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/main.Tpo $(DEPDIR)/main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/main.c' object='main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main.o `test -f 'knot/main.c' || echo '$(srcdir)/'`knot/main.c + +main.obj: knot/main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main.obj -MD -MP -MF $(DEPDIR)/main.Tpo -c -o main.obj `if test -f 'knot/main.c'; then $(CYGPATH_W) 'knot/main.c'; else $(CYGPATH_W) '$(srcdir)/knot/main.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/main.Tpo $(DEPDIR)/main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/main.c' object='main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main.obj `if test -f 'knot/main.c'; then $(CYGPATH_W) 'knot/main.c'; else $(CYGPATH_W) '$(srcdir)/knot/main.c'; fi` + +acl_tests.o: tests/common/acl_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acl_tests.o -MD -MP -MF $(DEPDIR)/acl_tests.Tpo -c -o acl_tests.o `test -f 'tests/common/acl_tests.c' || echo '$(srcdir)/'`tests/common/acl_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/acl_tests.Tpo $(DEPDIR)/acl_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/acl_tests.c' object='acl_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acl_tests.o `test -f 'tests/common/acl_tests.c' || echo '$(srcdir)/'`tests/common/acl_tests.c + +acl_tests.obj: tests/common/acl_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acl_tests.obj -MD -MP -MF $(DEPDIR)/acl_tests.Tpo -c -o acl_tests.obj `if test -f 'tests/common/acl_tests.c'; then $(CYGPATH_W) 'tests/common/acl_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/acl_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/acl_tests.Tpo $(DEPDIR)/acl_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/acl_tests.c' object='acl_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acl_tests.obj `if test -f 'tests/common/acl_tests.c'; then $(CYGPATH_W) 'tests/common/acl_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/acl_tests.c'; fi` + +da_tests.o: tests/common/da_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT da_tests.o -MD -MP -MF $(DEPDIR)/da_tests.Tpo -c -o da_tests.o `test -f 'tests/common/da_tests.c' || echo '$(srcdir)/'`tests/common/da_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/da_tests.Tpo $(DEPDIR)/da_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/da_tests.c' object='da_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o da_tests.o `test -f 'tests/common/da_tests.c' || echo '$(srcdir)/'`tests/common/da_tests.c + +da_tests.obj: tests/common/da_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT da_tests.obj -MD -MP -MF $(DEPDIR)/da_tests.Tpo -c -o da_tests.obj `if test -f 'tests/common/da_tests.c'; then $(CYGPATH_W) 'tests/common/da_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/da_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/da_tests.Tpo $(DEPDIR)/da_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/da_tests.c' object='da_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o da_tests.obj `if test -f 'tests/common/da_tests.c'; then $(CYGPATH_W) 'tests/common/da_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/da_tests.c'; fi` + +events_tests.o: tests/common/events_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT events_tests.o -MD -MP -MF $(DEPDIR)/events_tests.Tpo -c -o events_tests.o `test -f 'tests/common/events_tests.c' || echo '$(srcdir)/'`tests/common/events_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/events_tests.Tpo $(DEPDIR)/events_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/events_tests.c' object='events_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o events_tests.o `test -f 'tests/common/events_tests.c' || echo '$(srcdir)/'`tests/common/events_tests.c + +events_tests.obj: tests/common/events_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT events_tests.obj -MD -MP -MF $(DEPDIR)/events_tests.Tpo -c -o events_tests.obj `if test -f 'tests/common/events_tests.c'; then $(CYGPATH_W) 'tests/common/events_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/events_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/events_tests.Tpo $(DEPDIR)/events_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/events_tests.c' object='events_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o events_tests.obj `if test -f 'tests/common/events_tests.c'; then $(CYGPATH_W) 'tests/common/events_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/events_tests.c'; fi` + +skiplist_tests.o: tests/common/skiplist_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT skiplist_tests.o -MD -MP -MF $(DEPDIR)/skiplist_tests.Tpo -c -o skiplist_tests.o `test -f 'tests/common/skiplist_tests.c' || echo '$(srcdir)/'`tests/common/skiplist_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/skiplist_tests.Tpo $(DEPDIR)/skiplist_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/skiplist_tests.c' object='skiplist_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o skiplist_tests.o `test -f 'tests/common/skiplist_tests.c' || echo '$(srcdir)/'`tests/common/skiplist_tests.c + +skiplist_tests.obj: tests/common/skiplist_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT skiplist_tests.obj -MD -MP -MF $(DEPDIR)/skiplist_tests.Tpo -c -o skiplist_tests.obj `if test -f 'tests/common/skiplist_tests.c'; then $(CYGPATH_W) 'tests/common/skiplist_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/skiplist_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/skiplist_tests.Tpo $(DEPDIR)/skiplist_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/skiplist_tests.c' object='skiplist_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o skiplist_tests.obj `if test -f 'tests/common/skiplist_tests.c'; then $(CYGPATH_W) 'tests/common/skiplist_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/skiplist_tests.c'; fi` + +slab_tests.o: tests/common/slab_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT slab_tests.o -MD -MP -MF $(DEPDIR)/slab_tests.Tpo -c -o slab_tests.o `test -f 'tests/common/slab_tests.c' || echo '$(srcdir)/'`tests/common/slab_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/slab_tests.Tpo $(DEPDIR)/slab_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/slab_tests.c' object='slab_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o slab_tests.o `test -f 'tests/common/slab_tests.c' || echo '$(srcdir)/'`tests/common/slab_tests.c + +slab_tests.obj: tests/common/slab_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT slab_tests.obj -MD -MP -MF $(DEPDIR)/slab_tests.Tpo -c -o slab_tests.obj `if test -f 'tests/common/slab_tests.c'; then $(CYGPATH_W) 'tests/common/slab_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/slab_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/slab_tests.Tpo $(DEPDIR)/slab_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/slab_tests.c' object='slab_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o slab_tests.obj `if test -f 'tests/common/slab_tests.c'; then $(CYGPATH_W) 'tests/common/slab_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/slab_tests.c'; fi` + +fdset_tests.o: tests/common/fdset_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_tests.o -MD -MP -MF $(DEPDIR)/fdset_tests.Tpo -c -o fdset_tests.o `test -f 'tests/common/fdset_tests.c' || echo '$(srcdir)/'`tests/common/fdset_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_tests.Tpo $(DEPDIR)/fdset_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/fdset_tests.c' object='fdset_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_tests.o `test -f 'tests/common/fdset_tests.c' || echo '$(srcdir)/'`tests/common/fdset_tests.c + +fdset_tests.obj: tests/common/fdset_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_tests.obj -MD -MP -MF $(DEPDIR)/fdset_tests.Tpo -c -o fdset_tests.obj `if test -f 'tests/common/fdset_tests.c'; then $(CYGPATH_W) 'tests/common/fdset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/fdset_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_tests.Tpo $(DEPDIR)/fdset_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/fdset_tests.c' object='fdset_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_tests.obj `if test -f 'tests/common/fdset_tests.c'; then $(CYGPATH_W) 'tests/common/fdset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/fdset_tests.c'; fi` + +conf_tests.o: tests/knot/conf_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT conf_tests.o -MD -MP -MF $(DEPDIR)/conf_tests.Tpo -c -o conf_tests.o `test -f 'tests/knot/conf_tests.c' || echo '$(srcdir)/'`tests/knot/conf_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/conf_tests.Tpo $(DEPDIR)/conf_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/conf_tests.c' object='conf_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o conf_tests.o `test -f 'tests/knot/conf_tests.c' || echo '$(srcdir)/'`tests/knot/conf_tests.c + +conf_tests.obj: tests/knot/conf_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT conf_tests.obj -MD -MP -MF $(DEPDIR)/conf_tests.Tpo -c -o conf_tests.obj `if test -f 'tests/knot/conf_tests.c'; then $(CYGPATH_W) 'tests/knot/conf_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/conf_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/conf_tests.Tpo $(DEPDIR)/conf_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/conf_tests.c' object='conf_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o conf_tests.obj `if test -f 'tests/knot/conf_tests.c'; then $(CYGPATH_W) 'tests/knot/conf_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/conf_tests.c'; fi` + +dthreads_tests.o: tests/knot/dthreads_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dthreads_tests.o -MD -MP -MF $(DEPDIR)/dthreads_tests.Tpo -c -o dthreads_tests.o `test -f 'tests/knot/dthreads_tests.c' || echo '$(srcdir)/'`tests/knot/dthreads_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dthreads_tests.Tpo $(DEPDIR)/dthreads_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/dthreads_tests.c' object='dthreads_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dthreads_tests.o `test -f 'tests/knot/dthreads_tests.c' || echo '$(srcdir)/'`tests/knot/dthreads_tests.c + +dthreads_tests.obj: tests/knot/dthreads_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dthreads_tests.obj -MD -MP -MF $(DEPDIR)/dthreads_tests.Tpo -c -o dthreads_tests.obj `if test -f 'tests/knot/dthreads_tests.c'; then $(CYGPATH_W) 'tests/knot/dthreads_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/dthreads_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dthreads_tests.Tpo $(DEPDIR)/dthreads_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/dthreads_tests.c' object='dthreads_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dthreads_tests.obj `if test -f 'tests/knot/dthreads_tests.c'; then $(CYGPATH_W) 'tests/knot/dthreads_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/dthreads_tests.c'; fi` + +journal_tests.o: tests/knot/journal_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT journal_tests.o -MD -MP -MF $(DEPDIR)/journal_tests.Tpo -c -o journal_tests.o `test -f 'tests/knot/journal_tests.c' || echo '$(srcdir)/'`tests/knot/journal_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/journal_tests.Tpo $(DEPDIR)/journal_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/journal_tests.c' object='journal_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o journal_tests.o `test -f 'tests/knot/journal_tests.c' || echo '$(srcdir)/'`tests/knot/journal_tests.c + +journal_tests.obj: tests/knot/journal_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT journal_tests.obj -MD -MP -MF $(DEPDIR)/journal_tests.Tpo -c -o journal_tests.obj `if test -f 'tests/knot/journal_tests.c'; then $(CYGPATH_W) 'tests/knot/journal_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/journal_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/journal_tests.Tpo $(DEPDIR)/journal_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/journal_tests.c' object='journal_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o journal_tests.obj `if test -f 'tests/knot/journal_tests.c'; then $(CYGPATH_W) 'tests/knot/journal_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/journal_tests.c'; fi` + +server_tests.o: tests/knot/server_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT server_tests.o -MD -MP -MF $(DEPDIR)/server_tests.Tpo -c -o server_tests.o `test -f 'tests/knot/server_tests.c' || echo '$(srcdir)/'`tests/knot/server_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/server_tests.Tpo $(DEPDIR)/server_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/server_tests.c' object='server_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o server_tests.o `test -f 'tests/knot/server_tests.c' || echo '$(srcdir)/'`tests/knot/server_tests.c + +server_tests.obj: tests/knot/server_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT server_tests.obj -MD -MP -MF $(DEPDIR)/server_tests.Tpo -c -o server_tests.obj `if test -f 'tests/knot/server_tests.c'; then $(CYGPATH_W) 'tests/knot/server_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/server_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/server_tests.Tpo $(DEPDIR)/server_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/server_tests.c' object='server_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o server_tests.obj `if test -f 'tests/knot/server_tests.c'; then $(CYGPATH_W) 'tests/knot/server_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/server_tests.c'; fi` + +unittests_main.o: tests/unittests_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_main.o -MD -MP -MF $(DEPDIR)/unittests_main.Tpo -c -o unittests_main.o `test -f 'tests/unittests_main.c' || echo '$(srcdir)/'`tests/unittests_main.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_main.Tpo $(DEPDIR)/unittests_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/unittests_main.c' object='unittests_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_main.o `test -f 'tests/unittests_main.c' || echo '$(srcdir)/'`tests/unittests_main.c + +unittests_main.obj: tests/unittests_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_main.obj -MD -MP -MF $(DEPDIR)/unittests_main.Tpo -c -o unittests_main.obj `if test -f 'tests/unittests_main.c'; then $(CYGPATH_W) 'tests/unittests_main.c'; else $(CYGPATH_W) '$(srcdir)/tests/unittests_main.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_main.Tpo $(DEPDIR)/unittests_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/unittests_main.c' object='unittests_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_main.obj `if test -f 'tests/unittests_main.c'; then $(CYGPATH_W) 'tests/unittests_main.c'; else $(CYGPATH_W) '$(srcdir)/tests/unittests_main.c'; fi` + +cuckoo_tests.o: tests/libknot/libknot/cuckoo_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cuckoo_tests.o -MD -MP -MF $(DEPDIR)/cuckoo_tests.Tpo -c -o cuckoo_tests.o `test -f 'tests/libknot/libknot/cuckoo_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/cuckoo_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cuckoo_tests.Tpo $(DEPDIR)/cuckoo_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/cuckoo_tests.c' object='cuckoo_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cuckoo_tests.o `test -f 'tests/libknot/libknot/cuckoo_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/cuckoo_tests.c + +cuckoo_tests.obj: tests/libknot/libknot/cuckoo_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cuckoo_tests.obj -MD -MP -MF $(DEPDIR)/cuckoo_tests.Tpo -c -o cuckoo_tests.obj `if test -f 'tests/libknot/libknot/cuckoo_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/cuckoo_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/cuckoo_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cuckoo_tests.Tpo $(DEPDIR)/cuckoo_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/cuckoo_tests.c' object='cuckoo_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cuckoo_tests.obj `if test -f 'tests/libknot/libknot/cuckoo_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/cuckoo_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/cuckoo_tests.c'; fi` + +response_tests.o: tests/libknot/libknot/response_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests.o -MD -MP -MF $(DEPDIR)/response_tests.Tpo -c -o response_tests.o `test -f 'tests/libknot/libknot/response_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/response_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests.Tpo $(DEPDIR)/response_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/response_tests.c' object='response_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests.o `test -f 'tests/libknot/libknot/response_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/response_tests.c + +response_tests.obj: tests/libknot/libknot/response_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests.obj -MD -MP -MF $(DEPDIR)/response_tests.Tpo -c -o response_tests.obj `if test -f 'tests/libknot/libknot/response_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/response_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/response_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests.Tpo $(DEPDIR)/response_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/response_tests.c' object='response_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests.obj `if test -f 'tests/libknot/libknot/response_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/response_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/response_tests.c'; fi` + +dname_tests.o: tests/libknot/libknot/dname_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests.o -MD -MP -MF $(DEPDIR)/dname_tests.Tpo -c -o dname_tests.o `test -f 'tests/libknot/libknot/dname_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests.Tpo $(DEPDIR)/dname_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_tests.c' object='dname_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests.o `test -f 'tests/libknot/libknot/dname_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_tests.c + +dname_tests.obj: tests/libknot/libknot/dname_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests.obj -MD -MP -MF $(DEPDIR)/dname_tests.Tpo -c -o dname_tests.obj `if test -f 'tests/libknot/libknot/dname_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests.Tpo $(DEPDIR)/dname_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_tests.c' object='dname_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests.obj `if test -f 'tests/libknot/libknot/dname_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_tests.c'; fi` + +dname_table_tests.o: tests/libknot/libknot/dname_table_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_table_tests.o -MD -MP -MF $(DEPDIR)/dname_table_tests.Tpo -c -o dname_table_tests.o `test -f 'tests/libknot/libknot/dname_table_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_table_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_table_tests.Tpo $(DEPDIR)/dname_table_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_table_tests.c' object='dname_table_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_table_tests.o `test -f 'tests/libknot/libknot/dname_table_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_table_tests.c + +dname_table_tests.obj: tests/libknot/libknot/dname_table_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_table_tests.obj -MD -MP -MF $(DEPDIR)/dname_table_tests.Tpo -c -o dname_table_tests.obj `if test -f 'tests/libknot/libknot/dname_table_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_table_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_table_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_table_tests.Tpo $(DEPDIR)/dname_table_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_table_tests.c' object='dname_table_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_table_tests.obj `if test -f 'tests/libknot/libknot/dname_table_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_table_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_table_tests.c'; fi` + +nsec3_tests.o: tests/libknot/libknot/nsec3_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nsec3_tests.o -MD -MP -MF $(DEPDIR)/nsec3_tests.Tpo -c -o nsec3_tests.o `test -f 'tests/libknot/libknot/nsec3_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/nsec3_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nsec3_tests.Tpo $(DEPDIR)/nsec3_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/nsec3_tests.c' object='nsec3_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nsec3_tests.o `test -f 'tests/libknot/libknot/nsec3_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/nsec3_tests.c + +nsec3_tests.obj: tests/libknot/libknot/nsec3_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nsec3_tests.obj -MD -MP -MF $(DEPDIR)/nsec3_tests.Tpo -c -o nsec3_tests.obj `if test -f 'tests/libknot/libknot/nsec3_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/nsec3_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/nsec3_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nsec3_tests.Tpo $(DEPDIR)/nsec3_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/nsec3_tests.c' object='nsec3_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nsec3_tests.obj `if test -f 'tests/libknot/libknot/nsec3_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/nsec3_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/nsec3_tests.c'; fi` + +packet_tests.o: tests/libknot/libknot/packet_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests.o -MD -MP -MF $(DEPDIR)/packet_tests.Tpo -c -o packet_tests.o `test -f 'tests/libknot/libknot/packet_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/packet_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests.Tpo $(DEPDIR)/packet_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/packet_tests.c' object='packet_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests.o `test -f 'tests/libknot/libknot/packet_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/packet_tests.c + +packet_tests.obj: tests/libknot/libknot/packet_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests.obj -MD -MP -MF $(DEPDIR)/packet_tests.Tpo -c -o packet_tests.obj `if test -f 'tests/libknot/libknot/packet_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/packet_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/packet_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests.Tpo $(DEPDIR)/packet_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/packet_tests.c' object='packet_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests.obj `if test -f 'tests/libknot/libknot/packet_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/packet_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/packet_tests.c'; fi` + +query_tests.o: tests/libknot/libknot/query_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT query_tests.o -MD -MP -MF $(DEPDIR)/query_tests.Tpo -c -o query_tests.o `test -f 'tests/libknot/libknot/query_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/query_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/query_tests.Tpo $(DEPDIR)/query_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/query_tests.c' object='query_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o query_tests.o `test -f 'tests/libknot/libknot/query_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/query_tests.c + +query_tests.obj: tests/libknot/libknot/query_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT query_tests.obj -MD -MP -MF $(DEPDIR)/query_tests.Tpo -c -o query_tests.obj `if test -f 'tests/libknot/libknot/query_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/query_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/query_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/query_tests.Tpo $(DEPDIR)/query_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/query_tests.c' object='query_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o query_tests.obj `if test -f 'tests/libknot/libknot/query_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/query_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/query_tests.c'; fi` + +edns_tests.o: tests/libknot/libknot/edns_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests.o -MD -MP -MF $(DEPDIR)/edns_tests.Tpo -c -o edns_tests.o `test -f 'tests/libknot/libknot/edns_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/edns_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests.Tpo $(DEPDIR)/edns_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/edns_tests.c' object='edns_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests.o `test -f 'tests/libknot/libknot/edns_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/edns_tests.c + +edns_tests.obj: tests/libknot/libknot/edns_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests.obj -MD -MP -MF $(DEPDIR)/edns_tests.Tpo -c -o edns_tests.obj `if test -f 'tests/libknot/libknot/edns_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/edns_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/edns_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests.Tpo $(DEPDIR)/edns_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/edns_tests.c' object='edns_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests.obj `if test -f 'tests/libknot/libknot/edns_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/edns_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/edns_tests.c'; fi` + +node_tests.o: tests/libknot/libknot/node_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests.o -MD -MP -MF $(DEPDIR)/node_tests.Tpo -c -o node_tests.o `test -f 'tests/libknot/libknot/node_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/node_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests.Tpo $(DEPDIR)/node_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/node_tests.c' object='node_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests.o `test -f 'tests/libknot/libknot/node_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/node_tests.c + +node_tests.obj: tests/libknot/libknot/node_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests.obj -MD -MP -MF $(DEPDIR)/node_tests.Tpo -c -o node_tests.obj `if test -f 'tests/libknot/libknot/node_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/node_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/node_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests.Tpo $(DEPDIR)/node_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/node_tests.c' object='node_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests.obj `if test -f 'tests/libknot/libknot/node_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/node_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/node_tests.c'; fi` + +rdata_tests.o: tests/libknot/libknot/rdata_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests.o -MD -MP -MF $(DEPDIR)/rdata_tests.Tpo -c -o rdata_tests.o `test -f 'tests/libknot/libknot/rdata_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rdata_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests.Tpo $(DEPDIR)/rdata_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rdata_tests.c' object='rdata_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests.o `test -f 'tests/libknot/libknot/rdata_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rdata_tests.c + +rdata_tests.obj: tests/libknot/libknot/rdata_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests.obj -MD -MP -MF $(DEPDIR)/rdata_tests.Tpo -c -o rdata_tests.obj `if test -f 'tests/libknot/libknot/rdata_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rdata_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rdata_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests.Tpo $(DEPDIR)/rdata_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rdata_tests.c' object='rdata_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests.obj `if test -f 'tests/libknot/libknot/rdata_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rdata_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rdata_tests.c'; fi` + +rrset_tests.o: tests/libknot/libknot/rrset_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests.o -MD -MP -MF $(DEPDIR)/rrset_tests.Tpo -c -o rrset_tests.o `test -f 'tests/libknot/libknot/rrset_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rrset_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests.Tpo $(DEPDIR)/rrset_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rrset_tests.c' object='rrset_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests.o `test -f 'tests/libknot/libknot/rrset_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rrset_tests.c + +rrset_tests.obj: tests/libknot/libknot/rrset_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests.obj -MD -MP -MF $(DEPDIR)/rrset_tests.Tpo -c -o rrset_tests.obj `if test -f 'tests/libknot/libknot/rrset_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rrset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rrset_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests.Tpo $(DEPDIR)/rrset_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rrset_tests.c' object='rrset_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests.obj `if test -f 'tests/libknot/libknot/rrset_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rrset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rrset_tests.c'; fi` + +zone_tests.o: tests/libknot/libknot/zone_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests.o -MD -MP -MF $(DEPDIR)/zone_tests.Tpo -c -o zone_tests.o `test -f 'tests/libknot/libknot/zone_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests.Tpo $(DEPDIR)/zone_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tests.c' object='zone_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests.o `test -f 'tests/libknot/libknot/zone_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tests.c + +zone_tests.obj: tests/libknot/libknot/zone_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests.obj -MD -MP -MF $(DEPDIR)/zone_tests.Tpo -c -o zone_tests.obj `if test -f 'tests/libknot/libknot/zone_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests.Tpo $(DEPDIR)/zone_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tests.c' object='zone_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests.obj `if test -f 'tests/libknot/libknot/zone_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tests.c'; fi` + +zone_tree_tests.o: tests/libknot/libknot/zone_tree_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tree_tests.o -MD -MP -MF $(DEPDIR)/zone_tree_tests.Tpo -c -o zone_tree_tests.o `test -f 'tests/libknot/libknot/zone_tree_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tree_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tree_tests.Tpo $(DEPDIR)/zone_tree_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tree_tests.c' object='zone_tree_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tree_tests.o `test -f 'tests/libknot/libknot/zone_tree_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tree_tests.c + +zone_tree_tests.obj: tests/libknot/libknot/zone_tree_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tree_tests.obj -MD -MP -MF $(DEPDIR)/zone_tree_tests.Tpo -c -o zone_tree_tests.obj `if test -f 'tests/libknot/libknot/zone_tree_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tree_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tree_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tree_tests.Tpo $(DEPDIR)/zone_tree_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tree_tests.c' object='zone_tree_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tree_tests.obj `if test -f 'tests/libknot/libknot/zone_tree_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tree_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tree_tests.c'; fi` + +zonedb_tests.o: tests/libknot/libknot/zonedb_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests.o -MD -MP -MF $(DEPDIR)/zonedb_tests.Tpo -c -o zonedb_tests.o `test -f 'tests/libknot/libknot/zonedb_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zonedb_tests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests.Tpo $(DEPDIR)/zonedb_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zonedb_tests.c' object='zonedb_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests.o `test -f 'tests/libknot/libknot/zonedb_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zonedb_tests.c + +zonedb_tests.obj: tests/libknot/libknot/zonedb_tests.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests.obj -MD -MP -MF $(DEPDIR)/zonedb_tests.Tpo -c -o zonedb_tests.obj `if test -f 'tests/libknot/libknot/zonedb_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zonedb_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zonedb_tests.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests.Tpo $(DEPDIR)/zonedb_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zonedb_tests.c' object='zonedb_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests.obj `if test -f 'tests/libknot/libknot/zonedb_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zonedb_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zonedb_tests.c'; fi` + +unittests_libknot.o: tests/libknot/unittests_libknot.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot.o -MD -MP -MF $(DEPDIR)/unittests_libknot.Tpo -c -o unittests_libknot.o `test -f 'tests/libknot/unittests_libknot.c' || echo '$(srcdir)/'`tests/libknot/unittests_libknot.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot.Tpo $(DEPDIR)/unittests_libknot.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/unittests_libknot.c' object='unittests_libknot.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot.o `test -f 'tests/libknot/unittests_libknot.c' || echo '$(srcdir)/'`tests/libknot/unittests_libknot.c + +unittests_libknot.obj: tests/libknot/unittests_libknot.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot.obj -MD -MP -MF $(DEPDIR)/unittests_libknot.Tpo -c -o unittests_libknot.obj `if test -f 'tests/libknot/unittests_libknot.c'; then $(CYGPATH_W) 'tests/libknot/unittests_libknot.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/unittests_libknot.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot.Tpo $(DEPDIR)/unittests_libknot.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/unittests_libknot.c' object='unittests_libknot.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot.obj `if test -f 'tests/libknot/unittests_libknot.c'; then $(CYGPATH_W) 'tests/libknot/unittests_libknot.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/unittests_libknot.c'; fi` + +dname_tests_realdata.o: tests/libknot/realdata/libknot/dname_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests_realdata.o -MD -MP -MF $(DEPDIR)/dname_tests_realdata.Tpo -c -o dname_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/dname_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests_realdata.Tpo $(DEPDIR)/dname_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/dname_tests_realdata.c' object='dname_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/dname_tests_realdata.c + +dname_tests_realdata.obj: tests/libknot/realdata/libknot/dname_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests_realdata.obj -MD -MP -MF $(DEPDIR)/dname_tests_realdata.Tpo -c -o dname_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/dname_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests_realdata.Tpo $(DEPDIR)/dname_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/dname_tests_realdata.c' object='dname_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/dname_tests_realdata.c'; fi` + +response_tests_realdata.o: tests/libknot/realdata/libknot/response_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests_realdata.o -MD -MP -MF $(DEPDIR)/response_tests_realdata.Tpo -c -o response_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/response_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests_realdata.Tpo $(DEPDIR)/response_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/response_tests_realdata.c' object='response_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/response_tests_realdata.c + +response_tests_realdata.obj: tests/libknot/realdata/libknot/response_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests_realdata.obj -MD -MP -MF $(DEPDIR)/response_tests_realdata.Tpo -c -o response_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/response_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/response_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests_realdata.Tpo $(DEPDIR)/response_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/response_tests_realdata.c' object='response_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/response_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/response_tests_realdata.c'; fi` + +edns_tests_realdata.o: tests/libknot/realdata/libknot/edns_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests_realdata.o -MD -MP -MF $(DEPDIR)/edns_tests_realdata.Tpo -c -o edns_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/edns_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests_realdata.Tpo $(DEPDIR)/edns_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/edns_tests_realdata.c' object='edns_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/edns_tests_realdata.c + +edns_tests_realdata.obj: tests/libknot/realdata/libknot/edns_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests_realdata.obj -MD -MP -MF $(DEPDIR)/edns_tests_realdata.Tpo -c -o edns_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/edns_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests_realdata.Tpo $(DEPDIR)/edns_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/edns_tests_realdata.c' object='edns_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/edns_tests_realdata.c'; fi` + +node_tests_realdata.o: tests/libknot/realdata/libknot/node_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests_realdata.o -MD -MP -MF $(DEPDIR)/node_tests_realdata.Tpo -c -o node_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/node_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests_realdata.Tpo $(DEPDIR)/node_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/node_tests_realdata.c' object='node_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/node_tests_realdata.c + +node_tests_realdata.obj: tests/libknot/realdata/libknot/node_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests_realdata.obj -MD -MP -MF $(DEPDIR)/node_tests_realdata.Tpo -c -o node_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/node_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/node_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests_realdata.Tpo $(DEPDIR)/node_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/node_tests_realdata.c' object='node_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/node_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/node_tests_realdata.c'; fi` + +rdata_tests_realdata.o: tests/libknot/realdata/libknot/rdata_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests_realdata.o -MD -MP -MF $(DEPDIR)/rdata_tests_realdata.Tpo -c -o rdata_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rdata_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests_realdata.Tpo $(DEPDIR)/rdata_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rdata_tests_realdata.c' object='rdata_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rdata_tests_realdata.c + +rdata_tests_realdata.obj: tests/libknot/realdata/libknot/rdata_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests_realdata.obj -MD -MP -MF $(DEPDIR)/rdata_tests_realdata.Tpo -c -o rdata_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rdata_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests_realdata.Tpo $(DEPDIR)/rdata_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rdata_tests_realdata.c' object='rdata_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rdata_tests_realdata.c'; fi` + +rrset_tests_realdata.o: tests/libknot/realdata/libknot/rrset_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests_realdata.o -MD -MP -MF $(DEPDIR)/rrset_tests_realdata.Tpo -c -o rrset_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rrset_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests_realdata.Tpo $(DEPDIR)/rrset_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rrset_tests_realdata.c' object='rrset_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rrset_tests_realdata.c + +rrset_tests_realdata.obj: tests/libknot/realdata/libknot/rrset_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests_realdata.obj -MD -MP -MF $(DEPDIR)/rrset_tests_realdata.Tpo -c -o rrset_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rrset_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests_realdata.Tpo $(DEPDIR)/rrset_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rrset_tests_realdata.c' object='rrset_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rrset_tests_realdata.c'; fi` + +zone_tests_realdata.o: tests/libknot/realdata/libknot/zone_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests_realdata.o -MD -MP -MF $(DEPDIR)/zone_tests_realdata.Tpo -c -o zone_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zone_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests_realdata.Tpo $(DEPDIR)/zone_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zone_tests_realdata.c' object='zone_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zone_tests_realdata.c + +zone_tests_realdata.obj: tests/libknot/realdata/libknot/zone_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests_realdata.obj -MD -MP -MF $(DEPDIR)/zone_tests_realdata.Tpo -c -o zone_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zone_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests_realdata.Tpo $(DEPDIR)/zone_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zone_tests_realdata.c' object='zone_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zone_tests_realdata.c'; fi` + +zonedb_tests_realdata.o: tests/libknot/realdata/libknot/zonedb_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests_realdata.o -MD -MP -MF $(DEPDIR)/zonedb_tests_realdata.Tpo -c -o zonedb_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zonedb_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests_realdata.Tpo $(DEPDIR)/zonedb_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zonedb_tests_realdata.c' object='zonedb_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zonedb_tests_realdata.c + +zonedb_tests_realdata.obj: tests/libknot/realdata/libknot/zonedb_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests_realdata.obj -MD -MP -MF $(DEPDIR)/zonedb_tests_realdata.Tpo -c -o zonedb_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests_realdata.Tpo $(DEPDIR)/zonedb_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zonedb_tests_realdata.c' object='zonedb_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; fi` + +packet_tests_realdata.o: tests/libknot/realdata/libknot/packet_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests_realdata.o -MD -MP -MF $(DEPDIR)/packet_tests_realdata.Tpo -c -o packet_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/packet_tests_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests_realdata.Tpo $(DEPDIR)/packet_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/packet_tests_realdata.c' object='packet_tests_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/packet_tests_realdata.c + +packet_tests_realdata.obj: tests/libknot/realdata/libknot/packet_tests_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests_realdata.obj -MD -MP -MF $(DEPDIR)/packet_tests_realdata.Tpo -c -o packet_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/packet_tests_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests_realdata.Tpo $(DEPDIR)/packet_tests_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/packet_tests_realdata.c' object='packet_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/packet_tests_realdata.c'; fi` + +libknot_tests_loader_realdata.o: tests/libknot/realdata/libknot_tests_loader_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot_tests_loader_realdata.o -MD -MP -MF $(DEPDIR)/libknot_tests_loader_realdata.Tpo -c -o libknot_tests_loader_realdata.o `test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot_tests_loader_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libknot_tests_loader_realdata.Tpo $(DEPDIR)/libknot_tests_loader_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot_tests_loader_realdata.c' object='libknot_tests_loader_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot_tests_loader_realdata.o `test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot_tests_loader_realdata.c + +libknot_tests_loader_realdata.obj: tests/libknot/realdata/libknot_tests_loader_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot_tests_loader_realdata.obj -MD -MP -MF $(DEPDIR)/libknot_tests_loader_realdata.Tpo -c -o libknot_tests_loader_realdata.obj `if test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot_tests_loader_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libknot_tests_loader_realdata.Tpo $(DEPDIR)/libknot_tests_loader_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot_tests_loader_realdata.c' object='libknot_tests_loader_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot_tests_loader_realdata.obj `if test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot_tests_loader_realdata.c'; fi` + +unittests_libknot_realdata.o: tests/libknot/realdata/unittests_libknot_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot_realdata.o -MD -MP -MF $(DEPDIR)/unittests_libknot_realdata.Tpo -c -o unittests_libknot_realdata.o `test -f 'tests/libknot/realdata/unittests_libknot_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/unittests_libknot_realdata.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot_realdata.Tpo $(DEPDIR)/unittests_libknot_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/unittests_libknot_realdata.c' object='unittests_libknot_realdata.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot_realdata.o `test -f 'tests/libknot/realdata/unittests_libknot_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/unittests_libknot_realdata.c + +unittests_libknot_realdata.obj: tests/libknot/realdata/unittests_libknot_realdata.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot_realdata.obj -MD -MP -MF $(DEPDIR)/unittests_libknot_realdata.Tpo -c -o unittests_libknot_realdata.obj `if test -f 'tests/libknot/realdata/unittests_libknot_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/unittests_libknot_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/unittests_libknot_realdata.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot_realdata.Tpo $(DEPDIR)/unittests_libknot_realdata.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/unittests_libknot_realdata.c' object='unittests_libknot_realdata.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot_realdata.obj `if test -f 'tests/libknot/realdata/unittests_libknot_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/unittests_libknot_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/unittests_libknot_realdata.c'; fi` + +unittests_zp_main.o: zcompile/tests/unittests_zp_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_zp_main.o -MD -MP -MF $(DEPDIR)/unittests_zp_main.Tpo -c -o unittests_zp_main.o `test -f 'zcompile/tests/unittests_zp_main.c' || echo '$(srcdir)/'`zcompile/tests/unittests_zp_main.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_zp_main.Tpo $(DEPDIR)/unittests_zp_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/tests/unittests_zp_main.c' object='unittests_zp_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_zp_main.o `test -f 'zcompile/tests/unittests_zp_main.c' || echo '$(srcdir)/'`zcompile/tests/unittests_zp_main.c + +unittests_zp_main.obj: zcompile/tests/unittests_zp_main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_zp_main.obj -MD -MP -MF $(DEPDIR)/unittests_zp_main.Tpo -c -o unittests_zp_main.obj `if test -f 'zcompile/tests/unittests_zp_main.c'; then $(CYGPATH_W) 'zcompile/tests/unittests_zp_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/tests/unittests_zp_main.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_zp_main.Tpo $(DEPDIR)/unittests_zp_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/tests/unittests_zp_main.c' object='unittests_zp_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_zp_main.obj `if test -f 'zcompile/tests/unittests_zp_main.c'; then $(CYGPATH_W) 'zcompile/tests/unittests_zp_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/tests/unittests_zp_main.c'; fi` + +.l.c: + $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) + +libknotd_la-cf-lex.c: knot/conf/cf-lex.l + \ + $(am__skiplex) \ + $(SHELL) $(YLWRAP) `test -f 'knot/conf/cf-lex.l' || echo '$(srcdir)/'`knot/conf/cf-lex.l $(LEX_OUTPUT_ROOT).c libknotd_la-cf-lex.c -- $(LEX) $(LFLAGS) $(libknotd_la_LFLAGS) + +zlexer.c: zcompile/zlexer.l + \ + $(am__skiplex) \ + $(SHELL) $(YLWRAP) `test -f 'zcompile/zlexer.l' || echo '$(srcdir)/'`zcompile/zlexer.l $(LEX_OUTPUT_ROOT).c zlexer.c -- $(LEX) $(LFLAGS) $(AM_LFLAGS) + +.y.c: + $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) + +libknotd_la-cf-parse.c: knot/conf/cf-parse.y + \ + $(am__skipyacc) \ + $(SHELL) $(YLWRAP) `test -f 'knot/conf/cf-parse.y' || echo '$(srcdir)/'`knot/conf/cf-parse.y y.tab.c libknotd_la-cf-parse.c y.tab.h libknotd_la-cf-parse.h y.output libknotd_la-cf-parse.output -- $(YACC) $(YFLAGS) $(libknotd_la_YFLAGS) + +zparser.c: zcompile/zparser.y + \ + $(am__skipyacc) \ + $(SHELL) $(YLWRAP) `test -f 'zcompile/zparser.y' || echo '$(srcdir)/'`zcompile/zparser.y y.tab.c zparser.c y.tab.h zparser.h y.output zparser.output -- $(YACC) $(YFLAGS) $(AM_YFLAGS) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man8: $(man8_MANS) + @$(NORMAL_INSTALL) + test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ + done; } + +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man8dir)" && rm -f $$files; } + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) config.h +installdirs: + for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f libknotd_la-cf-lex.c + -rm -f libknotd_la-cf-parse.c + -rm -f libknotd_la-cf-parse.h + -rm -f zlexer.c + -rm -f zparser.c + -rm -f zparser.h + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \ + clean-noinstLTLIBRARIES clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libexecPROGRAMS install-sbinPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man8 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libexecPROGRAMS uninstall-man \ + uninstall-sbinPROGRAMS + +uninstall-man: uninstall-man8 + +.MAKE: all check install install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libexecPROGRAMS clean-libtool clean-noinstLTLIBRARIES \ + clean-sbinPROGRAMS ctags distclean distclean-compile \ + distclean-generic distclean-hdr distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libexecPROGRAMS install-man install-man8 install-pdf \ + install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-libexecPROGRAMS uninstall-man uninstall-man8 \ + uninstall-sbinPROGRAMS + + +# automake complains on % rules: +# `%'-style pattern rules are a GNU make extension + +tests/libknot/parsed_data.rc: tests/libknot/files/parsed_data + ../resource.sh tests/libknot/files/parsed_data >$@ + +tests/libknot/realdata/parsed_data.rc: tests/libknot/realdata/files/parsed_data + ../resource.sh tests/libknot/realdata/files/parsed_data >$@ + +tests/libknot/parsed_data_queries.rc: tests/libknot/files/parsed_data_queries + ../resource.sh tests/libknot/files/parsed_data_queries >$@ + +tests/libknot/raw_data_queries.rc: tests/libknot/files/raw_data_queries + ../resource.sh tests/libknot/files/raw_data_queries >$@ + +tests/libknot/raw_data.rc: tests/libknot/files/raw_data + ../resource.sh tests/libknot/files/raw_data >$@ + +tests/libknot/realdata/raw_data.rc: tests/libknot/realdata/files/raw_data + ../resource.sh tests/libknot/realdata/files/raw_data >$@ + +tests/sample_conf.rc: tests/files/sample_conf + ../resource.sh tests/files/sample_conf >$@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/common/WELL1024a.c b/src/common/WELL1024a.c new file mode 100644 index 0000000..dddf75e --- /dev/null +++ b/src/common/WELL1024a.c @@ -0,0 +1,116 @@ +/* ***************************************************************************** */ +/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */ +/* Makoto Matsumoto, Hiroshima University */ +/* Notice: This code can be used freely for personal, academic, */ +/* or non-commercial purposes. For commercial purposes, */ +/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */ +/* ***************************************************************************** */ + +#include <pthread.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <stdio.h> + +#include "WELL1024a.h" + +#define W 32 +#define M1 3 +#define M2 24 +#define M3 10 + +#define MAT0POS(t,v) (v^(v>>t)) +#define MAT0NEG(t,v) (v^(v<<(-(t)))) +#define Identity(v) (v) + +#define V0(s) (s)->state[(s)->i ] +#define VM1(s) (s)->state[((s)->i+M1) & 0x0000001fU] +#define VM2(s) (s)->state[((s)->i+M2) & 0x0000001fU] +#define VM3(s) (s)->state[((s)->i+M3) & 0x0000001fU] +#define VRm1(s) (s)->state[((s)->i+31) & 0x0000001fU] +#define newV0(s) (s)->state[((s)->i+31) & 0x0000001fU] +#define newV1(s) (s)->state[(s)->i ] + +#define FACT 2.32830643653869628906e-10 + +rngstate_t* InitWELLRNG1024a (unsigned *init) { + + rngstate_t *s = malloc(sizeof(rngstate_t)); + if (s == 0) { + return 0; + } + + s->i = 0; + for (int j = 0; j < WELL1024_WIDTH; j++) + s->state[j] = init[j]; + return s; +} + +double WELLRNG1024a (rngstate_t* s) { + unsigned z0 = VRm1(s); + unsigned z1 = Identity(V0(s)) ^ MAT0POS (8, VM1(s)); + unsigned z2 = MAT0NEG (-19, VM2(s)) ^ MAT0NEG(-14,VM3(s)); + newV1(s) = z1 ^ z2; + newV0(s) = MAT0NEG (-11,z0) ^ MAT0NEG(-7,z1) ^ MAT0NEG(-13,z2) ; + s->i = (s->i + 31) & 0x0000001fU; + return ((double) s->state[s->i] * FACT); +} + +/*! \brief TLS unique key for each thread seed. */ +static pthread_key_t tls_prng_key; +static pthread_once_t tls_prng_once = PTHREAD_ONCE_INIT; + +static void tls_prng_deinit(void *ptr) +{ + free(ptr); +} + +static void tls_prng_deinit_main() +{ + tls_prng_deinit(pthread_getspecific(tls_prng_key)); +} + +static void tls_prng_init() +{ + (void) pthread_key_create(&tls_prng_key, tls_prng_deinit); + atexit(tls_prng_deinit_main); // Main thread cleanup +} + +double tls_rand() +{ + /* Setup PRNG state for current thread. */ + (void)pthread_once(&tls_prng_once, tls_prng_init); + + /* Create PRNG state if not exists. */ + rngstate_t* s = pthread_getspecific(tls_prng_key); + if (!s) { + /* Initialize seed from system PRNG generator. */ + unsigned init[WELL1024_WIDTH]; + FILE *fp = fopen("/dev/urandom", "r"); + for (unsigned i = 0; i < WELL1024_WIDTH; ++i) { + int rc = fread(&init[i], sizeof(unsigned), 1, fp); + rc = rc; + } + fclose(fp); + + /* Initialize PRNG state. */ + s = InitWELLRNG1024a(init); + (void)pthread_setspecific(tls_prng_key, s); + } + + return WELLRNG1024a(s); +} + +void tls_seed_set(unsigned init[WELL1024_WIDTH]) +{ + /* Initialize new PRNG state if not exists. */ + rngstate_t* s = pthread_getspecific(tls_prng_key); + if (!s) { + s = InitWELLRNG1024a(init); + (void)pthread_setspecific(tls_prng_key, s); + } else { + /* Reset PRNG state if exists. */ + memcpy(s->state, init, sizeof(unsigned) * WELL1024_WIDTH); + s->i = 0; + } +} diff --git a/src/common/WELL1024a.h b/src/common/WELL1024a.h new file mode 100644 index 0000000..04bf1a1 --- /dev/null +++ b/src/common/WELL1024a.h @@ -0,0 +1,32 @@ +/* ***************************************************************************** */ +/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */ +/* Makoto Matsumoto, Hiroshima University */ +/* Notice: This code can be used freely for personal, academic, */ +/* or non-commercial purposes. For commercial purposes, */ +/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */ +/* ***************************************************************************** */ + +#define WELL1024_WIDTH 32 /* 128 bytes */ + +typedef struct { + unsigned i; + unsigned state[WELL1024_WIDTH]; +} rngstate_t; + +rngstate_t* InitWELLRNG1024a (unsigned *init); +double WELLRNG1024a (rngstate_t* s); + +/*! + * \brief Get pseudorandom number from PRNG initialized in thread-local storage. + * + * No need for initialization, TLS will take care of it. + * + * \retval Pseudorandom number. + */ +double tls_rand(); + +/*! + * \brief Set PRNG seed in thread-local storage to requested value. + * + */ +void tls_seed_set(unsigned init[WELL1024_WIDTH]); diff --git a/src/common/acl.c b/src/common/acl.c new file mode 100644 index 0000000..e73c4dd --- /dev/null +++ b/src/common/acl.c @@ -0,0 +1,185 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stdlib.h> + +#include "common/acl.h" + +static int acl_compare(void *k1, void *k2) +{ + sockaddr_t* a1 = (sockaddr_t *)k1; + sockaddr_t* a2 = (sockaddr_t *)k2; + + /* Check different length, IPv4 goes first. */ + int ldiff = a1->len - a2->len; + if (ldiff != 0) { + return ldiff < 0 ? -1 : 1; + } + + /* Compare integers if IPv4. */ + if (a1->len == sizeof(struct sockaddr_in)) { + + /* Allow if k1 == INADDR_ANY. */ + if (a1->addr4.sin_addr.s_addr == 0) { + return 0; + } + + /* Compare address. */ + ldiff = a1->addr4.sin_addr.s_addr - a2->addr4.sin_addr.s_addr; + if (ldiff != 0) { + return ldiff < 0 ? -1 : 1; + } + + /* Port = 0 means any port match. */ + if (a1->addr4.sin_port == 0) { + return 0; + } + + /* Compare ports on address match. */ + ldiff = ntohs(a1->addr4.sin_port) - ntohs(a2->addr4.sin_port); + if (ldiff != 0) { + return ldiff < 0 ? -1 : 1; + } + return 0; + } + + /* IPv6 matching. */ +#ifndef DISABLE_IPV6 + if (a1->len == sizeof(struct sockaddr_in6)) { + + /* Compare address. */ + /*! \todo Maybe use memcmp()? */ + ldiff = 0; + const unsigned int *a6 = (const unsigned int *)&a1->addr6.sin6_addr; + const unsigned int *b6 = (const unsigned int *)&a2->addr6.sin6_addr; + for (int i = 0; i < (sizeof(struct in6_addr)/ sizeof(int)) ; ++i) { + ldiff = a6[i] - b6[i]; + if (ldiff < 0) { + return -1; + } + if (ldiff > 0) { + return 1; + } + } + + /* Port = 0 means any port match. */ + if (a1->addr6.sin6_port == 0) { + return 0; + } + + /* Compare ports on address match. */ + ldiff = ntohs(a1->addr6.sin6_port) - ntohs(a2->addr6.sin6_port); + if (ldiff != 0) { + return ldiff < 0 ? -1 : 1; + } + return 0; + } +#endif + + return 0; +} + +acl_t *acl_new(acl_rule_t default_rule, const char *name) +{ + /* Trailing '\0' for NULL name. */ + size_t name_len = 1; + if (name) { + name_len += strlen(name); + } else { + name = ""; + } + + /* Allocate memory for ACL. */ + acl_t* acl = malloc(sizeof(acl_t) + name_len); + if (!acl) { + return 0; + } + + /* Initialize skip list. */ + acl->rules = skip_create_list(acl_compare); + if (!acl->rules) { + free(acl); + return 0; + } + + /* Initialize. */ + memcpy(&acl->name, name, name_len); + acl->default_rule = default_rule; + return acl; +} + +void acl_delete(acl_t **acl) +{ + if ((acl == NULL) || (*acl == NULL)) { + return; + } + + /* Truncate rules. */ + if (acl_truncate(*acl) != ACL_ACCEPT) { + return; + } + + /* Free ACL. */ + free(*acl); + *acl = 0; +} + +int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule) +{ + if (!acl || !addr || rule < 0) { + return ACL_ERROR; + } + + /* Insert into skip list. */ + sockaddr_t *key = malloc(sizeof(sockaddr_t)); + memcpy(key, addr, sizeof(sockaddr_t)); + + skip_insert(acl->rules, key, (void*)((ssize_t)rule + 1), 0); + + return ACL_ACCEPT; +} + +int acl_match(acl_t *acl, sockaddr_t* addr) +{ + if (!acl || !addr) { + return ACL_ERROR; + } + + /* Return default rule if not found. + * Conversion to the same length integer is made, + * but we can be sure, that the value range is within <-1,1>. + */ + ssize_t val = ((ssize_t)skip_find(acl->rules, addr)) - 1; + if (val < 0) { + return acl->default_rule; + } + + /* Return stored rule if found. */ + return (int)val; +} + +int acl_truncate(acl_t *acl) +{ + if (acl == NULL) { + return ACL_ERROR; + } + + /* Destroy all rules. */ + skip_destroy_list(&acl->rules, free, 0); + + return ACL_ACCEPT; +} diff --git a/src/common/acl.h b/src/common/acl.h new file mode 100644 index 0000000..c79db7f --- /dev/null +++ b/src/common/acl.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file acl.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Access control lists. + * + * An access control list is a named structure + * for efficient IP address and port matching. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_ACL_H_ +#define _KNOTD_ACL_H_ + +#include "common/skip-list.h" +#include "common/sockaddr.h" + +/*! \brief ACL rules types. */ +typedef enum acl_rule_t { + ACL_ERROR = -1, + ACL_DENY = 0, + ACL_ACCEPT = 1 +} acl_rule_t; + +/*! \brief ACL structure. */ +typedef struct acl_t { + acl_rule_t default_rule; + skip_list_t *rules; + const char name[]; +} acl_t; + +/*! + * \brief Create a new ACL. + * + * \param default_rule Default rule for address matching. + * \param name ACL symbolic name (or NULL). + * + * \retval New ACL instance when successful. + * \retval NULL on errors. + */ +acl_t *acl_new(acl_rule_t default_rule, const char *name); + +/*! + * \brief Delete ACL structure. + * + * \param acl Pointer to ACL instance. + */ +void acl_delete(acl_t **acl); + +/*! + * \brief Create new ACL rule. + * + * \todo Support address subnets. + * + * \param acl Pointer to ACL instance. + * \param addr IP address (will be duplicated). + * \param rule Rule. + * + * \retval ACL_ACCEPT if successful. + * \retval ACP_ERROR on error. + */ +int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule); + +/*! + * \brief Match address against ACL. + * + * \param acl Pointer to ACL instance. + * \param addr IP address. + * + * \retval ACL_ACCEPT if the address is accepted. + * \retval ACL_DENY if the address is not accepted. + * \retval ACP_ERROR on error. + */ +int acl_match(acl_t *acl, sockaddr_t* addr); + +/*! + * \brief Truncate ACL. + * + * All but the default rule will be dropped. + * + * \param acl Pointer to ACL instance. + * + * \retval ACL_ACCEPT if successful. + * \retval ACP_ERROR on error. + */ +int acl_truncate(acl_t *acl); + +/*! + * \brief Return ACL name. + * + * \param acl Pointer to ACL instance. + * + * \retval ACL name. + */ +static inline const char* acl_name(acl_t *acl) { + if (!acl) { + return 0; + } + + return acl->name; +} + +/*! + * \brief Return ACL rules. + * + * \param acl Pointer to ACL instance. + * + * \retval ACL rules skip-list. + */ +static inline skip_list_t* acl_rules(acl_t *acl) { + if (!acl) { + return 0; + } + + return acl->rules; +} + +#endif /* _KNOTD_ACL_H_ */ + +/*! @} */ diff --git a/src/common/base32.c b/src/common/base32.c new file mode 100644 index 0000000..43b86c1 --- /dev/null +++ b/src/common/base32.c @@ -0,0 +1,539 @@ +/* base32.c -- Encode binary data using printable characters. + Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006, 2010 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Adapted from base64.{h,c} by Ondřej Surý. base64.{h,c} was written + * by Simon Josefsson. Partially adapted from GNU MailUtils + * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review + * from Paul Eggert, Bruno Haible, and Stepan Kasal. + * + * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>. + * + * Be careful with error checking. Here is how you would typically + * use these functions: + * + * bool ok = base32_decode_alloc (in, inlen, &out, &outlen); + * if (!ok) + * FAIL: input was not valid base32 + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN + * + * size_t outlen = base32_encode_alloc (in, inlen, &out); + * if (out == NULL && outlen == 0 && inlen != 0) + * FAIL: input too long + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN. + * + */ + +/* Get prototype. */ +#include "base32.h" + +/* Get malloc. */ +#include <stdlib.h> + +/* Get UCHAR_MAX. */ +#include <limits.h> + +/* C89 compliant way to cast 'char' to 'unsigned char'. */ +static inline unsigned char to_uchar(char ch) +{ + return ch; +} + +/* Base32 encode IN array of size INLEN into OUT array of size OUTLEN. + If OUTLEN is less than BASE32_LENGTH(INLEN), write as many bytes as + possible. If OUTLEN is larger than BASE32_LENGTH(INLEN), also zero + terminate the output buffer. */ +void base32_encode(const char *in, size_t inlen, char *out, size_t outlen) +{ + static const char b32str[32] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + + while (inlen && outlen) { + *out++ = b32str[(to_uchar(in[0]) >> 3) & 0x1f]; + if (!--outlen) { + break; + } + *out++ = b32str[((to_uchar(in[0]) << 2) + + (--inlen ? to_uchar(in[1]) >> 6 : 0)) + & 0x1f]; + if (!--outlen) { + break; + } + *out++ =(inlen + ? b32str[(to_uchar(in[1]) >> 1) & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = (inlen + ? b32str[((to_uchar(in[1]) << 4) + + (--inlen ? to_uchar(in[2]) >> 4 : 0)) + & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = (inlen + ? b32str[((to_uchar(in[2]) << 1) + + (--inlen ? to_uchar(in[3]) >> 7 : 0)) + & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = (inlen + ? b32str[(to_uchar(in[3]) >> 2) & 0x1f] + : '='); + if (!--outlen) + { + break; + } + *out++ = (inlen + ? b32str[((to_uchar(in[3]) << 3) + + (--inlen ? to_uchar(in[4]) >> 5 : 0)) + & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = inlen ? b32str[to_uchar(in[4]) & 0x1f] : '='; + if (!--outlen) { + break; + } + if (inlen) { + inlen--; + } + if (inlen) { + in += 5; + } + } + + if (outlen) { + *out = '\0'; + } +} + +/* Allocate a buffer and store zero terminated base32 encoded data + from array IN of size INLEN, returning BASE32_LENGTH(INLEN), i.e., + the length of the encoded data, excluding the terminating zero. On + return, the OUT variable will hold a pointer to newly allocated + memory that must be deallocated by the caller. If output string + length would overflow, 0 is returned and OUT is set to NULL. If + memory allocation failed, OUT is set to NULL, and the return value + indicates length of the requested memory block, i.e., + BASE32_LENGTH(inlen) + 1. */ +size_t base32_encode_alloc(const char *in, size_t inlen, char **out) +{ + size_t outlen = 1 + BASE32_LENGTH (inlen); + + /* Check for overflow in outlen computation. + * + * If there is no overflow, outlen >= inlen. + * + * If the operation (inlen + 2) overflows then it yields at most +1, so + * outlen is 0. + * + * If the multiplication overflows, we lose at least half of the + * correct value, so the result is < ((inlen + 2) / 3) * 2, which is + * less than (inlen + 2) * 0.66667, which is less than inlen as soon as + * (inlen > 4). + */ + if (inlen > outlen) + { + *out = NULL; + return 0; + } + + *out = malloc(outlen); + if (!*out) { + return outlen; + } + + base32_encode(in, inlen, *out, outlen); + + return outlen - 1; +} + +/* With this approach this file works independent of the charset used + (think EBCDIC). However, it does assume that the characters in the + Base32 alphabet (A-Z2-7) are encoded in 0..255. POSIX + 1003.1-2001 require that char and unsigned char are 8-bit + quantities, though, taking care of that problem. But this may be a + potential problem on non-POSIX C99 platforms. + + IBM C V6 for AIX mishandles "#define B32(x) ...'x'...", so use "_" + as the formal parameter rather than "x". */ +#define B32(_) \ + ((_) == 'A' ? 0 \ + : (_) == 'B' ? 1 \ + : (_) == 'C' ? 2 \ + : (_) == 'D' ? 3 \ + : (_) == 'E' ? 4 \ + : (_) == 'F' ? 5 \ + : (_) == 'G' ? 6 \ + : (_) == 'H' ? 7 \ + : (_) == 'I' ? 8 \ + : (_) == 'J' ? 9 \ + : (_) == 'K' ? 10 \ + : (_) == 'L' ? 11 \ + : (_) == 'M' ? 12 \ + : (_) == 'N' ? 13 \ + : (_) == 'O' ? 14 \ + : (_) == 'P' ? 15 \ + : (_) == 'Q' ? 16 \ + : (_) == 'R' ? 17 \ + : (_) == 'S' ? 18 \ + : (_) == 'T' ? 19 \ + : (_) == 'U' ? 20 \ + : (_) == 'V' ? 21 \ + : (_) == 'W' ? 22 \ + : (_) == 'X' ? 23 \ + : (_) == 'Y' ? 24 \ + : (_) == 'Z' ? 25 \ + : (_) == '2' ? 26 \ + : (_) == '3' ? 27 \ + : (_) == '4' ? 28 \ + : (_) == '5' ? 29 \ + : (_) == '6' ? 30 \ + : (_) == '7' ? 31 \ + : -1) + +static const signed char b32[0x100] = { + B32 (0), B32 (1), B32 (2), B32 (3), + B32 (4), B32 (5), B32 (6), B32 (7), + B32 (8), B32 (9), B32 (10), B32 (11), + B32 (12), B32 (13), B32 (14), B32 (15), + B32 (16), B32 (17), B32 (18), B32 (19), + B32 (20), B32 (21), B32 (22), B32 (23), + B32 (24), B32 (25), B32 (26), B32 (27), + B32 (28), B32 (29), B32 (30), B32 (31), + B32 (32), B32 (33), B32 (34), B32 (35), + B32 (36), B32 (37), B32 (38), B32 (39), + B32 (40), B32 (41), B32 (42), B32 (43), + B32 (44), B32 (45), B32 (46), B32 (47), + B32 (48), B32 (49), B32 (50), B32 (51), + B32 (52), B32 (53), B32 (54), B32 (55), + B32 (56), B32 (57), B32 (58), B32 (59), + B32 (60), B32 (61), B32 (62), B32 (63), + B32 (64), B32 (65), B32 (66), B32 (67), + B32 (68), B32 (69), B32 (70), B32 (71), + B32 (72), B32 (73), B32 (74), B32 (75), + B32 (76), B32 (77), B32 (78), B32 (79), + B32 (80), B32 (81), B32 (82), B32 (83), + B32 (84), B32 (85), B32 (86), B32 (87), + B32 (88), B32 (89), B32 (90), B32 (91), + B32 (92), B32 (93), B32 (94), B32 (95), + B32 (96), B32 (97), B32 (98), B32 (99), + B32 (100), B32 (101), B32 (102), B32 (103), + B32 (104), B32 (105), B32 (106), B32 (107), + B32 (108), B32 (109), B32 (110), B32 (111), + B32 (112), B32 (113), B32 (114), B32 (115), + B32 (116), B32 (117), B32 (118), B32 (119), + B32 (120), B32 (121), B32 (122), B32 (123), + B32 (124), B32 (125), B32 (126), B32 (127), + B32 (128), B32 (129), B32 (130), B32 (131), + B32 (132), B32 (133), B32 (134), B32 (135), + B32 (136), B32 (137), B32 (138), B32 (139), + B32 (140), B32 (141), B32 (142), B32 (143), + B32 (144), B32 (145), B32 (146), B32 (147), + B32 (148), B32 (149), B32 (150), B32 (151), + B32 (152), B32 (153), B32 (154), B32 (155), + B32 (156), B32 (157), B32 (158), B32 (159), + B32 (160), B32 (161), B32 (162), B32 (163), + B32 (164), B32 (165), B32 (166), B32 (167), + B32 (168), B32 (169), B32 (170), B32 (171), + B32 (172), B32 (173), B32 (174), B32 (175), + B32 (176), B32 (177), B32 (178), B32 (179), + B32 (180), B32 (181), B32 (182), B32 (183), + B32 (184), B32 (185), B32 (186), B32 (187), + B32 (188), B32 (189), B32 (190), B32 (191), + B32 (192), B32 (193), B32 (194), B32 (195), + B32 (196), B32 (197), B32 (198), B32 (199), + B32 (200), B32 (201), B32 (202), B32 (203), + B32 (204), B32 (205), B32 (206), B32 (207), + B32 (208), B32 (209), B32 (210), B32 (211), + B32 (212), B32 (213), B32 (214), B32 (215), + B32 (216), B32 (217), B32 (218), B32 (219), + B32 (220), B32 (221), B32 (222), B32 (223), + B32 (224), B32 (225), B32 (226), B32 (227), + B32 (228), B32 (229), B32 (230), B32 (231), + B32 (232), B32 (233), B32 (234), B32 (235), + B32 (236), B32 (237), B32 (238), B32 (239), + B32 (240), B32 (241), B32 (242), B32 (243), + B32 (244), B32 (245), B32 (246), B32 (247), + B32 (248), B32 (249), B32 (250), B32 (251), + B32 (252), B32 (253), B32 (254), B32 (255) +}; + +#if UCHAR_MAX == 255 +#define uchar_in_range(c) true +#else +#define uchar_in_range(c) ((c) <= 255) +#endif + +/* Return true if CH is a character from the Base32 alphabet, and + false otherwise. Note that '=' is padding and not considered to be + part of the alphabet. */ +bool isbase32(char ch) +{ + return uchar_in_range(to_uchar(ch)) && 0 <= b32[to_uchar(ch)]; +} + +/* Decode base32 encoded input array IN of length INLEN to output + array OUT that can hold *OUTLEN bytes. Return true if decoding was + successful, i.e. if the input was valid base32 data, false + otherwise. If *OUTLEN is too small, as many bytes as possible will + be written to OUT. On return, *OUTLEN holds the length of decoded + bytes in OUT. Note that as soon as any non-alphabet characters are + encountered, decoding is stopped and false is returned. This means + that, when applicable, you must remove any line terminators that is + part of the data stream before calling this function. */ +bool base32_decode(const char *in, size_t inlen, char *out, size_t *outlen) +{ + size_t outleft = *outlen; + + while (inlen >= 2) { + if (!isbase32(in[0]) || !isbase32(in[1])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[0])] << 3) + | (b32[to_uchar(in[1])] >> 2)); + outleft--; + } + + if (inlen == 2) { + break; + } + + if (in[2] == '=') { + if (inlen != 8) { + break; + } + + if ((in[3] != '=') || + (in[4] != '=') || + (in[5] != '=') || + (in[6] != '=') || + (in[7] != '=')) { + break; + } + } else { + if (!isbase32(in[2]) || !isbase32(in[3])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[1])] << 6) + | ((b32[to_uchar(in[2])] << 1) & 0x3E) + | (b32[to_uchar(in[3])] >> 4)); + outleft--; + } + + if (inlen == 4) { + break; + } + + if (in[4] == '=') { + if (inlen != 8) { + break; + } + + if ((in[5] != '=') || + (in[6] != '=') || + (in[7] != '=')) { + break; + } + } else { + if (!isbase32 (in[3]) || !isbase32(in[4])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[3])] << 4) + | (b32[to_uchar(in[4])] >> 1)); + outleft--; + } + + if (inlen == 5) { + break; + } + + if (in[5] == '=') { + if (inlen != 8) { + break; + } + + if ((in[6] != '=') + || (in[7] != '=')) { + break; + } + } else { + if (!isbase32 (in[5]) + || !isbase32 (in[6])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[4])] + << 7) + | (b32[to_uchar(in[5])] << 2) + | (b32[to_uchar(in[6])] + >> 3)); + outleft--; + } + + if (inlen == 7) { + break; + } + + if (in[7] == '=') { + if (inlen != 8) { + break; + } + } else { + if (!isbase32 (in[7])) { + break; + } + + if (outleft) { + *out++ = + ((b32[to_uchar(in[6])] + << 5) | (b32[ + to_uchar(in[7])])); + outleft--; + } + } + } + } + } + + in += 8; + inlen -= 8; + } + + *outlen -= outleft; + + if (inlen != 0) { + return false; + } + + return true; +} + +/* Allocate an output buffer in *OUT, and decode the base32 encoded + data stored in IN of size INLEN to the *OUT buffer. On return, the + size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL, + if the caller is not interested in the decoded length. *OUT may be + NULL to indicate an out of memory error, in which case *OUTLEN + contains the size of the memory block needed. The function returns + true on successful decoding and memory allocation errors. (Use the + *OUT and *OUTLEN parameters to differentiate between successful + decoding and memory error.) The function returns false if the + input was invalid, in which case *OUT is NULL and *OUTLEN is + undefined. */ +bool base32_decode_alloc(const char *in, size_t inlen, char **out, + size_t *outlen) +{ + /* This may allocate a few bytes too much, depending on input, + but it's not worth the extra CPU time to compute the exact amount. + The exact amount is 5 * inlen / 8, minus 1 if the input ends + with "=" and minus another 1 if the input ends with "==", etc. + Dividing before multiplying avoids the possibility of overflow. */ + size_t needlen = 5 * (inlen / 8) + 4; + + *out = malloc(needlen); + if (!*out) { + return true; + } + + if (!base32_decode(in, inlen, *out, &needlen)) { + free (*out); + *out = NULL; + return false; + } + + if (outlen) { + *outlen = needlen; + } + + return true; +} + +#ifdef MAIN + +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <stdio.h> +#include "base32.h" + +int main(int argc, char **argv) { + int i = 1; + size_t inlen, outlen, argvlen; + char *out; + char *in; + bool ok; + + while (argc > 1) { + argv++; argc--; + argvlen = strlen(*argv); + + outlen = base32_encode_alloc(*argv, argvlen, &out); + + if (out == NULL && outlen == 0 && inlen != 0) { + fprintf(stderr, "ERROR(encode): input too long: %zd\n", + outlen); + return 1; + } + + if (out == NULL) { + fprintf(stderr, "ERROR(encode): memory allocation error" + "\n"); + return 1; + } + + ok = base32_decode_alloc(out, outlen, &in, &inlen); + + if (!ok) { + fprintf(stderr, "ERROR(decode): input was not valid " + "base32: `%s'\n", out); + return 1; + } + + if (in == NULL) { + fprintf(stderr, "ERROR(decode): memory allocation " + "error\n"); + } + + if ((inlen != argvlen) || + strcmp(*argv, in) != 0) { + fprintf(stderr, "ERROR(encode/decode): input `%s' and " + "output `%s'\n", *argv, in); + return 1; + } + printf("INPUT: `%s'\nENCODE: `%s'\nDECODE: `%s'\n", *argv, out, + in); + } +} + +#endif diff --git a/src/common/base32.h b/src/common/base32.h new file mode 100644 index 0000000..45df9fa --- /dev/null +++ b/src/common/base32.h @@ -0,0 +1,121 @@ +/* base32.h -- Encode binary data using printable characters. + Copyright (C) 2004, 2005, 2006, 2010 Free Software Foundation, Inc. + Written by Ondřej Surý & Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BASE32_H_ +#define _BASE32_H_ + +/* Get size_t. */ +#include <stddef.h> + +/* Get bool. */ +#include <stdbool.h> + +/*! + * \brief Counts the size of the Base32-encoded output for given input length. + * + * \note This uses that the expression (n+(k-1))/k means the smallest + * integer >= n/k, i.e., the ceiling of n/k. + */ +#define BASE32_LENGTH(inlen) ((((inlen) + 4) / 5) * 8) + +/*! + * \brief Checks if the given character belongs to the Base32 alphabet. + * + * \param ch Character to check. + * + * \retval true if \a ch belongs to the Base32 alphabet. + * \retval false otherwise. + */ +extern bool isbase32(char ch); + +/*! + * \brief Encodes the given character array using Base32 encoding. + * + * If \a outlen is less than BASE32_LENGTH(\a inlen), the function writes as + * many bytes as possible to the output buffer. If \a outlen is more than + * BASE32_LENGTH(\a inlen), the output will be zero-terminated. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. + * \param outlen Size of the output buffer. + */ +extern void base32_encode(const char *in, size_t inlen, char *out, + size_t outlen); + +/*! + * \brief Encodes the given character array using Base32 encoding and allocates + * space for the output. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. + * + * \return Size of the allocated output buffer (0 if failed). + */ +extern size_t base32_encode_alloc(const char *in, size_t inlen, char **out); + +/*! + * \brief Decodes the given character array in Base32 encoding. + * + * If \a *outlen is too small, as many bytes as possible will be written to + * \a out. On return, \a *outlen holds the length of decoded bytes in \a out. + * + * \note As soon as any non-alphabet characters are encountered, decoding is + * stopped and false is returned. This means that, when applicable, you + * must remove any line terminators that is part of the data stream before + * calling this function. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. + * \param outlen Size of the output buffer. + * + * \retval true if decoding was successful, i.e. if the input was valid base32 + * data. + * \retval false otherwise. + */ +extern bool base32_decode(const char *in, size_t inlen, char *out, + size_t *outlen); + +/*! + * \brief Allocate an output buffer and decode the base32 encoded data to it. + * + * On return, the size of the decoded data is stored in \a *outlen. \a outlen + * may be NULL, if the caller is not interested in the decoded length. \a *out + * may be NULL to indicate an out of memory error, in which case \a *outlen + * contains the size of the memory block needed. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. \a *out may be NULL to indicate an out of memory + * error in which case \a *outlen contains the size of the memory + * block needed + * \param outlen Size of the output buffer. May be NULL, if the caller is not + * interested in the decoded length + * + * \retval true on successful decoding and memory allocation errors. (Use the + * \a *out and \a *outlen parameters to differentiate between + * successful decoding and memory error.) + * \retval false if the input was invalid, in which case \a *out is NULL and + * \a *outlen is undefined. + */ +extern bool base32_decode_alloc(const char *in, size_t inlen, char **out, + size_t *outlen); + +#endif /* _BASE32_H_ */ diff --git a/src/common/base32hex.c b/src/common/base32hex.c new file mode 100644 index 0000000..cd2d2ce --- /dev/null +++ b/src/common/base32hex.c @@ -0,0 +1,562 @@ +/* base32hex.c -- Encode binary data using printable characters. + Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006, 2010 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Adapted from base32.{h,c}. base32.{h,c} was adapted from + * base64.{h,c} by Ondřej Surý. base64.{h,c} was written by Simon + * Josefsson. Partially adapted from GNU MailUtils + * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review + * from Paul Eggert, Bruno Haible, and Stepan Kasal. + * + * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>. + * + * Be careful with error checking. Here is how you would typically + * use these functions: + * + * bool ok = base32hex_decode_alloc (in, inlen, &out, &outlen); + * if (!ok) + * FAIL: input was not valid base32hex + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN + * + * size_t outlen = base32hex_encode_alloc (in, inlen, &out); + * if (out == NULL && outlen == 0 && inlen != 0) + * FAIL: input too long + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN. + * + */ + +/* Get prototype. */ +#include "base32hex.h" + +/* Get malloc. */ +#include <stdlib.h> + +/* Get UCHAR_MAX. */ +#include <limits.h> + +/* C89 compliant way to cast 'char' to 'unsigned char'. */ +static inline unsigned char to_uchar(char ch) +{ + return ch; +} + +/* Base32hex encode IN array of size INLEN into OUT array of size OUTLEN. + If OUTLEN is less than BASE32HEX_LENGTH(INLEN), write as many bytes as + possible. If OUTLEN is larger than BASE32HEX_LENGTH(INLEN), also zero + terminate the output buffer. */ +void base32hex_encode(const char *in, size_t inlen, char *out, size_t outlen) +{ + static const char b32str[32] = + "0123456789ABCDEFGHIJKLMNOPQRSTUV"; + + while (inlen && outlen) { + *out++ = b32str[(to_uchar(in[0]) >> 3) & 0x1f]; + if (!--outlen) { + break; + } + *out++ = b32str[((to_uchar(in[0]) << 2) + + (--inlen ? to_uchar(in[1]) >> 6 : 0)) + & 0x1f]; + if (!--outlen) { + break; + } + *out++ =(inlen + ? b32str[(to_uchar(in[1]) >> 1) & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = (inlen + ? b32str[((to_uchar(in[1]) << 4) + + (--inlen ? to_uchar(in[2]) >> 4 : 0)) + & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = (inlen + ? b32str[((to_uchar(in[2]) << 1) + + (--inlen ? to_uchar(in[3]) >> 7 : 0)) + & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = (inlen + ? b32str[(to_uchar(in[3]) >> 2) & 0x1f] + : '='); + if (!--outlen) + { + break; + } + *out++ = (inlen + ? b32str[((to_uchar(in[3]) << 3) + + (--inlen ? to_uchar(in[4]) >> 5 : 0)) + & 0x1f] + : '='); + if (!--outlen) { + break; + } + *out++ = inlen ? b32str[to_uchar(in[4]) & 0x1f] : '='; + if (!--outlen) { + break; + } + if (inlen) { + inlen--; + } + if (inlen) { + in += 5; + } + } + + if (outlen) { + *out = '\0'; + } +} + +/* Allocate a buffer and store zero terminated base32hex encoded data + from array IN of size INLEN, returning BASE32HEX_LENGTH(INLEN), i.e., + the length of the encoded data, excluding the terminating zero. On + return, the OUT variable will hold a pointer to newly allocated + memory that must be deallocated by the caller. If output string + length would overflow, 0 is returned and OUT is set to NULL. If + memory allocation failed, OUT is set to NULL, and the return value + indicates length of the requested memory block, i.e., + BASE32HEX_LENGTH(inlen) + 1. */ +size_t base32hex_encode_alloc(const char *in, size_t inlen, char **out) +{ + size_t outlen = 1 + BASE32HEX_LENGTH (inlen); + + /* Check for overflow in outlen computation. + * + * If there is no overflow, outlen >= inlen. + * + * If the operation (inlen + 2) overflows then it yields at most +1, so + * outlen is 0. + * + * If the multiplication overflows, we lose at least half of the + * correct value, so the result is < ((inlen + 2) / 3) * 2, which is + * less than (inlen + 2) * 0.66667, which is less than inlen as soon as + * (inlen > 4). + */ + if (inlen > outlen) + { + *out = NULL; + return 0; + } + + *out = malloc(outlen); + if (!*out) { + return outlen; + } + + base32hex_encode(in, inlen, *out, outlen); + + return outlen - 1; +} + +/* With this approach this file works independent of the charset used + (think EBCDIC). However, it does assume that the characters in the + Base32hex alphabet (A-Z2-7) are encoded in 0..255. POSIX + 1003.1-2001 require that char and unsigned char are 8-bit + quantities, though, taking care of that problem. But this may be a + potential problem on non-POSIX C99 platforms. + + IBM C V6 for AIX mishandles "#define B32(x) ...'x'...", so use "_" + as the formal parameter rather than "x". */ +#define B32(_) \ + ((_) == '0' ? 0 \ + : (_) == '1' ? 1 \ + : (_) == '2' ? 2 \ + : (_) == '3' ? 3 \ + : (_) == '4' ? 4 \ + : (_) == '5' ? 5 \ + : (_) == '6' ? 6 \ + : (_) == '7' ? 7 \ + : (_) == '8' ? 8 \ + : (_) == '9' ? 9 \ + : (_) == 'A' ? 10 \ + : (_) == 'B' ? 11 \ + : (_) == 'C' ? 12 \ + : (_) == 'D' ? 13 \ + : (_) == 'E' ? 14 \ + : (_) == 'F' ? 15 \ + : (_) == 'G' ? 16 \ + : (_) == 'H' ? 17 \ + : (_) == 'I' ? 18 \ + : (_) == 'J' ? 19 \ + : (_) == 'K' ? 20 \ + : (_) == 'L' ? 21 \ + : (_) == 'M' ? 22 \ + : (_) == 'N' ? 23 \ + : (_) == 'O' ? 24 \ + : (_) == 'P' ? 25 \ + : (_) == 'Q' ? 26 \ + : (_) == 'R' ? 27 \ + : (_) == 'S' ? 28 \ + : (_) == 'T' ? 29 \ + : (_) == 'U' ? 30 \ + : (_) == 'V' ? 31 \ + : (_) == 'a' ? 10 \ + : (_) == 'b' ? 11 \ + : (_) == 'c' ? 12 \ + : (_) == 'd' ? 13 \ + : (_) == 'e' ? 14 \ + : (_) == 'f' ? 15 \ + : (_) == 'g' ? 16 \ + : (_) == 'h' ? 17 \ + : (_) == 'i' ? 18 \ + : (_) == 'j' ? 19 \ + : (_) == 'k' ? 20 \ + : (_) == 'l' ? 21 \ + : (_) == 'm' ? 22 \ + : (_) == 'n' ? 23 \ + : (_) == 'o' ? 24 \ + : (_) == 'p' ? 25 \ + : (_) == 'q' ? 26 \ + : (_) == 'r' ? 27 \ + : (_) == 's' ? 28 \ + : (_) == 't' ? 29 \ + : (_) == 'u' ? 30 \ + : (_) == 'v' ? 31 \ + : -1) + +static const signed char b32[0x100] = { + B32 (0), B32 (1), B32 (2), B32 (3), + B32 (4), B32 (5), B32 (6), B32 (7), + B32 (8), B32 (9), B32 (10), B32 (11), + B32 (12), B32 (13), B32 (14), B32 (15), + B32 (16), B32 (17), B32 (18), B32 (19), + B32 (20), B32 (21), B32 (22), B32 (23), + B32 (24), B32 (25), B32 (26), B32 (27), + B32 (28), B32 (29), B32 (30), B32 (31), + B32 (32), B32 (33), B32 (34), B32 (35), + B32 (36), B32 (37), B32 (38), B32 (39), + B32 (40), B32 (41), B32 (42), B32 (43), + B32 (44), B32 (45), B32 (46), B32 (47), + B32 (48), B32 (49), B32 (50), B32 (51), + B32 (52), B32 (53), B32 (54), B32 (55), + B32 (56), B32 (57), B32 (58), B32 (59), + B32 (60), B32 (61), B32 (62), B32 (63), + B32 (64), B32 (65), B32 (66), B32 (67), + B32 (68), B32 (69), B32 (70), B32 (71), + B32 (72), B32 (73), B32 (74), B32 (75), + B32 (76), B32 (77), B32 (78), B32 (79), + B32 (80), B32 (81), B32 (82), B32 (83), + B32 (84), B32 (85), B32 (86), B32 (87), + B32 (88), B32 (89), B32 (90), B32 (91), + B32 (92), B32 (93), B32 (94), B32 (95), + B32 (96), B32 (97), B32 (98), B32 (99), + B32 (100), B32 (101), B32 (102), B32 (103), + B32 (104), B32 (105), B32 (106), B32 (107), + B32 (108), B32 (109), B32 (110), B32 (111), + B32 (112), B32 (113), B32 (114), B32 (115), + B32 (116), B32 (117), B32 (118), B32 (119), + B32 (120), B32 (121), B32 (122), B32 (123), + B32 (124), B32 (125), B32 (126), B32 (127), + B32 (128), B32 (129), B32 (130), B32 (131), + B32 (132), B32 (133), B32 (134), B32 (135), + B32 (136), B32 (137), B32 (138), B32 (139), + B32 (140), B32 (141), B32 (142), B32 (143), + B32 (144), B32 (145), B32 (146), B32 (147), + B32 (148), B32 (149), B32 (150), B32 (151), + B32 (152), B32 (153), B32 (154), B32 (155), + B32 (156), B32 (157), B32 (158), B32 (159), + B32 (160), B32 (161), B32 (162), B32 (163), + B32 (164), B32 (165), B32 (166), B32 (167), + B32 (168), B32 (169), B32 (170), B32 (171), + B32 (172), B32 (173), B32 (174), B32 (175), + B32 (176), B32 (177), B32 (178), B32 (179), + B32 (180), B32 (181), B32 (182), B32 (183), + B32 (184), B32 (185), B32 (186), B32 (187), + B32 (188), B32 (189), B32 (190), B32 (191), + B32 (192), B32 (193), B32 (194), B32 (195), + B32 (196), B32 (197), B32 (198), B32 (199), + B32 (200), B32 (201), B32 (202), B32 (203), + B32 (204), B32 (205), B32 (206), B32 (207), + B32 (208), B32 (209), B32 (210), B32 (211), + B32 (212), B32 (213), B32 (214), B32 (215), + B32 (216), B32 (217), B32 (218), B32 (219), + B32 (220), B32 (221), B32 (222), B32 (223), + B32 (224), B32 (225), B32 (226), B32 (227), + B32 (228), B32 (229), B32 (230), B32 (231), + B32 (232), B32 (233), B32 (234), B32 (235), + B32 (236), B32 (237), B32 (238), B32 (239), + B32 (240), B32 (241), B32 (242), B32 (243), + B32 (244), B32 (245), B32 (246), B32 (247), + B32 (248), B32 (249), B32 (250), B32 (251), + B32 (252), B32 (253), B32 (254), B32 (255) +}; + +#if UCHAR_MAX == 255 +#define uchar_in_range(c) true +#else +#define uchar_in_range(c) ((c) <= 255) +#endif + +/* Return true if CH is a character from the Base32hex alphabet, and + false otherwise. Note that '=' is padding and not considered to be + part of the alphabet. */ +bool isbase32hex(char ch) +{ + return uchar_in_range(to_uchar(ch)) && 0 <= b32[to_uchar(ch)]; +} + +/* Decode base32hex encoded input array IN of length INLEN to output + array OUT that can hold *OUTLEN bytes. Return true if decoding was + successful, i.e. if the input was valid base32hex data, false + otherwise. If *OUTLEN is too small, as many bytes as possible will + be written to OUT. On return, *OUTLEN holds the length of decoded + bytes in OUT. Note that as soon as any non-alphabet characters are + encountered, decoding is stopped and false is returned. This means + that, when applicable, you must remove any line terminators that is + part of the data stream before calling this function. */ +bool base32hex_decode(const char *in, size_t inlen, char *out, size_t *outlen) +{ + size_t outleft = *outlen; + + while (inlen >= 2) { + if (!isbase32hex(in[0]) || !isbase32hex(in[1])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[0])] << 3) + | (b32[to_uchar(in[1])] >> 2)); + outleft--; + } + + if (inlen == 2) { + break; + } + + if (in[2] == '=') { + if (inlen != 8) { + break; + } + + if ((in[3] != '=') || + (in[4] != '=') || + (in[5] != '=') || + (in[6] != '=') || + (in[7] != '=')) { + break; + } + } else { + if (!isbase32hex(in[2]) || !isbase32hex(in[3])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[1])] << 6) + | ((b32[to_uchar(in[2])] << 1) & 0x3E) + | (b32[to_uchar(in[3])] >> 4)); + outleft--; + } + + if (inlen == 4) { + break; + } + + if (in[4] == '=') { + if (inlen != 8) { + break; + } + + if ((in[5] != '=') || + (in[6] != '=') || + (in[7] != '=')) { + break; + } + } else { + if (!isbase32hex (in[3]) || !isbase32hex(in[4])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[3])] << 4) + | (b32[to_uchar(in[4])] >> 1)); + outleft--; + } + + if (inlen == 5) { + break; + } + + if (in[5] == '=') { + if (inlen != 8) { + break; + } + + if ((in[6] != '=') + || (in[7] != '=')) { + break; + } + } else { + if (!isbase32hex (in[5]) + || !isbase32hex (in[6])) { + break; + } + + if (outleft) { + *out++ = ((b32[to_uchar(in[4])] + << 7) + | (b32[to_uchar(in[5])] << 2) + | (b32[to_uchar(in[6])] + >> 3)); + outleft--; + } + + if (inlen == 7) { + break; + } + + if (in[7] == '=') { + if (inlen != 8) { + break; + } + } else { + if (!isbase32hex (in[7])) { + break; + } + + if (outleft) { + *out++ = + ((b32[to_uchar(in[6])] + << 5) | (b32[ + to_uchar(in[7])])); + outleft--; + } + } + } + } + } + + in += 8; + inlen -= 8; + } + + *outlen -= outleft; + + if (inlen != 0) { + return false; + } + + return true; +} + +/* Allocate an output buffer in *OUT, and decode the base32hex encoded + data stored in IN of size INLEN to the *OUT buffer. On return, the + size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL, + if the caller is not interested in the decoded length. *OUT may be + NULL to indicate an out of memory error, in which case *OUTLEN + contains the size of the memory block needed. The function returns + true on successful decoding and memory allocation errors. (Use the + *OUT and *OUTLEN parameters to differentiate between successful + decoding and memory error.) The function returns false if the + input was invalid, in which case *OUT is NULL and *OUTLEN is + undefined. */ +bool base32hex_decode_alloc(const char *in, size_t inlen, char **out, + size_t *outlen) +{ + /* This may allocate a few bytes too much, depending on input, + but it's not worth the extra CPU time to compute the exact amount. + The exact amount is 5 * inlen / 8, minus 1 if the input ends + with "=" and minus another 1 if the input ends with "==", etc. + Dividing before multiplying avoids the possibility of overflow. */ + size_t needlen = 5 * (inlen / 8) + 4; + + *out = malloc(needlen); + if (!*out) { + return true; + } + + if (!base32hex_decode(in, inlen, *out, &needlen)) { + free (*out); + *out = NULL; + return false; + } + + if (outlen) { + *outlen = needlen; + } + + return true; +} + +#ifdef MAIN + +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <stdio.h> +#include "base32hex.h" + +int main(int argc, char **argv) { + int i = 1; + size_t inlen, outlen, argvlen; + char *out; + char *in; + bool ok; + + while (argc > 1) { + argv++; argc--; + argvlen = strlen(*argv); + + outlen = base32hex_encode_alloc(*argv, argvlen, &out); + + if (out == NULL && outlen == 0 && inlen != 0) { + fprintf(stderr, "ERROR(encode): input too long: %zd\n", + outlen); + return 1; + } + + if (out == NULL) { + fprintf(stderr, "ERROR(encode): memory allocation error" + "\n"); + return 1; + } + + ok = base32hex_decode_alloc(out, outlen, &in, &inlen); + + if (!ok) { + fprintf(stderr, "ERROR(decode): input was not valid " + "base32hex: `%s'\n", out); + return 1; + } + + if (in == NULL) { + fprintf(stderr, "ERROR(decode): memory allocation " + "error\n"); + } + + if ((inlen != argvlen) || + strcmp(*argv, in) != 0) { + fprintf(stderr, "ERROR(encode/decode): input `%s' and " + "output `%s'\n", *argv, in); + return 1; + } + printf("INPUT: `%s'\nENCODE: `%s'\nDECODE: `%s'\n", *argv, out, + in); + } +} + +#endif diff --git a/src/common/base32hex.h b/src/common/base32hex.h new file mode 100644 index 0000000..9ac4fa8 --- /dev/null +++ b/src/common/base32hex.h @@ -0,0 +1,124 @@ +/* base32hex.h -- Encode binary data using printable characters. + Copyright (C) 2004, 2005, 2006, 2010 Free Software Foundation, Inc. + Written by Ondřej Surý & Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BASE32HEX_H_ +#define _BASE32HEX_H_ + +/* Get size_t. */ +#include <stddef.h> + +/* Get bool. */ +#include <stdbool.h> + +/*! + * \brief Counts the size of the Base32Hex-encoded output for given input + * length. + * + * \note This uses that the expression (n+(k-1))/k means the smallest + * integer >= n/k, i.e., the ceiling of n/k. + */ +#define BASE32HEX_LENGTH(inlen) ((((inlen) + 4) / 5) * 8) + +/*! + * \brief Checks if the given character belongs to the Base32Hex alphabet. + * + * \param ch Character to check. + * + * \retval true if \a ch belongs to the Base32Hex alphabet. + * \retval false otherwise. + */ +extern bool isbase32hex(char ch); + +/*! + * \brief Encodes the given character array using Base32 encoding with extended + * hex alphabet. + * + * If \a outlen is less than BASE32HEX_LENGTH(\a inlen), the function writes as + * many bytes as possible to the output buffer. If \a outlen is more than + * BASE32HEX_LENGTH(\a inlen), the output will be zero-terminated. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. + * \param outlen Size of the output buffer. + */ +extern void base32hex_encode(const char *in, size_t inlen, char *out, + size_t outlen); + +/*! + * \brief Encodes the given character array using Base32 encoding with extended + * hex alphabet and allocates space for the output. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. + * + * \return Size of the allocated output buffer (0 if failed). + */ +extern size_t base32hex_encode_alloc(const char *in, size_t inlen, char **out); + +/*! + * \brief Decodes the given character array in Base32 encoding with extended + * hex alphabet. + * + * If \a *outlen is too small, as many bytes as possible will be written to + * \a out. On return, \a *outlen holds the length of decoded bytes in \a out. + * + * \note As soon as any non-alphabet characters are encountered, decoding is + * stopped and false is returned. This means that, when applicable, you + * must remove any line terminators that is part of the data stream before + * calling this function. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. + * \param outlen Size of the output buffer. + * + * \retval true if decoding was successful, i.e. if the input was valid + * base32hex data. + * \retval false otherwise. + */ +extern bool base32hex_decode(const char *in, size_t inlen, char *out, + size_t *outlen); + +/*! + * \brief Allocate an output buffer and decode the base32hex encoded data to it. + * + * On return, the size of the decoded data is stored in \a *outlen. \a outlen + * may be NULL, if the caller is not interested in the decoded length. \a *out + * may be NULL to indicate an out of memory error, in which case \a *outlen + * contains the size of the memory block needed. + * + * \param in Input array of characters. + * \param inlen Length of the input array. + * \param out Output buffer. \a *out may be NULL to indicate an out of memory + * error in which case \a *outlen contains the size of the memory + * block needed + * \param outlen Size of the output buffer. May be NULL, if the caller is not + * interested in the decoded length + * + * \retval true on successful decoding and memory allocation errors. (Use the + * \a *out and \a *outlen parameters to differentiate between + * successful decoding and memory error.) + * \retval false if the input was invalid, in which case \a *out is NULL and + * \a *outlen is undefined. + */ +extern bool base32hex_decode_alloc(const char *in, size_t inlen, char **out, + size_t *outlen); + +#endif /* _BASE32HEX_H_ */ diff --git a/src/common/crc.c b/src/common/crc.c new file mode 100644 index 0000000..33bf903 --- /dev/null +++ b/src/common/crc.c @@ -0,0 +1,155 @@ +/* + Copyright (c) 2006-2011, Thomas Pircher <tehpeh@gmx.net> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/** + * \file crc.c + * Functions and types for CRC checks. + * + * Generated on Fri May 6 11:25:47 2011, + * by pycrc v0.7.7, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 32 + * Poly = 0x04c11db7 + * XorIn = 0xffffffff + * ReflectIn = True + * XorOut = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#include "crc.h" +#include <stdint.h> +#include <stdlib.h> + +/** + * Static table used for the table_driven implementation. + *****************************************************************************/ +static const crc_t crc_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +/** + * Reflect all bits of a \a data word of \a data_len bytes. + * + * \param data The data word to be reflected. + * \param data_len The width of \a data expressed in number of bits. + * \return The reflected data. + *****************************************************************************/ +crc_t crc_reflect(crc_t data, size_t data_len) +{ + unsigned int i; + crc_t ret; + + ret = data & 0x01; + for (i = 1; i < data_len; i++) { + data >>= 1; + ret = (ret << 1) | (data & 0x01); + } + return ret; +} + + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len) +{ + unsigned int tbl_idx; + + while (data_len--) { + tbl_idx = (crc ^ *data) & 0xff; + crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff; + + data++; + } + return crc & 0xffffffff; +} + + + diff --git a/src/common/crc.h b/src/common/crc.h new file mode 100644 index 0000000..41971a9 --- /dev/null +++ b/src/common/crc.h @@ -0,0 +1,110 @@ +/* + Copyright (c) 2006-2011, Thomas Pircher <tehpeh@gmx.net> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ +/** + * \file crc.h + * Functions and types for CRC checks. + * + * Generated on Fri May 6 11:25:43 2011, + * by pycrc v0.7.7, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 32 + * Poly = 0x04c11db7 + * XorIn = 0xffffffff + * ReflectIn = True + * XorOut = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#ifndef __CRC_H__ +#define __CRC_H__ + +#include <stdint.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * The definition of the used algorithm. + *****************************************************************************/ +#define CRC_ALGO_TABLE_DRIVEN 1 + + +/** + * The type of the CRC values. + * + * This type must be big enough to contain at least 32 bits. + *****************************************************************************/ +typedef uint32_t crc_t; + + +/** + * Reflect all bits of a \a data word of \a data_len bytes. + * + * \param data The data word to be reflected. + * \param data_len The width of \a data expressed in number of bits. + * \return The reflected data. + *****************************************************************************/ +crc_t crc_reflect(crc_t data, size_t data_len); + + +/** + * Calculate the initial crc value. + * + * \return The initial crc value. + *****************************************************************************/ +static inline crc_t crc_init(void) +{ + return 0xffffffff; +} + + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len); + + +/** + * Calculate the final crc value. + * + * \param crc The current crc value. + * \return The final crc value. + *****************************************************************************/ +static inline crc_t crc_finalize(crc_t crc) +{ + return crc ^ 0xffffffff; +} + + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* __CRC_H__ */ diff --git a/src/common/dynamic-array.c b/src/common/dynamic-array.c new file mode 100644 index 0000000..1e2efac --- /dev/null +++ b/src/common/dynamic-array.c @@ -0,0 +1,224 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <pthread.h> +#include <assert.h> +#include <stdio.h> + +#include <urcu.h> + +//#include "common.h" +#include "common/dynamic-array.h" + +#ifndef ERR_ALLOC_FAILED +#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \ + __FILE__, __LINE__) +#endif + +//#define DA_DEBUG + +#ifndef dbg_da +#ifdef DA_DEBUG +#define dbg_da(msg...) fprintf(stderr, msg) +#else +#define dbg_da(msg...) +#endif +#endif + +/*----------------------------------------------------------------------------*/ +/* Private functions */ +/*----------------------------------------------------------------------------*/ + +enum da_resize_type { + DA_LARGER, DA_SMALLER +}; + +typedef enum da_resize_type da_resize_type_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \retval 1 On success. + * \retval -1 On failure. + */ +static int da_resize(da_array_t *array, da_resize_type_t type) +{ + dbg_da("da_resize(): array pointer: %p, items pointer: %p\n", array, + array->items); + + unsigned new_size = ((type == DA_LARGER) + ? (array->allocated *= 2) + : (array->allocated /= 2)); + + void *new_items = malloc(new_size * array->item_size); + if (new_items == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + dbg_da("Place for new items: %p\n", new_items); + + // copy the contents from the old array to the new + memcpy(new_items, array->items, array->count * array->item_size); + + // do RCU update + void *old_items = rcu_xchg_pointer(&array->items, new_items); + array->allocated = new_size; + + dbg_da("Old items pointer: %p\n", old_items); + + // wait for readers to finish + synchronize_rcu(); + // deallocate the old array + dbg_da("RCU synchronized, deallocating old items array at address %p." + "\n", old_items); + free(old_items); + + return 1; +} + +/*----------------------------------------------------------------------------*/ +/* Public functions */ +/*----------------------------------------------------------------------------*/ + +da_array_t *da_create(unsigned count, size_t item_size) +{ + da_array_t *a = (da_array_t *)malloc(sizeof(da_array_t)); + if (a == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + da_initialize(a, count, item_size); + return a; +} + +/*----------------------------------------------------------------------------*/ + +int da_initialize(da_array_t *array, unsigned count, size_t item_size) +{ + assert(array != NULL); + pthread_mutex_init(&array->mtx, NULL); + pthread_mutex_lock(&array->mtx); + + array->items = malloc(count * item_size); + if (array->items == NULL) { + array->allocated = 0; + array->count = 0; + ERR_ALLOC_FAILED; + return -1; + } + + array->allocated = count; + array->count = 0; + array->item_size = item_size; + memset(array->items, 0, count * item_size); + + pthread_mutex_unlock(&array->mtx); + return 0; +} + +/*----------------------------------------------------------------------------*/ + +int da_reserve(da_array_t *array, unsigned count) +{ + pthread_mutex_lock(&array->mtx); + unsigned res = 0; + + assert(array->allocated >= array->count); + if ((array->allocated - array->count) >= count) { + dbg_da("Enough place in the array, no resize needed.\n"); + res = 0; + } else { + dbg_da("Resizing array.\n"); + res = da_resize(array, DA_LARGER); + } + pthread_mutex_unlock(&array->mtx); + + return res; +} + +/*----------------------------------------------------------------------------*/ + +int da_occupy(da_array_t *array, unsigned count) +{ + pthread_mutex_lock(&array->mtx); + unsigned res = 0; + assert(array->allocated >= array->count); + + if ((array->allocated - array->count) < count) { + dbg_da("Not enough place to occupy.\n"); + res = -1; + } else { + array->count += count; + } + + pthread_mutex_unlock(&array->mtx); + return res; +} + +/*----------------------------------------------------------------------------*/ + +unsigned da_try_reserve(const da_array_t *array, unsigned count) +{ + assert(array->allocated >= array->count); + if ((array->allocated - array->count) >= count) { + return 0; + } + + return 1; +} + +/*----------------------------------------------------------------------------*/ + +void da_release(da_array_t *array, unsigned count) +{ + pthread_mutex_lock(&array->mtx); + + assert(array->allocated >= array->count); + assert(array->count >= count); + dbg_da("Decreasing count of items in array.\n"); + array->count -= count; + + pthread_mutex_unlock(&array->mtx); +} + +/*----------------------------------------------------------------------------*/ + +void da_destroy(da_array_t *array) +{ + pthread_mutex_lock(&array->mtx); + void *old_items = rcu_dereference(array->items); + rcu_set_pointer(&array->items, NULL); + pthread_mutex_unlock(&array->mtx); + + synchronize_rcu(); + free(old_items); + pthread_mutex_destroy(&array->mtx); +} + +/*----------------------------------------------------------------------------*/ + +void *da_get_items(const da_array_t *array) +{ + return array->items; +} + +/*----------------------------------------------------------------------------*/ + +unsigned da_get_count(const da_array_t *array) +{ + return array->count; +} diff --git a/src/common/dynamic-array.h b/src/common/dynamic-array.h new file mode 100644 index 0000000..77a5d13 --- /dev/null +++ b/src/common/dynamic-array.h @@ -0,0 +1,156 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file dynamic-array.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Safe dynamic array implementation. + * + * \todo Somehow check if the array is initialized and do not use otherwise. + * Maybe some magic, or so. + * \todo This structure is too slow because of the mutex. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_COMMON_DYNAMIC_ARRAY_H_ +#define _KNOTD_COMMON_DYNAMIC_ARRAY_H_ + +#include <string.h> +#include <pthread.h> + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dynamic array structure. + * + * Before using the dynamic array, it must be initialized using da_initialize(). + * When getting individual items always use da_get_items() to obtain pointer to + * the actual array. + * + * Items in the array cannot be dereferenced (it uses void * for storing the + * the items). It is needed to type-cast the item array (obtained by calling + * da_get_items()) to a proper type before dereferencing. + * + * When adding items, first reserve enough space for them by callling + * da_reserve() and subsequently tell the array about the inserted items by + * calling da_occupy(). When removing, the array must be told about the fact + * by calling da_release(). + * + * For getting the actual number of items in array use da_get_count(). + * + * When the array is no more needed, the da_destroy() function must be called + * before deallocating the structure. + */ +struct da_array { + /*! \brief The actual array. The items can't be dereferenced directly.*/ + void *items; + + /*! + * \brief Size of the stored items in bytes (used in counting of space + * needed. + */ + size_t item_size; + + /*! + * \brief Size of allocated space in number of items that can be stored. + */ + unsigned allocated; + + /*! \brief Number of items actually stored in the array. */ + unsigned count; + + /*! \brief Mutex. */ + pthread_mutex_t mtx; +}; + +typedef struct da_array da_array_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates and initializes the dynamic array. + * + * Initialization comprises of allocating place for \a count items of size + * \a item_size and setting the items to zeros. + * + * \retval 0 if successful. + * \retval -1 if not successful. + */ +da_array_t *da_create(unsigned count, size_t item_size); + +/*! + * \brief Initializes the dynamic array. + * + * Initialization comprises of allocating place for \a count items of size + * \a item_size and setting the items to zeros. + * + * \retval 0 if successful. + * \retval -1 if not successful. + */ +int da_initialize(da_array_t *array, unsigned count, size_t item_size); + +/*! + * \brief Reserves space for \a count more items. + * + * \retval 0 if successful and resizing was not necessary. + * \retval 1 if successful and the array was enlarged. + * \retval -1 if not successful - resizing was needed but could not be done. + */ +int da_reserve(da_array_t *array, unsigned count); + +/*! + * \brief Increases the number of items in array by \a count. + * + * \retval 0 If successful. + * \retval -1 If not successful (not enough allocated space, i.e. must run + * da_reserve()). + */ +int da_occupy(da_array_t *array, unsigned count); + +/*! + * \brief Tries to reserve space for \a count more items. + * + * \retval 0 if successful and resizing is not necessary. + * \retval 1 if successful but the array will need to be resized. + */ +unsigned da_try_reserve(const da_array_t *array, unsigned count); + +/*! + * \brief Releases space taken by \a count items. + */ +void da_release(da_array_t *array, unsigned count); + +/*! + * \brief Poperly deallocates the array. + */ +void da_destroy(da_array_t *array); + +/*! + * \brief Returns the array of items as a void *. + */ +void *da_get_items(const da_array_t *array); + +/*! + * \brief Returns count of items in the array. + */ +unsigned da_get_count(const da_array_t *array); + +/*----------------------------------------------------------------------------*/ + +#endif /* _KNOTD_COMMON_DYNAMIC_ARRAY_H_ */ + +/*! @} */ diff --git a/src/common/errors.c b/src/common/errors.c new file mode 100644 index 0000000..f1e650d --- /dev/null +++ b/src/common/errors.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "common/errors.h" + +/*! + * \brief Looks up the given id in the lookup table. + * + * \param table Lookup table. + * \param id ID to look up. + * + * \return Item in the lookup table with the given id or NULL if no such is + * present. + */ +static const error_table_t *error_lookup_by_id(const error_table_t *table, + int id) +{ + while (table->name != 0) { + if (table->id == id) { + return table; + } + table++; + } + + return 0; +} + +const char *error_to_str(const error_table_t *table, int code) +{ + const error_table_t *msg = error_lookup_by_id(table, code); + if (msg != 0) { + return msg->name; + } else { + return "Unknown error."; + } +} + +int _map_errno(int fallback_value, int arg0, ...) +{ + /* Iterate all variable-length arguments. */ + va_list ap; + va_start(ap, arg0); + + /* KNOTD_ERROR serves as a sentinel. */ + for (int c = arg0; c != 0; c = va_arg(ap, int)) { + + /* Error code matches with mapped. */ + if (c == errno) { + /* Return negative value of the code. */ + return -abs(c); + } + } + va_end(ap); + + /* Fallback error code. */ + return fallback_value; +} diff --git a/src/common/errors.h b/src/common/errors.h new file mode 100644 index 0000000..a2773ac --- /dev/null +++ b/src/common/errors.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file errors.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Error codes and function for getting error message. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_COMMON_ERROR_H_ +#define _KNOTD_COMMON_ERROR_H_ + +#include <errno.h> + +/*! \brief Error lookup table. */ +typedef struct error_table_t { + int id; + const char *name; +} error_table_t; + +/*! + * \brief Returns error message for the given error code. + * + * \param table Table of error messages to use. + * \param code Error code. + * + * \return String containing the error message. + */ +const char *error_to_str(const error_table_t *table, int code); + +/*! + * \brief Safe errno mapper that automatically appends sentinel value. + * + * \see _map_errno() + * + * \param fallback_value Fallback error value (used if the code could not be + * mapped. + * \param err POSIX errno. + * \param ... List of handled codes. + * + * \return Mapped error code. + */ +#define map_errno(fallback_value, err...) _map_errno(fallback_value, err, 0) + +/*! + * \brief Returns a mapped POSIX errcode. + * + * \warning Last error must be 0, it serves as a sentinel value. + * Use map_errno() instead. + * + * \param fallback_value Fallback error value (used if the code could not be + * mapped. + * \param arg0 First mandatory argument. + * \param ... List of handled codes. + * + * \return Mapped error code. + */ +int _map_errno(int fallback_value, int arg0, ...); + +#endif /* _KNOTD_COMMON_ERROR_H_ */ + +/*! @} */ diff --git a/src/common/evqueue.c b/src/common/evqueue.c new file mode 100644 index 0000000..ca3027f --- /dev/null +++ b/src/common/evqueue.c @@ -0,0 +1,130 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "common/evqueue.h" + +/*! \brief Singleton application-wide event queue. */ +evqueue_t *s_evqueue = 0; + +evqueue_t *evqueue_new() +{ + evqueue_t* q = malloc(sizeof(evqueue_t)); + + /* Initialize fds. */ + if (pipe(q->fds) < 0) { + free(q); + q = 0; + } + + return q; +} + +void evqueue_free(evqueue_t **q) +{ + /* Check. */ + if (!q) { + return; + } + + /* Invalidate pointer to queue. */ + evqueue_t *eq = *q; + *q = 0; + + /* Deinitialize. */ + close(eq->fds[EVQUEUE_READFD]); + close(eq->fds[EVQUEUE_WRITEFD]); + free(eq); +} + +int evqueue_poll(evqueue_t *q, const struct timespec *ts, + const sigset_t *sigmask) +{ + /* Check. */ + if (!q) { + return -1; + } + + /* Prepare fd set. */ + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(q->fds[EVQUEUE_READFD], &rfds); + + /* Wait for events. */ + int ret = pselect(q->fds[EVQUEUE_READFD] + 1, &rfds, 0, 0, ts, sigmask); + if (ret < 0) { + return -1; + } + + return ret; +} + +int evqueue_read(evqueue_t *q, void *dst, size_t len) +{ + if (!q || !dst || len == 0) { + return -1; + } + + return read(q->fds[EVQUEUE_READFD], dst, len); +} + +int evqueue_write(evqueue_t *q, const void *src, size_t len) +{ + if (!q || !src || len == 0) { + return -1; + } + + return write(q->fds[EVQUEUE_WRITEFD], src, len); +} + +int evqueue_get(evqueue_t *q, event_t *ev) +{ + /* Check. */ + if (!q || !ev) { + return -1; + } + + /* Read data. */ + int ret = evqueue_read(q, ev, sizeof(event_t)); + if (ret != sizeof(event_t)) { + return -1; + } + + /* Set parent. */ + ev->parent = q; + + return 0; +} + +int evqueue_add(evqueue_t *q, const event_t *ev) +{ + /* Check. */ + if (!q || !ev) { + return -1; + } + + /* Write data. */ + int ret = evqueue_write(q, ev, sizeof(event_t)); + if (ret != sizeof(event_t)) { + return -1; + } + + return 0; +} + diff --git a/src/common/evqueue.h b/src/common/evqueue.h new file mode 100644 index 0000000..ffb3860 --- /dev/null +++ b/src/common/evqueue.h @@ -0,0 +1,200 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file evqueue.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Event queue. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_COMMON_EVQUEUE_H_ +#define _KNOTD_COMMON_EVQUEUE_H_ + +#include <pthread.h> +#include <signal.h> // sigset_t +#include <time.h> +#include <sys/time.h> + +//#include "knot/common.h" +#include "common/lists.h" + +struct event_t; + +/*! + * \brief Event callback. + * + * Pointer to whole event structure is passed to the callback. + * Callback should return 0 on success and negative integer on error. + * + * Example callback: + * \code + * int print_callback(event_t *t) { + * return printf("Callback: %s\n", t->data); + * } + * \endcode + */ +typedef int (*event_cb_t)(struct event_t *); + +/*! + * \brief Event structure. + */ +typedef struct event_t { + node n; /*!< Node for event queue. */ + int type; /*!< Event type. */ + struct timeval tv; /*!< Event scheduled time. */ + void *data; /*!< Usable data ptr. */ + event_cb_t cb; /*!< Event callback. */ + void *parent; /*!< Pointer to parent (evqueue, scheduler...) */ +} event_t; + +/*! + * \brief Event queue constants. + */ +enum { + EVQUEUE_READFD = 0, + EVQUEUE_WRITEFD = 1 +}; + +/*! + * \brief Event queue structure. + */ +typedef struct { + int fds[2]; /*!< Read and Write fds. */ +} evqueue_t; + +/*! + * \brief Create new event queue. + * + * Event queue is thread-safe and POSIX signal-safe. + * It uses piped fds for queueing and pselect(2) to + * wait for events. + * + * \retval New instance on success. + * \retval NULL on error. + */ +evqueue_t *evqueue_new(); + +/*! + * \brief Deinitialize and free event queue. + * + * \param q Pointer to queue instance. + * \note *q is set to 0. + */ +void evqueue_free(evqueue_t **q); + +/*! + * \brief Poll for new events. + * + * Unblocked signals during polling are specified + * in a sigmask. + * + * \param q Event queue. + * \param ts Timeout (or NULL for infinite). + * \param sigmask Bitmask of signals to receive (or NULL). + * + * \retval Number of polled events on success. + * \retval -1 On error or signal interrupt. + */ +int evqueue_poll(evqueue_t *q, const struct timespec *ts, const sigset_t *sigmask); + +/*! + * \brief Return evqueue pollable fd. + * + * \param q Event queue. + * + * \retval File descriptor available for polling. + * \retval -1 On error. + */ +static inline int evqueue_pollfd(evqueue_t *q) { + return q->fds[EVQUEUE_READFD]; +} + +/*! + * \brief Read data from event queue. + * + * This function is useful for sending custom + * events or other data types through the event queue. + * + * \param q Event queue. + * \param dst Destination buffer. + * \param len Number of bytes to read. + * + * \retval Number of read bytes on success. + * \retval -1 on error, \see read(2). + */ +int evqueue_read(evqueue_t *q, void *dst, size_t len); + +/*! + * \brief Write data to event queue. + * + * This function is useful for sending custom + * events or other data types through the event queue. + * + * \param q Event queue. + * \param src Source buffer. + * \param len Number of bytes to write. + * + * \retval Number of written bytes on success. + * \retval -1 on error, \see write(2). + */ +int evqueue_write(evqueue_t *q, const void *src, size_t len); + +/*! + * \brief Read event from event queue. + * + * \param q Event queue. + * \param ev Event structure for writing. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int evqueue_get(evqueue_t *q, event_t *ev); + +/*! + * \brief Add event to queue. + * + * \param q Event queue. + * \param ev Event structure to read. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int evqueue_add(evqueue_t *q, const event_t *ev); + +/* Singleton event queue pointer. */ +extern evqueue_t *s_evqueue; + +/*! + * \brief Event queue singleton. + */ +static inline evqueue_t *evqueue() { + return s_evqueue; +} + +/*! + * \brief Set event queue singleton. + */ +static inline void evqueue_set(evqueue_t *q) { + s_evqueue = q; +} + +#endif /* _KNOTD_COMMON_EVQUEUE_H_ */ + +/*! @} */ diff --git a/src/common/evsched.c b/src/common/evsched.c new file mode 100644 index 0000000..4e56028 --- /dev/null +++ b/src/common/evsched.c @@ -0,0 +1,309 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/time.h> +#include <stdlib.h> +#include <stdio.h> + +#include "common/evsched.h" + +/*! + * \brief Set event timer to T (now) + dt miliseconds. + */ +static void evsched_settimer(event_t *e, uint32_t dt) +{ + if (!e) { + return; + } + + /* Get absolute time T. */ + gettimeofday(&e->tv, 0); + + /* Add number of seconds. */ + e->tv.tv_sec += dt / 1000; + + /* Add the number of microseconds. */ + e->tv.tv_usec += (dt % 1000) * 1000; + + /* Check for overflow. */ + while (e->tv.tv_usec > 999999) { + e->tv.tv_sec += 1; + e->tv.tv_usec -= 1 * 1000 * 1000; + } +} + +/*! \brief Singleton application-wide event scheduler. */ +evsched_t *s_evsched = 0; + +evsched_t *evsched_new() +{ + evsched_t *s = malloc(sizeof(evsched_t)); + if (!s) { + return 0; + } + + /* Initialize event calendar. */ + pthread_mutex_init(&s->rl, 0); + pthread_mutex_init(&s->mx, 0); + pthread_cond_init(&s->notify, 0); + pthread_mutex_init(&s->cache.lock, 0); + slab_cache_init(&s->cache.alloc, sizeof(event_t)); + init_list(&s->calendar); + return s; +} + +void evsched_delete(evsched_t **s) +{ + if (!s) { + return; + } + if (!*s) { + return; + } + + /* Deinitialize event calendar. */ + pthread_mutex_destroy(&(*s)->rl); + pthread_mutex_destroy(&(*s)->mx); + pthread_cond_destroy(&(*s)->notify); + node *n = 0, *nxt = 0; + WALK_LIST_DELSAFE(n, nxt, (*s)->calendar) { + evsched_event_free((*s), (event_t*)n); + } + + /* Free allocator. */ + slab_cache_destroy(&(*s)->cache.alloc); + pthread_mutex_destroy(&(*s)->cache.lock); + + /* Free scheduler. */ + free(*s); + *s = 0; +} + +event_t *evsched_event_new(evsched_t *s, int type) +{ + if (!s) { + return 0; + } + + /* Allocate. */ + pthread_mutex_lock(&s->cache.lock); + event_t *e = slab_cache_alloc(&s->cache.alloc); + pthread_mutex_unlock(&s->cache.lock); + + /* Initialize. */ + memset(e, 0, sizeof(event_t)); + e->type = type; + return e; +} + +void evsched_event_free(evsched_t *s, event_t *ev) +{ + if (!s || !ev) { + return; + } + + pthread_mutex_lock(&s->cache.lock); + slab_free(ev); + pthread_mutex_unlock(&s->cache.lock); +} + +event_t* evsched_next(evsched_t *s) +{ + /* Check. */ + if (!s) { + return 0; + } + + /* Lock calendar. */ + pthread_mutex_lock(&s->mx); + + while(1) { + + /* Check event queue. */ + if (!EMPTY_LIST(s->calendar)) { + + /* Get current time. */ + struct timeval dt; + gettimeofday(&dt, 0); + + /* Get next event. */ + event_t *next_ev = HEAD(s->calendar); + + /* Immediately return. */ + if (timercmp(&dt, &next_ev->tv, >=)) { + rem_node(&next_ev->n); + pthread_mutex_unlock(&s->mx); + pthread_mutex_lock(&s->rl); + s->current = next_ev; + return next_ev; + } + + /* Wait for next event or interrupt. Unlock calendar. */ + struct timespec ts; + ts.tv_sec = next_ev->tv.tv_sec; + ts.tv_nsec = next_ev->tv.tv_usec * 1000L; + pthread_cond_timedwait(&s->notify, &s->mx, &ts); + } else { + /* Block until an event is scheduled. Unlock calendar.*/ + pthread_cond_wait(&s->notify, &s->mx); + } + } + + /* Unlock calendar, this shouldn't happen. */ + pthread_mutex_unlock(&s->mx); + return 0; + +} + +int evsched_event_finished(evsched_t *s) +{ + if (!s) { + return -1; + } + + /* Mark as finished. */ + if (s->current) { + s->current = 0; + pthread_mutex_unlock(&s->rl); + return 0; + } + + /* Finished event is not current. */ + return -1; +} + +int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt) +{ + if (!s || !ev || dt < 0) { + return -1; + } + + /* Update event timer. */ + evsched_settimer(ev, dt); + + /* Lock calendar. */ + pthread_mutex_lock(&s->mx); + + /* Schedule event. */ + node *n = 0, *prev = 0; + if (!EMPTY_LIST(s->calendar)) { + WALK_LIST(n, s->calendar) { + event_t* cur = (event_t *)n; + if (timercmp(&cur->tv, &ev->tv, <)) { + prev = n; + } else { + break; + } + } + } + + /* Append to list. */ + ev->parent = s; + if (prev) { + insert_node(&ev->n, prev); + } else { + add_head(&s->calendar, &ev->n); + } + + + /* Unlock calendar. */ + pthread_cond_signal(&s->notify); + pthread_mutex_unlock(&s->mx); + + return 0; +} + +event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t dt) +{ + if (!s) { + return 0; + } + + /* Create event. */ + event_t *e = evsched_event_new(s, EVSCHED_CB); + if (!e) { + return 0; + } + e->cb = cb; + e->data = data; + + /* Schedule. */ + if (evsched_schedule(s, e, dt) != 0) { + evsched_event_free(s, e); + e = 0; + } + + return e; +} + +event_t* evsched_schedule_term(evsched_t *s, uint32_t dt) +{ + if (!s) { + return 0; + } + + /* Create event. */ + event_t *e = evsched_event_new(s, EVSCHED_TERM); + if (!e) { + return 0; + } + + /* Schedule. */ + if (evsched_schedule(s, e, dt) != 0) { + evsched_event_free(s, e); + e = 0; + } + + return e; +} + +int evsched_cancel(evsched_t *s, event_t *ev) +{ + if (!s || !ev) { + return -1; + } + + /* Lock calendar. */ + pthread_mutex_lock(&s->mx); + + /* Make sure not running. */ + pthread_mutex_lock(&s->rl); + + /* Find in list. */ + event_t *n = 0; + int found = 0; + WALK_LIST(n, s->calendar) { + if (n == ev) { + found = 1; + break; + } + } + + /* Remove from list. */ + if (found) { + rem_node(&ev->n); + } + + /* Enable running events. */ + pthread_mutex_unlock(&s->rl); + + /* Unlock calendar. */ + pthread_cond_signal(&s->notify); + pthread_mutex_unlock(&s->mx); + + return 0; +} + diff --git a/src/common/evsched.h b/src/common/evsched.h new file mode 100644 index 0000000..2a682e1 --- /dev/null +++ b/src/common/evsched.h @@ -0,0 +1,240 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file evsched.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Event scheduler. + * + * Scheduler works with the same event_t type as event queue. + * It is also thread-safe so the scheduler can run in a separate thread + * while events can be enqueued from different threads. + * + * Guideline is, that the scheduler run loop should exit with + * a special event type EVSCHED_TERM. + * + * Example usage: + * \code + * evsched_t *s = evsched_new(); + * + * // Schedule myfunc() after 1000ms + * evsched_schedule_cb(s, myfunc, data, 1000) + * + * // Schedule termination event after 1500ms + * evsched_schedule_term(s, 1500); + * + * // Event scheduler main loop + * while (1) { + * // Wait for next scheduled event + * event_t *ev = evsched_next(); + * + * // Break on termination event + * if (ev->type == EVSCHED_TERM) { + * evsched_event_free(s, ev); + * break; + * } + * + * // Execute and discard event + * if (ev->cb) { + * ev->cb(ev); + * } + * evsched_event_free(s, ev); // Free executed event + * } + * + * // Delete event scheduler + * evsched_delete(s); + * \endcode + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_COMMON_EVSCHED_H_ +#define _KNOTD_COMMON_EVSCHED_H_ + +#include <pthread.h> +#include "common/slab/slab.h" +#include "common/lists.h" +#include "common/evqueue.h" + +/*! + * \brief Scheduler event types. + */ +typedef enum evsched_ev_t { + EVSCHED_NOOP = 0, /*!< No-op action, skip. */ + EVSCHED_CB, /*!< Callback action. */ + EVSCHED_TERM /*!< Terminal action, stop event scheduler. */ +} evsched_ev_t; + +/*! + * \brief Event scheduler structure. + * + * Keeps list of scheduled events. Events are executed in their scheduled + * time and kept in an ordered list (queue). + * Scheduler is terminated with a special EVSCHED_TERM event type. + */ +typedef struct { + pthread_mutex_t rl; /*!< Event running lock. */ + event_t *current; /*!< Current running event. */ + pthread_mutex_t mx; /*!< Event queue locking. */ + pthread_cond_t notify; /*!< Event queue notification. */ + list calendar; /*!< Event calendar. */ + struct { + slab_cache_t alloc; /*!< Events SLAB cache. */ + pthread_mutex_t lock; /*!< Events cache spin lock. */ + } cache; +} evsched_t; + +/*! + * \brief Create new event scheduler instance. + * + * \retval New instance on success. + * \retval NULL on error. + */ +evsched_t *evsched_new(); + +/*! + * \brief Deinitialize and free event scheduler instance. + * + * \param s Pointer to event scheduler instance. + * \note *sched is set to 0. + */ +void evsched_delete(evsched_t **s); + +/*! + * \brief Create an empty event. + * + * \param s Pointer to event scheduler instance. + * \param type Event type. + * \retval New instance on success. + * \retval NULL on error. + */ +event_t *evsched_event_new(evsched_t *s, int type); + +/*! + * \brief Dispose event instance. + * + * \param s Pointer to event scheduler instance. + * \param ev Event instance. + */ +void evsched_event_free(evsched_t *s, event_t *ev); + +/*! + * \brief Fetch next-event. + * + * Scheduler may block until a next event is available. + * Send scheduler an EVSCHED_NOOP or EVSCHED_TERM event to unblock it. + * + * \warning Returned event must be marked as finished, or deadlock occurs. + * + * \param s Event scheduler. + * + * \retval Scheduled event. + * \retval NULL on error. + */ +event_t* evsched_next(evsched_t *s); + +/*! + * \brief Mark running event as finished. + * + * Need to call this after each event returned by evsched_next() is finished. + * + * \param s Event scheduler. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int evsched_event_finished(evsched_t *s); + +/*! + * \brief Schedule an event. + * + * \param s Event scheduler. + * \param ev Prepared event. + * \param dt Time difference in milliseconds from now (dt is relative). + * + * \retval 0 on success. + * \retval <0 on error. + */ +int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt); + +/*! + * \brief Schedule callback event. + * + * Execute callback after dt miliseconds has passed. + * + * \param s Event scheduler. + * \param cb Callback handler. + * \param data Data for callback. + * \param dt Time difference in milliseconds from now (dt is relative). + * + * \retval Event instance on success. + * \retval NULL on error. + */ +event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t dt); + +/*! + * \brief Schedule termination event. + * + * Special action for scheduler termination. + * + * \param s Event scheduler. + * \param dt Time difference in milliseconds from now (dt is relative). + * + * \retval Event instance on success. + * \retval NULL on error. + */ +event_t* evsched_schedule_term(evsched_t *s, uint32_t dt); + +/*! + * \brief Cancel a scheduled event. + * + * \warning May block until current running event is finished (as it cannot + * interrupt running event). + * + * \warning Never cancel event in it's callback. As it never finishes, + * it deadlocks. + * + * \param s Event scheduler. + * \param ev Scheduled event. + * + * \retval 0 on success. + * \retval <0 on error. + */ +int evsched_cancel(evsched_t *s, event_t *ev); + +/* Singleton event scheduler pointer. */ +extern evsched_t *s_evsched; + +/*! + * \brief Event scheduler singleton. + */ +static inline evsched_t *evsched() { + return s_evsched; +} + +/*! + * \brief Set event scheduler singleton. + */ +static inline void evsched_set(evsched_t *s) { + s_evsched = s; +} + + +#endif /* _KNOTD_COMMON_EVSCHED_H_ */ + +/*! @} */ diff --git a/src/common/fdset.c b/src/common/fdset.c new file mode 100644 index 0000000..8c070ad --- /dev/null +++ b/src/common/fdset.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* Required for RTLD_DEFAULT. */ +#endif + +#include <dlfcn.h> +#include <string.h> +#include <stdio.h> +#include "common/fdset.h" +#include <config.h> + +struct fdset_backend_t _fdset_backend = { +}; + +/*! \brief Set backend implementation. */ +static void fdset_set_backend(struct fdset_backend_t *backend) { + memcpy(&_fdset_backend, backend, sizeof(struct fdset_backend_t)); +} + +/* Linux epoll API. */ +#ifdef HAVE_EPOLL_WAIT + #include "common/fdset_epoll.h" +#endif /* HAVE_EPOLL_WAIT */ + +/* BSD kqueue API */ +#ifdef HAVE_KQUEUE + #include "common/fdset_kqueue.h" +#endif /* HAVE_KQUEUE */ + +/* POSIX poll API */ +#ifdef HAVE_POLL + #include "common/fdset_poll.h" +#endif /* HAVE_POLL */ + +/*! \brief Bootstrap polling subsystem (it is called automatically). */ +void __attribute__ ((constructor)) fdset_init() +{ + /* Preference: epoll */ +#ifdef HAVE_EPOLL_WAIT + if (dlsym(RTLD_DEFAULT, "epoll_wait") != 0) { + fdset_set_backend(&FDSET_EPOLL); + return; + } +#endif + + /* Preference: kqueue */ +#ifdef HAVE_KQUEUE + if (dlsym(RTLD_DEFAULT, "kqueue") != 0) { + fdset_set_backend(&FDSET_KQUEUE); + return; + } +#endif + + /* Fallback: poll */ +#ifdef HAVE_POLL + if (dlsym(RTLD_DEFAULT, "poll") != 0) { + fdset_set_backend(&FDSET_POLL); + return; + } +#endif + + /* This shouldn't happen. */ + fprintf(stderr, "fdset: fatal error - no valid fdset backend found\n"); + return; +} diff --git a/src/common/fdset.h b/src/common/fdset.h new file mode 100644 index 0000000..10196bf --- /dev/null +++ b/src/common/fdset.h @@ -0,0 +1,196 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file fdset.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Wrapper for native I/O multiplexing. + * + * Selects best implementation according to config. + * - select() + * - poll() \todo + * - epoll() + * - kqueue() + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_FDSET_H_ +#define _KNOTD_FDSET_H_ + +#include <stddef.h> + +/*! \brief Opaque pointer to implementation-specific fdset data. */ +typedef struct fdset_t fdset_t; + +/*! \brief Unified event types. */ +enum fdset_event_t { + OS_EV_READ = 1 << 0, /*!< Readable event. */ + OS_EV_WRITE = 1 << 1, /*!< Writeable event. */ + OS_EV_ERROR = 1 << 2 /*!< Error event. */ +}; + +/*! \brief File descriptor set iterator. */ +typedef struct fdset_it_t { + int fd; /*!< Current file descriptor. */ + int events; /*!< Returned events. */ + size_t pos; /* Internal usage. */ +} fdset_it_t; + +/*! + * \brief File descriptor set implementation backend. + * \notice Functions documentation following. + * \internal + */ +struct fdset_backend_t +{ + fdset_t* (*fdset_new)(); + int (*fdset_destroy)(fdset_t*); + int (*fdset_add)(fdset_t*, int, int); + int (*fdset_remove)(fdset_t*, int); + int (*fdset_wait)(fdset_t*); + int (*fdset_begin)(fdset_t*, fdset_it_t*); + int (*fdset_end)(fdset_t*, fdset_it_t*); + int (*fdset_next)(fdset_t*, fdset_it_t*); + const char* (*fdset_method)(); +}; + +/*! + * \brief Selected backend. + * \internal + */ +extern struct fdset_backend_t _fdset_backend; + +/*! + * \brief Create new fdset. + * + * FDSET implementation depends on system. + * + * \retval Pointer to initialized FDSET structure if successful. + * \retval NULL on error. + */ +static inline fdset_t *fdset_new() { + return _fdset_backend.fdset_new(); +} + +/*! + * \brief Destroy FDSET. + * + * \retval 0 if successful. + * \retval -1 on error. + */ +static inline int fdset_destroy(fdset_t * fdset) { + return _fdset_backend.fdset_destroy(fdset); +} + +/*! + * \brief Add file descriptor to watched set. + * + * \param fdset Target set. + * \param fd Added file descriptor. + * \param events Mask of watched events. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +static inline int fdset_add(fdset_t *fdset, int fd, int events) { + return _fdset_backend.fdset_add(fdset, fd, events); +} + + +/*! + * \brief Remove file descriptor from watched set. + * + * \param fdset Target set. + * \param fd File descriptor to be removed. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +static inline int fdset_remove(fdset_t *fdset, int fd) { + return _fdset_backend.fdset_remove(fdset, fd); +} + +/*! + * \brief Poll set for new events. + * + * \param fdset Target set. + * + * \retval Number of events if successful. + * \retval -1 on errors. + * + * \todo Timeout. + */ +static inline int fdset_wait(fdset_t *fdset) { + return _fdset_backend.fdset_wait(fdset); +} + +/*! + * \brief Set event iterator to the beginning of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +static inline int fdset_begin(fdset_t *fdset, fdset_it_t *it) { + return _fdset_backend.fdset_begin(fdset, it); +} + +/*! + * \brief Set event iterator to the end of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +static inline int fdset_end(fdset_t *fdset, fdset_it_t *it) { + return _fdset_backend.fdset_end(fdset, it); +} + +/*! + * \brief Set event iterator to the next event. + * + * Event iterator fd will be set to -1 if next event doesn't exist. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +static inline int fdset_next(fdset_t *fdset, fdset_it_t *it) { + return _fdset_backend.fdset_next(fdset, it); +} + +/*! + * \brief Returned name of underlying poll method. + * + * \retval Name if successful. + * \retval NULL if no method was loaded (shouldn't happen). + */ +static inline const char* fdset_method() { + return _fdset_backend.fdset_method(); +} + +#endif /* _KNOTD_FDSET_H_ */ + +/*! @} */ diff --git a/src/common/fdset_epoll.c b/src/common/fdset_epoll.c new file mode 100644 index 0000000..cb2e3e1 --- /dev/null +++ b/src/common/fdset_epoll.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#ifdef HAVE_EPOLL_WAIT + +#include <sys/epoll.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "fdset_epoll.h" + +#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ +#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */ + +struct fdset_t { + int epfd; + struct epoll_event *events; + size_t nfds; + size_t reserved; + size_t polled; +}; + +fdset_t *fdset_epoll_new() +{ + fdset_t *set = malloc(sizeof(fdset_t)); + if (!set) { + return 0; + } + + /* Blank memory. */ + memset(set, 0, sizeof(fdset_t)); + + /* Create epoll fd. */ + set->epfd = epoll_create(OS_FDS_CHUNKSIZE); + + return set; +} + +int fdset_epoll_destroy(fdset_t * fdset) +{ + if(!fdset) { + return -1; + } + + /* Teardown epoll. */ + close(fdset->epfd); + + /* OK if NULL. */ + free(fdset->events); + free(fdset); + return 0; +} + +int fdset_epoll_add(fdset_t *fdset, int fd, int events) +{ + if (!fdset || fd < 0 || events <= 0) { + return -1; + } + + /* Realloc needed. */ + if (fdset->nfds == fdset->reserved) { + const size_t chunk = OS_FDS_CHUNKSIZE; + const size_t nsize = (fdset->reserved + chunk) * + sizeof(struct epoll_event); + struct epoll_event *events_n = malloc(nsize); + if (!events_n) { + return -1; + } + + /* Clear and copy old fdset data. */ + memset(events_n, 0, nsize); + memcpy(events_n, fdset->events, + fdset->nfds * sizeof(struct epoll_event)); + free(fdset->events); + fdset->events = events_n; + fdset->reserved += chunk; + } + + /* Add to epoll set. */ + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + ev.events = EPOLLIN; /*! \todo MAP events. */ + ev.data.fd = fd; + if (epoll_ctl(fdset->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { + return -1; + } + + ++fdset->nfds; + return 0; +} + +int fdset_epoll_remove(fdset_t *fdset, int fd) +{ + if (!fdset || fd < 0) { + return -1; + } + + /* Attempt to remove from set. */ + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + if (epoll_ctl(fdset->epfd, EPOLL_CTL_DEL, fd, &ev) < 0) { + return -1; + } + + /* Overwrite current item. */ + --fdset->nfds; + + /*! \todo Return memory if overallocated (nfds is far lower than reserved). */ + return 0; +} + +int fdset_epoll_wait(fdset_t *fdset) +{ + if (!fdset || fdset->nfds < 1 || !fdset->events) { + return -1; + } + + /* Poll new events. */ + fdset->polled = 0; + int nfds = epoll_wait(fdset->epfd, fdset->events, fdset->nfds, -1); + + /* Check. */ + if (nfds < 0) { + return -1; + } + + /* Events array is ordered from 0 to nfds. */ + fdset->polled = nfds; + return nfds; +} + +int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it) { + return -1; + } + + /* Find first. */ + it->pos = 0; + return fdset_next(fdset, it); +} + +int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it || fdset->nfds < 1) { + return -1; + } + + /* Check for polled events. */ + if (fdset->polled < 1) { + it->fd = -1; + it->pos = 0; + return -1; + } + + /* No end found, ends on the beginning. */ + size_t nid = fdset->polled - 1; + it->fd = fdset->events[nid].data.fd; + it->pos = nid; + it->events = 0; /*! \todo Map events. */ + return -1; +} + +int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it || fdset->nfds < 1) { + return -1; + } + + /* Check boundaries. */ + if (it->pos >= fdset->polled) { + return -1; + } + + /* Select next. */ + size_t nid = it->pos++; + it->fd = fdset->events[nid].data.fd; + it->events = 0; /*! \todo Map events. */ + return 0; +} + +const char* fdset_epoll_method() +{ + return "epoll"; +} + +/* Package APIs. */ +struct fdset_backend_t FDSET_EPOLL = { + .fdset_new = fdset_epoll_new, + .fdset_destroy = fdset_epoll_destroy, + .fdset_add = fdset_epoll_add, + .fdset_remove = fdset_epoll_remove, + .fdset_wait = fdset_epoll_wait, + .fdset_begin = fdset_epoll_begin, + .fdset_end = fdset_epoll_end, + .fdset_next = fdset_epoll_next, + .fdset_method = fdset_epoll_method +}; + +#endif diff --git a/src/common/fdset_epoll.h b/src/common/fdset_epoll.h new file mode 100644 index 0000000..551394d --- /dev/null +++ b/src/common/fdset_epoll.h @@ -0,0 +1,133 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file fdset_epoll.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Wrapper for epoll I/O multiplexing. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_FDSET_EPOLL_H_ +#define _KNOTD_FDSET_EPOLL_H_ + +#include "fdset.h" + +/*! + * \brief Create new fdset. + * + * Linux epoll() backend. + * + * \retval Pointer to initialized FDSET structure if successful. + * \retval NULL on error. + */ +fdset_t *fdset_epoll_new(); + +/*! + * \brief Destroy FDSET. + * + * \retval 0 if successful. + * \retval -1 on error. + */ +int fdset_epoll_destroy(fdset_t * fdset); + +/*! + * \brief Add file descriptor to watched set. + * + * \param fdset Target set. + * \param fd Added file descriptor. + * \param events Mask of watched events. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_epoll_add(fdset_t *fdset, int fd, int events); + +/*! + * \brief Remove file descriptor from watched set. + * + * \param fdset Target set. + * \param fd File descriptor to be removed. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_epoll_remove(fdset_t *fdset, int fd); + +/*! + * \brief Poll set for new events. + * + * \param fdset Target set. + * + * \retval Number of events if successful. + * \retval -1 on errors. + * + * \todo Timeout. + */ +int fdset_epoll_wait(fdset_t *fdset); + +/*! + * \brief Set event iterator to the beginning of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Set event iterator to the end of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Set event iterator to the next event. + * + * Event iterator fd will be set to -1 if next event doesn't exist. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Returned name of epoll method. + * + * \retval Name if successful. + * \retval NULL if no method was loaded (shouldn't happen). + */ +const char* fdset_epoll_method(); + +/*! \brief Exported API. */ +extern struct fdset_backend_t FDSET_EPOLL; + +#endif /* _KNOTD_FDSET_EPOLL_H_ */ + +/*! @} */ diff --git a/src/common/fdset_kqueue.c b/src/common/fdset_kqueue.c new file mode 100644 index 0000000..c7199ae --- /dev/null +++ b/src/common/fdset_kqueue.c @@ -0,0 +1,251 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#ifdef HAVE_KQUEUE + +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/event.h> +#include <sys/time.h> + +#include "fdset_kqueue.h" + +#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ +#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */ + +struct fdset_t { + int kq; + struct kevent *events; + struct kevent *revents; + size_t nfds; + size_t reserved; + size_t polled; +}; + +fdset_t *fdset_kqueue_new() +{ + fdset_t *set = malloc(sizeof(fdset_t)); + if (!set) { + return 0; + } + + /* Blank memory. */ + memset(set, 0, sizeof(fdset_t)); + + /* Create kqueue fd. */ + set->kq = kqueue(); + if (set->kq < 0) { + free(set); + set = 0; + } + + return set; +} + +int fdset_kqueue_destroy(fdset_t * fdset) +{ + if(!fdset) { + return -1; + } + + /* Teardown kqueue. */ + close(fdset->kq); + + /* OK if NULL. */ + free(fdset->revents); + free(fdset->events); + free(fdset); + return 0; +} + +int fdset_kqueue_realloc(void **old, size_t oldsize, size_t nsize) +{ + void *nmem = malloc(nsize); + if (!nmem) { + return -1; + } + + /* Clear and copy old fdset data. */ + memset(nmem, 0, nsize); + if (oldsize > 0) { + memcpy(nmem, *old, oldsize); + free(*old); + } + + *old = nmem; + return 0; +} + +int fdset_kqueue_add(fdset_t *fdset, int fd, int events) +{ + if (!fdset || fd < 0 || events <= 0) { + return -1; + } + + /* Realloc needed. */ + if (fdset->nfds == fdset->reserved) { + const size_t chunk = OS_FDS_CHUNKSIZE; + const size_t nsize = (fdset->reserved + chunk) * + sizeof(struct kevent); + const size_t oldsize = fdset->nfds * sizeof(struct kevent); + + if (fdset_kqueue_realloc(&fdset->events, oldsize, nsize) < 0) { + return -1; + } + + if (fdset_kqueue_realloc(&fdset->revents, oldsize, nsize) < 0) { + return -1; + } + + } + + /* Add to kqueue set. */ + int evfilt = EVFILT_READ; /*! \todo Map events. */ + EV_SET(&fdset->events[fdset->nfds], fd, evfilt, + EV_ADD|EV_ENABLE, 0, 0, 0); + + ++fdset->nfds; + return 0; +} + +int fdset_kqueue_remove(fdset_t *fdset, int fd) +{ + if (!fdset || fd < 0) { + return -1; + } + + /* Find in set. */ + int pos = -1; + for (int i = 0; i < fdset->nfds; ++i) { + if (fdset->events[i].ident == fd) { + pos = i; + break; + } + } + + if (pos < 0) { + return -1; + } + + /* Remove filters. */ + EV_SET(&fdset->events[pos], fd, EVFILT_READ, + EV_DISABLE|EV_DELETE, 0, 0, 0); + + /* Attempt to remove from set. */ + size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct kevent); + memmove(fdset->events + pos, fdset->events + (pos + 1), remaining); + + /* Overwrite current item. */ + --fdset->nfds; + + /*! \todo Return memory if overallocated (nfds is far lower than reserved). */ + return 0; +} + +int fdset_kqueue_wait(fdset_t *fdset) +{ + if (!fdset || fdset->nfds < 1 || !fdset->events) { + return -1; + } + + /* Poll new events. */ + fdset->polled = 0; + int nfds = kevent(fdset->kq, fdset->events, fdset->nfds, + fdset->revents, fdset->nfds, 0); + + /* Check. */ + if (nfds < 0) { + return -1; + } + + /* Events array is ordered from 0 to nfds. */ + fdset->polled = nfds; + return nfds; +} + +int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it) { + return -1; + } + + /* Find first. */ + it->pos = 0; + return fdset_next(fdset, it); +} + +int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it || fdset->nfds < 1) { + return -1; + } + + /* Check for polled events. */ + if (fdset->polled < 1) { + it->fd = -1; + it->pos = 0; + return -1; + } + + /* No end found, ends on the beginning. */ + size_t nid = fdset->polled - 1; + it->fd = fdset->revents[nid].ident; + it->pos = nid; + it->events = 0; /*! \todo Map events. */ + return -1; +} + +int fdset_kqueue_next(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it || fdset->nfds < 1) { + return -1; + } + + /* Check boundaries. */ + if (it->pos >= fdset->polled) { + return -1; + } + + /* Select next. */ + size_t nid = it->pos++; + it->fd = fdset->revents[nid].ident; + it->events = 0; /*! \todo Map events. */ + return 0; +} + +const char* fdset_kqueue_method() +{ + return "kqueue"; +} + +/* Package APIs. */ +struct fdset_backend_t FDSET_KQUEUE = { + .fdset_new = fdset_kqueue_new, + .fdset_destroy = fdset_kqueue_destroy, + .fdset_add = fdset_kqueue_add, + .fdset_remove = fdset_kqueue_remove, + .fdset_wait = fdset_kqueue_wait, + .fdset_begin = fdset_kqueue_begin, + .fdset_end = fdset_kqueue_end, + .fdset_next = fdset_kqueue_next, + .fdset_method = fdset_kqueue_method +}; + +#endif diff --git a/src/common/fdset_kqueue.h b/src/common/fdset_kqueue.h new file mode 100644 index 0000000..f64482f --- /dev/null +++ b/src/common/fdset_kqueue.h @@ -0,0 +1,133 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file fdset_kqueue.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Wrapper for kqueue I/O multiplexing. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_FDSET_KQUEUE_H_ +#define _KNOTD_FDSET_KQUEUE_H_ + +#include "fdset.h" + +/*! + * \brief Create new fdset. + * + * BSD kqueue() backend. + * + * \retval Pointer to initialized FDSET structure if successful. + * \retval NULL on error. + */ +fdset_t *fdset_kqueue_new(); + +/*! + * \brief Destroy FDSET. + * + * \retval 0 if successful. + * \retval -1 on error. + */ +int fdset_kqueue_destroy(fdset_t * fdset); + +/*! + * \brief Add file descriptor to watched set. + * + * \param fdset Target set. + * \param fd Added file descriptor. + * \param events Mask of watched events. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_kqueue_add(fdset_t *fdset, int fd, int events); + +/*! + * \brief Remove file descriptor from watched set. + * + * \param fdset Target set. + * \param fd File descriptor to be removed. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_kqueue_remove(fdset_t *fdset, int fd); + +/*! + * \brief Poll set for new events. + * + * \param fdset Target set. + * + * \retval Number of events if successful. + * \retval -1 on errors. + * + * \todo Timeout. + */ +int fdset_kqueue_wait(fdset_t *fdset); + +/*! + * \brief Set event iterator to the beginning of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Set event iterator to the end of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Set event iterator to the next event. + * + * Event iterator fd will be set to -1 if next event doesn't exist. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_kqueue_next(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Returned name of kqueue method. + * + * \retval Name if successful. + * \retval NULL if no method was loaded (shouldn't happen). + */ +const char* fdset_kqueue_method(); + +/*! \brief Exported API. */ +extern struct fdset_backend_t FDSET_KQUEUE; + +#endif /* _KNOTD_FDSET_KQUEUE_H_ */ + +/*! @} */ diff --git a/src/common/fdset_poll.c b/src/common/fdset_poll.c new file mode 100644 index 0000000..8682eaf --- /dev/null +++ b/src/common/fdset_poll.c @@ -0,0 +1,230 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#ifdef HAVE_POLL + +#include <stdlib.h> +#include <string.h> +#include <sys/poll.h> +#include <stddef.h> + +#include "common/fdset_poll.h" + +#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ +#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */ + +struct fdset_t { + struct pollfd *fds; + nfds_t nfds; + size_t reserved; + size_t polled; + size_t begin; +}; + +fdset_t *fdset_poll_new() +{ + fdset_t *set = malloc(sizeof(fdset_t)); + if (!set) { + return 0; + } + + /* Blank memory. */ + memset(set, 0, sizeof(fdset_t)); + return set; +} + +int fdset_poll_destroy(fdset_t * fdset) +{ + if(!fdset) { + return -1; + } + + /*! \todo No teardown required I guess. */ + + /* OK if NULL. */ + free(fdset->fds); + free(fdset); + return 0; +} + +int fdset_poll_add(fdset_t *fdset, int fd, int events) +{ + if (!fdset || fd < 0 || events <= 0) { + return -1; + } + + /* Realloc needed. */ + if (fdset->nfds == fdset->reserved) { + const size_t chunk = OS_FDS_CHUNKSIZE; + const size_t nsize = sizeof(struct pollfd) * (fdset->reserved + chunk); + struct pollfd *fds_n = malloc(nsize); + if (!fds_n) { + return -1; + } + + /* Clear and copy old fdset data. */ + memset(fds_n, 0, nsize); + memcpy(fds_n, fdset->fds, fdset->nfds * sizeof(struct pollfd)); + free(fdset->fds); + fdset->fds = fds_n; + fdset->reserved += chunk; + } + + /* Append. */ + int nid = fdset->nfds++; + fdset->fds[nid].fd = fd; + fdset->fds[nid].events = POLLIN; /*! \todo Map events to POLL events. */ + return 0; +} + +int fdset_poll_remove(fdset_t *fdset, int fd) +{ + if (!fdset || fd < 0) { + return -1; + } + + /* Find file descriptor. */ + unsigned found = 0; + size_t pos = 0; + for (size_t i = 0; i < fdset->nfds; ++i) { + if (fdset->fds[i].fd == fd) { + found = 1; + pos = i; + break; + } + } + + /* Check. */ + if (!found) { + return -1; + } + + /* Overwrite current item. */ + size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct pollfd); + memmove(fdset->fds + pos, fdset->fds + (pos + 1), remaining); + --fdset->nfds; + + /*! \todo Return memory if overallocated (nfds is far lower than reserved). */ + /*! \todo Maybe >64 free chunks is excess? */ + return 0; +} + +int fdset_poll_wait(fdset_t *fdset) +{ + if (!fdset || fdset->nfds < 1 || !fdset->fds) { + return -1; + } + + /* Initialize pointers. */ + fdset->polled = 0; + fdset->begin = 0; + + /* Poll for events. */ + int ret = poll(fdset->fds, fdset->nfds, -1); + if (ret < 0) { + return -1; + } + + /* Set pointers for iterating. */ + fdset->polled = ret; + fdset->begin = 0; + return ret; +} + +int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it) { + return -1; + } + + /* Find first. */ + it->pos = 0; + return fdset_next(fdset, it); +} + +int fdset_poll_end(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it || fdset->nfds < 1) { + return -1; + } + + /* Check for polled events. */ + if (fdset->polled < 1) { + it->fd = -1; + it->pos = 0; + return -1; + } + + /* Trace last matching item from the end. */ + struct pollfd* pfd = fdset->fds + fdset->nfds - 1; + while (pfd != fdset->fds) { + if (pfd->events & pfd->revents) { + it->fd = pfd->fd; + it->pos = pfd - fdset->fds; + return 0; + } + } + + /* No end found, ends on the beginning. */ + it->fd = -1; + it->pos = 0; + return -1; +} + +int fdset_poll_next(fdset_t *fdset, fdset_it_t *it) +{ + if (!fdset || !it || fdset->nfds < 1) { + return -1; + } + + /* Find next with matching flags. */ + for (; it->pos < fdset->nfds; ++it->pos) { + struct pollfd* pfd = fdset->fds + it->pos; + if (pfd->events & pfd->revents) { + it->fd = pfd->fd; + it->events = pfd->revents; /*! \todo MAP events. */ + ++it->pos; /* Next will start after current. */ + return 0; + } + } + + /* No matching event found. */ + it->fd = -1; + it->pos = 0; + return -1; +} + +const char* fdset_poll_method() +{ + return "poll"; +} + +/* Package APIs. */ +struct fdset_backend_t FDSET_POLL = { + .fdset_new = fdset_poll_new, + .fdset_destroy = fdset_poll_destroy, + .fdset_add = fdset_poll_add, + .fdset_remove = fdset_poll_remove, + .fdset_wait = fdset_poll_wait, + .fdset_begin = fdset_poll_begin, + .fdset_end = fdset_poll_end, + .fdset_next = fdset_poll_next, + .fdset_method = fdset_poll_method +}; + +#endif diff --git a/src/common/fdset_poll.h b/src/common/fdset_poll.h new file mode 100644 index 0000000..d72b5bb --- /dev/null +++ b/src/common/fdset_poll.h @@ -0,0 +1,133 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file fdset_poll.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Wrapper for poll I/O multiplexing. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_FDSET_POLL_H_ +#define _KNOTD_FDSET_POLL_H_ + +#include "fdset.h" + +/*! + * \brief Create new fdset. + * + * POSIX poll() backend. + * + * \retval Pointer to initialized FDSET structure if successful. + * \retval NULL on error. + */ +fdset_t *fdset_poll_new(); + +/*! + * \brief Destroy FDSET. + * + * \retval 0 if successful. + * \retval -1 on error. + */ +int fdset_poll_destroy(fdset_t * fdset); + +/*! + * \brief Add file descriptor to watched set. + * + * \param fdset Target set. + * \param fd Added file descriptor. + * \param events Mask of watched events. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_poll_add(fdset_t *fdset, int fd, int events); + +/*! + * \brief Remove file descriptor from watched set. + * + * \param fdset Target set. + * \param fd File descriptor to be removed. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_poll_remove(fdset_t *fdset, int fd); + +/*! + * \brief Poll set for new events. + * + * \param fdset Target set. + * + * \retval Number of events if successful. + * \retval -1 on errors. + * + * \todo Timeout. + */ +int fdset_poll_wait(fdset_t *fdset); + +/*! + * \brief Set event iterator to the beginning of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Set event iterator to the end of last polled events. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_poll_end(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Set event iterator to the next event. + * + * Event iterator fd will be set to -1 if next event doesn't exist. + * + * \param fdset Target set. + * \param it Event iterator. + * + * \retval 0 if successful. + * \retval -1 on errors. + */ +int fdset_poll_next(fdset_t *fdset, fdset_it_t *it); + +/*! + * \brief Returned name of poll method. + * + * \retval Name if successful. + * \retval NULL if no method was loaded (shouldn't happen). + */ +const char* fdset_poll_method(); + +/*! \brief Exported API. */ +extern struct fdset_backend_t FDSET_POLL; + +#endif /* _KNOTD_FDSET_POLL_H_ */ + +/*! @} */ diff --git a/src/common/general-tree.c b/src/common/general-tree.c new file mode 100644 index 0000000..202b31a --- /dev/null +++ b/src/common/general-tree.c @@ -0,0 +1,215 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include "common/general-tree.h" +#include "common/errors.h" + +MOD_TREE_DEFINE(general_tree_node, avl); + +static void gen_rem_func(struct general_tree_node *n1) +{ + free(n1); +} + +general_tree_t *gen_tree_new(int (*comp_func)(void *, void *)) +{ + general_tree_t *ret = malloc(sizeof(general_tree_t)); + if (ret == NULL) { + return NULL; + } + ret->tree = malloc(sizeof(general_avl_tree_t)); + if (ret->tree == NULL) { + free(ret); + return NULL; + } + MOD_TREE_INIT(ret->tree, comp_func); + return ret; +} + +int gen_tree_add(general_tree_t *tree, + void *node, int (*mrg_func)(void **n1, void **n2)) +{ + struct general_tree_node *tree_node = + malloc(sizeof(struct general_tree_node)); + if (tree_node == NULL) { + return -1; + } + memset(tree_node, 0, sizeof(struct general_tree_node)); + tree_node->data = node; + int merged = 0; + MOD_TREE_INSERT(tree->tree, general_tree_node, avl, + tree_node, mrg_func, &merged); + if (merged) { + free(tree_node); + } + return merged; +} + +void gen_tree_remove(general_tree_t *tree, + void *what) +{ + struct general_tree_node tree_node; + tree_node.data = what; + MOD_TREE_REMOVE(tree->tree, general_tree_node, avl, &tree_node, + gen_rem_func); +} + +void *gen_tree_find(general_tree_t *tree, + void *what) +{ + struct general_tree_node tree_node; + tree_node.data = what; + struct general_tree_node *found_node = + MOD_TREE_FIND(tree->tree, general_tree_node, avl, &tree_node); + if (found_node) { + return found_node->data; + } else { + return NULL; + } +} + +int gen_tree_find_less_or_equal(general_tree_t *tree, + void *what, + void **found) +{ + if (tree == NULL || tree->tree == NULL) { + return -1; + } + + /* Check if tree is empty. */ + if (tree->tree->th_root == NULL) { + *found = NULL; + return 0; + } + + struct general_tree_node *f = NULL, *prev = NULL; + struct general_tree_node tree_node; + tree_node.data = what; + int exact_match = + MOD_TREE_FIND_LESS_EQUAL(tree->tree, general_tree_node, avl, + &tree_node, &f, &prev); + if (exact_match < 0) { + *found = NULL; + exact_match = 0; + } else if (exact_match == 0) { + assert(prev != NULL); + *found = prev->data; + } else { + assert(f != NULL); + *found = f->data; + } +// *found = (exact_match > 0) ? f->data : prev->data; + return exact_match; +} + +void gen_tree_apply_inorder(general_tree_t *tree, + void (*app_func) + (void *node, void *data), void *data) +{ + MOD_TREE_FORWARD_APPLY(tree->tree, general_tree_node, avl, + app_func, data); +} + +void gen_tree_destroy(general_tree_t **tree, + void (*dest_func)(void *node, void *data), void *data) +{ +// gen_tree_apply_inorder(*tree, print_node, NULL); + MOD_TREE_DESTROY((*tree)->tree, general_tree_node, avl, dest_func, + gen_rem_func, data); + free((*tree)->tree); + free(*tree); + *tree = NULL; +} + +void gen_tree_clear(general_tree_t *tree) +{ + MOD_TREE_DESTROY(tree->tree, general_tree_node, avl, NULL, + gen_rem_func, NULL); +} + +//static void add_node_to_tree(void *n, void *data) +//{ +// general_tree_t *tree = (general_tree_t *)data; +// gen_tree_add(tree, n, NULL); +//} + +static int gen_tree_copy_node(const struct general_tree_node *from, + struct general_tree_node **to) +{ + if (from == NULL) { + return 0; + } + + *to = malloc(sizeof(struct general_tree_node)); + if (*to == NULL) { + return -1; + } + memset(*to, 0, sizeof(struct general_tree_node)); + + (*to)->data = from->data; + (*to)->avl.avl_height = from->avl.avl_height; + + int ret = gen_tree_copy_node(from->avl.avl_left, + &(*to)->avl.avl_left); + if (ret != 0) { + return ret; + } + + ret = gen_tree_copy_node(from->avl.avl_right, + &(*to)->avl.avl_right); + if (ret != 0) { + /*! \todo Partially cleaunp tree! */ + (*to)->avl.avl_left = NULL; + return ret; + } + + return 0; +} + +general_tree_t *gen_tree_shallow_copy(general_tree_t *tree) +{ + general_tree_t *new_tree = malloc(sizeof(general_tree_t)); + if (new_tree == NULL) { + return NULL; + } + new_tree->tree = malloc(sizeof(general_avl_tree_t)); + if (new_tree->tree == NULL) { + free(new_tree); + return NULL; + } + + MOD_TREE_INIT(new_tree->tree, tree->tree->th_cmp); + assert(new_tree->tree->th_cmp == tree->tree->th_cmp); + +// gen_tree_apply_inorder(tree, add_node_to_tree, new_tree); + + if (gen_tree_copy_node(tree->tree->th_root, + &new_tree->tree->th_root) != 0) { + return NULL; + } + + /* CLEANUP */ +// gen_tree_apply_inorder(tree, print_node, NULL); +// printf("--------------------------\n"); +// gen_tree_apply_inorder(new_tree, print_node, NULL); + + return new_tree; +} + diff --git a/src/common/general-tree.h b/src/common/general-tree.h new file mode 100644 index 0000000..552638a --- /dev/null +++ b/src/common/general-tree.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_COMMON_GENERAL_TREE_H_ +#define _KNOTD_COMMON_GENERAL_TREE_H_ + +#include "common/modified_tree.h" + +typedef MOD_TREE_HEAD(tree, general_tree_node) general_avl_tree_t; + +/* Define tree with void * nodes */ +struct general_tree_node { + MOD_TREE_ENTRY(general_tree_node) avl; +// int (*cmp_func)(void *n1, +// void *n2); +// int (*mrg_func)(void **n1, +// void **n2); +// void (*app_func)(void *n, +// void *data); + void *data; +}; + +struct general_tree { +// int (*cmp_func)(void *n1, +// void *n2); +// int (*mrg_func)(void **n1, +// void **n2); + general_avl_tree_t *tree; +}; + +typedef struct general_tree general_tree_t; + +general_tree_t *gen_tree_new(int (*cmp_func)(void *p1, void *p2)); + +int gen_tree_add(general_tree_t *tree, + void *node, + int (*mrg_func)(void **n1, void **n2)); + +void *gen_tree_find(general_tree_t *tree, + void *what); + +void gen_tree_remove(general_tree_t *tree, + void *what); + +void gen_tree_apply_inorder(general_tree_t *tree, + void (*app_func)(void *node, void *data), + void *data); + +void gen_tree_destroy(general_tree_t **tree, + void (*dest_func)(void *node, void *data), void *data); + +void gen_tree_clear(general_tree_t *tree); + +int gen_tree_find_less_or_equal(general_tree_t *tree, + void *what, + void **found); + +general_tree_t *gen_tree_shallow_copy(general_tree_t *tree); + +#endif // _KNOTD_COMMON_GENERAL_TREE_H_ diff --git a/src/common/latency.c b/src/common/latency.c new file mode 100644 index 0000000..a563f58 --- /dev/null +++ b/src/common/latency.c @@ -0,0 +1,197 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef PROF_LATENCY + +#include <sys/resource.h> +#include <sys/socket.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> + + +/*! \brief Profiler statistics. */ +typedef struct pstat_t { + double M; /*!< \brief Mean value. */ + unsigned long min, max; /*!< \brief Minimum, maximum. */ + unsigned long total; /*!< \brief Total profiled time. */ + unsigned long count; /*!< \brief Number of profiled calls. */ +} pstat_t; + +/*! \brief Function call profile. */ +typedef struct profile_t { + const char* call; + pstat_t stat; +} profile_t; + +/*! \brief Observed function call codes. */ +enum pcall_code_t { + PF_RECVFROM = 0, + PF_SENDTO, + PF_PTHREAD_MUTEX_LOCK, + PF_PTHREAD_MUTEX_UNLOCK, + PF_CALL_SIZE +} pcall_code_t; + +/*! \brief Table of observed function calls. */ +static profile_t table[] = { + { "recvfrom", {0} }, + { "sendto", {0} }, + { "pthread_mutex_lock", {0} }, + { "pthread_mutex_unlock", {0} }, + { "NULL", {0} } +}; + + +/*! \brief Add value to statistics. */ +static inline void add_stat(pstat_t *stat, unsigned long val) { + + if (val < stat->min) { + stat->min = val; + } + if (val > stat->max) { + stat->max = val; + } + + stat->total += val; + + double Mprev = stat->M, M = stat->M; + M += (val - M)/((double)stat->count + 1); + stat->M = M; + //S += (val - M)*(x[i] - Mprev); + + ++stat->count; +} + +/*! \brief Call profiler table initialization (automatically called on load). */ +void __attribute__ ((constructor)) profiler_init() +{ + for (int i = 0; i < PF_CALL_SIZE; ++i) { + pstat_t* stat = &table[i].stat; + stat->M = 0; + stat->max = 0; + stat->min = (unsigned long)~0; + stat->total = 0; + stat->count = 0; + } +} + +/*! \brief Call profiler table evaluation (automatically called on exit). */ +void __attribute__ ((destructor)) profiler_deinit() +{ + + /* Get resource usage. */ + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage) < 0) { + memset(&usage, 0, sizeof(struct rusage)); + } + + fprintf(stderr, "\nStatistics:"); + fprintf(stderr, "\n==================\n"); + + fprintf(stderr, "User time: %.03lf ms\nSystem time: %.03lf ms\n", + usage.ru_utime.tv_sec * (double) 1000.0 + + usage.ru_utime.tv_usec / (double)1000.0, + usage.ru_stime.tv_sec * (double) 1000.0 + + usage.ru_stime.tv_usec / (double)1000.0); + fprintf(stderr, "Voluntary context switches: %lu\nInvoluntary context switches: %lu\n", + usage.ru_nvcsw, + usage.ru_nivcsw); + fprintf(stderr, "==================\n"); + fprintf(stderr, "\n"); + + /* Callers statistics. */ + for (int i = 0; i < PF_CALL_SIZE; ++i) { + pstat_t* stat = &table[i].stat; + fprintf(stderr, "%s: M=%lf min=%lu,max=%lu (total=%lu, %lu times) (usec)\n", + table[i].call, stat->M, stat->min, stat->max, stat->total, + stat->count); + } + +} + +ssize_t pf_recvfrom(int socket, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen, + const char* caller, const char* file, int line) +{ + unsigned long elapsed = 0; + int ret = 0; + perf_begin(); + ret = recvfrom(socket, buf, len, flags, from, fromlen); + perf_end(elapsed); + + /* Discard wakeup delays, count statistics otherwise. */ + if (elapsed < 200000) { + add_stat(&table[PF_RECVFROM].stat, elapsed); + } + return ret; +} + +ssize_t pf_sendto(int socket, const void *buf, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen, + const char* caller, const char* file, int line) +{ + unsigned long elapsed = 0; + int ret = 0; + perf_begin(); + ret = sendto(socket, buf, len, flags, to, tolen); + perf_end(elapsed); + + /* Discard wakeup delays, count statistics otherwise. */ + if (elapsed < 200000) { + add_stat(&table[PF_SENDTO].stat, elapsed); + } + return ret; +} + +/* Pthreads */ +int pf_pthread_mutex_lock(pthread_mutex_t *mutex, + const char* caller, const char* file, int line) +{ + unsigned long elapsed = 0; + int ret = 0; + perf_begin(); + ret = pthread_mutex_lock(mutex); + perf_end(elapsed); + + /* Discard wakeup delays, count statistics otherwise. */ + if (elapsed < 200000) { + add_stat(&table[PF_PTHREAD_MUTEX_LOCK].stat, elapsed); + } + + return ret; +} + +int pf_pthread_mutex_unlock(pthread_mutex_t *mutex, + const char* caller, const char* file, int line) +{ + unsigned long elapsed = 0; + int ret = 0; + perf_begin(); + ret = pthread_mutex_unlock(mutex); + perf_end(elapsed); + + /* Discard wakeup delays, count statistics otherwise. */ + if (elapsed < 200000) { + add_stat(&table[PF_PTHREAD_MUTEX_UNLOCK].stat, elapsed); + } + + return ret; +} + +#endif // PROF_LATENCY diff --git a/src/common/latency.h b/src/common/latency.h new file mode 100644 index 0000000..d965c56 --- /dev/null +++ b/src/common/latency.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file latency.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Utilities for latency profiling. + * + * Selected calls latency profiler is enabled with PROF_LATENCY define. + * You can roughly profile own code with perf_begin() and perf_end() macros. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_COMMON_LATENCY_H_ +#define _KNOTD_COMMON_LATENCY_H_ + +/* Optional. */ +#ifdef PROF_LATENCY + +/* Do not include from latency.c */ +#include <sys/time.h> +#include <sys/socket.h> +#include <pthread.h> + +/* Profiler tools */ + +/*! \brief Time profile begin macro. */ +#define perf_begin() \ +do { \ + struct timeval __begin; \ + gettimeofday(&__begin, 0) + +/*! \brief Time profile end macro + * \param d Will contain the number of microseconds passed from perf_begin(). + */ +#define perf_end(d) \ + struct timeval __end; \ + gettimeofday(&__end, 0); \ + unsigned long __us = (__end.tv_sec - __begin.tv_sec) * 1000L * 1000L; \ + __us += (__end.tv_usec - __begin.tv_usec); \ + (d) = __us; \ +} while(0) + +/* Prototypes. */ + +/*! \brief Profiled recvfrom(). */ +ssize_t pf_recvfrom(int socket, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen, + const char* caller, const char* file, int line); + +/*! \brief Profiled sendto(). */ +ssize_t pf_sendto(int socket, const void *buf, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen, + const char* caller, const char* file, int line); + +/*! \brief Profiled pthread_mutex_lock(). */ +int pf_pthread_mutex_lock(pthread_mutex_t *mutex, + const char* caller, const char* file, int line); + +/*! \brief Profiled pthread_mutex_unlock(). */ +int pf_pthread_mutex_unlock(pthread_mutex_t *mutex, + const char* caller, const char* file, int line); + +/* + * Sockets. + */ + +/*! \brief Rerouted recvfrom(). */ +#define recvfrom(s, buf, len, flags, from, fromlen) \ + pf_recvfrom((s), (buf), (len), (flags), (from), (fromlen), \ + __FUNCTION__, __FILE__, __LINE__) + +/*! \brief Rerouted sendto(). */ +#define sendto(s, buf, len, flags, to, tolen) \ + pf_sendto((s), (buf), (len), (flags), (to), (tolen), \ + __FUNCTION__, __FILE__, __LINE__) + +/* + * Pthreads. + */ + +/*! \brief Rerouted pthread_mutex_lock(). */ +#define pthread_mutex_lock(m) \ + pf_pthread_mutex_lock(m, __FUNCTION__, __FILE__, __LINE__) + +/*! \brief Rerouted pthread_mutex_unlock(). */ +#define pthread_mutex_unlock(m) \ + pf_pthread_mutex_unlock(m, __FUNCTION__, __FILE__, __LINE__) + +#else // PROF_LATENCY + +/* Profiler tools */ +#define perf_begin() +#define perf_end(d) + +#endif // PROF_LATENCY +#endif // _KNOTD_COMMON_LATENCY_H_ + +/*! @} */ diff --git a/src/common/libtap/README b/src/common/libtap/README new file mode 100644 index 0000000..d57b81d --- /dev/null +++ b/src/common/libtap/README @@ -0,0 +1,231 @@ +NAME +==== + +libtap - Write tests in C + +SYNOPSIS +======== + + #include <tap.h> + + int foo () {return 3;} + char *bar () {return "fnord";} + + int main () { + plan(5); + ok(foo() == 3); + is(bar(), "eek"); + ok(foo() <= 8732, "foo <= %d", 8732); + like(bar(), "f(yes|no)r*[a-f]$", "is like"); + cmp_ok(foo(), ">=", 10, "foo is greater than ten"); + return exit_status(); + } + +results in: + + 1..5 + ok 1 + not ok 2 + # Failed test at synopsis.c line 9. + # got: 'fnord' + # expected: 'eek' + ok 3 - foo <= 8732 + ok 4 - is like + not ok 5 - foo is greater than ten + # Failed test 'foo is greater than ten' + # at synopsis.c line 12. + # 3 + # >= + # 10 + # Looks like you failed 2 tests of 5 run. + +DESCRIPTION +=========== + +tap is an easy to read and easy to write way of creating tests for your +software. This library creates functions that can be used to generate it for +your C programs. It is mostly based on the Test::More Perl module. + +FUNCTIONS +========= + +- plan(tests) +- plan(NO_PLAN) + + Use this to start a series of tests. When you know how many tests there + will be, you can put a number as a number of tests you expect to run. If + you do not know how many tests there will be, you can use plan(NO_PLAN) + or not call this function. When you pass it a number of tests to run, a + message similar to the following will appear in the output: + + 1..5 + +- ok(test) +- ok(test, fmt, ...) + + Specify a test. the test can be any statement returning a true or false + value. You may optionally pass a format string describing the test. + + ok(r = reader_new("Of Mice and Men"), "create a new reader"); + ok(reader_go_to_page(r, 55), "can turn the page"); + ok(r->page == 55, "page turned to the right one"); + + Should print out: + + ok 1 - create a new reader + ok 2 - can turn the page + ok 3 - page turned to the right one + + On failure, a diagnostic message will be printed out. + + not ok 3 - page turned to the right one + # Failed test 'page turned to the right one' + # at reader.c line 13. + +- is(got, expected) +- is(got, expected, fmt, ...) +- isnt(got, expected) +- isnt(got, expected, fmt, ...) + + Tests that the string you got is what you expected. with isnt, it is the + reverse. + + is("this", "that", "this is that"); + + prints: + + not ok 1 - this is that + # Failed test 'this is that' + # at is.c line 6. + # got: 'this' + # expected: 'that' + +- cmp_ok(a, op, b) +- cmp_ok(a, op, b, fmt, ...) + + Compares two ints with any binary operator that doesn't require an lvalue. + This is nice to use since it provides a better error message than an + equivalent ok. + + cmp_ok(420, ">", 666); + + prints: + + not ok 1 + # Failed test at cmpok.c line 5. + # 420 + # > + # 666 + +- like(got, expected) +- like(got, expected, fmt, ...) +- unlike(got, expected) +- unlike(got, expected, fmt, ...) + + Tests that the string you got matches the expected extended POSIX regex. + unlike is the reverse. These macros are the equivalent of a skip on + Windows. + + like("stranger", "^s.(r).*\\1$", "matches the regex"); + + prints: + + ok 1 - matches the regex + +- pass() +- pass(fmt, ...) +- fail() +- fail(fmt, ...) + + Speciy that a test succeeded or failed. Use these when the statement is + longer than you can fit into the argument given to an ok() test. + +- dies_ok(code) +- dies_ok(code, fmt, ...) +- lives_ok(code) +- lives_ok(code, fmt, ...) + + Tests whether the given code causes your program to exit. The code gets + passed to a macro that will test it in a forked process. If the code + succeeds it will be executed in the parent process. You can test things + like passing a function a null pointer and make sure it doesnt + dereference it and crash. + + dies_ok({abort();}, "abort does close your program"); + dies_ok({int x = 0/0;}, "divide by zero crash"); + lives ok({pow(3.0, 5.0)}, "nothing wrong with taking 3**5"); + + On Windows, these macros are the equivalent of a skip. + +- exit_status() + + Summarizes the tests that occurred. If there was no plan, it will print + out the number of tests as. + + 1..5 + + It will also print a diagnostic message about how many + failures there were. + + # Looks like you failed 2 tests of 3 run. + + If all planned tests were successful, it will return 0. If any test fails, + it will return the number of failed tests (including ones that were + missing). If they all passed, but there were missing tests, it will return + 255. + +- note(fmt, ...) +- diag(fmt, ...) + + print out a message to the tap output. note prints to stdout and diag + prints to stderr. Each line is preceeded by a "# " so that you know its a + diagnostic message. + + note("This is\na note\nto describe\nsomething."); + + prints: + + # This is + # a note + # to describe + # something + + ok() and these functions return ints so you can use them like: + + ok(1) && note("yo!"); + ok(0) || diag("I have no idea what just happened"); + +- skip(test, n) +- skip(test, n, fmt, ...) +- endskip + + Skip a series of n tests if test is true. You may give a reason why you are + skipping them or not. The (possibly) skipped tests must occur between the + skip and endskip macros. + + skip(TRUE, 2); + ok(1); + ok(0); + endskip; + + prints: + + ok 1 # skip + ok 2 # skip + +- todo() +- todo(fmt, ...) +- endtodo + + Specifies a series of tests that you expect to fail because they are not + yet implemented. + + todo() + ok(0); + endtodo; + + prints: + + not ok 1 # TODO + # Failed (TODO) test at todo.c line 7 + diff --git a/src/common/libtap/tap.c b/src/common/libtap/tap.c new file mode 100644 index 0000000..61e0528 --- /dev/null +++ b/src/common/libtap/tap.c @@ -0,0 +1,313 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +//#include "common.h" +#include "tap.h" + +static int expected_tests = NO_PLAN; +static int failed_tests; +static int current_test; +static char *todo_mesg; + +void +plan (int tests) { + expected_tests = tests; + if (tests != NO_PLAN) + printf("1..%d\n", tests); +} + +static char * +vstrdupf (const char *fmt, va_list args) { + char *str; + int size; + va_list args2; + va_copy(args2, args); + if (!fmt) + fmt = ""; + size = vsnprintf(NULL, 0, fmt, args2) + 2; + str = malloc(size); + vsprintf(str, fmt, args); + va_end(args2); + return str; +} + +int +vok_at_loc (const char *file, int line, int test, const char *fmt, + va_list args) +{ + char *name = vstrdupf(fmt, args); + printf("%sok %d", test ? "" : "not ", ++current_test); + if (*name) + printf(" - %s", name); + if (todo_mesg) { + printf(" # TODO"); + if (*todo_mesg) + printf(" %s", todo_mesg); + } + printf("\n"); + if (!test) { + if (*name) + diag(" Failed%s test '%s'\n at %s line %d.", + todo_mesg ? " (TODO)" : "", name, file, line); + else + diag(" Failed%s test at %s line %d.", + todo_mesg ? " (TODO)" : "", file, line); + if (!todo_mesg) + failed_tests++; + } + free(name); + return test; +} + +int +ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + return test; +} + +static int +mystrcmp (const char *a, const char *b) { + return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); +} + +#define eq(a, b) (!mystrcmp(a, b)) +#define ne(a, b) (mystrcmp(a, b)) + +int +is_at_loc (const char *file, int line, const char *got, const char *expected, + const char *fmt, ...) +{ + int test = eq(got, expected); + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + diag(" got: '%s'", got); + diag(" expected: '%s'", expected); + } + return test; +} + +int +isnt_at_loc (const char *file, int line, const char *got, const char *expected, + const char *fmt, ...) +{ + int test = ne(got, expected); + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + diag(" got: '%s'", got); + diag(" expected: anything else"); + } + return test; +} + +int +cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, + const char *fmt, ...) +{ + int test = eq(op, "||") ? a || b + : eq(op, "&&") ? a && b + : eq(op, "|") ? a | b + : eq(op, "^") ? a ^ b + : eq(op, "&") ? a & b + : eq(op, "==") ? a == b + : eq(op, "!=") ? a != b + : eq(op, "<") ? a < b + : eq(op, ">") ? a > b + : eq(op, "<=") ? a <= b + : eq(op, ">=") ? a >= b + : eq(op, "<<") ? a << b + : eq(op, ">>") ? a >> b + : eq(op, "+") ? a + b + : eq(op, "-") ? a - b + : eq(op, "*") ? a * b + : eq(op, "/") ? a / b + : eq(op, "%") ? a % b + : diag("unrecognized operator '%s'", op); + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + diag(" %d", a); + diag(" %s", op); + diag(" %d", b); + } + return test; +} + +static void +vdiag_to_fh (FILE *fh, const char *fmt, va_list args) { + char *mesg, *line; + int i; + if (!fmt) + return; + mesg = vstrdupf(fmt, args); + line = mesg; + for (i = 0; *line; i++) { + char c = mesg[i]; + if (!c || c == '\n') { + mesg[i] = '\0'; + fprintf(fh, "# %s\n", line); + if (!c) break; + mesg[i] = c; + line = &mesg[i+1]; + } + } + free(mesg); + return; +} + +int +diag (const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vdiag_to_fh(stderr, fmt, args); + va_end(args); + return 0; +} + +int +note (const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vdiag_to_fh(stdout, fmt, args); + va_end(args); + return 0; +} + +int +exit_status () { + int retval = 0; + if (expected_tests == NO_PLAN) { + printf("1..%d\n", current_test); + } + else if (current_test != expected_tests) { + diag("Looks like you planned %d test%s but ran %d.", + expected_tests, expected_tests > 1 ? "s" : "", current_test); + retval = 255; + } + if (failed_tests) { + diag("Looks like you failed %d test%s of %d run.", + failed_tests, failed_tests > 1 ? "s" : "", current_test); + if (expected_tests == NO_PLAN) + retval = failed_tests; + else + retval = expected_tests - current_test + failed_tests; + } + return retval; +} + +void +skippy (int n, const char *fmt, ...) { + char *why; + va_list args; + va_start(args, fmt); + why = vstrdupf(fmt, args); + va_end(args); + while (n --> 0) { + printf("ok %d ", ++current_test); + note("skip %s\n", why); + } + free(why); +} + +void +ctodo (int ignore, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + todo_mesg = vstrdupf(fmt, args); + va_end(args); +} + +void +cendtodo () { + free(todo_mesg); + todo_mesg = NULL; +} + +#ifndef _WIN32 +#include <sys/mman.h> +#include <regex.h> + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +/* Create a shared memory int to keep track of whether a piece of code executed +dies. to be used in the dies_ok and lives_ok macros */ +int +tap_test_died (int status) { + static int *test_died = NULL; + int prev; + if (!test_died) { + test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + *test_died = 0; + } + prev = *test_died; + *test_died = status; + return prev; +} + +int +like_at_loc (int for_match, const char *file, int line, const char *got, + const char *expected, const char *fmt, ...) +{ + int test; + regex_t re; + int err = regcomp(&re, expected, REG_EXTENDED); + if (err) { + char errbuf[256]; + regerror(err, &re, errbuf, sizeof errbuf); + fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", + expected, errbuf, file, line); + exit(255); + } + err = regexec(&re, got, 0, NULL, 0); + regfree(&re); + test = for_match ? !err : err; + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + if (for_match) { + diag(" '%s'", got); + diag(" doesn't match: '%s'", expected); + } + else { + diag(" '%s'", got); + diag(" matches: '%s'", expected); + } + } + return test; +} +#endif + diff --git a/src/common/libtap/tap.h b/src/common/libtap/tap.h new file mode 100644 index 0000000..2e89b90 --- /dev/null +++ b/src/common/libtap/tap.h @@ -0,0 +1,101 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __TAP_H__ +#define __TAP_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#define NO_PLAN -1 +#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define pass(...) ok(1, ## __VA_ARGS__) +#define fail(...) ok(0, ## __VA_ARGS__) +#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) + +int vok_at_loc (const char *file, int line, int test, const char *fmt, + va_list args); +void plan (int tests); +int ok_at_loc (const char *file, int line, int test, const char *fmt, + ...); +int diag (const char *fmt, ...); +int note (const char *fmt, ...); +int exit_status (void); +void skippy (int n, const char *fmt, ...); +void ctodo (int ignore, const char *fmt, ...); +void cendtodo (void); +int is_at_loc (const char *file, int line, const char *got, + const char *expected, const char *fmt, ...); +int isnt_at_loc (const char *file, int line, const char *got, + const char *expected, const char *fmt, ...); +int cmp_ok_at_loc (const char *file, int line, int a, const char *op, + int b, const char *fmt, ...); + +#ifdef _WIN32 +#define like(...) skippy(1, "like is not implemented on MSWin32") +#define unlike(...) like() +#else +#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) +#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) +int like_at_loc (int for_match, const char *file, int line, + const char *got, const char *expected, + const char *fmt, ...); +#endif + +#define skip(test, ...) do {if (test) {skippy(__VA_ARGS__, NULL); break;} +#define endskip } while (0) + +#define todo(...) ctodo(0, ## __VA_ARGS__, NULL) +#define endtodo cendtodo() + +#define dies_ok(code, ...) dies_ok_common(code, 1, ## __VA_ARGS__) +#define lives_ok(code, ...) dies_ok_common(code, 0, ## __VA_ARGS__) + +#ifdef _WIN32 +#define dies_ok_common(...) \ + skippy(1, "Death detection is not supported on MSWin32") +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +int tap_test_died (int status); +#define dies_ok_common(code, for_death, ...) \ + do { \ + tap_test_died(1); \ + int cpid = fork(); \ + switch (cpid) { \ + case -1: \ + perror("fork error"); \ + exit(EXIT_FAILURE); \ + case 0: /* child */ \ + close(1); close(2); \ + code \ + tap_test_died(0); \ + exit(EXIT_SUCCESS); \ + } \ + if (waitpid(cpid, NULL, 0) < 0) { \ + perror("waitpid error"); \ + exit(EXIT_FAILURE); \ + } \ + int it_died = tap_test_died(0); \ + if (!it_died) {code} \ + ok(for_death ? it_died : !it_died, ## __VA_ARGS__); \ + } while (0) +#endif +#endif diff --git a/src/common/libtap/tap_unit.h b/src/common/libtap/tap_unit.h new file mode 100644 index 0000000..c248fde --- /dev/null +++ b/src/common/libtap/tap_unit.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file tap_unit.h + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief libtap test unit. + * + * Contains description of a single test unit API. + * + * Export unit_api in each module header file, + * and set function pointer to according test routines. + * + * <b>Example code for myunit.h</b> + * \code + * #ifndef MYUNIT_TEST_H + * #define MYUNIT_TEST_H + * + * // Export unittest symbol + * unit_api mymodule; + * + * #endif // MYUNIT_TEST_H + * \endcode + * + * <b>Example code for myunit.c</b> + * \code + * #include "myunit.h" + * + * // Function to return unit test count + * int myunit_count(int argc, char *argv[]) { + * return 1; // Number of tests in this unit + * } + * + * // Function to perform tests + * int myunit_run(int argc, char *argv[]) { + * // 1. test + * ok(1 == 1, "test OK"); + * return 0; + * } + * + * // Declare module API + * unit_api mymodule = { + * "My module", + * &myunit_count, + * &myunit_run + * }; + * \endcode + * + * To incorporate test, add it to unit tests main(). + * + * See https://github.com/zorgnax/libtap for libtap API reference. + * + * \addtogroup tests + * @{ + */ + +#ifndef _TAP_UNIT_H_ +#define _TAP_UNIT_H_ + +#include "common/libtap/tap.h" + +/*! \brief Pointer to function for unit_api. */ +typedef int(unitapi_f)(int, char*[]); + + +/*! + * \brief Basic Unit APIs. + * + * Each unit should have one global variable with + * an initialized instance of unit_api. + */ +typedef struct { + const char *name; /*!< Test unit name. */ + unitapi_f *count; /*!< Function to calculate number of tests. */ + unitapi_f *run; /*!< Function to run unit tests. */ +} unit_api; + +#endif // _TAP_UNIT_H_ + +/*! @} */ + diff --git a/src/common/lists.c b/src/common/lists.c new file mode 100644 index 0000000..9a93733 --- /dev/null +++ b/src/common/lists.c @@ -0,0 +1,160 @@ +/* + * BIRD Library -- Linked Lists + * + * (c) 1998 Martin Mares <mj@ucw.cz> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +/** + * DOC: Linked lists + * + * The BIRD library provides a set of functions for operating on linked + * lists. The lists are internally represented as standard doubly linked + * lists with synthetic head and tail which makes all the basic operations + * run in constant time and contain no extra end-of-list checks. Each list + * is described by a &list structure, nodes can have any format as long + * as they start with a &node structure. If you want your nodes to belong + * to multiple lists at once, you can embed multiple &node structures in them + * and use the SKIP_BACK() macro to calculate a pointer to the start of the + * structure from a &node pointer, but beware of obscurity. + * + * There also exist safe linked lists (&slist, &snode and all functions + * being prefixed with |s_|) which support asynchronous walking very + * similar to that used in the &fib structure. + */ + +#define _BIRD_LISTS_C_ + +#include <stdlib.h> +#include <string.h> +#include "common/lists.h" + +/** + * add_tail - append a node to a list + * @l: linked list + * @n: list node + * + * add_tail() takes a node @n and appends it at the end of the list @l. + */ +LIST_INLINE void +add_tail(list *l, node *n) +{ + node *z = l->tail; + + n->next = (node *) &l->null; + n->prev = z; + z->next = n; + l->tail = n; +} + +/** + * add_head - prepend a node to a list + * @l: linked list + * @n: list node + * + * add_head() takes a node @n and prepends it at the start of the list @l. + */ +LIST_INLINE void +add_head(list *l, node *n) +{ + node *z = l->head; + + n->next = z; + n->prev = (node *) &l->head; + z->prev = n; + l->head = n; +} + +/** + * insert_node - insert a node to a list + * @n: a new list node + * @after: a node of a list + * + * Inserts a node @n to a linked list after an already inserted + * node @after. + */ +LIST_INLINE void +insert_node(node *n, node *after) +{ + node *z = after->next; + + n->next = z; + n->prev = after; + after->next = n; + z->prev = n; +} + +/** + * rem_node - remove a node from a list + * @n: node to be removed + * + * Removes a node @n from the list it's linked in. + */ +LIST_INLINE void +rem_node(node *n) +{ + node *z = n->prev; + node *x = n->next; + + z->next = x; + x->prev = z; + n->prev = 0; + n->next = 0; +} + +/** + * init_list - create an empty list + * @l: list + * + * init_list() takes a &list structure and initializes its + * fields, so that it represents an empty list. + */ +LIST_INLINE void +init_list(list *l) +{ + l->head = (node *) &l->null; + l->null = NULL; + l->tail = (node *) &l->head; +} + +/** + * add_tail_list - concatenate two lists + * @to: destination list + * @l: source list + * + * This function appends all elements of the list @l to + * the list @to in constant time. + */ +LIST_INLINE void +add_tail_list(list *to, list *l) +{ + node *p = to->tail; + node *q = l->head; + + p->next = q; + q->prev = p; + q = l->tail; + q->next = (node *) &to->null; + to->tail = q; +} + +/** + * list_dup - duplicate list + * @to: destination list + * @l: source list + * + * This function duplicates all elements of the list @l to + * the list @to in linear time. + * + * This function only works with a homogenous item size. + */ +void list_dup(list *dst, list *src, size_t itemsz) +{ + node *n = 0; + WALK_LIST(n, *src) { + node *i = malloc(itemsz); + memcpy(i, n, itemsz); + add_tail(dst, i); + } +} diff --git a/src/common/lists.h b/src/common/lists.h new file mode 100644 index 0000000..972ea49 --- /dev/null +++ b/src/common/lists.h @@ -0,0 +1,103 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* + * BIRD Library -- Linked Lists + * + * (c) 1998 Martin Mares <mj@ucw.cz> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_LISTS_H_ +#define _BIRD_LISTS_H_ + +/* + * I admit the list structure is very tricky and also somewhat awkward, + * but it's both efficient and easy to manipulate once one understands the + * basic trick: The list head always contains two synthetic nodes which are + * always present in the list: the head and the tail. But as the `next' + * entry of the tail and the `prev' entry of the head are both NULL, the + * nodes can overlap each other: + * + * head head_node.next + * null head_node.prev tail_node.next + * tail tail_node.prev + */ + +#include <string.h> // size_t + +typedef struct node { + struct node *next, *prev; +} node; + +typedef struct list { /* In fact two overlayed nodes */ + struct node *head, *null, *tail; +} list; + +#define NODE (node *) +#define HEAD(list) ((void *)((list).head)) +#define TAIL(list) ((void *)((list).tail)) +#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; \ + n=(void *)((NODE (n))->next)) +#define WALK_LIST_DELSAFE(n,nxt,list) \ + for(n=HEAD(list); (nxt=(void *)((NODE (n))->next)); n=(void *) nxt) +/* WALK_LIST_FIRST supposes that called code removes each processed node */ +#define WALK_LIST_FIRST(n,list) \ + while(n=HEAD(list), (NODE (n))->next) +#define WALK_LIST_BACKWARDS(n,list) for(n=TAIL(list);(NODE (n))->prev; \ + n=(void *)((NODE (n))->prev)) +#define WALK_LIST_BACKWARDS_DELSAFE(n,prv,list) \ + for(n=TAIL(list); prv=(void *)((NODE (n))->prev); n=(void *) prv) + +#define EMPTY_LIST(list) (!(list).head->next) + +/*! \brief Free every node in the list. */ +#define WALK_LIST_FREE(list) \ + do { \ + node *n=0,*nxt=0; \ + WALK_LIST_DELSAFE(n,nxt,list) { \ + free(n); \ + } \ + } while(0) + +void add_tail(list *, node *); +void add_head(list *, node *); +void rem_node(node *); +void add_tail_list(list *, list *); +void init_list(list *); +void insert_node(node *, node *); +void list_dup(list *dst, list *src, size_t itemsz); + +/*! + * \brief List item for string lists. + */ +typedef struct strnode_t { + node n; + char *str; +} strnode_t; + +/*! \todo This is broken atm. +#ifndef _BIRD_LISTS_C_ +#define LIST_INLINE extern inline +#include "knot/lib/lists.c" +#undef LIST_INLINE +#else +#define LIST_INLINE +#endif +*/ +#define LIST_INLINE + +#endif diff --git a/src/common/modified_tree.h b/src/common/modified_tree.h new file mode 100644 index 0000000..4c3e325 --- /dev/null +++ b/src/common/modified_tree.h @@ -0,0 +1,292 @@ +/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h') -*- C -*- */ + +/* Copyright (c) 2005 Ian Piumarta + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the 'Software'), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * provided that the above copyright notice(s) and this permission notice appear + * in all copies of the Software and that both the above copyright notice(s) and + * this permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. + */ + +/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and + * Evgenii M. Landis, 'An algorithm for the organization of information', + * Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian). Also in Myron + * J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)]. + * + * An AVL tree is headed by pointers to the root node and to a function defining + * the ordering relation between nodes. Each node contains an arbitrary payload + * plus three fields per tree entry: the depth of the subtree for which it forms + * the root and two pointers to child nodes (singly-linked for minimum space, at + * the expense of direct access to the parent node given a pointer to one of the + * children). The tree is rebalanced after every insertion or removal. The + * tree may be traversed in two directions: forward (in-order left-to-right) and + * reverse (in-order, right-to-left). + * + * Because of the recursive nature of many of the operations on trees it is + * necessary to define a number of helper functions for each type of tree node. + * The macro TREE_DEFINE(node_tag, entry_name) defines these functions with + * unique names according to the node_tag. This macro should be invoked, + * thereby defining the necessary functions, once per node tag in the program. + * + * For details on the use of these macros, see the tree(3) manual page. + */ + +#ifndef _modified_tree_h +#define _modified_tree_h + + +#define MOD_TREE_DELTA_MAX 1 + +#define MOD_TREE_ENTRY(type) \ + struct { \ + struct type *avl_left; \ + struct type *avl_right; \ + int avl_height; \ + } + +#define MOD_TREE_HEAD(name, type) \ + struct name { \ + struct type *th_root; \ + int (*th_cmp)(void *lhs, void *rhs); \ + } + +#define MOD_TREE_INITIALIZER(cmp) { 0, cmp} + +#define MOD_TREE_DELTA(self, field) \ + (( (((self)->field.avl_left) ? (self)->field.avl_left->field.avl_height : 0)) \ + - (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0)) + +/* Recursion prevents the following from being defined as macros. */ + +#define MOD_TREE_DEFINE(node, field) \ + \ + struct node *MOD_TREE_BALANCE_##node##_##field(struct node *); \ + \ + struct node *MOD_TREE_ROTL_##node##_##field(struct node *self) \ + { \ + struct node *r= self->field.avl_right; \ + self->field.avl_right= r->field.avl_left; \ + r->field.avl_left= MOD_TREE_BALANCE_##node##_##field(self); \ + return MOD_TREE_BALANCE_##node##_##field(r); \ + } \ + \ + struct node *MOD_TREE_ROTR_##node##_##field(struct node *self) \ + { \ + struct node *l= self->field.avl_left; \ + self->field.avl_left= l->field.avl_right; \ + l->field.avl_right= MOD_TREE_BALANCE_##node##_##field(self); \ + return MOD_TREE_BALANCE_##node##_##field(l); \ + } \ + \ + struct node *MOD_TREE_BALANCE_##node##_##field(struct node *self) \ + { \ + int delta= MOD_TREE_DELTA(self, field); \ + \ + if (delta < -MOD_TREE_DELTA_MAX) \ + { \ + if (MOD_TREE_DELTA(self->field.avl_right, field) > 0) \ + self->field.avl_right= MOD_TREE_ROTR_##node##_##field(self->field.avl_right); \ + return MOD_TREE_ROTL_##node##_##field(self); \ + } \ + else if (delta > MOD_TREE_DELTA_MAX) \ + { \ + if (MOD_TREE_DELTA(self->field.avl_left, field) < 0) \ + self->field.avl_left= MOD_TREE_ROTL_##node##_##field(self->field.avl_left); \ + return MOD_TREE_ROTR_##node##_##field(self); \ + } \ + self->field.avl_height= 0; \ + if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height)) \ + self->field.avl_height= self->field.avl_left->field.avl_height; \ + if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height)) \ + self->field.avl_height= self->field.avl_right->field.avl_height; \ + self->field.avl_height += 1; \ + return self; \ + } \ + \ + struct node *MOD_TREE_INSERT_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs), int (*merge)(void **lhs, void **rhs), int *merged)\ + { \ + if (!self) { \ + *merged = 0; \ + return elm; } \ + int cmp = compare(elm->data, self->data); \ + if (cmp < 0) \ + self->field.avl_left= MOD_TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare, merge, merged); \ + else if (cmp > 0) \ + self->field.avl_right= MOD_TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare, merge, merged); \ + else if (merge) { \ + merge(&(elm->data), &(self->data)); \ + *merged = 1; } \ + else \ + self->field.avl_right= MOD_TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare, merge, merged); \ + return MOD_TREE_BALANCE_##node##_##field(self); \ + } \ + \ + struct node *MOD_TREE_FIND_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs)) \ + { \ + if (!compare) \ + return 0; \ + if (!self) \ + return 0; \ + if (compare(elm->data, self->data) == 0) \ + return self; \ + if (compare(elm->data, self->data) < 0) \ + return MOD_TREE_FIND_##node##_##field(self->field.avl_left, elm, compare); \ + else \ + return MOD_TREE_FIND_##node##_##field(self->field.avl_right, elm, compare); \ + } \ + \ + int MOD_TREE_FIND_LESS_EQUAL_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs), struct node **found, struct node **prev) \ + { \ + if (!self) \ + return 0; \ + if (compare(elm->data, self->data) == 0) { \ + *found = self; \ + return 1; \ + } \ + if (compare(elm->data, self->data) < 0) { \ + int ret = MOD_TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_left, elm, compare, found, prev); \ + if (ret == 0 && *prev == NULL) { \ + *prev = self; \ + ret = -1; \ + } \ + return ret; \ + } else { \ + *found = self; \ + *prev = self; \ + return MOD_TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_right, elm, compare, found, prev); \ + } \ + } \ + \ + struct node *MOD_TREE_MOVE_RIGHT_##node##_##field(struct node *self, struct node *rhs) \ + { \ + if (!self) \ + return rhs; \ + self->field.avl_right= MOD_TREE_MOVE_RIGHT_##node##_##field(self->field.avl_right, rhs); \ + return MOD_TREE_BALANCE_##node##_##field(self); \ + } \ + \ + struct node *MOD_TREE_REMOVE_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs), void (*del)(struct node *lhs)) \ + { \ + if (!self) return 0; \ + \ + if (compare(elm->data, self->data) == 0) \ + { \ + struct node *tmp= MOD_TREE_MOVE_RIGHT_##node##_##field(self->field.avl_left, self->field.avl_right); \ + self->field.avl_left= 0; \ + self->field.avl_right= 0; \ + del(self); \ + return tmp; \ + } \ + if (compare(elm->data, self->data) < 0) \ + self->field.avl_left= MOD_TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare, del); \ + else \ + self->field.avl_right= MOD_TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare, del); \ + return MOD_TREE_BALANCE_##node##_##field(self); \ + } \ + \ + void MOD_TREE_FORWARD_APPLY_ALL_##node##_##field \ + (struct node *self, void (*function)(void *node, void *data), void *data) \ + { \ + if (self) \ + { \ + MOD_TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \ + function(self->data, data); \ + MOD_TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \ + } \ + } \ + \ + void MOD_TREE_REVERSE_APPLY_ALL_##node##_##field \ + (struct node *self, void (*function)(struct node *node, void *data), void *data) \ + { \ + if (self) \ + { \ + MOD_TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \ + function(self, data); \ + MOD_TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \ + } \ + } \ + \ + void MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field \ + (struct node *self, void (*function)(struct node *node, void *data), void *data) \ + { \ + if (self) \ + { \ + MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \ + MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \ + function(self, data); \ + } \ + } \ + \ +void MOD_TREE_DESTROY_ALL_##node##_##field \ + (struct node *self, void (*function)(void *node, void *data), void(*dest)(struct node *node), void *data) \ +{ \ + if (self) \ + { \ + MOD_TREE_DESTROY_ALL_##node##_##field(self->field.avl_left, function, dest, data); \ + MOD_TREE_DESTROY_ALL_##node##_##field(self->field.avl_right, function, dest, data); \ + if (function != NULL) \ + function(self->data, data); \ + dest(self); \ + } \ +} \ + \ + void MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field \ + (struct node *self, void (*function)(struct node *node, void *data), void *data) \ + { \ + if (self) \ + { \ + MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_right, function, data); \ + MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_left, function, data); \ + function(self, data); \ + } \ +} + +#define MOD_TREE_INSERT(head, node, field, elm, merge, merged) \ + ((head)->th_root= MOD_TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp, merge, merged)) + +#define MOD_TREE_FIND(head, node, field, elm) \ + (MOD_TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp)) + +#define MOD_TREE_FIND_LESS_EQUAL(head, node, field, elm, found, prev) \ + (MOD_TREE_FIND_LESS_EQUAL_##node##_##field((head)->th_root, (elm), (head)->th_cmp, found, prev)) + +#define MOD_TREE_REMOVE(head, node, field, elm, rem) \ + ((head)->th_root= MOD_TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp, (rem))) + +#define MOD_TREE_DEPTH(head, field) \ + ((head)->th_root->field.avl_height) + +#define MOD_TREE_FORWARD_APPLY(head, node, field, function, data) \ + MOD_TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data) + +#define MOD_TREE_REVERSE_APPLY(head, node, field, function, data) \ + MOD_TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data) + +#define MOD_TREE_POST_ORDER_APPLY(head, node, field, function, data) \ + MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field((head)->th_root, function, data) + +#define MOD_TREE_DESTROY(head, node, field, function, dest, data) \ + MOD_TREE_DESTROY_ALL_##node##_##field((head)->th_root, function, dest, data) + +#define MOD_TREE_REVERSE_APPLY_POST(head, node, field, function, data) \ + MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field((head)->th_root, function, data) + +#define MOD_TREE_INIT(head, cmp) do { \ + (head)->th_root= 0; \ + (head)->th_cmp= (cmp); \ + } while (0) + + +#endif /* __MOD_TREE_h */ diff --git a/src/common/print.c b/src/common/print.c new file mode 100644 index 0000000..9764568 --- /dev/null +++ b/src/common/print.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> + +#include "print.h" + +void hex_printf(const char *data, int length, printf_t print_handler) +{ + int ptr = 0; + for (; ptr < length; ptr++) { + print_handler("0x%02x ", (unsigned char)*(data + ptr)); + } + print_handler("\n"); +} + +void hex_print(const char *data, int length) +{ + hex_printf(data, length, &printf); +} + +void bit_printf(const char *data, int length, printf_t print_handler) +{ + unsigned char mask = 0x01; + int ptr = 0; + int bit = 0; + for (; ptr < length; ptr++) { + for (bit = 7; bit >= 0; bit--) { + if ((mask << bit) & (unsigned char)*(data + ptr)) { + print_handler("1"); + } else { + print_handler("0"); + } + } + print_handler(" "); + } + print_handler("\n"); +} + +void bit_print(const char *data, int length) +{ + bit_printf(data, length, &printf); +} diff --git a/src/common/print.h b/src/common/print.h new file mode 100644 index 0000000..482f55e --- /dev/null +++ b/src/common/print.h @@ -0,0 +1,72 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file print.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Custom printing functions. + * + * Downloaded hex_print, bit_print from http://www.digitalpeer.com/id/print + * Updated with generic printf handler. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_COMMON_PRINT_H_ +#define _KNOTD_COMMON_PRINT_H_ + +typedef int (*printf_t)(const char *fmt, ...); + +/*! + * \brief Prints the given data as hexadecimal characters. + * + * \param data Data to print. + * \param length Size of the \a data array. + */ +void hex_print(const char *data, int length); + +/*! + * \brief Prints the given data as hexadecimal characters using the given + * handler. + * + * \param data Data to print. + * \param length Size of the \a data array. + * \param print_handler Handler for printing. + */ +void hex_printf(const char *data, int length, printf_t print_handler); + +/*! + * \brief Prints the given data as a bitmap. + * + * \param data Data to print. + * \param length Size of the \a data array. + */ +void bit_print(const char *data, int length); + +/*! + * \brief Prints the given data as a bitmap using the given handler. + * + * \param data Data to print. + * \param length Size of the \a data array. + * \param print_handler Handler for printing. + */ +void bit_printf(const char *data, int length, printf_t print_handler); + +#endif /* _KNOTD_COMMON_PRINT_H_ */ + +/*! @} */ diff --git a/src/common/ref.c b/src/common/ref.c new file mode 100644 index 0000000..3b9c033 --- /dev/null +++ b/src/common/ref.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> + +#include "ref.h" + +void ref_init(ref_t *p, ref_destructor_t dtor) +{ + if (p) { + p->count = 0; + p->dtor = dtor; + } +} + +void ref_retain(ref_t *p) +{ + if (p) { + __sync_add_and_fetch(&p->count, 1); + } +} + +void ref_release(ref_t *p) +{ + if (p) { + int rc = __sync_sub_and_fetch(&p->count, 1); + if (rc == 0 && p->dtor) { + p->dtor(p); + } + } +} diff --git a/src/common/ref.h b/src/common/ref.h new file mode 100644 index 0000000..13a7037 --- /dev/null +++ b/src/common/ref.h @@ -0,0 +1,90 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file ref.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Atomic reference counting structures. + * + * Reference counting allows implicit sharing of objects + * between threads with custom destructor functions. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_REF_H_ +#define _KNOTD_REF_H_ + +#include <stddef.h> + +struct ref_t; + +/*! \brief Prototype for object destructor callback. */ +typedef void (*ref_destructor_t)(struct ref_t * p); + +/*! + * \brief Structure for reference counting. + * + * Size equals to two sizes of pointer size. + * Structure may be embedded to the structures which + * we want to use for reference counting. + * + * \code + * struct mystruct { + * ref_t ref; + * int mydata; + * char *mystr; + * } + * \endcode + */ +typedef struct ref_t { + size_t count; /*! \brief Reference counter. */ + ref_destructor_t dtor; /*! \brief Object destructor function. */ +} ref_t; + +/*! + * \brief Initialize reference counter. + * + * Set reference counter to 0 and initialize destructor callback. + * + * \param p Reference-counted object. + * \param dtor Destructor function. + */ +void ref_init(ref_t *p, ref_destructor_t dtor); + +/*! + * \brief Mark object as used by the caller. + * + * Reference counter will be incremented. + * + * \param p Reference-counted object. + */ +void ref_retain(ref_t *p); + +/*! + * \brief Marks object as unused by the caller. + * + * Reference counter will be decremented. + * + * \param p Reference-counted object. + */ +void ref_release(ref_t *p); + +#endif /* _KNOTD_REF_H_ */ + +/*! @} */ diff --git a/src/common/skip-list.c b/src/common/skip-list.c new file mode 100644 index 0000000..79e9429 --- /dev/null +++ b/src/common/skip-list.c @@ -0,0 +1,437 @@ +/* Copyright (c) 2010 the authors listed at the following URL, and/or +the authors of referenced articles or incorporated external code: +http://en.literateprograms.org/Skip_list_(C)?action=history&offset=20080313195128 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Retrieved from: http://en.literateprograms.org/Skip_list_(C)?oldid=12811 +*/ + +/* + * Modifications by Lubos Slovak, 2010-2011 + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <assert.h> + +//#include "common.h" +#include "common/skip-list.h" + +#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \ + __FILE__, __LINE__) + +/*----------------------------------------------------------------------------*/ + +static const float P = 0.5; + +/*! + * \brief Maximum level of a node, i.e. maximum number of skip list levels. + */ +static const int MAX_LEVEL = 6; + +/*----------------------------------------------------------------------------*/ +/* Private functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Generates random real number between 0 and 1. + */ +static float frand() +{ + unsigned seed = (unsigned)time(0); + return (float) rand_r(&seed) / RAND_MAX; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns random level between 0 and MAX_LEVEL. + */ +static int skip_random_level() +{ + static int first = 1; + int lvl = 0; + + if (first) { + first = 0; + } + + while (frand() < P && lvl < MAX_LEVEL) { + lvl++; + } + + return lvl; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a new skip list node with the given key and value. + * + * \param level Level of the skip list node. + * \param key Key of the new node. + * \param value Value to be stored in the node. + * + * \return Pointer to the newly created node or NULL if not successful. + */ +static skip_node_t *skip_make_node(int level, void *key, void *value) +{ + skip_node_t *sn = (skip_node_t *)malloc(sizeof(skip_node_t)); + if (sn == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + sn->forward = (skip_node_t **)calloc(level + 1, sizeof(skip_node_t *)); + if (sn->forward == NULL) { + ERR_ALLOC_FAILED; + free(sn); + return NULL; + } + sn->key = key; + sn->value = value; + return sn; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Properly deallocates the given skip list node, and optionally destroys + * its key and value. + * + * \param node Skip list node to be deleted. + * \param destroy_key Function for properly destroying the key. If set tu NULL, + * the object at which the key points will not be destroyed. + * \param destroy_value Function for properly destroying the key. If set tu + * NULL, the object at which the value points will not be + * destroyed. + */ +static void skip_delete_node(skip_node_t **node, void (*destroy_key)(void *), + void (*destroy_value)(void *)) +{ + if (destroy_key != NULL) { + destroy_key((*node)->key); + } + if (destroy_value != NULL) { + destroy_value((*node)->value); + } + + free((*node)->forward); + free(*node); + + node = NULL; +} + +/*----------------------------------------------------------------------------*/ +/* Public functions */ +/*----------------------------------------------------------------------------*/ + +skip_list_t *skip_create_list(int (*compare_keys)(void *, void *)) +{ + assert(compare_keys != NULL); + + skip_list_t *ss = (skip_list_t *)malloc(sizeof(skip_list_t)); + if (ss == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + ss->head = skip_make_node(MAX_LEVEL, NULL, NULL); + if (ss->head == NULL) { + ERR_ALLOC_FAILED; + free(ss); + return NULL; + } + + ss->level = 0; + ss->compare_keys = compare_keys; + + return ss; +} + +/*----------------------------------------------------------------------------*/ + +void skip_destroy_list(skip_list_t **list, void (*destroy_key)(void *), + void (*destroy_value)(void *)) +{ + assert((*list) != NULL); + assert((*list)->head != NULL); + + skip_node_t *x; + + while ((*list)->head->forward[0] != NULL) { + x = (*list)->head->forward[0]; + for (int i = 0; i <= (*list)->level; i++) { + if ((*list)->head->forward[i] != x) { + break; + } + (*list)->head->forward[i] = x->forward[i]; + } + + // delete the item + skip_delete_node(&x, destroy_key, destroy_value); + + while ((*list)->level > 0 + && (*list)->head->forward[(*list)->level] == NULL) { + (*list)->level--; + } + } + + // free the head + skip_delete_node(&(*list)->head, NULL, NULL); + + free(*list); + *list = NULL; +} + +/*----------------------------------------------------------------------------*/ + +void *skip_find(const skip_list_t *list, void *key) +{ + assert(list != NULL); + assert(list->head != NULL); + assert(list->compare_keys != NULL); + + int i; + skip_node_t *x = list->head; + for (i = list->level; i >= 0; i--) { + while (x->forward[i] != NULL + && list->compare_keys(x->forward[i]->key, key) == -1) { + x = x->forward[i]; + } + } + x = x->forward[0]; + + if (x != NULL && list->compare_keys(x->key, key) == 0) { + return x->value; + } + return NULL; +} + +/*----------------------------------------------------------------------------*/ + +void *skip_find_less_or_equal(const skip_list_t *list, void *key) +{ + assert(list != NULL); + assert(list->head != NULL); + assert(list->compare_keys != NULL); + + int i; + skip_node_t *x = list->head; + for (i = list->level; i >= 0; i--) { + while (x->forward[i] != NULL + && list->compare_keys(x->forward[i]->key, key) <= 0) { + x = x->forward[i]; + } + } + + return x->value; +} + +/*----------------------------------------------------------------------------*/ + +int skip_insert(skip_list_t *list, void *key, void *value, + int (*merge_values)(void **, void **)) +{ + assert(list != NULL); + assert(list->head != NULL); + assert(list->compare_keys != NULL); + + int i; + skip_node_t *x = list->head; + skip_node_t *update[MAX_LEVEL + 1]; + memset(update, 0, MAX_LEVEL + 1); + + for (i = list->level; i >= 0; i--) { + while (x->forward[i] != NULL + && list->compare_keys(x->forward[i]->key, key) == -1) { + x = x->forward[i]; + } + update[i] = x; + } + x = x->forward[0]; + + if (x == NULL || list->compare_keys(x->key, key) != 0) { + int lvl = skip_random_level(); + + if (lvl > list->level) { + for (i = list->level + 1; i <= lvl; i++) { + update[i] = list->head; + } + list->level = lvl; + } + + x = skip_make_node(lvl, key, value); + if (x == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + for (i = 0; i <= lvl; i++) { + x->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = x; + } + + return 0; + } else { // already in the list + if (merge_values != NULL) { // if merge function provided, merge + return (merge_values(&x->value, &value) == 0) ? 2 : -2; + } else { + return 1; + } + } +} + +/*----------------------------------------------------------------------------*/ + +int skip_remove(skip_list_t *list, void *key, void (*destroy_key)(void *), + void (*destroy_value)(void *)) +{ + assert(list != NULL); + assert(list->head != NULL); + assert(list->compare_keys != NULL); + + int i; + skip_node_t *x = list->head; + skip_node_t *update[MAX_LEVEL + 1]; + memset(update, 0, MAX_LEVEL + 1); + + for (i = list->level; i >= 0; i--) { + while (x->forward[i] != NULL + && list->compare_keys(x->forward[i]->key, key) == -1) { + x = x->forward[i]; + } + update[i] = x; + } + x = x->forward[0]; + + if (x != NULL && list->compare_keys(x->key, key) == 0) { + for (i = 0; i <= list->level; i++) { + if (update[i]->forward[i] != x) { + break; + } + update[i]->forward[i] = x->forward[i]; + } + + // delete the item + skip_delete_node(&x, destroy_key, destroy_value); + + while (list->level > 0 + && list->head->forward[list->level] == NULL) { + list->level--; + } + return 0; + } else { + return -1; + } +} + +/*----------------------------------------------------------------------------*/ + +int skip_is_empty(const skip_list_t *list) +{ + if (!list) { + return 1; + } + + return (list->head->forward[0] == NULL); +} + +/*----------------------------------------------------------------------------*/ + +const skip_node_t *skip_first(const skip_list_t *list) +{ + if (!list) { + return NULL; + } + + return list->head->forward[0]; +} + +/*----------------------------------------------------------------------------*/ + +const skip_node_t *skip_next(const skip_node_t *node) +{ + return node->forward[0]; +} + +/*----------------------------------------------------------------------------*/ + +void skip_print_list(const skip_list_t *list, + void (*print_item)(void *, void *)) +{ + assert(list != NULL); + assert(list->head != NULL); + assert(list->compare_keys != NULL); + assert(print_item != NULL); + + skip_node_t *x = list->head->forward[0]; + while (x != NULL) { + print_item(x->key, x->value); + x = x->forward[0]; + } +} + +/*----------------------------------------------------------------------------*/ + +skip_list_t *skip_copy_list(const skip_list_t *list) +{ + skip_list_t *ss = (skip_list_t *)malloc(sizeof(skip_list_t)); + if (ss == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + ss->head = skip_make_node(list->level, NULL, NULL); + if (ss->head == NULL) { + ERR_ALLOC_FAILED; + free(ss); + return NULL; + } + + ss->level = list->level; + ss->compare_keys = list->compare_keys; + + skip_node_t *x = list->head->forward[0]; + skip_node_t *prev = list->head; + skip_node_t *new_prev = ss->head; + while (x != NULL) { + //print_item(x->key, x->value); + + // create new node + skip_node_t *n = skip_make_node(list->level, x->key, x->value); + if (n == NULL) { + skip_destroy_list(&ss, NULL, NULL); + return NULL; + } + // set forward pointers from the previous node + for (int i = 0; i <= list->level; ++i) { + if (prev->forward[i] == x) { + new_prev->forward[i] = n; + } + } + + prev = x; + x = x->forward[0]; + new_prev = n; + } + + return ss; +} diff --git a/src/common/skip-list.h b/src/common/skip-list.h new file mode 100644 index 0000000..784f366 --- /dev/null +++ b/src/common/skip-list.h @@ -0,0 +1,215 @@ +/*! + * \file skip-list.h + * + * \author Copyright (c) 2010 the authors listed at the following URL, and/or + * the authors of referenced articles or incorporated external code: + * http://en.literateprograms.org/Skip_list_(C)?action=history&offset=20080313195128 + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Generic skip-list implementation. + * + * Original retrieved from http://en.literateprograms.org/Skip_list_(C)?oldid=12811 + * Modifications by Lubos Slovak, 2010 + * + * \addtogroup common_lib + * @{ + */ + +/* Copyright (c) 2010 the authors listed at the following URL, and/or +the authors of referenced articles or incorporated external code: +http://en.literateprograms.org/Skip_list_(C)?action=history&offset=20080313195128 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Retrieved from: http://en.literateprograms.org/Skip_list_(C)?oldid=12811 +*/ + +#ifndef _KNOTD_COMMON_SKIP_LIST_H_ +#define _KNOTD_COMMON_SKIP_LIST_H_ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Skip list node. + */ +struct skip_node { + void *key; /*!< Key of the node. Used for ordering. */ + + void *value; /*!< Value stored in the node. */ + + /*! \brief Pointers to next item on various levels. */ + struct skip_node **forward; +}; + +typedef struct skip_node skip_node_t; + +/*! + * \brief Skip list. + * + * \todo Implement quasi-randomization. + */ +struct skip_list { + /*! \brief Head of the list (with no actual key and value stored). */ + skip_node_t *head; + + /*! \brief Actual maximum level of the list. */ + int level; + + /*! \brief Function for comparing two skip list item's keys. */ + int (*compare_keys)(void *, void *); +}; + +typedef struct skip_list skip_list_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a new generic skip list. + * + * \param compare_keys Function for comparing the keys. + * \todo What should compare_keys exactly return? + * + * \return Pointer to the newly created skip list if successful. NULL otherwise. + */ +skip_list_t *skip_create_list(int (*compare_keys)(void *, void *)); + +/*! + * \brief Properly destroys the list, possibly also with the keys and values. + * + * \param list Skip list to be destroyed. + * \param destroy_key Function for properly destroying the key. If set tu NULL, + * the object at which the key points will not be destroyed. + * \param destroy_value Function for properly destroying the key. If set tu + * NULL, the object at which the value points will not be + * destroyed. + */ +void skip_destroy_list(skip_list_t **list, void (*destroy_key)(void *), + void (*destroy_value)(void *)); + +/*! + * \brief Inserts a new key-value pair into the skip list. + * + * The \a merge_values function should merge the second value to the first + * value. It must not delete the first value. The second value also should not + * be deleted (as this is concern of the caller). + * + * \param list The skip list to insert to. + * \param key Key of the item to be inserted. Used for ordering. + * \param value Value of the item to be inserted. + * \param merge_values Function for merging the saved values. Optional. If set + * to NULL, the skip list will not merge values when + * attempting to insert item with key already present in the + * list. + * \todo What are the function parameters and what should it + * return as integer? + * + * \retval 0 If successful and the key was not yet present in the list. + * \retval 1 If the key was already present and the new value was ignored + * (because no merging function was provided). + * \retval 2 If successful, the key was already present and the values were + * merged. + * \retval -1 If an error occured and the key was not present in the list. + * \retval -2 If the key is already present in the list and merging was + * unsuccessful. + */ +int skip_insert(skip_list_t *list, void *key, void *value, + int (*merge_values)(void **, void **)); + +/*! + * \brief Removes an item with the given key from the list and optionally + * deletes the item's key and value. + * + * \param list Skip list to delete from. + * \param key Key of the item to be deleted. + * \param destroy_key Function for properly destroying the key. If set tu NULL, + * the object at which the key points will not be destroyed. + * \param destroy_value Function for properly destroying the key. If set tu + * NULL, the object at which the value points will not be + * destroyed. + * + * \retval 0 If successful. + * \retval -1 If the item was not present in the list. + */ +int skip_remove(skip_list_t *list, void *key, void (*destroy_key)(void *), + void (*destroy_value)(void *)); + +/*! + * \brief Tries to find item with the given key in the list. + * + * \param list Skip list to search in. + * \param key Key of the item to be found. + * + * \return Value stored in the item with key \a key, or NULL if the key was not + * found. + */ +void *skip_find(const skip_list_t *list, void *key); + +/*! + * \brief Returns item with largest key smaller or equal than \a key. + * + * \param list Skip list to search in. + * \param key Key of the item to be found. + * + * \return Value stored in the item with largest key smaller or equal than \a + * key, or NULL if the key was not found. + */ +void *skip_find_less_or_equal(const skip_list_t *list, void *key); + +/*! + * \brief Checks if the skip list is empty. + * + * \param list Skip list to check. + * + * \retval 1 if empty. + * \retval 0 if non-empty. + */ +int skip_is_empty(const skip_list_t *list); + +/*! + * \brief Returns the first item in the skip list. + */ +const skip_node_t *skip_first(const skip_list_t *list); + +/*! + * \brief Returns the next item in the skip list. + */ +const skip_node_t *skip_next(const skip_node_t *node); + +/*! + * \brief Prints the whole list using the given print function. + * + * \param list Skip list to be printed. + * \param print_item Function for printing the key-value pair. + */ +void skip_print_list(const skip_list_t *list, + void (*print_item)(void *, void *)); + +/*! + * \brief Copies the skip list. + * + * \param list Skip list to be copied. + * + * \return Copy of \a list. + * + * \todo Test!!! + */ +skip_list_t *skip_copy_list(const skip_list_t *list); + +#endif /* _KNOTD_COMMON_SKIP_LIST_H_ */ + +/*! @} */ diff --git a/src/common/slab/alloc-common.h b/src/common/slab/alloc-common.h new file mode 100644 index 0000000..32878ab --- /dev/null +++ b/src/common/slab/alloc-common.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file alloc-common.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Common macros for alloc. + * + * \addtogroup alloc + * @{ + */ + +#ifndef _KNOTD_COMMON_ALLOC_COMMON_H_ +#define _KNOTD_COMMON_ALLOC_COMMON_H_ + +#include <stdio.h> + +//#define MEM_DEBUG +//#define MEM_NOSLAB +//#define MEM_POISON +#define MEM_SLAB_CAP 5 // Cap slab_cache empty slab count (undefined = inf) +#define MEM_COLORING // Slab cache coloring +//#define MEM_SLAB_DEPOT // Use slab depot for slab caching (not thread-safe) + +/* Eliminate compiler warning with unused parameters. */ +#ifndef UNUSED +#define UNUSED(param) (void)(param) +#endif + +/* Optimisation macros. */ +#ifndef likely +#define likely(x) __builtin_expect((x),1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect((x),0) +#endif + +#ifdef MEM_DEBUG +#define dbg_mem(msg...) fprintf(stderr, msg) +#else +#define dbg_mem(msg...) +#endif + + +#endif /* _KNOTD_COMMON_ALLOC_COMMON_H_ */ + +/*! @} */ diff --git a/src/common/slab/malloc.c b/src/common/slab/malloc.c new file mode 100644 index 0000000..ec5a68d --- /dev/null +++ b/src/common/slab/malloc.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +/* + * Skip unit if not debugging memory. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/resource.h> + +#include "common/slab/alloc-common.h" + +#ifdef MEM_DEBUG +/* + * ((destructor)) attribute executes this function after main(). + * \see http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html + */ +void __attribute__ ((destructor)) usage_dump() +#else +void usage_dump() +#endif +{ + /* Get resource usage. */ + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage) < 0) { + memset(&usage, 0, sizeof(struct rusage)); + } + + fprintf(stderr, "\nMemory statistics:"); + fprintf(stderr, "\n==================\n"); + + fprintf(stderr, "User time: %.03lf ms\nSystem time: %.03lf ms\n", + usage.ru_utime.tv_sec * (double) 1000.0 + + usage.ru_utime.tv_usec / (double)1000.0, + usage.ru_stime.tv_sec * (double) 1000.0 + + usage.ru_stime.tv_usec / (double)1000.0); + fprintf(stderr, "Major page faults: %lu (required I/O)\nMinor page faults: %lu\n", + usage.ru_majflt, usage.ru_minflt); + fprintf(stderr, "Number of swaps: %lu\n", + usage.ru_nswap); + fprintf(stderr, "Voluntary context switches: %lu\nInvoluntary context switches: %lu\n", + usage.ru_nvcsw, + usage.ru_nivcsw); + fprintf(stderr, "==================\n"); +} diff --git a/src/common/slab/malloc.h b/src/common/slab/malloc.h new file mode 100644 index 0000000..8ca9f58 --- /dev/null +++ b/src/common/slab/malloc.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file malloc.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Memory allocation related functions. + * + * \addtogroup alloc + * @{ + */ + +#ifndef _KNOTD_COMMON_MALLOC_H_ +#define _KNOTD_COMMON_MALLOC_H_ + +#include <stdlib.h> + +/*! \brief Print usage statistics. + * + * \note This function has destructor attribute set if MEM_DEBUG is enabled. + * + * \warning Not all printed statistics are available on every OS, + * consult manual page for getrusage(2). + */ +void usage_dump(); + +#endif // _KNOTD_COMMON_MALLOC_H_ + +/*! @} */ diff --git a/src/common/slab/slab.c b/src/common/slab/slab.c new file mode 100644 index 0000000..ccdf7ca --- /dev/null +++ b/src/common/slab/slab.c @@ -0,0 +1,732 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <sys/mman.h> + +#include "common/slab/alloc-common.h" +#include "common/slab/slab.h" + +/* + * Magic constants. + */ +#define SLAB_MAGIC 0x51 /*!< "Sl" magic byte (slab type). */ +#define LOBJ_MAGIC 0x0B /*!< "Ob" magic byte (object type). */ +#define POISON_DWORD 0xdeadbeef /*!< Memory boundary guard magic. */ +#define SLAB_MINCOLOR 64 /*!< Minimum space reserved for cache coloring. */ +#define SLAB_HEADER sizeof(slab_t) /*!< Slab header size. */ +#define ALIGN_PTRSZ __attribute__ ((__aligned__(sizeof(void*)))) + +/*! \brief Fast cache id lookup table. + * + * Provides O(1) lookup. + * Filled with interesting values from default + * or on-demand. + */ +unsigned ALIGN_PTRSZ SLAB_CACHE_LUT[SLAB_SIZE] = { + [24] = SLAB_GP_COUNT + 1, + [800] = SLAB_GP_COUNT + 2 +}; + +/*! \brief Find the next highest power of 2. */ +static inline unsigned get_next_pow2(unsigned v) +{ + // Next highest power of 2 + --v; + v |= v >> 1; v |= v >> 2; + v |= v >> 4; v |= v >> 8; + v |= v >> 16; + ++v; + + return v; +} + +/*! \brief Return binary logarithm of a number, which is a power of 2. */ +static inline unsigned fastlog2(unsigned v) +{ + // Works if we know the size is a power of 2 + register unsigned int r = (v & 0xAAAAAAAA) != 0; + r |= ((v & 0xFFFF0000) != 0) << 4; + r |= ((v & 0xFF00FF00) != 0) << 3; + r |= ((v & 0xF0F0F0F0) != 0) << 2; + r |= ((v & 0xCCCCCCCC) != 0) << 1; + return r; +} + +/*! + * \brief Fast hashing function. + * + * Finds the next highest power of 2 and returns binary logarithm. + * Values are stored in LUT cache for future access. + */ +static unsigned slab_cache_id(unsigned size) +{ + // Assert cache id of the smallest bufsize is 0 + if(size <= SLAB_MIN_BUFLEN) { + return 0; + } + + // Check LUT + unsigned id = 0; + if ((id = SLAB_CACHE_LUT[size])) { + return id; + } else { + + // Compute binary logarithm + // Next highest power of 2 + id = fastlog2(get_next_pow2(size)); + + // Shift cacheid of SLAB_MIN_BUFLEN to 0 + id -= SLAB_EXP_OFFSET; + + // Store + SLAB_CACHE_LUT[size] = id; + } + + return id; +} + +/* + * Slab run-time constants. + */ + +size_t SLAB_MASK = 0; /*!< \brief Slab address mask (for computing offsets). */ +static unsigned SLAB_LOGSIZE = 0; /*!< \brief Binary logarithm of slab size. */ + +/*! + * Depot is a caching sub-allocator of slabs. + * It mitigates performance impact of sequentially allocating and freeing + * from a slab with just a few slab items by caching N slabs before returning + * them to the system. + * + * \todo With wider use, locking or RCU will be necessary. + */ +#ifdef MEM_SLAB_DEPOT +static slab_depot_t _depot_g; /*! \brief Global slab depot. */ +#endif // MEM_SLAB_DEPOT + +/*! + * \brief Allocate a slab of given bufsize from depot. + * + * \retval Reserved memory for slab on success. + * \retval NULL on errors. + */ +static void* slab_depot_alloc(size_t bufsize) +{ + void *page = 0; +#ifdef MEM_SLAB_DEPOT + if (_depot_g.available) { + for (int i = _depot_g.available - 1; i > -1 ; --i) { + if(_depot_g.cache[i]->bufsize == bufsize) { + page = _depot_g.cache[i]; + _depot_g.cache[i] = _depot_g.cache[--_depot_g.available]; + return page; + } + } + page = _depot_g.cache[--_depot_g.available]; + } else { + if(posix_memalign(&page, SLAB_SIZE, SLAB_SIZE) == 0) { + ((slab_t*)page)->bufsize = 0; + } else { + page = 0; + } + + } +#else // MEM_SLAB_DEPOT + if(posix_memalign(&page, SLAB_SIZE, SLAB_SIZE) == 0) { + ((slab_t*)page)->bufsize = 0; + } else { + page = 0; + } +#endif // MEM_SLAB_DEPOT + + return page; +} + +/*! + * \brief Return a slab to the depot. + * + * \note If the depot is full, slab gets immediately freed. + */ +static inline void slab_depot_free(void* slab) +{ +#ifdef MEM_SLAB_DEPOT + if (_depot_g.available < SLAB_DEPOT_SIZE) { + _depot_g.cache[_depot_g.available++] = slab; + } else { + free(slab); + } +#else // MEM_SLAB_DEPOT + free(slab); +#endif // MEM_SLAB_DEPOT +} + +/*! \brief Initialize slab depot. */ +static void slab_depot_init() +{ +#ifdef MEM_SLAB_DEPOT + _depot_g.available = 0; +#endif // MEM_SLAB_DEPOT +} + +/*! \brief Destroy slab depot. */ +static void slab_depot_destroy() +{ +#ifdef MEM_SLAB_DEPOT + while(_depot_g.available) { + free(_depot_g.cache[--_depot_g.available]); + } +#endif // MEM_SLAB_DEPOT +} + +/* + * Initializers. + */ + +/*! \brief Initializes slab subsystem (it is called automatically). */ +void __attribute__ ((constructor)) slab_init() +{ + // Fetch page size + SLAB_LOGSIZE = fastlog2(SLAB_SIZE); + + // Compute slab page mask + SLAB_MASK = 0; + for (int i = 0; i < SLAB_LOGSIZE; ++i) { + SLAB_MASK |= 1 << i; + } + SLAB_MASK = ~SLAB_MASK; + + // Initialize depot + slab_depot_init(); +} + +/*! \brief Deinitializes slab subsystem (it is called automatically). */ +void __attribute__ ((destructor)) slab_deinit() +{ + // Deinitialize global allocator + if (SLAB_LOGSIZE) { + slab_depot_destroy(); + SLAB_LOGSIZE = SLAB_MASK = 0; + } +} + +/* + * Cache helper functions. + */ + +/* \notice Not used right now. +static void slab_dump(slab_t* slab) { + + printf("%s: buffers (bufsize=%zuB, %u/%u free): \n", + __func__, slab->cache->bufsize, slab->bufs_free, + slab->bufs_count); + + void** buf = slab->head; + int i = 0, n = 0; + while(buf != 0) { + size_t diff = (size_t)((char*)buf - (char*)slab->base); + printf("-> %lu", diff / slab->cache->bufsize); + buf = (void**)(*buf); + if (++i == 10) { + printf("\n"); + i = 0; + } + ++n; + } + + printf("\n"); +} +*/ + +/*! + * \brief Free all slabs from a slab cache. + * \return Number of freed slabs. + */ +static inline int slab_cache_free_slabs(slab_t* slab) +{ + int count = 0; + while (slab) { + slab_t* next = slab->next; + slab_destroy(&slab); + ++count; + slab = next; + + } + return count; +} + +/* + * Slab helper functions. + */ + +/*! \brief Return number of slabs in a linked list. */ +static inline unsigned slab_list_walk(slab_t* slab) +{ + unsigned count = 0; + while(slab) { + slab = slab->next; + ++count; + } + return count; +} + +/*! \brief Remove slab from a linked list. */ +static void slab_list_remove(slab_t* slab) +{ + // Disconnect from list + if (slab->prev) { + slab->prev->next = slab->next; + } + if(slab->next) { + slab->next->prev = slab->prev; + } + + // Disconnect from cache + slab_cache_t* cache = slab->cache; + { + if (cache->slabs_free == slab) { + cache->slabs_free = slab->next; + } else if (cache->slabs_full == slab) { + cache->slabs_full = slab->next; + } + } +} + +/*! \brief Insert slab into a linked list. */ +static void slab_list_insert(slab_t** list, slab_t* item) +{ + // If list exists, push to the top + item->prev = 0; + item->next = *list; + if(*list) { + (*list)->prev = item; + } + *list = item; +} + +/*! \brief Move slab from one linked list to another. */ +static inline void slab_list_move(slab_t** target, slab_t* slab) +{ + slab_list_remove(slab); + slab_list_insert(target, slab); +} + +/* + * API functions. + */ + +slab_t* slab_create(slab_cache_t* cache) +{ + const size_t size = SLAB_SIZE; + + slab_t* slab = slab_depot_alloc(cache->bufsize); + + if (unlikely(slab < 0)) { + dbg_mem("%s: failed to allocate aligned memory block\n", + __func__); + return 0; + } + + /* Initialize slab. */ + slab->magic = SLAB_MAGIC; + slab->cache = cache; + slab_list_insert(&cache->slabs_free, slab); +#ifdef MEM_SLAB_CAP + ++cache->empty; +#endif + + /* Already initialized? */ + if (slab->bufsize == cache->bufsize) { + return slab; + } else { + slab->bufsize = cache->bufsize; + } + + /* Ensure the item size can hold at least a size of ptr. */ + size_t item_size = slab->bufsize; + if (unlikely(item_size < SLAB_MIN_BUFLEN)) { + item_size = SLAB_MIN_BUFLEN; + } + + /* Ensure at least some space for coloring */ + size_t data_size = size - sizeof(slab_t); +#ifdef MEM_COLORING + size_t free_space = data_size % item_size; + if (unlikely(free_space < SLAB_MINCOLOR)) { + free_space = SLAB_MINCOLOR; + } + + + /// unsigned short color = __sync_fetch_and_add(&cache->color, 1); + unsigned short color = (cache->color += sizeof(void*)); + color = color % free_space; +#else + const unsigned short color = 0; +#endif + + /* Calculate useable data size */ + data_size -= color; + slab->bufs_count = data_size / item_size; + slab->bufs_free = slab->bufs_count; + + // Save first item as next free + slab->base = (char*)slab + sizeof(slab_t) + color; + slab->head = (void**)slab->base; + + // Create freelist, skip last member, which is set to NULL + char* item = (char*)slab->head; + for(unsigned i = 0; i < slab->bufs_count - 1; ++i) { + *((void**)item) = item + item_size; + item += item_size; + } + + // Set last buf to NULL (tail) + *((void**)item) = (void*)0; + + // Ensure the last item has a NULL next + dbg_mem("%s: created slab (%p, %p) (%zu B)\n", + __func__, slab, slab + size, size); + return slab; +} + +void slab_destroy(slab_t** slab) +{ + /* Disconnect from the list */ + slab_list_remove(*slab); + + /* Free slab */ + slab_depot_free(*slab); + + /* Invalidate pointer. */ + dbg_mem("%s: deleted slab %p\n", __func__, *slab); + *slab = 0; +} + +void* slab_alloc(slab_t* slab) +{ + // Fetch first free item + void **item = 0; + { + if((item = slab->head)) { + slab->head = (void**)*item; + --slab->bufs_free; + } else { + // No more free items + return 0; + } + } + +#ifdef MEM_DEBUG + // Increment statistics + __sync_add_and_fetch(&slab->cache->stat_allocs, 1); +#endif + + // Move to full? + if (unlikely(slab->bufs_free == 0)) { + slab_list_move(&slab->cache->slabs_full, slab); + } else { +#ifdef MEM_SLAB_CAP + // Mark not empty? + if (unlikely(slab->bufs_free == slab->bufs_count - 1)) { + --slab->cache->empty; + } +#endif + } + + return item; +} + +void slab_free(void* ptr) +{ + // Null pointer check + if (unlikely(!ptr)) { + return; + } + + // Get slab start address + slab_t* slab = slab_from_ptr(ptr); + assert(slab); + + // Check if it exists in directory + if (slab->magic == SLAB_MAGIC) { + + // Return buf to slab + *((void**)ptr) = (void*)slab->head; + slab->head = (void**)ptr; + ++slab->bufs_free; + +#ifdef MEM_DEBUG + // Increment statistics + __sync_add_and_fetch(&slab->cache->stat_frees, 1); +#endif + + // Return to partial + if(unlikely(slab->bufs_free == 1)) { + slab_list_move(&slab->cache->slabs_free, slab); + } else { +#ifdef MEM_SLAB_CAP + // Recycle if empty + if(unlikely(slab_isempty(slab))) { + if(slab->cache->empty == MEM_SLAB_CAP) { + slab_destroy(&slab); + } else { + ++slab->cache->empty; + } + } +#endif + } + + } else { + + // Pointer is not a slab + // Presuming it's a large block + slab_obj_t* bs = (slab_obj_t*)ptr - 1; + +#ifdef MEM_POISON + // Remove memory barrier + mprotect(ptr + bs->size, sizeof(int), PROT_READ|PROT_WRITE); +#endif + + // Unmap + dbg_mem("%s: unmapping large block of %zu bytes at %p\n", + __func__, bs->size, ptr); + free(bs); + } +} + +int slab_cache_init(slab_cache_t* cache, size_t bufsize) +{ + if (unlikely(!bufsize)) { + return -1; + } + + cache->empty = 0; + cache->bufsize = bufsize; + cache->slabs_free = cache->slabs_full = 0; + cache->color = 0; + + /* Initialize stats */ + cache->stat_allocs = cache->stat_frees = 0; + + dbg_mem("%s: created cache of size %zu\n", + __func__, bufsize); + + return 0; +} + +void slab_cache_destroy(slab_cache_t* cache) { + + // Free slabs + unsigned free_s = slab_cache_free_slabs(cache->slabs_free); + unsigned full_s = slab_cache_free_slabs(cache->slabs_full); +#ifndef MEM_DEBUG + UNUSED(free_s); + UNUSED(full_s); +#else + dbg_mem("%s: %u empty/partial, %u full caches\n", + __func__, free_s, full_s); +#endif + + // Invalidate cache + cache->bufsize = 0; + cache->slabs_free = cache->slabs_full = 0; +} + +void* slab_cache_alloc(slab_cache_t* cache) +{ + slab_t* slab = cache->slabs_free; + if(!cache->slabs_free) { + slab = slab_create(cache); + if (slab == NULL) { + return NULL; + } + } + + + return slab_alloc(slab); +} + +int slab_cache_reap(slab_cache_t* cache) +{ + // For now, just free empty slabs + slab_t* slab = cache->slabs_free; + int count = 0; + while (slab) { + slab_t* next = slab->next; + if (slab_isempty(slab)) { + slab_destroy(&slab); + ++count; + } + slab = next; + + } + + cache->empty = 0; + return count; +} + +int slab_alloc_init(slab_alloc_t* alloc) +{ + // Invalidate + memset(alloc, 0, sizeof(slab_alloc_t)); + + // Initialize descriptors cache + slab_cache_init(&alloc->descriptors, sizeof(slab_cache_t)); + + return 0; +} + +void slab_alloc_destroy(slab_alloc_t* alloc) +{ + // Destroy all caches + for (unsigned i = 0; i < SLAB_CACHE_COUNT; ++i) { + if (alloc->caches[i] != 0) { + slab_cache_destroy(alloc->caches[i]); + } + } + + // Destroy cache for descriptors + slab_cache_destroy(&alloc->descriptors); +} + +void* slab_alloc_alloc(slab_alloc_t* alloc, size_t size) +{ + // Invalid size check + if (unlikely(!size)) { + return 0; + } + +#ifdef MEM_POISON + // Reserve memory for poison + size += sizeof(int); +#endif + // Directly map large block + if (unlikely(size > SLAB_SIZE/2)) { + + // Map block + size += sizeof(slab_obj_t); + slab_obj_t* p = 0; + p = malloc(size); + + dbg_mem("%s: mapping large block of %zu bytes at %p\n", + __func__, size, p + 1); + + /* Initialize. */ + p->magic = LOBJ_MAGIC; + p->size = size - sizeof(slab_obj_t); + +#ifdef MEM_POISON + // Reduce real size + p->size -= sizeof(int); + + // Memory barrier + int* pb = (int*)((char*)p + size - sizeof(int)); + *pb = POISON_DWORD; + mprotect(pb, sizeof(int), PROT_NONE); +#endif + + return p + 1; + } + + // Get cache id from size + unsigned cache_id = slab_cache_id(size); + + // Check if associated cache exists + if (unlikely(alloc->caches[cache_id] == 0)) { + + // Assert minimum cache size + if (unlikely(size < SLAB_MIN_BUFLEN)) { + size = SLAB_MIN_BUFLEN; + } + + // Calculate cache bufsize + size_t bufsize = size; + if (cache_id < SLAB_GP_COUNT) { + bufsize = get_next_pow2(size); + } + + // Create cache + dbg_mem("%s: creating cache of %zuB (req. %zuB) (id=%u)\n", + __func__, bufsize, size, cache_id); + + slab_cache_t* cache = slab_cache_alloc(&alloc->descriptors); + slab_cache_init(cache, bufsize); + alloc->caches[cache_id] = cache; + } + + // Allocate from cache + void* mem = slab_cache_alloc(alloc->caches[cache_id]); + +#ifdef MEM_POISON + // Memory barrier + /*! \todo Broken, need to store the barrier byte size. */ + //int* pb = (int*)((char*)mem + size - sizeof(int)); + //mprotect(pb, sizeof(int), PROT_NONE); +#endif + return mem; +} + +void *slab_alloc_realloc(slab_alloc_t* alloc, void *ptr, size_t size) +{ + // realloc(0) equals to free(ptr) + if (!size) { + slab_free(ptr); + return 0; + } + + // Allocate new buf + void *nptr = slab_alloc_alloc(alloc, size); + assert(nptr); + + // Copy memory if present + if (ptr) { + slab_t* slab = slab_from_ptr(ptr); + memcpy(nptr, ptr, slab->cache->bufsize); + + // Free old buf + slab_free(ptr); + } + + return nptr; +} + +void slab_alloc_stats(slab_alloc_t* alloc) +{ +#ifdef MEM_DEBUG + printf("Cache usage:\n"); + for (int i = 0; i < SLAB_CACHE_COUNT; ++i) { + + if (!alloc->caches[i]) + continue; + + slab_cache_t* cache = alloc->caches[i]; + unsigned free_s = slab_list_walk(cache->slabs_free); + unsigned full_s = slab_list_walk(cache->slabs_full); + printf("%4zu: allocs=%lu frees=%lu " + "(%u empty+partial, %u full)\n", + cache->bufsize, cache->stat_allocs, + cache->stat_frees, free_s, full_s); + } +#else + printf("Cache usage: not available, enable MEM_DEBUG and recompile.\n"); +#endif +} + diff --git a/src/common/slab/slab.h b/src/common/slab/slab.h new file mode 100644 index 0000000..d64188e --- /dev/null +++ b/src/common/slab/slab.h @@ -0,0 +1,353 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file slab.h + * + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief SLAB allocator. + * + * SLAB cache works with either custom SLAB sizes and + * Next-Highest-Power-Of-2 sizes. + * + * Slab size is a multiple of PAGE_SIZE and uses + * system allocator for larger blocks. + * + * Allocated SLABs are PAGE_SIZE aligned for a fast O(1) + * address-from-item lookup. This results in nearly none memory + * overhead for a very small blocks (<64B), but it requires the + * underlying allocator to be effective in allocating page size aligned memory + * as well. The major disadvantage is that each Slab must be aligned to it's + * size as opposed to boundary tags. + * + * Slab implements simple coloring mechanism to improve + * cache line utilisation. + * + * \ref SLAB_SIZE is a fixed size of a slab. As a rule of thumb, the slab is + * effective when the maximum allocated block size is below 1/4 of a SLAB_SIZE. + * f.e. 16kB SLAB is most effective up to 4kB block size. + * + * \ref MEM_POISON flag enables checking read/writes after the allocated memory + * and segmentation fault. This poses a significant time and space overhead. + * Enable only when debugging. + * + * \ref MEM_SLAB_CAP defines a maximum limit of a number of empty slabs that a cache + * can keep at a time. This results in a slight performance regression, + * but actively recycles unuse memory. + * + * \ref MEM_DEPOT_COUNT defines how many recycled slabs will be cached for a later + * use instead of returning them immediately to the OS. This significantly + * reduces a number of syscalls in some cases. + * f.e. 16 means 16 * SLAB_SIZE cache, for 16kB slabs = 256kB cache + * + * \ref MEM_COLORING enables simple cache coloring. This is generally a useful + * feature since all slabs are page size aligned and + * (depending on architecture) this slightly improves performance + * and cacheline usage at the cost of a minimum of 64 bytes per slab of + * overhead. Undefine MEM_COLORING in common.h to disable coloring. + * + * Optimal usage for a specific behavior (similar allocation sizes): + * \code + * slab_cache_t cache; + * slab_cache_init(&cache, N); // Initialize, N means cache chunk size + * ... + * void* mem = slab_cache_alloc(&cache); // Allocate N bytes + * ... + * slab_free(mem); // Recycle memory + * ... + * slab_cache_destroy(&cache); // Deinitialize cache + * \endcode + * + * + * \todo Allocate slab headers elsewhere and use just first sizeof(void*) bytes + * in each slab as a pointer to slab header. This could improve the + * performance. + * + * \note Slab allocation is not thread safe for performance reasons. + * + * \addtogroup alloc + * @{ + */ + +#ifndef _KNOTD_COMMON_SLAB_H_ +#define _KNOTD_COMMON_SLAB_H_ + +#include <pthread.h> +#include <stdint.h> + +/* Constants. */ +#define SLAB_SIZE (4096*4) //!< Slab size (16K blocks) +#define SLAB_MIN_BUFLEN 8 //!< Minimal allocation block size is 8B. +#define SLAB_EXP_OFFSET 3 //!< Minimal allocation size is 8B = 2^3, exp is 3. +#define SLAB_GP_COUNT 10 //!< General-purpose caches count. +#define SLAB_US_COUNT 10 //!< User-specified caches count. +#define SLAB_DEPOT_SIZE 16 //!< N slabs cached = N*SLAB_SIZE kB cap +#define SLAB_CACHE_COUNT (SLAB_GP_COUNT + SLAB_US_COUNT) //!< Slab cache count. +struct slab_cache_t; + +/* Macros. */ + +/*! \brief Return slab base address from pointer. */ +#define slab_from_ptr(p) ((void*)((size_t)(p) & SLAB_MASK)) + +/*! \brief Return true if slab is empty. */ +#define slab_isempty(s) ((s)->bufs_free == (s)->bufs_count) + +/*! + * \brief Slab descriptor. + * + * Slab is a block of memory used for an allocation of + * smaller objects (bufs) later on. + * Each slab is currently aligned to page size to easily + * determine slab address from buf pointer. + * + * \warning Do not use slab_t directly as it cannot grow, see slab_cache_t. + */ +typedef struct slab_t { + char magic; /*!< Identifies memory block type. */ + unsigned short bufsize; /*!< Slab bufsize. */ + struct slab_cache_t *cache; /*!< Owner cache. */ + struct slab_t *prev, *next; /*!< Neighbours in slab lists. */ + unsigned bufs_count; /*!< Number of bufs in slab. */ + unsigned bufs_free; /*!< Number of available bufs. */ + void **head; /*!< Pointer to first available buf. */ + char* base; /*!< Base address for bufs. */ +} slab_t; + +/*! + * \brief Slab depot. + * + * To mitigate slab initialization costs, depot keeps a finite number of + * stacked slabs before returning them to the system. + */ +typedef struct slab_depot_t { + size_t available; /*!< Number of available pages. */ + slab_t* cache[SLAB_DEPOT_SIZE]; /*!< Stack of free slabs. */ +} slab_depot_t; + +/*! + * \brief Large object descriptor. + * + * Large object differs from slab with magic byte and + * contains object size. + * + * Magic needs to be first to overlap with slab_t magic byte. + */ +typedef struct slab_obj_t { + char magic; /*!< Identifies memory block type. */ + size_t size; /*!< Object size. */ +} slab_obj_t; + +/*! + * \brief Slab cache descriptor. + * + * Slab cache is a list of 0..n slabs with the same buf size. + * It is responsible for slab state keeping. + * + * Once a slab is created, it is moved to free list. + * When it is full, it is moved to full list. + * Once a buf from full slab is freed, the slab is moved to + * free list again (there may be some hysteresis for mitigating + * a sequential alloc/free). + * + * Allocation of new slabs is on-demand, empty slabs are reused if possible. + * + * \note Slab implementation is different from Bonwick (Usenix 2001) + * http://www.usenix.org/event/usenix01/bonwick.html + * as it doesn't feature empty and partial list. + * This is due to fact, that user space allocator rarely + * needs to count free slabs. There is no way the OS could + * notify the application, that the memory is scarce. + * A slight performance increased is measured in benchmark. + * + * \note Statistics are only available if MEM_DEBUG is enabled. + */ +typedef struct slab_cache_t { + unsigned short color; /*!< Current cache color. */ + unsigned short empty; /*!< Number of empty slabs. */ + size_t bufsize; /*!< Cache object (buf) size. */ + slab_t *slabs_free; /*!< List of free slabs. */ + slab_t *slabs_full; /*!< List of full slabs. */ + + /* Statistics. */ + unsigned long stat_allocs; /*!< Allocation count. */ + unsigned long stat_frees; /*!< Free count. */ +} slab_cache_t; + +/*! + * \brief Slab allocator descriptor. + * + * \note For a number of slab caches, consult SLAB_GP_COUNT + * and a number of specific records in SLAB_CACHE_LUT lookup table. + * + * \warning It is currently not advised to use this general purpose allocator, + * as it usually doesn't yield an expected performance for higher + * bookkeeping costs and it also depends on the allocation behavior + * as well. Look for slab_cache for a specialized use in most cases. + */ +typedef struct slab_alloc_t { + slab_cache_t descriptors; /*!< Slab cache for cache descriptors. */ + slab_cache_t* caches[SLAB_CACHE_COUNT]; /*!< Number of slab caches. */ +} slab_alloc_t; + +/*! + * \brief Create a slab of predefined size. + * + * At the moment, slabs are equal to page size and page size aligned. + * This enables quick and efficient buf to slab lookup by pointer arithmetic. + * + * Slab uses simple coloring scheme with and the memory block is always + * sizeof(void*) aligned. + * + * \param cache Parent cache. + * \retval Slab instance on success. + * \retval NULL on error. + */ +slab_t* slab_create(slab_cache_t* cache); + +/*! + * \brief Destroy slab instance. + * + * Slab is disconnected from any list and freed. + * Dereferenced slab parameter is set to NULL. + * + * \param slab Pointer to given slab. + */ +void slab_destroy(slab_t** slab); + +/*! + * \brief Allocate a buf from slab. + * + * Returns a pointer to allocated memory or NULL on error. + * + * \param slab Given slab instance. + * \retval Pointer to allocated memory. + * \retval NULL on error. + */ +void* slab_alloc(slab_t* slab); + +/*! + * \brief Recycle memory. + * + * Given memory is returned to owner slab. + * Memory content may be rewritten. + * + * \param ptr Returned memory. + */ +void slab_free(void* ptr); + +/*! + * \brief Create a slab cache. + * + * Create a slab cache with no allocated slabs. + * Slabs are allocated on-demand. + * + * \param cache Pointer to uninitialized cache. + * \param bufsize Single item size for later allocs. + * \retval 0 on success. + * \retval -1 on error; + */ +int slab_cache_init(slab_cache_t* cache, size_t bufsize); + +/*! + * \brief Destroy a slab cache. + * + * Destroy a slab cache and all associated slabs. + * + * \param cache Pointer to slab cache. + */ +void slab_cache_destroy(slab_cache_t* cache); + +/*! + * \brief Allocate from the cache. + * + * It tries to use partially free caches first, + * empty caches second and allocates a new cache + * as a last resort. + * + * \param cache Given slab cache. + * \retval Pointer to allocated memory. + * \retval NULL on error. + */ +void* slab_cache_alloc(slab_cache_t* cache); + +/*! + * \brief Free unused slabs from cache. + * + * \param cache Given slab cache. + * \return Number of freed slabs. + */ +int slab_cache_reap(slab_cache_t* cache); + +/*! + * \brief Create a general purpose slab allocator. + * + * \note Please consult struct slab_alloc_t for performance hints. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int slab_alloc_init(slab_alloc_t* alloc); + +/*! + * \brief Delete slab allocator. + * + * This destroys all associated caches and frees memory. + * + * \param alloc Given allocator instance. + */ +void slab_alloc_destroy(slab_alloc_t* alloc); + +/*! + * \brief Allocate a block of memory. + * + * Returns a block of allocated memory. + * + * \note At least SLAB_MIN_BUFSIZE bytes is allocated. + * + * \note Please consult struct slab_alloc_t for performance hints. + * + * \param alloc Allocator instance. + * \param size Requested block size. + * \retval Pointer to allocated memory. + * \retval NULL on error. + */ +void* slab_alloc_alloc(slab_alloc_t* alloc, size_t size); + +/*! + * \brief Reallocate data from one slab to another. + * + * \param alloc Allocator instance. + * \param ptr Pointer to allocated memory. + * \param size Requested memory block size. + * \retval Pointer to newly allocated memory. + * \retval NULL on error. + * + * \todo Realloc could be probably implement more effectively. + */ +void *slab_alloc_realloc(slab_alloc_t* alloc, void *ptr, size_t size); + +/*! + * + * \brief Dump allocator stats. + * + * \param alloc Allocator instance. + */ +void slab_alloc_stats(slab_alloc_t* alloc); + +#endif /* _KNOTD_COMMON_SLAB_H_ */ + +/*! @} */ diff --git a/src/common/sockaddr.c b/src/common/sockaddr.c new file mode 100644 index 0000000..cd3a4b9 --- /dev/null +++ b/src/common/sockaddr.c @@ -0,0 +1,174 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include "common/sockaddr.h" + +int sockaddr_init(sockaddr_t *addr, int af) +{ + /* Reset pointer. */ + memset(addr, 0, sizeof(sockaddr_t)); + addr->family = -1; + + /* Initialize address size. */ + switch(af) { + case AF_INET: + addr->len = sizeof(struct sockaddr_in); + break; +#ifndef DISABLE_IPV6 + case AF_INET6: + addr->len = sizeof(struct sockaddr_in6); + break; +#endif + default: + return -1; + } + + /* Update pointer. */ + addr->family = af; + return sockaddr_update(addr); +} + +int sockaddr_update(sockaddr_t *addr) +{ + /* Update internal pointer. */ + switch(addr->len) { + case sizeof(struct sockaddr_in): + addr->ptr = (struct sockaddr*)&addr->addr4; + break; +#ifndef DISABLE_IPV6 + case sizeof(struct sockaddr_in6): + addr->ptr = (struct sockaddr*)&addr->addr6; + break; +#endif + default: + return -1; + } + + return 0; +} + +int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port) +{ + if (!dst || !addr || port < 0) { + return -1; + } + + /* Initialize. */ + dst->family = -1; + dst->ptr = 0; + dst->len = 0; + sockaddr_init(dst, family); + + /* Initialize depending on address family. */ + void *paddr = 0; + switch(family) { + case AF_INET: + dst->addr4.sin_family = family; + dst->addr4.sin_port = htons(port); + paddr = &dst->addr4.sin_addr; + dst->addr4.sin_addr.s_addr = INADDR_ANY; + break; +#ifndef DISABLE_IPV6 + case AF_INET6: + dst->addr6.sin6_family = family; + dst->addr6.sin6_port = htons(port); + paddr = &dst->addr6.sin6_addr; + memcpy(&dst->addr6.sin6_addr, + &in6addr_any, sizeof(in6addr_any)); + break; +#endif + default: + return -1; + } + + /* Convert address. */ + return inet_pton(family, addr, paddr); +} + +int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size) +{ + if (!addr || !dst || size == 0) { + return -1; + } + + /* Minimum length. */ + size_t minlen = INET_ADDRSTRLEN; + + /* Check unsupported IPv6. */ +#ifdef DISABLE_IPV6 + if (addr->family == AF_INET6) { + return -1; + } +#else + minlen = INET6_ADDRSTRLEN; +#endif + + /* Check minimum length. */ + if (size < minlen) { + return -1; + } + + /* Convert. */ +#ifdef DISABLE_IPV6 + dst[0] = '\0'; +#else + /* Load IPv6 addr if default. */ + if (addr->family == AF_INET6) { + inet_ntop(addr->family, &addr->addr6.sin6_addr, + dst, size); + } +#endif + /* Load IPv4 if set. */ + if (addr->family == AF_INET) { + inet_ntop(addr->family, &addr->addr4.sin_addr, + dst, size); + } + + return 0; +} + +int sockaddr_portnum(sockaddr_t *addr) +{ + if (!addr) { + return -1; + } + + switch(addr->family) { + + /* IPv4 */ + case AF_INET: + return ntohs(addr->addr4.sin_port); + break; + + /* IPv6 */ +#ifndef DISABLE_IPV6 + case AF_INET6: + return ntohs(addr->addr6.sin6_port); + break; +#endif + + /* N/A */ + default: + return -1; + break; + } +} diff --git a/src/common/sockaddr.h b/src/common/sockaddr.h new file mode 100644 index 0000000..51ba779 --- /dev/null +++ b/src/common/sockaddr.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file sockaddr.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Socket address abstraction layer. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_SOCKADDR_H_ +#define _KNOTD_SOCKADDR_H_ + +/* BSD IPv6 */ +#ifndef __POSIX_VISIBLE +#define __POSIX_VISIBLE = 200112 +#endif + +#include <netinet/in.h> +#include <arpa/inet.h> + +/*! \brief Universal socket address. */ +typedef struct sockaddr_t { + int family; /*!< Address family. */ + struct sockaddr* ptr; /*!< Pointer to used sockaddr. */ + socklen_t len; /*!< Length of used sockaddr. */ + union { + struct sockaddr_in addr4; /*!< IPv4 sockaddr. */ +#ifndef DISABLE_IPV6 + struct sockaddr_in6 addr6; /*!< IPv6 sockaddr. */ +#endif + }; +} sockaddr_t; + +/*! \brief Maximum address length in string format. */ +#ifdef DISABLE_IPV6 +#define SOCKADDR_STRLEN INET_ADDRSTRLEN +#else +#define SOCKADDR_STRLEN INET6_ADDRSTRLEN +#endif + +/*! + * \brief Initialize address structure. + * + * Members ptr and len will be initialized to correct address family. + * + * \param addr Socket address structure. + * \param af Requested address family. + * + * \retval 0 on success. + * \retval -1 on unsupported address family (probably INET6). + */ +int sockaddr_init(sockaddr_t *addr, int af); + +/*! + * \brief Update internal pointers according to length. + * + * \param addr Socket address structure. + * + * \retval 0 on success. + * \retval -1 on invalid size. + */ +int sockaddr_update(sockaddr_t *addr); + +/*! + * \brief Set address and port. + * + * \param dst Target address structure. + * \param family Address family. + * \param addr IP address in string format. + * \param port Port. + * + * \retval 0 if addr is not valid address in string format. + * \retval positive value in case of success. + * \retval -1 on error. + * \see inet_pton(3) + */ +int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port); + +/*! + * \brief Return string representation of socket address. + * + * \param addr Socket address structure. + * \param dst Destination for string representation. + * \param size Maximum number of written bytes. + * + * \retval 0 on success. + * \retval -1 on invalid parameters. + */ +int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size); + +/*! + * \brief Return port number from address. + * + * \param addr Socket address structure. + * + * \retval Port number on success. + * \retval -1 on errors. + */ +int sockaddr_portnum(sockaddr_t *addr); + +#endif /* _KNOTD_SOCKADDR_H_ */ + +/*! @} */ diff --git a/src/common/tree.h b/src/common/tree.h new file mode 100644 index 0000000..efea65b --- /dev/null +++ b/src/common/tree.h @@ -0,0 +1,268 @@ +/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h') -*- C -*- */ + +/* Copyright (c) 2005 Ian Piumarta + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the 'Software'), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * provided that the above copyright notice(s) and this permission notice appear + * in all copies of the Software and that both the above copyright notice(s) and + * this permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. + */ + +/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and + * Evgenii M. Landis, 'An algorithm for the organization of information', + * Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian). Also in Myron + * J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)]. + * + * An AVL tree is headed by pointers to the root node and to a function defining + * the ordering relation between nodes. Each node contains an arbitrary payload + * plus three fields per tree entry: the depth of the subtree for which it forms + * the root and two pointers to child nodes (singly-linked for minimum space, at + * the expense of direct access to the parent node given a pointer to one of the + * children). The tree is rebalanced after every insertion or removal. The + * tree may be traversed in two directions: forward (in-order left-to-right) and + * reverse (in-order, right-to-left). + * + * Because of the recursive nature of many of the operations on trees it is + * necessary to define a number of helper functions for each type of tree node. + * The macro TREE_DEFINE(node_tag, entry_name) defines these functions with + * unique names according to the node_tag. This macro should be invoked, + * thereby defining the necessary functions, once per node tag in the program. + * + * For details on the use of these macros, see the tree(3) manual page. + */ + +/* Downloaded from http://piumarta.com/software/tree/ */ + +#ifndef __tree_h +#define __tree_h + + +#define TREE_DELTA_MAX 1 + +#define TREE_ENTRY(type) \ + struct { \ + struct type *avl_left; \ + struct type *avl_right; \ + int avl_height; \ + } + +#define TREE_HEAD(name, type) \ + struct name { \ + struct type *th_root; \ + int (*th_cmp)(struct type *lhs, struct type *rhs); \ + } + +#define TREE_INITIALIZER(cmp) { 0, cmp } + +#define TREE_DELTA(self, field) \ + (( (((self)->field.avl_left) ? (self)->field.avl_left->field.avl_height : 0)) \ + - (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0)) + +/* Recursion prevents the following from being defined as macros. */ + +#define TREE_DEFINE(node, field) \ + \ + struct node *TREE_BALANCE_##node##_##field(struct node *); \ + \ + struct node *TREE_ROTL_##node##_##field(struct node *self) \ + { \ + struct node *r= self->field.avl_right; \ + self->field.avl_right= r->field.avl_left; \ + r->field.avl_left= TREE_BALANCE_##node##_##field(self); \ + return TREE_BALANCE_##node##_##field(r); \ + } \ + \ + struct node *TREE_ROTR_##node##_##field(struct node *self) \ + { \ + struct node *l= self->field.avl_left; \ + self->field.avl_left= l->field.avl_right; \ + l->field.avl_right= TREE_BALANCE_##node##_##field(self); \ + return TREE_BALANCE_##node##_##field(l); \ + } \ + \ + struct node *TREE_BALANCE_##node##_##field(struct node *self) \ + { \ + int delta= TREE_DELTA(self, field); \ + \ + if (delta < -TREE_DELTA_MAX) \ + { \ + if (TREE_DELTA(self->field.avl_right, field) > 0) \ + self->field.avl_right= TREE_ROTR_##node##_##field(self->field.avl_right); \ + return TREE_ROTL_##node##_##field(self); \ + } \ + else if (delta > TREE_DELTA_MAX) \ + { \ + if (TREE_DELTA(self->field.avl_left, field) < 0) \ + self->field.avl_left= TREE_ROTL_##node##_##field(self->field.avl_left); \ + return TREE_ROTR_##node##_##field(self); \ + } \ + self->field.avl_height= 0; \ + if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height)) \ + self->field.avl_height= self->field.avl_left->field.avl_height; \ + if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height)) \ + self->field.avl_height= self->field.avl_right->field.avl_height; \ + self->field.avl_height += 1; \ + return self; \ + } \ + \ + struct node *TREE_INSERT_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \ + { \ + if (!self) \ + return elm; \ + if (compare(elm, self) < 0) \ + self->field.avl_left= TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare); \ + else \ + self->field.avl_right= TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare); \ + return TREE_BALANCE_##node##_##field(self); \ + } \ + \ + struct node *TREE_FIND_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \ + { \ + if (!self) \ + return 0; \ + if (compare(elm, self) == 0) \ + return self; \ + if (compare(elm, self) < 0) \ + return TREE_FIND_##node##_##field(self->field.avl_left, elm, compare); \ + else \ + return TREE_FIND_##node##_##field(self->field.avl_right, elm, compare); \ + } \ + \ + int TREE_FIND_LESS_EQUAL_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs), struct node **found, struct node **prev) \ + { \ + if (!self) \ + return 0; \ + if (compare(elm, self) == 0) { \ + *found = self; \ + return 1; \ + } \ + if (compare(elm, self) < 0) { \ + int ret = TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_left, elm, compare, found, prev); \ + if (ret == 0 && *prev == NULL) { \ + *prev = self; \ + ret = -1; \ + } \ + return ret; \ + } else { \ + *found = self; \ + *prev = self; \ + return TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_right, elm, compare, found, prev); \ + } \ + } \ + \ + struct node *TREE_MOVE_RIGHT_##node##_##field(struct node *self, struct node *rhs) \ + { \ + if (!self) \ + return rhs; \ + self->field.avl_right= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_right, rhs); \ + return TREE_BALANCE_##node##_##field(self); \ + } \ + \ + struct node *TREE_REMOVE_##node##_##field \ + (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \ + { \ + if (!self) return 0; \ + \ + if (compare(elm, self) == 0) \ + { \ + struct node *tmp= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_left, self->field.avl_right); \ + self->field.avl_left= 0; \ + self->field.avl_right= 0; \ + return tmp; \ + } \ + if (compare(elm, self) < 0) \ + self->field.avl_left= TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare); \ + else \ + self->field.avl_right= TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare); \ + return TREE_BALANCE_##node##_##field(self); \ + } \ + \ + void TREE_FORWARD_APPLY_ALL_##node##_##field \ + (struct node *self, void (*function)(struct node *node, void *data), void *data) \ + { \ + if (self) \ + { \ + TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \ + function(self, data); \ + TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \ + } \ + } \ + \ + void TREE_REVERSE_APPLY_ALL_##node##_##field \ + (struct node *self, void (*function)(struct node *node, void *data), void *data) \ + { \ + if (self) \ + { \ + TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \ + function(self, data); \ + TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \ + } \ + } \ + \ + void TREE_POST_ORDER_APPLY_ALL_##node##_##field \ + (struct node *self, void (*function)(struct node *node, void *data), void *data) \ + { \ + if (self) \ + { \ + TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \ + TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \ + function(self, data); \ + } \ + } \ + \ + void TREE_REVERSE_APPLY_POST_ALL_##node##_##field \ + (struct node *self, void (*function)(struct node *node, void *data), void *data) \ + { \ + if (self) \ + { \ + TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_right, function, data); \ + TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_left, function, data); \ + function(self, data); \ + } \ +} + +#define TREE_INSERT(head, node, field, elm) \ + ((head)->th_root= TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp)) + +#define TREE_FIND(head, node, field, elm) \ + (TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp)) + +#define TREE_FIND_LESS_EQUAL(head, node, field, elm, found, prev) \ + (TREE_FIND_LESS_EQUAL_##node##_##field((head)->th_root, (elm), (head)->th_cmp, found, prev)) + +#define TREE_REMOVE(head, node, field, elm) \ + ((head)->th_root= TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp)) + +#define TREE_DEPTH(head, field) \ + ((head)->th_root->field.avl_height) + +#define TREE_FORWARD_APPLY(head, node, field, function, data) \ + TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data) + +#define TREE_REVERSE_APPLY(head, node, field, function, data) \ + TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data) + +#define TREE_POST_ORDER_APPLY(head, node, field, function, data) \ + TREE_POST_ORDER_APPLY_ALL_##node##_##field((head)->th_root, function, data) + +#define TREE_REVERSE_APPLY_POST(head, node, field, function, data) \ + TREE_REVERSE_APPLY_POST_ALL_##node##_##field((head)->th_root, function, data) + +#define TREE_INIT(head, cmp) do { \ + (head)->th_root= 0; \ + (head)->th_cmp= (cmp); \ + } while (0) + + +#endif /* __tree_h */ diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..521adb8 --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,307 @@ +/* src/config.h.in. Generated from configure.ac by autoheader. */ + +/* Enable brief debugging messages. */ +#undef DEBUG_ENABLE_BRIEF + +/* Enable details debugging messages. */ +#undef DEBUG_ENABLE_DETAILS + +/* Enable verbose debugging messages. */ +#undef DEBUG_ENABLE_VERBOSE + +/* recvmmsg enabled */ +#undef ENABLE_RECVMMSG + +/* Define to 1 if you have the <arpa/inet.h> header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the <arpa/nameser.h> header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the `epoll_wait' function. */ +#undef HAVE_EPOLL_WAIT + +/* Define to 1 if you have the <ev.h> header file. */ +#undef HAVE_EV_H + +/* Define to 1 if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `kqueue' function. */ +#undef HAVE_KQUEUE + +/* ldns present */ +#undef HAVE_LDNS + +/* Define to 1 if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the <malloc.h> header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Support mmx instructions */ +#undef HAVE_MMX + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the <netdb.h> header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + +/* Define to 1 if you have the `regcomp' function. */ +#undef HAVE_REGCOMP + +/* Define to 1 if you have the <resolv.h> header file. */ +#undef HAVE_RESOLV_H + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the `sqrt' function. */ +#undef HAVE_SQRT + +/* Support SSE (Streaming SIMD Extensions) instructions */ +#undef HAVE_SSE + +/* Support SSE2 (Streaming SIMD Extensions 2) instructions */ +#undef HAVE_SSE2 + +/* Support SSE3 (Streaming SIMD Extensions 3) instructions */ +#undef HAVE_SSE3 + +/* Support SSSE3 (Supplemental Streaming SIMD Extensions 3) instructions */ +#undef HAVE_SSSE3 + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if you have the <syslog.h> header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the <urcu.h> header file. */ +#undef HAVE_URCU_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the <vfork.h> header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE + +/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>, + <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>, + <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT64_T + +/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>, + <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef int64_t + +/* Define to `int' if <sys/types.h> does not define. */ +#undef pid_t + +/* Define to `unsigned int' if <sys/types.h> does not define. */ +#undef size_t + +/* Define to `int' if <sys/types.h> does not define. */ +#undef ssize_t + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef uint16_t + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef uint64_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/src/knot/common.h b/src/knot/common.h new file mode 100644 index 0000000..e9cfce1 --- /dev/null +++ b/src/knot/common.h @@ -0,0 +1,133 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file common.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Common macros, includes and utilities. + * + * \addtogroup utils + * @{ + */ + +#ifndef _KNOTD_COMMON_H_ +#define _KNOTD_COMMON_H_ + +#include <signal.h> +#include <stdint.h> +#include <config.h> + +/* + * Common types and constants. + */ + +#ifndef UINT_DEFINED +typedef unsigned int uint; /*!< \brief Unsigned. */ +#define UINT_DEFINED +#endif + +#define PROJECT_EXEC SBINDIR "/" "knotd" /*!< \brief Project executable. */ +#define ZONEPARSER_EXEC LIBEXECDIR "/" "knot-zcompile" /*!< \brief Zoneparser executable. */ +#define PID_FILE "knot.pid" /*!< \brief Server PID file name. */ + +/* + * Server. + */ + +#define CPU_ESTIMATE_MAGIC 0 /*!< \brief Extra threads to the number of cores.*/ +#define DEFAULT_THR_COUNT 2 /*!< \brief Default thread count. */ +#define DEFAULT_PORT 53531 /*!< \brief Default interface port. */ +#define TCP_BACKLOG_SIZE 5 /*!< \brief TCP listen backlog size. */ +#define XFR_THREADS_COUNT 3 /*!< \brief Number of threads for XFR handler. */ +#define RECVMMSG_BATCHLEN 32 /*!< \brief Define for recvmmsg() batch size. */ + +///*! \brief If defined, zone structures will use hash table for lookup. */ +//#define COMPRESSION_PEDANTIC + +///*! +// * \brief If defined, tests will use ldns library to parse sample data. +// * +// * If not defined, some tests will be disabled. +// */ +//#define TEST_WITH_LDNS + +///*! \brief If defined, the statistics module will be enabled. */ +//#define STAT_COMPILE + + +#ifdef HAVE_LDNS +#define TEST_WITH_LDNS +#endif + +/* + * Common includes. + */ + +#include "common/latency.h" +#include "common/print.h" +#include "knot/other/log.h" +#include "knot/other/debug.h" + +/*! \brief Eliminate compiler warning with unused parameters. */ +#define UNUSED(param) (void)(param) + +/*! \brief Type-safe minimum macro. */ +#define MIN(a, b) \ + ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; }) + +/*! \brief Type-safe maximum macro. */ +#define MAX(a, b) \ + ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) + +/* Optimisation macros. */ +#ifndef likely +/*! \brief Optimize for x to be true value. */ +#define likely(x) __builtin_expect((x),1) +#endif +#ifndef unlikely +/*! \brief Optimize for x to be false value. */ +#define unlikely(x) __builtin_expect((x),0) +#endif + +/*! \todo Refactor theese. We should have an allocator function handling this.*/ +#ifndef ERR_ALLOC_FAILED +#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d (%s)\n", \ + __FILE__, __LINE__, PACKAGE_STRING) +#endif + +#ifndef CHECK_ALLOC_LOG +#define CHECK_ALLOC_LOG(var, ret) \ + do { \ + if ((var) == NULL) { \ + ERR_ALLOC_FAILED; \ + return (ret); \ + } \ + } while (0) +#endif + +#ifndef CHECK_ALLOC +#define CHECK_ALLOC(var, ret) \ + do { \ + if ((var) == NULL) { \ + return (ret); \ + } \ + } while (0) +#endif + +#endif /* _KNOTD_COMMON_H_ */ + +/*! @} */ diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l new file mode 100644 index 0000000..97ac8f8 --- /dev/null +++ b/src/knot/conf/cf-lex.l @@ -0,0 +1,218 @@ +/*! + * \file cf-lex.l + * + * \author Ondrej Sury <ondrej.sury@nic.cz> + * + * \brief Server configuration structures and API. + * + * IP address conversions from BIRD, (c) 1998--2000 Martin Mares <mj@ucw.cz> + */ +%{ + +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "common/sockaddr.h" +#include "knot/conf/conf.h" +#include "knot/other/log.h" +#include "libknotd_la-cf-parse.h" /* Automake generated header. */ + +/* Imported symbols. */ +#define lval (yylval->tok) +extern void cf_error(void *scanner, const char *msg); +extern int (*cf_read_hook)(char *buf, size_t nbytes); +void switch_input(const char *str, void *scanner) +{ + yy_scan_string(str, scanner); +} + +//#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max); +#define YY_NO_UNPUT + +%} + +%option reentrant +%option bison-bridge +%option noyywrap +%option noinput +%option nounput +%option noreject +%option yylineno +%option prefix = "cf_" +%option outfile = "lex.yy.c" + +ALPHA [a-zA-Z_] +DIGIT [0-9] +HEXA [0-9a-fA-F] +ALNUM [a-zA-Z_0-9] +BLANK [ \t\n] + +%% +\#.*\n /* Ignore comments */; +{BLANK}+ /* Ignore whitespace */; +: /* Optional : in assignments. */; +[\!\$\%\^\&\*\(\)\/\+\-\@\{\}\;\,] { return yytext[0]; } +system { lval.t = yytext; return SYSTEM; } +identity { lval.t = yytext; return IDENTITY; } +version { lval.t = yytext; return VERSION; } +storage { lval.t = yytext; return STORAGE; } +key { lval.t = yytext; return KEY; } +keys { lval.t = yytext; return KEYS; } +remotes { lval.t = yytext; return REMOTES; } + +zones { lval.t = yytext; return ZONES; } +file { lval.t = yytext; return FILENAME; } +semantic-checks { lval.t = yytext; return SEMANTIC_CHECKS; } +notify-retries { lval.t = yytext; return NOTIFY_RETRIES; } +notify-timeout { lval.t = yytext; return NOTIFY_TIMEOUT; } +zonefile-sync { lval.t = yytext; return DBSYNC_TIMEOUT; } +ixfr-fslimit { lval.t = yytext; return IXFR_FSLIMIT; } +xfr-in { lval.t = yytext; return XFR_IN; } +xfr-out { lval.t = yytext; return XFR_OUT; } +notify-in { lval.t = yytext; return NOTIFY_IN; } +notify-out { lval.t = yytext; return NOTIFY_OUT; } +workers { lval.t = yytext; return WORKERS; } + +interfaces { lval.t = yytext; return INTERFACES; } +address { lval.t = yytext; return ADDRESS; } +port { lval.t = yytext; return PORT; } + +log { lval.t = yytext; return LOG; } + +any { lval.t = yytext; lval.i = LOG_ANY; return LOG_SRC; } +server { lval.t = yytext; lval.i = LOG_SERVER; return LOG_SRC; } +answering { lval.t = yytext; lval.i = LOG_ANSWER; return LOG_SRC; } +zone { lval.t = yytext; lval.i = LOG_ZONE; return LOG_SRC; } +stdout { lval.t = yytext; lval.i = LOGT_STDOUT; return LOG_DEST; } +stderr { lval.t = yytext; lval.i = LOGT_STDERR; return LOG_DEST; } +syslog { lval.t = yytext; lval.i = LOGT_SYSLOG; return LOG_DEST; } +all { lval.t = yytext; lval.i = LOG_UPTO(LOG_DEBUG); return LOG_LEVEL; } +debug { lval.t = yytext; lval.i = LOG_MASK(LOG_DEBUG); return LOG_LEVEL; } +info { lval.t = yytext; lval.i = LOG_MASK(LOG_INFO); return LOG_LEVEL; } +notice { lval.t = yytext; lval.i = LOG_MASK(LOG_NOTICE); return LOG_LEVEL; } +warning { lval.t = yytext; lval.i = LOG_MASK(LOG_WARNING); return LOG_LEVEL; } +error { lval.t = yytext; lval.i = LOG_MASK(LOG_ERR); return LOG_LEVEL; } + +on|off { + lval.t = yytext; + lval.i = 0; + if (strcmp(yytext, "on") == 0) { + lval.i = 1; + } + return BOOL; +} + +{DIGIT}+[smhd] { + size_t mpos = strlen(yytext) - 1; + char multiplier = yytext[mpos]; + yytext[mpos] = '\0'; + lval.i = atoi(yytext); + if (lval.i < 1) { + cf_error(yyscanner, "interval must be a positive integer"); + return END; + } + + /* Handle multiplier. */ + switch(multiplier) { + case 'm': lval.i *= 60; break; /* minutes */ + case 'h': lval.i *= 60*60; break; /* hours */ + case 'd': lval.i *= 24*60*60; break; /* days */ + case 's': /* seconds */ + default: break; + } + + return INTERVAL; +} + +{DIGIT}+[kMG] { + size_t mpos = strlen(yytext) - 1; + char multiplier = yytext[mpos]; + yytext[mpos] = '\0'; + lval.i = atol(yytext); + if (lval.i < 1) { + cf_error(yyscanner, "size must be a positive integer"); + return END; + } + + /* Handle multiplier. */ + switch(multiplier) { + case 'k': lval.l = lval.i * 1024; break; /* kB */ + case 'M': lval.l = lval.i * 1024*1024; break; /* MB */ + case 'G': lval.l = lval.i * 1024*1024*1024; break; /* GB */ + default: break; + } + + return SIZE; +} + +{DIGIT}+ { + lval.i = atol(yytext); + return NUM; +} + +{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ { + unsigned char buf[sizeof(struct in_addr)]; + if (inet_pton(AF_INET, yytext, buf)) { + lval.t = strdup(yytext); + return IPA; + } + cf_error(yyscanner, "Invalid IP address."); +} + +\[({HEXA}*::|({HEXA}*:){3,})({HEXA}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+)\] { +#ifdef DISABLE_IPV6 + lval.t = strdup(yytext); + cf_error(yyscanner, "IPv6 address support not compiled."); + return TEXT; +#else + unsigned char buf[sizeof(struct in6_addr)]; + yytext[strlen(yytext)-1] = '\0'; + if (inet_pton(AF_INET6, yytext+1, buf)) { + lval.t = strdup(yytext+1); + return IPA6; + } + cf_error(yyscanner, "Invalid IPv6 address."); +#endif + } + +({HEXA}*::|({HEXA}*:){3,})({HEXA}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) { +#ifdef DISABLE_IPV6 + lval.t = strdup(yytext); + cf_error(yyscanner, "IPv6 address support not compiled."); + return TEXT; +#else + unsigned char buf[sizeof(struct in6_addr)]; + if (inet_pton(AF_INET6, yytext, buf)) { + lval.t = strdup(yytext); + return IPA6; + } + cf_error(yyscanner, "Invalid IPv6 address."); +#endif +} + +gss-tsig { lval.alg = KNOT_TSIG_ALG_GSS_TSIG; return TSIG_ALGO_NAME; } +hmac-md5 { lval.alg = KNOT_TSIG_ALG_HMAC_MD5; return TSIG_ALGO_NAME; } +hmac-sha1 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA1; return TSIG_ALGO_NAME; } +hmac-sha224 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA224; return TSIG_ALGO_NAME; } +hmac-sha256 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA256; return TSIG_ALGO_NAME; } +hmac-sha384 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA384; return TSIG_ALGO_NAME; } +hmac-sha512 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA512; return TSIG_ALGO_NAME; } + +["][^"\n]*["] { + yytext[yyleng-1] = 0; + lval.t = strdup(yytext + 1); + return TEXT; +} + +["][^"\n]*\n cf_error(yyscanner, "Unterminated string."); + +[a-zA-Z0-9\.\-\_]+ { + lval.t = strdup(yytext); + return TEXT /* Last resort, alphanumeric word. */; +} + +<<EOF>> return END; + +%% + diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y new file mode 100644 index 0000000..d793865 --- /dev/null +++ b/src/knot/conf/cf-parse.y @@ -0,0 +1,646 @@ +/*! + * \file cf-parse.y + * + * \author Ondrej Sury <ondrej.sury@nic.cz> + * + * \brief Server configuration structures and API. + */ +%{ +/* Headers */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "libknot/dname.h" +#include "knot/conf/conf.h" +#include "libknotd_la-cf-parse.h" /* Automake generated header. */ + +extern int cf_lex (YYSTYPE *lvalp, void *scanner); +extern void cf_error(void *scanner, const char *msg); +extern conf_t *new_config; +static conf_iface_t *this_iface = 0; +static conf_iface_t *this_remote = 0; +static conf_zone_t *this_zone = 0; +static list *this_list = 0; +static conf_log_t *this_log = 0; +static conf_log_map_t *this_logmap = 0; +//#define YYERROR_VERBOSE 1 + +static void conf_start_iface(char* ifname) +{ + this_iface = malloc(sizeof(conf_iface_t)); + memset(this_iface, 0, sizeof(conf_iface_t)); + this_iface->name = ifname; + this_iface->address = 0; // No default address (mandatory) + this_iface->port = CONFIG_DEFAULT_PORT; + add_tail(&new_config->ifaces, &this_iface->n); + ++new_config->ifaces_count; +} + +static void conf_start_remote(char *remote) +{ + this_remote = malloc(sizeof(conf_iface_t)); + memset(this_remote, 0, sizeof(conf_iface_t)); + this_remote->name = remote; + this_remote->address = 0; // No default address (mandatory) + this_remote->port = 0; // Port wildcard + add_tail(&new_config->remotes, &this_remote->n); + ++new_config->remotes_count; +} + +static void conf_acl_item(void *scanner, char *item) +{ + /* Find existing node in remotes. */ + node* r = 0; conf_iface_t* found = 0; + WALK_LIST (r, new_config->remotes) { + if (strcmp(((conf_iface_t*)r)->name, item) == 0) { + found = (conf_iface_t*)r; + break; + } + } + + /* Append to list if found. */ + if (!found) { + char buf[512]; + snprintf(buf, sizeof(buf), "remote '%s' is not defined", item); + cf_error(scanner, buf); + } else { + /* check port if xfrin/notify-out */ + if (this_list == &this_zone->acl.xfr_in || + this_list == &this_zone->acl.notify_out) { + if (found->port == 0) { + cf_error(scanner, "remote specified for XFR/IN or NOTIFY/OUT " + " needs to have valid port!"); + free(item); + return; + } + } + conf_remote_t *remote = malloc(sizeof(conf_remote_t)); + if (!remote) { + cf_error(scanner, "out of memory"); + } else { + remote->remote = found; + add_tail(this_list, &remote->n); + } + } + + /* Free text token. */ + free(item); + } + +static int conf_key_exists(void *scanner, char *item) +{ + /* Find existing node in keys. */ + knot_dname_t *sample = knot_dname_new_from_str(item, strlen(item), 0); + char buf[512]; + conf_key_t* r = 0; + WALK_LIST (r, new_config->keys) { + if (knot_dname_compare(r->k.name, sample) == 0) { + snprintf(buf, sizeof(buf), "key '%s' is already defined", item); + cf_error(scanner, buf); + knot_dname_free(&sample); + return 1; + } + } + + knot_dname_free(&sample); + return 0; +} + +static int conf_key_add(void *scanner, knot_key_t **key, char *item) +{ + /* Reset */ + *key = 0; + + /* Find in keys */ + knot_dname_t *sample = knot_dname_new_from_str(item, strlen(item), 0); + + conf_key_t* r = 0; + WALK_LIST (r, new_config->keys) { + if (knot_dname_compare(r->k.name, sample) == 0) { + *key = &r->k; + knot_dname_free(&sample); + return 0; + } + } + + char buf[512]; + snprintf(buf, sizeof(buf), "key '%s' is not defined", item); + cf_error(scanner, buf); + knot_dname_free(&sample); + return 1; +} + +%} + +%pure-parser +%parse-param{void *scanner} +%lex-param{void *scanner} +%name-prefix = "cf_" + +%union { + struct { + char *t; + long i; + size_t l; + tsig_algorithm_t alg; + } tok; +} + +%token END INVALID_TOKEN +%token <tok> TEXT +%token <tok> NUM +%token <tok> INTERVAL +%token <tok> SIZE +%token <tok> BOOL + +%token <tok> SYSTEM IDENTITY VERSION STORAGE KEY KEYS +%token <tok> TSIG_ALGO_NAME +%token <tok> WORKERS + +%token <tok> REMOTES + +%token <tok> ZONES FILENAME +%token <tok> SEMANTIC_CHECKS +%token <tok> NOTIFY_RETRIES +%token <tok> NOTIFY_TIMEOUT +%token <tok> DBSYNC_TIMEOUT +%token <tok> IXFR_FSLIMIT +%token <tok> XFR_IN +%token <tok> XFR_OUT +%token <tok> NOTIFY_IN +%token <tok> NOTIFY_OUT + +%token <tok> INTERFACES ADDRESS PORT +%token <tok> IPA +%token <tok> IPA6 + +%token <tok> LOG +%token <tok> LOG_DEST +%token <tok> LOG_SRC +%token <tok> LOG_LEVEL + +%% + +config: conf_entries END { return 0; } ; + +conf_entries: + /* EMPTY */ + | conf_entries conf + ; + +interface_start: + | TEXT { conf_start_iface($1.t); } + | REMOTES { conf_start_iface(strdup($1.t)); } /* Allow strings reserved by token. */ + | LOG_SRC { conf_start_iface(strdup($1.t)); } + | LOG { conf_start_iface(strdup($1.t)); } + | LOG_LEVEL { conf_start_iface(strdup($1.t)); } + ; + +interface: + interface_start '{' + | interface PORT NUM ';' { + if (this_iface->port != CONFIG_DEFAULT_PORT) { + cf_error(scanner, "only one port definition is allowed in interface section\n"); + } else { + this_iface->port = $3.i; + } + } + | interface ADDRESS IPA ';' { + if (this_iface->address != 0) { + cf_error(scanner, "only one address is allowed in interface section\n"); + } else { + this_iface->address = $3.t; + this_iface->family = AF_INET; + } + } + | interface ADDRESS IPA '@' NUM ';' { + if (this_iface->address != 0) { + cf_error(scanner, "only one address is allowed in interface section\n"); + } else { + this_iface->address = $3.t; + this_iface->family = AF_INET; + if (this_iface->port != CONFIG_DEFAULT_PORT) { + cf_error(scanner, "only one port definition is allowed in interface section\n"); + } else { + this_iface->port = $5.i; + } + } + } + | interface ADDRESS IPA6 ';' { + if (this_iface->address != 0) { + cf_error(scanner, "only one address is allowed in interface section\n"); + } else { + this_iface->address = $3.t; + this_iface->family = AF_INET6; + } + } + | interface ADDRESS IPA6 '@' NUM ';' { + if (this_iface->address != 0) { + cf_error(scanner, "only one address is allowed in interface section\n"); + } else { + this_iface->address = $3.t; + this_iface->family = AF_INET6; + if (this_iface->port != CONFIG_DEFAULT_PORT) { + cf_error(scanner, "only one port definition is allowed in interface section\n"); + } else { + this_iface->port = $5.i; + } + } + } + ; + +interfaces: + INTERFACES '{' + | interfaces interface '}' { + if (this_iface->address == 0) { + char buf[512]; + snprintf(buf, sizeof(buf), "interface '%s' has no defined address", this_iface->name); + cf_error(scanner, buf); + } + } + ; + +system: + SYSTEM '{' + | system VERSION TEXT ';' { new_config->version = $3.t; } + | system IDENTITY TEXT ';' { new_config->identity = $3.t; } + | system STORAGE TEXT ';' { new_config->storage = $3.t; } + | system KEY TSIG_ALGO_NAME TEXT ';' { + fprintf(stderr, "warning: Config option 'system.key' is deprecated " + "and has no effect.\n"); + free($4.t); + } + | system WORKERS NUM ';' { + if ($3.i <= 0) { + cf_error(scanner, "worker count must be greater than 0\n"); + } else { + new_config->workers = $3.i; + } + } + ; + +keys: + KEYS '{' + | keys TEXT TSIG_ALGO_NAME TEXT ';' { + /* Normalize to FQDN */ + char *fqdn = $2.t; + if (fqdn[strlen(fqdn) - 1] != '.') { + char* tmp = malloc(strlen(fqdn) + 1 + 1); /* '.', '\0' */ + if (!tmp) { + cf_error(scanner, "out of memory when allocating string"); + free(fqdn); + fqdn = 0; + } else { + strcpy(tmp, fqdn); + strcat(tmp, "."); + free(fqdn); + fqdn = tmp; + } + } + + if (!conf_key_exists(scanner, fqdn)) { + knot_dname_t *dname = knot_dname_new_from_str(fqdn, strlen(fqdn), 0); + if (!dname) { + char buf[512]; + snprintf(buf, sizeof(buf), "key name '%s' not in valid domain " + "name format", fqdn); + cf_error(scanner, buf); + free(fqdn); + free($4.t); + } else { + conf_key_t *k = malloc(sizeof(conf_key_t)); + memset(k, 0, sizeof(conf_key_t)); + k->k.name = dname; + k->k.algorithm = $3.alg; + k->k.secret = $4.t; + add_tail(&new_config->keys, &k->n); + ++new_config->key_count; + free(fqdn); + } + } else { + free(fqdn); + free($4.t); + } +} + +remote_start: + | TEXT { conf_start_remote($1.t); } + | LOG_SRC { conf_start_remote(strdup($1.t)); } + | LOG { conf_start_remote(strdup($1.t)); } + | LOG_LEVEL { conf_start_remote(strdup($1.t)); } + ; + +remote: + remote_start '{' + | remote PORT NUM ';' { + if (this_remote->port != 0) { + cf_error(scanner, "only one port definition is allowed in remote section\n"); + } else { + this_remote->port = $3.i; + } + } + | remote ADDRESS IPA ';' { + if (this_remote->address != 0) { + cf_error(scanner, "only one address is allowed in remote section\n"); + } else { + this_remote->address = $3.t; + this_remote->family = AF_INET; + } + } + | remote ADDRESS IPA '@' NUM ';' { + if (this_remote->address != 0) { + cf_error(scanner, "only one address is allowed in remote section\n"); + } else { + this_remote->address = $3.t; + this_remote->family = AF_INET; + if (this_remote->port != 0) { + cf_error(scanner, "only one port definition is allowed in remote section\n"); + } else { + this_remote->port = $5.i; + } + } + } + | remote ADDRESS IPA6 ';' { + if (this_remote->address != 0) { + cf_error(scanner, "only one address is allowed in remote section\n"); + } else { + this_remote->address = $3.t; + this_remote->family = AF_INET6; + } + } + | remote ADDRESS IPA6 '@' NUM ';' { + if (this_remote->address != 0) { + cf_error(scanner, "only one address is allowed in remote section\n"); + } else { + this_remote->address = $3.t; + this_remote->family = AF_INET6; + if (this_remote->port != 0) { + cf_error(scanner, "only one port definition is allowed in remote section\n"); + } else { + this_remote->port = $5.i; + } + } + } + | remote KEY TEXT ';' { + if (this_remote->key != 0) { + cf_error(scanner, "only one TSIG key definition is allowed in remote section\n"); + } else { + conf_key_add(scanner, &this_remote->key, $3.t); + } + } + ; + +remotes: + REMOTES '{' + | remotes remote '}' { + if (this_remote->address == 0) { + char buf[512]; + snprintf(buf, sizeof(buf), "remote '%s' has no defined address", this_remote->name); + cf_error(scanner, buf); + } + } + ; + +zone_acl_start: + XFR_IN { + this_list = &this_zone->acl.xfr_in; + } + | XFR_OUT { + this_list = &this_zone->acl.xfr_out; + } + | NOTIFY_IN { + this_list = &this_zone->acl.notify_in; + } + | NOTIFY_OUT { + this_list = &this_zone->acl.notify_out; + } + ; + +zone_acl_item: + | TEXT { conf_acl_item(scanner, $1.t); } + | LOG_SRC { conf_acl_item(scanner, strdup($1.t)); } + | LOG { conf_acl_item(scanner, strdup($1.t)); } + | LOG_LEVEL { conf_acl_item(scanner, strdup($1.t)); } + ; + +zone_acl_list: + zone_acl_start + | zone_acl_list zone_acl_item ',' + | zone_acl_list zone_acl_item ';' + ; + +zone_acl: + zone_acl_start '{' + | zone_acl TEXT ';' { + /* Find existing node in remotes. */ + node* r = 0; conf_iface_t* found = 0; + WALK_LIST (r, new_config->remotes) { + if (strcmp(((conf_iface_t*)r)->name, $2.t) == 0) { + found = (conf_iface_t*)r; + break; + } + } + + /* Append to list if found. */ + if (!found) { + char buf[256]; + snprintf(buf, sizeof(buf), "remote '%s' is not defined", $2.t); + cf_error(scanner, buf); + } else { + conf_remote_t *remote = malloc(sizeof(conf_remote_t)); + if (!remote) { + cf_error(scanner, "out of memory"); + } else { + remote->remote = found; + add_tail(this_list, &remote->n); + } + } + + /* Free text token. */ + free($2.t); + } + ; + +zone_start: TEXT { + this_zone = malloc(sizeof(conf_zone_t)); + memset(this_zone, 0, sizeof(conf_zone_t)); + this_zone->enable_checks = -1; // Default policy applies + this_zone->notify_timeout = -1; // Default policy applies + this_zone->notify_retries = 0; // Default policy applies + this_zone->ixfr_fslimit = -1; // Default policy applies + this_zone->dbsync_timeout = -1; // Default policy applies + this_zone->name = $1.t; + + // Append mising dot to ensure FQDN + size_t nlen = strlen(this_zone->name); + if (this_zone->name[nlen - 1] != '.') { + this_zone->name = realloc(this_zone->name, nlen + 1 + 1); + strcat(this_zone->name, "."); + } + + /* Check domain name. */ + knot_dname_t *dn = knot_dname_new_from_str(this_zone->name, + nlen + 1, + 0); + if (dn == 0) { + free(this_zone->name); + free(this_zone); + cf_error(scanner, "invalid zone origin"); + } else { + /* Directly discard dname, won't be needed. */ + knot_dname_free(&dn); + add_tail(&new_config->zones, &this_zone->n); + ++new_config->zones_count; + + /* Initialize ACL lists. */ + init_list(&this_zone->acl.xfr_in); + init_list(&this_zone->acl.xfr_out); + init_list(&this_zone->acl.notify_in); + init_list(&this_zone->acl.notify_out); + } + } + ; + +zone: + zone_start '{' + | zone zone_acl '}' + | zone zone_acl_list + | zone FILENAME TEXT ';' { this_zone->file = $3.t; } + | zone SEMANTIC_CHECKS BOOL ';' { this_zone->enable_checks = $3.i; } + | zone DBSYNC_TIMEOUT NUM ';' { this_zone->dbsync_timeout = $3.i; } + | zone DBSYNC_TIMEOUT INTERVAL ';' { this_zone->dbsync_timeout = $3.i; } + | zone IXFR_FSLIMIT SIZE ';' { new_config->ixfr_fslimit = $3.l; } + | zone IXFR_FSLIMIT NUM ';' { this_zone->ixfr_fslimit = $3.i; } + | zone NOTIFY_RETRIES NUM ';' { + if ($3.i < 1) { + cf_error(scanner, "notify retries must be positive integer"); + } else { + this_zone->notify_retries = $3.i; + } + } + | zone NOTIFY_TIMEOUT NUM ';' { + if ($3.i < 1) { + cf_error(scanner, "notify timeout must be positive integer"); + } else { + this_zone->notify_timeout = $3.i; + } + } + ; + +zones: + ZONES '{' + | zones zone '}' + | zones SEMANTIC_CHECKS BOOL ';' { new_config->zone_checks = $3.i; } + | zones IXFR_FSLIMIT SIZE ';' { new_config->ixfr_fslimit = $3.l; } + | zones IXFR_FSLIMIT NUM ';' { new_config->ixfr_fslimit = $3.i; } + | zones NOTIFY_RETRIES NUM ';' { + if ($3.i < 1) { + cf_error(scanner, "notify retries must be positive integer"); + } else { + new_config->notify_retries = $3.i; + } + } + | zones NOTIFY_TIMEOUT NUM ';' { + if ($3.i < 1) { + cf_error(scanner, "notify timeout must be positive integer"); + } else { + new_config->notify_timeout = $3.i; + } + } + | zones DBSYNC_TIMEOUT NUM ';' { + if ($3.i < 1) { + cf_error(scanner, "zonefile sync timeout must be positive integer"); + } else { + new_config->dbsync_timeout = $3.i; + } + } + | zones DBSYNC_TIMEOUT INTERVAL ';' { new_config->dbsync_timeout = $3.i; } + ; + +log_prios_start: { + this_logmap = malloc(sizeof(conf_log_map_t)); + this_logmap->source = 0; + this_logmap->prios = 0; + add_tail(&this_log->map, &this_logmap->n); +} +; + +log_prios: + log_prios_start + | log_prios LOG_LEVEL ',' { this_logmap->prios |= $2.i; } + | log_prios LOG_LEVEL ';' { this_logmap->prios |= $2.i; } + ; + +log_src: + | log_src LOG_SRC log_prios { + this_logmap->source = $2.i; + this_logmap = 0; + } + ; + +log_dest: LOG_DEST { + /* Find already existing rule. */ + this_log = 0; + node *n = 0; + WALK_LIST(n, new_config->logs) { + conf_log_t* log = (conf_log_t*)n; + if (log->type == $1.i) { + this_log = log; + break; + } + } + + if (!this_log) { + this_log = malloc(sizeof(conf_log_t)); + this_log->type = $1.i; + this_log->file = 0; + init_list(&this_log->map); + add_tail(&new_config->logs, &this_log->n); + ++new_config->logs_count; + } +} +; + +log_file: FILENAME TEXT { + /* Find already existing rule. */ + this_log = 0; + node *n = 0; + WALK_LIST(n, new_config->logs) { + conf_log_t* log = (conf_log_t*)n; + if (log->type == LOGT_FILE) { + if (strcmp($2.t, log->file) == 0) { + this_log = log; + free($2.t); + break; + } + } + } + + /* Create new rule. */ + if (!this_log) { + this_log = malloc(sizeof(conf_log_t)); + this_log->type = LOGT_FILE; + this_log->file = strcpath($2.t); + init_list(&this_log->map); + add_tail(&new_config->logs, &this_log->n); + ++new_config->logs_count; + } +} +; + +log_end: { +} +; + +log_start: + | log_start log_dest '{' log_src '}' + | log_start log_file '{' log_src '}' + ; + +log: LOG '{' log_start log_end; + + +conf: ';' | system '}' | interfaces '}' | keys '}' | remotes '}' | zones '}' | log '}'; + +%% + diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c new file mode 100644 index 0000000..4e2d665 --- /dev/null +++ b/src/knot/conf/conf.c @@ -0,0 +1,715 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <pthread.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include <urcu.h> +#include "knot/conf/conf.h" +#include "knot/common.h" +#include "knot/other/error.h" + +/* + * Defaults. + */ + +/*! \brief Default config paths. */ +static const char *DEFAULT_CONFIG[] = { + SYSCONFDIR "/" "knot.conf", +}; + +#define DEFAULT_CONF_COUNT 1 /*!< \brief Number of default config paths. */ + +/* + * Utilities. + */ + +/*! + * \brief Recursively create directories. + * + * Similar to "mkdir -p". + * * \retval 0 on success. + * \retval <0 on error. + */ +static int rmkdir(char *path, int mode) +{ + char *p = path; + while((p = strchr(p + 1, '/'))) { + *p = '\0'; + mkdir(path, mode); + *p = '/'; + } + + // Final path + return mkdir(path, mode); +} + +/* Prototypes for cf-parse.y */ +extern int cf_parse(void *scanner); +extern int cf_get_lineno(void *scanner); +extern char *cf_get_text(void *scanner); +extern int cf_lex_init(void *scanner); +extern void cf_set_in(FILE *f, void *scanner); +extern void cf_lex_destroy(void *scanner); +extern void switch_input(const char *str, void *scanner); + +conf_t *new_config = 0; /*!< \brief Currently parsed config. */ +static volatile int _parser_res = 0; /*!< \brief Parser result. */ +static pthread_mutex_t _parser_lock = PTHREAD_MUTEX_INITIALIZER; + +/*! \brief Config error report. */ +void cf_error(void *scanner, const char *msg) +{ + int lineno = -1; + char *text = "???"; + if (scanner) { + lineno = cf_get_lineno(scanner); + text = (char *)cf_get_text(scanner); + } + + log_server_error("Config '%s' - %s on line %d (current token '%s').\n", + new_config->filename, msg, lineno, text); + + + _parser_res = KNOTD_EPARSEFAIL; +} + +/* + * Config helper functions. + */ + +/*! \brief Free TSIG key. */ +static void key_free(conf_key_t *k) +{ + /* Secure erase. */ + if (k->k.secret) { + memset(k->k.secret, 0, strlen(k->k.secret)); + } + free(k->k.secret); + knot_dname_free(&k->k.name); + free(k); +} + +/*! \brief Free config interfaces. */ +static void iface_free(conf_iface_t *iface) +{ + if (!iface) { + return; + } + + free(iface->name); + free(iface->address); + free(iface); +} + +/*! \brief Free config logs. */ +static void log_free(conf_log_t *log) +{ + if (!log) { + return; + } + + if (log->file) { + free(log->file); + } + + /* Free loglevel mapping. */ + node *n = 0, *nxt = 0; + WALK_LIST_DELSAFE(n, nxt, log->map) { + free((conf_log_map_t*)n); + } + + free(log); +} + +/*! \brief Free config zones. */ +static void zone_free(conf_zone_t *zone) +{ + if (!zone) { + return; + } + + /* Free ACL lists. */ + WALK_LIST_FREE(zone->acl.xfr_in); + WALK_LIST_FREE(zone->acl.xfr_out); + WALK_LIST_FREE(zone->acl.notify_in); + WALK_LIST_FREE(zone->acl.notify_out); + + free(zone->name); + free(zone->file); + free(zone->db); + free(zone->ixfr_db); + free(zone); +} + +/*! + * \brief Call config hooks that need updating. + * + * This function is called automatically after config update. + * + * \todo Selective hooks. + */ +static void conf_update_hooks(conf_t *conf) +{ + node *n = 0; + conf->_touched = CONF_ALL; + WALK_LIST (n, conf->hooks) { + conf_hook_t *hook = (conf_hook_t*)n; + if ((hook->sections & conf->_touched) && hook->update) { + hook->update(conf, hook->data); + } + } +} + +/*! + * \brief Process parsed configuration. + * + * This functions is called automatically after config parsing. + * It is needed to setup needed primitives, check and update paths. + * + * \retval 0 on success. + * \retval <0 on error. + */ +static int conf_process(conf_t *conf) +{ + // Check + if (!conf->storage) { + conf->storage = strdup("/var/lib/"PROJECT_EXEC); + } + + // Normalize paths + conf->storage = strcpath(conf->storage); + struct stat st; + if (stat(conf->storage, &st) != 0) { + rmkdir(conf->storage, S_IRWXU); + } + + // Create PID file + conf->pidfile = strcdup(conf->storage, "/" PID_FILE); + + // Postprocess zones + node *n = 0; + WALK_LIST (n, conf->zones) { + conf_zone_t *zone = (conf_zone_t*)n; + + // Default policy for dbsync timeout + if (zone->dbsync_timeout < 0) { + zone->dbsync_timeout = conf->dbsync_timeout; + } + + // Default policy for semantic checks + if (zone->enable_checks < 0) { + zone->enable_checks = conf->zone_checks; + } + + // Default policy for NOTIFY retries + if (zone->notify_retries <= 0) { + zone->notify_retries = conf->notify_retries; + } + + // Default policy for NOTIFY timeout + if (zone->notify_timeout <= 0) { + zone->notify_timeout = conf->notify_timeout; + } + + // Default policy for IXFR FSLIMIT + if (zone->ixfr_fslimit == 0) { + zone->ixfr_fslimit = conf->ixfr_fslimit; + } + + // Normalize zone filename + zone->file = strcpath(zone->file); + + // Create zone db filename + size_t stor_len = strlen(conf->storage); + size_t size = stor_len + strlen(zone->name) + 4; // db/,\0 + char *dest = malloc(size); + strcpy(dest, conf->storage); + if (conf->storage[stor_len - 1] != '/') { + strcat(dest, "/"); + } + + strcat(dest, zone->name); + strcat(dest, "db"); + zone->db = dest; + + // Create IXFR db filename + stor_len = strlen(conf->storage); + size = stor_len + strlen(zone->name) + 9; // diff.db/,\0 + dest = malloc(size); + strcpy(dest, conf->storage); + if (conf->storage[stor_len - 1] != '/') { + strcat(dest, "/"); + } + + strcat(dest, zone->name); + strcat(dest, "diff.db"); + zone->ixfr_db = dest; + } + + return 0; +} + +/* + * Singletion configuration API. + */ + +conf_t *s_config = 0; /*! \brief Singleton config instance. */ + +/*! \brief Singleton config constructor (automatically called on load). */ +void __attribute__ ((constructor)) conf_init() +{ + // Create new config + s_config = conf_new(0); + + /* Create default interface. */ + conf_iface_t * iface = malloc(sizeof(conf_iface_t)); + memset(iface, 0, sizeof(conf_iface_t)); + iface->name = strdup("any"); + iface->address = strdup("0.0.0.0"); + iface->port = CONFIG_DEFAULT_PORT; + add_tail(&s_config->ifaces, &iface->n); + ++s_config->ifaces_count; + + /* Create default storage. */ + s_config->storage = strdup("/var/lib/"PROJECT_EXEC); + + /* Create default logs. */ + + /* Syslog */ + conf_log_t *log = malloc(sizeof(conf_log_t)); + log->type = LOGT_SYSLOG; + log->file = 0; + init_list(&log->map); + + conf_log_map_t *map = malloc(sizeof(conf_log_map_t)); + map->source = LOG_ANY; + map->prios = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR); + add_tail(&log->map, &map->n); + add_tail(&s_config->logs, &log->n); + ++s_config->logs_count; + + /* Stderr */ + log = malloc(sizeof(conf_log_t)); + log->type = LOGT_STDERR; + log->file = 0; + init_list(&log->map); + + map = malloc(sizeof(conf_log_map_t)); + map->source = LOG_ANY; + map->prios = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR); + add_tail(&log->map, &map->n); + add_tail(&s_config->logs, &log->n); + ++s_config->logs_count; + + /* Process config. */ + conf_process(s_config); +} + +/*! \brief Singleton config destructor (automatically called on exit). */ +void __attribute__ ((destructor)) conf_deinit() +{ + if (s_config) { + conf_free(s_config); + s_config = 0; + } +} + +/*! + * \brief Parse config (from file). + * \return yyparser return value. + */ +static int conf_fparser(conf_t *conf) +{ + if (!conf->filename) { + return KNOTD_EINVAL; + } + + int ret = KNOTD_EOK; + pthread_mutex_lock(&_parser_lock); + // { + // Hook new configuration + new_config = conf; + FILE *f = fopen(conf->filename, "r"); + if (f == 0) { + pthread_mutex_unlock(&_parser_lock); + return KNOTD_ENOENT; + } + + // Parse config + _parser_res = KNOTD_EOK; + new_config->filename = conf->filename; + void *sc = NULL; + cf_lex_init(&sc); + cf_set_in(f, sc); + cf_parse(sc); + cf_lex_destroy(sc); + ret = _parser_res; + fclose(f); + // } + pthread_mutex_unlock(&_parser_lock); + return ret; +} + +/*! \brief Parse config (from string). + * \return yyparser return value. + */ +static int conf_strparser(conf_t *conf, const char *src) +{ + if (!src) { + return KNOTD_EINVAL; + } + + int ret = KNOTD_EOK; + pthread_mutex_lock(&_parser_lock); + // { + // Hook new configuration + new_config = conf; + if (src == 0) { + pthread_mutex_unlock(&_parser_lock); + return KNOTD_ENOENT; + } + + // Parse config + _parser_res = KNOTD_EOK; + char *oldfn = new_config->filename; + new_config->filename = "(stdin)"; + void *sc = NULL; + cf_lex_init(&sc); + switch_input(src, sc); + cf_parse(sc); + cf_lex_destroy(sc); + new_config->filename = oldfn; + ret = _parser_res; + // } + pthread_mutex_unlock(&_parser_lock); + return ret; +} + +/* + * API functions. + */ + +conf_t *conf_new(const char* path) +{ + conf_t *c = malloc(sizeof(conf_t)); + memset(c, 0, sizeof(conf_t)); + + // Add path + if (path) { + c->filename = strdup(path); + } + + // Initialize lists + init_list(&c->logs); + init_list(&c->ifaces); + init_list(&c->zones); + init_list(&c->hooks); + init_list(&c->remotes); + init_list(&c->keys); + + // Defaults + c->zone_checks = 0; + c->notify_retries = CONFIG_NOTIFY_RETRIES; + c->notify_timeout = CONFIG_NOTIFY_TIMEOUT; + c->dbsync_timeout = CONFIG_DBSYNC_TIMEOUT; + c->ixfr_fslimit = -1; + + return c; +} + +int conf_add_hook(conf_t * conf, int sections, + int (*on_update)(const conf_t*, void*), void *data) +{ + conf_hook_t *hook = malloc(sizeof(conf_hook_t)); + if (!hook) { + return KNOTD_ENOMEM; + } + + hook->sections = sections; + hook->update = on_update; + hook->data = data; + add_tail(&conf->hooks, &hook->n); + ++conf->hooks_count; + + return KNOTD_EOK; +} + +int conf_parse(conf_t *conf) +{ + /* Parse file. */ + int ret = conf_fparser(conf); + + /* Postprocess config. */ + conf_process(conf); + + /* Update hooks. */ + conf_update_hooks(conf); + + if (ret < 0) { + return KNOTD_EPARSEFAIL; + } + + return KNOTD_EOK; +} + +int conf_parse_str(conf_t *conf, const char* src) +{ + /* Parse config from string. */ + int ret = conf_strparser(conf, src); + + /* Postprocess config. */ + conf_process(conf); + + /* Update hooks */ + conf_update_hooks(conf); + + if (ret < 0) { + return KNOTD_EPARSEFAIL; + } + + return KNOTD_EOK; +} + +void conf_truncate(conf_t *conf, int unload_hooks) +{ + if (!conf) { + return; + } + + node *n = 0, *nxt = 0; + + // Unload hooks + if (unload_hooks) { + WALK_LIST_DELSAFE(n, nxt, conf->hooks) { + //! \todo call hook unload. + free((conf_hook_t*)n); + } + conf->hooks_count = 0; + init_list(&conf->hooks); + } + + // Free keys + WALK_LIST_DELSAFE(n, nxt, conf->keys) { + key_free((conf_key_t *)n); + } + + // Free interfaces + WALK_LIST_DELSAFE(n, nxt, conf->ifaces) { + iface_free((conf_iface_t*)n); + } + conf->ifaces_count = 0; + init_list(&conf->ifaces); + + // Free logs + WALK_LIST_DELSAFE(n, nxt, conf->logs) { + log_free((conf_log_t*)n); + } + conf->logs_count = 0; + init_list(&conf->logs); + + // Free remotes + WALK_LIST_DELSAFE(n, nxt, conf->remotes) { + iface_free((conf_iface_t*)n); + } + conf->remotes_count = 0; + init_list(&conf->remotes); + + // Free zones + WALK_LIST_DELSAFE(n, nxt, conf->zones) { + zone_free((conf_zone_t*)n); + } + conf->zones_count = 0; + init_list(&conf->zones); + + if (conf->filename) { + free(conf->filename); + conf->filename = 0; + } + if (conf->identity) { + free(conf->identity); + conf->identity = 0; + } + if (conf->version) { + free(conf->version); + conf->version = 0; + } + if (conf->storage) { + free(conf->storage); + conf->storage = 0; + } + if (conf->pidfile) { + free(conf->pidfile); + conf->pidfile = 0; + } +} + +void conf_free(conf_t *conf) +{ + if (!conf) { + return; + } + + // Truncate config + conf_truncate(conf, 1); + + // Free config + free(conf); +} + +char* conf_find_default() +{ + /* Try sequentially each default path. */ + char *path = 0; + for (int i = 0; i < DEFAULT_CONF_COUNT; ++i) { + path = strcpath(strdup(DEFAULT_CONFIG[i])); + + /* Break, if the path exists. */ + struct stat st; + if (stat(path, &st) == 0) { + break; + } + + log_server_notice("Config '%s' does not exist.\n", + path); + + /* Keep the last item. */ + if (i < DEFAULT_CONF_COUNT - 1) { + free(path); + path = 0; + } + } + + log_server_info("Using '%s' as default configuration.\n", + path); + return path; +} + +int conf_open(const char* path) +{ + /* Check path. */ + if (!path) { + return KNOTD_EINVAL; + } + + /* Check if exists. */ + FILE *fp = fopen(path, "r"); + if (fp == 0) { + return KNOTD_ENOENT; + } else { + fclose(fp); + } + + /* Create new config. */ + conf_t *nconf = conf_new(path); + + /* Parse config. */ + int ret = conf_fparser(nconf); + if (ret != KNOTD_EOK) { + conf_free(nconf); + return ret; + } + + /* Replace current config. */ + conf_t *oldconf = rcu_xchg_pointer(&s_config, nconf); + + /* Copy hooks. */ + if (oldconf) { + node *n = 0, *nxt = 0; + WALK_LIST_DELSAFE (n, nxt, oldconf->hooks) { + conf_hook_t *hook = (conf_hook_t*)n; + conf_add_hook(nconf, hook->sections, + hook->update, hook->data); + } + } + + /* Postprocess config. */ + conf_process(nconf); + + /* Synchronize. */ + synchronize_rcu(); + + /* Free old config. */ + if (oldconf) { + conf_free(oldconf); + } + + /* Update hooks. */ + conf_update_hooks(nconf); + + return KNOTD_EOK; +} + +char* strcdup(const char *s1, const char *s2) +{ + if (!s1 || !s2) { + return 0; + } + + size_t slen = strlen(s1); + size_t nlen = slen + strlen(s2) + 1; + char* dst = malloc(nlen); + if (!dst) { + return 0; + } + + memcpy(dst, s1, slen); + strcpy(dst + slen, s2); // With trailing '\0' + return dst; +} + +char* strcpath(char *path) +{ + // NULL path + if (!path) { + return 0; + } + + // Remote trailing slash + size_t plen = strlen(path); + if (path[plen - 1] == '/') { + path[--plen] = '\0'; + } + + // Expand '~' + char* tild_p = strchr(path,'~'); + if (tild_p != 0) { + // Get full path + char *tild_exp = getenv("HOME"); + size_t tild_len = strlen(tild_exp); + if (tild_exp[tild_len - 1] == '/') { + tild_exp[--tild_len] = '\0'; + } + + // Expand + char *npath = malloc(plen + tild_len + 1); + npath[0] = '\0'; + strncpy(npath, path, (size_t)(tild_p - path)); + strcat(npath, tild_exp); + strcat(npath, tild_p + 1); + free(path); + path = npath; + } + + return path; +} + diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h new file mode 100644 index 0000000..ef35e41 --- /dev/null +++ b/src/knot/conf/conf.h @@ -0,0 +1,361 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file conf.h + * + * \author Ondrej Sury <ondrej.sury@nic.cz> + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Server configuration structures and API. + * + * \addtogroup config + * @{ + */ + +#ifndef _KNOTD_CONF_H_ +#define _KNOTD_CONF_H_ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <urcu.h> + +#include "libknot/dname.h" +#include "libknot/util/descriptor.h" +#include "libknot/tsig.h" +#include "common/lists.h" +#include "knot/other/log.h" + +/* Constants. */ +#define CONFIG_DEFAULT_PORT 53 +#define CONFIG_NOTIFY_RETRIES 5 /*!< 5 retries (suggested in RFC1996) */ +#define CONFIG_NOTIFY_TIMEOUT 60 /*!< 60s (suggested in RFC1996) */ +#define CONFIG_DBSYNC_TIMEOUT (60*60) /*!< 1 hour. */ + +/*! + * \brief Configuration for the interface + * + * This structure holds the configuration of the various interfaces + * used in the configuration. Same interface could be used for + * listening and outgoing function. + */ +typedef struct conf_iface_t { + node n; + char *name; /*!< Internal name for the interface. */ + char *address; /*!< IP (IPv4/v6) address for this interface */ + int port; /*!< Port number for this interface */ + int family; /*!< Address family. */ + knot_key_t *key; /*!< TSIG key (only valid for remotes). */ +} conf_iface_t; + +/*! + * \brief Node containing poiner to remote. + * + * Used for zone ACL lists to prevent node duplication. + */ +typedef struct conf_remote_t { + node n; /*!< List node. */ + conf_iface_t *remote; /*!< Pointer to interface descriptor. */ +} conf_remote_t; + +/*! + * \brief Zone configuration. + * + * This structure holds the configuration for the zone. In it's most + * basic form, it just allows to read a zone from the specific + * location on the disk. It also allows to have multiple DNS servers + * as a source for the zone transfer and multiple DNS servers to allow + * zone transfers. Same logic applies for the NOTIFY. + * + * \todo Missing XFR type (AXFR/IXFR/IXFR-ONLY) for each server. + */ +typedef struct conf_zone_t { + node n; + char *name; /*!< Zone name. */ + enum knot_rr_class cls; /*!< Zone class (IN or CH). */ + char *file; /*!< Path to a zone file. */ + char *db; /*!< Path to a database file. */ + char *ixfr_db; /*!< Path to a IXFR database file. */ + size_t ixfr_fslimit; /*!< File size limit for IXFR journal. */ + int dbsync_timeout; /*!< Interval between syncing to zonefile.*/ + int enable_checks; /*!< Semantic checks for parser.*/ + int notify_retries; /*!< NOTIFY query retries. */ + int notify_timeout; /*!< Timeout for NOTIFY response (s). */ + struct { + list xfr_in; /*!< Remotes accepted for for xfr-in.*/ + list xfr_out; /*!< Remotes accepted for xfr-out.*/ + list notify_in; /*!< Remotes accepted for notify-in.*/ + list notify_out; /*!< Remotes accepted for notify-out.*/ + } acl; +} conf_zone_t; + +/*! + * \brief Mapping of loglevels to message sources. + */ +typedef struct conf_log_map_t { + node n; + int source; /*!< Log message source mask. */ + int prios; /*!< Log priorities mask. */ +} conf_log_map_t; + +/*! + * \brief Log facility descriptor. + */ +typedef struct conf_log_t { + node n; + logtype_t type; /*!< Type of the log (SYSLOG/STDERR/FILE). */ + char *file; /*!< Filename in case of LOG_FILE, else NULL. */ + list map; /*!< Log levels mapping. */ +} conf_log_t; + +/*! + * \brief Configuration sections. + */ +typedef enum conf_section_t { + CONF_LOG = 1 << 0, /*!< Log section. */ + CONF_IFACES = 1 << 1, /*!< Interfaces. */ + CONF_ZONES = 1 << 2, /*!< Zones. */ + CONF_OTHER = 1 << 3, /*!< Other sections. */ + CONF_ALL = ~0 /*!< All sections. */ +} conf_section_t; + +/*! + * \brief TSIG key list item. + */ +typedef struct conf_key_t { + node n; + knot_key_t k; +} conf_key_t; + +/*! + * \brief Main config structure. + * + * Configuration structure. + */ +typedef struct conf_t { + /* + * System + */ + char *filename; /*!< Name of the config file. */ + char *identity; /*!< Identity to return on CH TXT id.server. */ + char *version; /*!< Version for CH TXT version.{bind|server} */ + char *storage; /*!< Persistent storage path for databases and such. */ + char *pidfile; /*!< PID file path. */ + int workers; /*!< Number of workers per interface. */ + + /* + * Log + */ + list logs; /*!< List of logging facilites. */ + int logs_count; /*!< Count of logging facilities. */ + + /* + * Interfaces + */ + list ifaces; /*!< List of interfaces. */ + int ifaces_count; /*!< Count of interfaces. */ + + /* + * TSIG keys + */ + list keys; /*!< List of TSIG keys. */ + int key_count; /*!< Count of TSIG keys. */ + + /* + * Remotes + */ + list remotes; /*!< List of remotes. */ + int remotes_count;/*!< Count of remotes. */ + + /* + * Zones + */ + list zones; /*!< List of zones. */ + int zones_count; /*!< Count of zones. */ + int zone_checks; /*!< Semantic checks for parser.*/ + int notify_retries; /*!< NOTIFY query retries. */ + int notify_timeout; /*!< Timeout for NOTIFY response in seconds. */ + int dbsync_timeout; /*!< Default interval between syncing to zonefile.*/ + size_t ixfr_fslimit; /*!< File size limit for IXFR journal. */ + + /* + * Implementation specifics + */ + list hooks; /*!< List of config hooks. */ + int hooks_count; /*!< Count of config hooks. */ + int _touched; /*!< Bitmask of sections touched by last update. */ +} conf_t; + +/*! + * \brief Config hook prototype. + */ +typedef struct conf_hook_t { + node n; + int sections; /*!< Bitmask of watched sections. */ + int (*update)(const conf_t*, void*); /*!< Function executed on config load. */ + void *data; +} conf_hook_t; + +/* + * Specific configuration API. + */ + +/*! + * \brief Create new configuration structure. + * + * \param path Path to configuration file. + * \retval new structure if successful. + * \retval NULL on error. + */ +conf_t *conf_new(const char* path); + +/*! + * \brief Register on-update callback. + * + * \param conf Configuration context. + * \param sections Bitmask of watched sections or CONF_ALL. + * \param on_update Callback. + * \param data User specified data for hook. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ENOMEM out of memory error. + */ +int conf_add_hook(conf_t * conf, int sections, + int (*on_update)(const conf_t*, void*), void *data); + +/*! + * \brief Parse configuration from associated file. + * + * \note Registered callbacks may be executed if applicable. + * + * \param conf Configuration context. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EPARSEFAIL on parser error. + */ +int conf_parse(conf_t *conf); + +/*! + * \brief Parse configuration from string. + * + * \note Registered callbacks may be executed if applicable. + * + * \param conf Configuration context. + * \param src Source string. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EPARSEFAIL on parser error. + */ +int conf_parse_str(conf_t *conf, const char* src); + +/*! + * \brief Truncate configuration context. + * + * \param conf Configuration context. + * \param unload_hooks If true, hooks will be unregistered and freed as well. + */ +void conf_truncate(conf_t *conf, int unload_hooks); + +/*! + * \brief Destroy configuration context. + * + * \param conf Configuration context. + */ +void conf_free(conf_t *conf); + +/* + * Singleton configuration API. + */ + +/*! + * \brief Find implicit configuration file. + * + * Ordering: + * 1. ~/.knot/knot.conf (if exists) + * 2. /etc/knot/knot.conf (fallback) + * + * \return Path to implicit configuration file. + */ +char* conf_find_default(); + +/*! + * \brief Open singleton configuration from file. + * + * \note Registered callbacks may be executed if applicable. + * + * \param path Path to configuration file. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on null path. + * \retval KNOTD_ENOENT if the path doesn't exist. + */ +int conf_open(const char* path); + +/* Imported singleton */ +extern conf_t *s_config; + +/*! + * \brief Singleton configuration context accessor. + * + * \return Configuration context. + */ +static inline conf_t* conf() { + return s_config; // Inline for performance reasons. +} + +/*! + * \brief Lock configuration for reading. + * + * \return Configuration context. + */ +static inline void conf_read_lock() { + rcu_read_lock(); +} + +/*! + * \brief Unlock configuration for reading. + */ +static inline void conf_read_unlock() { + rcu_read_unlock(); +} + +/* + * Utilities. + */ + +/*! + * \brief Create new string from a concatenation of s1 and s2. + * + * \param s1 First string. + * \param s2 Second string. + * + * \retval Newly allocated string on success. + * \retval NULL on error. + */ +char* strcdup(const char *s1, const char *s2); + +/*! + * \brief Normalize file path and expand '~' placeholders. + * + * \note Old pointer may be freed. + * + * \retval Pointer to normalized path. + */ +char* strcpath(char *path); + +#endif /* _KNOTD_CONF_H_ */ + +/*! @} */ diff --git a/src/knot/conf/logconf.c b/src/knot/conf/logconf.c new file mode 100644 index 0000000..a57afd9 --- /dev/null +++ b/src/knot/conf/logconf.c @@ -0,0 +1,102 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "knot/other/debug.h" +#include "knot/conf/logconf.h" +#include "knot/conf/conf.h" +#include "knot/other/log.h" +#include "knot/other/error.h" +#include "common/lists.h" +#include "knot/common.h" + +int log_conf_hook(const struct conf_t *conf, void *data) +{ + // Data not used + int ret = 0; + UNUSED(data); + + // Check if log declaration exists, otherwise ignore + if (conf->logs_count < 1) { + return KNOTD_EINVAL; + } + + // Find maximum log facility id + node *n = 0; size_t files = 0; + WALK_LIST(n, conf->logs) { + conf_log_t* log = (conf_log_t*)n; + if (log->type == LOGT_FILE) { + ++files; + } + } + + // Initialize logsystem + log_truncate(); + if ((ret = log_setup(files)) < 0) { + return ret; + } + + // Setup logs + int loaded_sections = 0; + n = 0; + WALK_LIST(n, conf->logs) { + + // Calculate offset + conf_log_t* log = (conf_log_t*)n; + int facility = log->type; + if (facility == LOGT_FILE) { + facility = log_open_file(log->file); + if (facility < 0) { + log_server_error("Failed to open " + "logfile '%s'.\n", log->file); + continue; + } + } + + // Auto-assign fatal errors to syslog or stderr + if (facility <= LOGT_STDERR) { + int mask = LOG_MASK(LOG_FATAL); + log_levels_add(facility, LOG_ANY, mask); + loaded_sections |= 1 << facility; + } + + // Setup sources mapping + node *m = 0; + WALK_LIST(m, log->map) { + + // Assign mapped level + conf_log_map_t *map = (conf_log_map_t*)m; + log_levels_add(facility, map->source, map->prios); + } + } + + // Load defaults for syslog or stderr + int bmask = LOG_MASK(LOG_ERR)|LOG_MASK(LOG_FATAL); + if (!(loaded_sections & (1 << LOGT_SYSLOG))) { + log_levels_set(LOGT_SYSLOG, LOG_ANY, bmask); + } + if (!(loaded_sections & (1 << LOGT_STDERR))) { + log_levels_set(LOGT_STDERR, LOG_ANY, bmask); + } + + return KNOTD_EOK; +} + diff --git a/src/knot/conf/logconf.h b/src/knot/conf/logconf.h new file mode 100644 index 0000000..7b9e054 --- /dev/null +++ b/src/knot/conf/logconf.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file log.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Logging facility (configuration file interface). + * + * \addtogroup logging + * @{ + */ + +#ifndef _KNOTD_LOGCONF_H_ +#define _KNOTD_LOGCONF_H_ + +struct conf_t; + +/*! + * \brief Setup logging facilities from config. + * + * \see syslog.h + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOMEM out of memory error. + */ +int log_conf_hook(const struct conf_t *conf, void *data); + +#endif /* _KNOTD_LOGCONF_H_ */ + +/*! @} */ diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c new file mode 100644 index 0000000..16c3863 --- /dev/null +++ b/src/knot/ctl/knotc_main.c @@ -0,0 +1,658 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <sys/select.h> +#include <sys/stat.h> +#include <getopt.h> + +#include "knot/common.h" +#include "knot/other/error.h" +#include "knot/ctl/process.h" +#include "knot/conf/conf.h" +#include "knot/conf/logconf.h" +#include "knot/zone/zone-load.h" + +/*! \brief Controller constants. */ +enum knotc_constants_t { + WAITPID_TIMEOUT = 10 /*!< \brief Timeout for waiting for process. */ +}; + +/*! \brief Print help. */ +void help(int argc, char **argv) +{ + printf("Usage: %sc [parameters] start|stop|restart|reload|running|" + "compile\n", PACKAGE_NAME); + printf("Parameters:\n" + " -c [file], --config=[file] Select configuration file.\n" + " -j [num], --jobs=[num] Number of parallel tasks to run (only for 'compile').\n" + " -f, --force Force operation - override some checks.\n" + " -v, --verbose Verbose mode - additional runtime information.\n" + " -V, --version Print %s server version.\n" + " -w, --wait Wait for the server to finish start/stop operations.\n" + " -i, --interactive Interactive mode (do not daemonize).\n" + " -h, --help Print help and usage.\n", + PACKAGE_NAME); + printf("Actions:\n" + " start Start %s server zone (no-op if running).\n" + " stop Stop %s server (no-op if not running).\n" + " restart Stops and then starts %s server.\n" + " reload Reload %s configuration and compiled zones.\n" + " running check if server is running.\n" + "\n" + " compile Compile zone file.\n", + PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME); +} + +/*! + * \brief Check if the zone needs recompilation. + * + * \param db Path to zone db file. + * \param source Path to zone source file. + * + * \retval KNOTD_EOK if up to date. + * \retval KNOTD_ERROR if needs recompilation. + */ +int check_zone(const char *db, const char* source) +{ + /* Check zonefile. */ + struct stat st; + if (stat(source, &st) != 0) { + fprintf(stderr, "Zone file '%s' doesn't exist.\n", source); + return KNOTD_ENOENT; + } + + /* Read zonedb header. */ + zloader_t *zl = 0; + knot_zload_open(&zl, db); + if (!zl) { + return KNOTD_ERROR; + } + + /* Check source files and mtime. */ + int ret = KNOTD_ERROR; + int src_changed = strcmp(source, zl->source) != 0; + if (!src_changed && !knot_zload_needs_update(zl)) { + ret = KNOTD_EOK; + } + + knot_zload_close(zl); + return ret; +} + +pid_t wait_cmd(pid_t proc, int *rc) +{ + /* Wait for finish. */ + sigset_t newset; + sigfillset(&newset); + sigprocmask(SIG_BLOCK, &newset, 0); + proc = waitpid(proc, rc, 0); + sigprocmask(SIG_UNBLOCK, &newset, 0); + return proc; +} + +pid_t start_cmd(const char *argv[], int argc) +{ + pid_t chproc = fork(); + if (chproc == 0) { + + /* Duplicate, it doesn't run from stack address anyway. */ + char **args = malloc((argc + 1) * sizeof(char*)); + memset(args, 0, (argc + 1) * sizeof(char*)); + int ci = 0; + for (int i = 0; i < argc; ++i) { + if (strlen(argv[i]) > 0) { + args[ci++] = strdup(argv[i]); + } + } + args[ci] = 0; + + /* Execute command. */ + fflush(stdout); + fflush(stderr); + execvp(args[0], args); + + /* Execute failed. */ + fprintf(stderr, "Failed to run executable '%s'\n", args[0]); + for (int i = 0; i < argc; ++i) { + free(args[i]); + } + free(args); + + exit(1); + return -1; + } + + return chproc; +} + +int exec_cmd(const char *argv[], int argc) +{ + int ret = 0; + pid_t proc = start_cmd(argv, argc); + wait_cmd(proc, &ret); + return ret; +} + +/*! \brief Zone compiler task. */ +typedef struct { + conf_zone_t *zone; + pid_t proc; +} knotc_zctask_t; + +/*! \brief Create set of watched tasks. */ +knotc_zctask_t *zctask_create(int count) +{ + if (count <= 0) { + return 0; + } + + knotc_zctask_t *t = malloc(count * sizeof(knotc_zctask_t)); + for (unsigned i = 0; i < count; ++i) { + t[i].proc = -1; + t[i].zone = 0; + } + + return t; +} + +/*! \brief Wait for single task to finish. */ +int zctask_wait(knotc_zctask_t *tasks, int count) +{ + /* Wait for children to finish. */ + int rc = 0; + pid_t pid = wait_cmd(-1, &rc); + + /* Find task. */ + conf_zone_t *z = 0; + for (unsigned i = 0; i < count; ++i) { + if (tasks[i].proc == pid) { + tasks[i].proc = -1; /* Invalidate. */ + z = tasks[i].zone; + break; + } + } + + if (z == 0) { + fprintf(stderr, "error: Failed to find zone for finished " + "zone compilation process.\n"); + return 1; + } + + /* Evaluate. */ + if (!WIFEXITED(rc)) { + fprintf(stderr, "error: Compilation of '%s' " + "failed, process was killed.\n", + z->name); + return 1; + } else { + if (rc < 0 || WEXITSTATUS(rc) != 0) { + fprintf(stderr, "error: Compilation of " + "'%s' failed, knot-zcompile " + "return code was '%d'\n", + z->name, WEXITSTATUS(rc)); + return 1; + } + } + + return 0; +} + +/*! \brief Register running zone compilation process. */ +int zctask_add(knotc_zctask_t *tasks, int count, pid_t pid, conf_zone_t *zone) +{ + /* Find free space. */ + for (unsigned i = 0; i < count; ++i) { + if (tasks[i].proc == -1) { + tasks[i].proc = pid; + tasks[i].zone = zone; + return 0; + } + } + + /* Free space not found. */ + return -1; +} + +/*! + * \brief Execute specified action. + * + * \param action Action to be executed (start, stop, restart...) + * \param argv Additional arguments vector. + * \param argc Addition arguments count. + * \param pid Specified PID for action. + * \param verbose True if running in verbose mode. + * \param force True if forced operation is required. + * \param wait Wait for the operation to finish. + * \param interactive Interactive mode. + * \param jobs Number of parallel tasks to run. + * \param pidfile Specified PID file for action. + * + * \retval 0 on success. + * \retval error return code for main on error. + * + * \todo Make enumerated flags instead of many parameters... + */ +int execute(const char *action, char **argv, int argc, pid_t pid, int verbose, + int force, int wait, int interactive, int jobs, const char *pidfile) +{ + int valid_cmd = 0; + int rc = 0; + if (strcmp(action, "start") == 0) { + + // Check PID + valid_cmd = 1; +// if (pid < 0 && pid == KNOT_ERANGE) { +// fprintf(stderr, "control: Another server instance " +// "is already starting.\n"); +// return 1; +// } + if (pid > 0 && pid_running(pid)) { + + fprintf(stderr, "control: Server PID found, " + "already running.\n"); + + if (!force) { + return 1; + } else { + fprintf(stderr, "control: forcing " + "server start, killing old pid=%ld.\n", + (long)pid); + kill(pid, SIGKILL); + pid_remove(pidfile); + } + } + + // Lock configuration + conf_read_lock(); + + // Prepare command + const char *cfg = conf()->filename; + const char *args[] = { + PROJECT_EXEC, + interactive ? "" : "-d", + cfg ? "-c" : "", + cfg ? cfg : "", + verbose ? "-v" : "", + argc > 0 ? argv[0] : "" + }; + + // Unlock configuration + conf_read_unlock(); + + // Execute command + if (interactive) { + printf("control: Running in interactive mode.\n"); + fflush(stderr); + fflush(stdout); + } + if ((rc = exec_cmd(args, 6)) < 0) { + pid_remove(pidfile); + rc = 1; + } + fflush(stderr); + fflush(stdout); + + // Wait for finish + if (wait && !interactive) { + if (verbose) { + fprintf(stdout, "control: waiting for server " + "to load.\n"); + } + /* Periodically read pidfile and wait for + * valid result. */ + pid = 0; + while(pid == 0 || !pid_running(pid)) { + pid = pid_read(pidfile); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500 * 1000; + select(0, 0, 0, 0, &tv); + } + } + } + if (strcmp(action, "stop") == 0) { + + // Check PID + valid_cmd = 1; + rc = 0; + if (pid <= 0 || !pid_running(pid)) { + fprintf(stderr, "Server PID not found, " + "probably not running.\n"); + + if (!force) { + rc = 1; + } else { + fprintf(stderr, "control: forcing " + "server stop.\n"); + } + } + + // Stop + if (rc == 0) { + if (kill(pid, SIGTERM) < 0) { + pid_remove(pidfile); + rc = 1; + } + } + + // Wait for finish + if (rc == 0 && wait) { + if (verbose) { + fprintf(stdout, "control: waiting for server " + "to stop.\n"); + } + /* Periodically read pidfile and wait for + * valid result. */ + while(pid_running(pid)) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500 * 1000; + select(0, 0, 0, 0, &tv); + } + } + } + if (strcmp(action, "restart") == 0) { + valid_cmd = 1; + execute("stop", argv, argc, pid, verbose, force, wait, + interactive, jobs, pidfile); + + int i = 0; + while((pid = pid_read(pidfile)) > 0) { + + if (!pid_running(pid)) { + pid_remove(pidfile); + break; + } + if (i == WAITPID_TIMEOUT) { + fprintf(stderr, "Timeout while " + "waiting for the server to finish.\n"); + //pid_remove(pidfile); + break; + } else { + sleep(1); + ++i; + } + } + + printf("Restarting server.\n"); + rc = execute("start", argv, argc, -1, verbose, force, wait, + interactive, jobs, pidfile); + } + if (strcmp(action, "reload") == 0) { + + // Check PID + valid_cmd = 1; + if (pid <= 0 || !pid_running(pid)) { + fprintf(stderr, "Server PID not found, " + "probably not running.\n"); + + if (force) { + fprintf(stderr, "control: forcing " + "server stop.\n"); + } else { + return 1; + } + } + + // Stop + if (kill(pid, SIGHUP) < 0) { + pid_remove(pidfile); + rc = 1; + } + } + if (strcmp(action, "running") == 0) { + + // Check PID + valid_cmd = 1; + if (pid <= 0) { + printf("Server PID not found, " + "probably not running.\n"); + rc = 1; + } else { + if (!pid_running(pid)) { + printf("Server PID not found, " + "probably not running.\n"); + fprintf(stderr, + "warning: PID file is stale.\n"); + } else { + printf("Server running as PID %ld.\n", + (long)pid); + } + rc = 0; + } + } + if (strcmp(action, "compile") == 0) { + + // Print job count + if (jobs > 1) { + printf("warning: Will attempt to compile %d zones " + "in parallel, this increases memory consumption " + "for large zones.\n", jobs); + } + + // Check zone + valid_cmd = 1; + + // Lock configuration + conf_read_lock(); + + // Generate databases for all zones + node *n = 0; + int running = 0; + knotc_zctask_t *tasks = zctask_create(jobs); + WALK_LIST(n, conf()->zones) { + + // Fetch zone + conf_zone_t *zone = (conf_zone_t*)n; + + // Check source files and mtime + int zone_status = check_zone(zone->db, zone->file); + if (zone_status == KNOTD_EOK) { + printf("Zone '%s' is up-to-date.\n", + zone->name); + + if (force) { + fprintf(stderr, "control: forcing " + "zone recompilation.\n"); + } else { + continue; + } + } + + // Check for not existing source + if (zone_status == KNOTD_ENOENT) { + continue; + } + + /* Evaluate space for new task. */ + if (running == jobs) { + zctask_wait(tasks, jobs); + --running; + } + + const char *args[] = { + ZONEPARSER_EXEC, + zone->enable_checks ? "-s" : "", + verbose ? "-v" : "", + "-o", + zone->db, + zone->name, + zone->file + }; + + // Execute command + if (verbose) { + printf("Compiling '%s' as '%s'...\n", + zone->name, zone->db); + } + fflush(stdout); + fflush(stderr); + pid_t zcpid = start_cmd(args, 7); + zctask_add(tasks, jobs, zcpid, zone); + ++running; + } + + /* Wait for all running tasks. */ + while (running > 0) { + zctask_wait(tasks, jobs); + --running; + } + free(tasks); + + // Unlock configuration + conf_read_unlock(); + } + if (!valid_cmd) { + fprintf(stderr, "Invalid command: '%s'\n", action); + return 1; + } + + // Log + if (verbose) { + printf("'%s' finished (return code %d)\n", action, rc); + } + return rc; +} + +int main(int argc, char **argv) +{ + // Parse command line arguments + int c = 0, li = 0; + int force = 0; + int verbose = 0; + int wait = 0; + int interactive = 0; + int jobs = 1; + const char* config_fn = 0; + + /* Long options. */ + struct option opts[] = { + {"wait", no_argument, 0, 'w'}, + {"force", no_argument, 0, 'f'}, + {"config", required_argument, 0, 'c'}, + {"verbose", no_argument, 0, 'v'}, + {"interactive", no_argument, 0, 'i'}, + {"jobs", required_argument, 0, 'c'}, + {"version", no_argument, 0, 'V'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + while ((c = getopt_long(argc, argv, "wfc:vij:Vh", opts, &li)) != -1) { + switch (c) + { + case 'w': + wait = 1; + break; + case 'f': + force = 1; + break; + case 'c': + config_fn = optarg; + break; + case 'v': + verbose = 1; + break; + case 'i': + interactive = 1; + break; + case 'j': + jobs = atoi(optarg); + if (jobs < 1) { + fprintf(stderr, "Invalid parameter '%s' to " + "'-j', expects number <1..n>\n", + optarg); + help(argc, argv); + return 1; + } + break; + case 'V': + printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION); + return 0; + case 'h': + case '?': + default: + help(argc, argv); + return 1; + } + } + + // Check if there's at least one remaining non-option + if (argc - optind < 1) { + help(argc, argv); + return 1; + } + + // Initialize log (no output) + log_init(); + log_levels_set(LOGT_SYSLOG, LOG_ANY, 0); + log_levels_set(LOGT_STDOUT, LOG_ANY, 0); + closelog(); + + // Find implicit configuration file + char *default_fn = 0; + if (!config_fn) { + default_fn = conf_find_default(); + config_fn = default_fn; + } + + // Open configuration + if (conf_open(config_fn) != 0) { + fprintf(stderr, "Failed to parse configuration '%s'.\n", + config_fn); + free(default_fn); + return 1; + } + + // Free default config filename if exists + free(default_fn); + + // Verbose mode + if (verbose) { + int mask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG); + log_levels_add(LOGT_STDOUT, LOG_ANY, mask); + } + + // Fetch PID + char* pidfile = pid_filename(); + if (!pidfile) { + fprintf(stderr, "No configuration found, " + "please specify with '-c' parameter.\n"); + log_close(); + return 1; + } + + pid_t pid = pid_read(pidfile); + + // Actions + const char* action = argv[optind]; + + // Execute action + int rc = execute(action, argv + optind + 1, argc - optind - 1, + pid, verbose, force, wait, interactive, jobs, pidfile); + + // Finish + free(pidfile); + log_close(); + return rc; +} diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c new file mode 100644 index 0000000..e46fa37 --- /dev/null +++ b/src/knot/ctl/process.c @@ -0,0 +1,126 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <signal.h> + +#include "knot/common.h" +#include "knot/ctl/process.h" +#include "knot/conf/conf.h" +#include "knot/other/error.h" + +char* pid_filename() +{ + conf_read_lock(); + + /* Read configuration. */ + char* ret = 0; + if (conf()) { + ret = strdup(conf()->pidfile); + } + + conf_read_unlock(); + + return ret; +} + +pid_t pid_read(const char* fn) +{ + char buf[64]; + + if (fn) { + FILE *fp = fopen(fn, "r"); + if (!fp) { + return KNOTD_ENOENT; + } + + int readb = 0; + int rc = fread(buf, 1, 1, fp); + while (rc > 0) { + if (++readb == sizeof(buf) - 1) { + break; + } + rc = fread(buf + readb, 1, 1, fp); + } + buf[readb] = '\0'; + fclose(fp); + + // Check read result + if (readb < 1) { + return KNOTD_ENOENT; + } + + // Convert pid + char* ep = 0; + unsigned long pid = strtoul(buf, &ep, 10); + if ((errno == ERANGE) || (*ep && !isspace(*ep))) { + return KNOTD_ERANGE; + } + + return (pid_t)pid; + } + + return KNOTD_EINVAL; +} + +int pid_write(const char* fn) +{ + if (!fn) { + return KNOTD_EINVAL; + } + + // Convert + char buf[64]; + int wbytes = 0; + wbytes = snprintf(buf, sizeof(buf), "%lu", (unsigned long) getpid()); + if (wbytes < 0) { + return KNOTD_EINVAL; + } + + // Write + FILE *fp = fopen(fn, "w"); + if (fp) { + int rc = fwrite(buf, wbytes, 1, fp); + fclose(fp); + if (rc < 0) { + return KNOTD_ERROR; + } + + return 0; + } + + return KNOTD_ENOENT; +} + +int pid_remove(const char* fn) +{ + if (unlink(fn) < 0) { + return KNOTD_EINVAL; + } + + return KNOTD_EOK; +} + +int pid_running(pid_t pid) +{ + return kill(pid, 0) == 0; +} + diff --git a/src/knot/ctl/process.h b/src/knot/ctl/process.h new file mode 100644 index 0000000..d8f2f4c --- /dev/null +++ b/src/knot/ctl/process.h @@ -0,0 +1,88 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file process.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Functions for POSIX process handling. + * + * \addtogroup ctl + * @{ + */ + +#ifndef _KNOTD_PROCESS_H_ +#define _KNOTD_PROCESS_H_ + +#include <unistd.h> + +/*! + * \brief Return a filename of the default compiled database file. + * + * \retval Filename of the database file. + * \retval NULL if not exists. + */ +char* pid_filename(); + +/*! + * \brief Read PID from given file. + * + * \param fn Filename containing PID. + * + * \retval PID on success (positive integer). + * \retval KNOTD_EINVAL on null path. + * \retval KNOTD_ENOENT if the filename content cannot be read. + * \retval KNOTD_ERANGE if the stored PID is out of range. + */ +pid_t pid_read(const char* fn); + +/*! + * \brief Write PID to given file. + * + * \param fn Filename containing PID. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on null path. + * \retval KNOTD_ENOENT filename cannot be opened for writing. + * \retval KNOTD_ERROR unspecified error. + */ +int pid_write(const char* fn); + +/*! + * \brief Remove file containing PID. + * + * \param fn Filename containing PID. + * + * \warning Filename content won't be checked. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL failed to remove filename. + */ +int pid_remove(const char* fn); + +/*! + * \brief Return true if the PID is running. + * + * \param pid Process ID. + * + * \retval 1 if running. + * \retval 0 if not running (or error). + */ +int pid_running(pid_t pid); + +#endif // _KNOTD_PROCESS_H_ + +/*! @} */ diff --git a/src/knot/main.c b/src/knot/main.c new file mode 100644 index 0000000..4091055 --- /dev/null +++ b/src/knot/main.c @@ -0,0 +1,336 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <getopt.h> +#include "common.h" + +#include "knot/common.h" +#include "knot/other/error.h" +#include "knot/server/server.h" +#include "zcompile/zcompile.h" +#include "knot/ctl/process.h" +#include "knot/conf/conf.h" +#include "knot/conf/logconf.h" +#include "common/evqueue.h" +#include "knot/server/zones.h" + +/*----------------------------------------------------------------------------*/ + +/* Signal flags. */ +static volatile short sig_req_stop = 0; +static volatile short sig_req_reload = 0; +static volatile short sig_stopping = 0; + +// SIGINT signal handler +void interrupt_handle(int s) +{ + // Reload configuration + if (s == SIGHUP) { + sig_req_reload = 1; + return; + } + + // Stop server + if (s == SIGINT || s == SIGTERM) { + if (sig_stopping == 0) { + sig_req_stop = 1; + sig_stopping = 1; + } else { + log_server_notice("OK! Exiting immediately.\n"); + exit(1); + } + } +} + +void help(int argc, char **argv) +{ + printf("Usage: %sd [parameters]\n", + PACKAGE_NAME); + printf("Parameters:\n" + " -c, --config [file] Select configuration file.\n" + " -d, --daemonize Run server as a daemon.\n" + " -v, --verbose Verbose mode - additional runtime information.\n" + " -V, --version Print version of the server.\n" + " -h, --help Print help and usage.\n"); +} + +int main(int argc, char **argv) +{ + // Parse command line arguments + int c = 0, li = 0; + int verbose = 0; + int daemonize = 0; + char* config_fn = 0; + + /* Long options. */ + struct option opts[] = { + {"config", required_argument, 0, 'c'}, + {"daemonize", no_argument, 0, 'd'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + while ((c = getopt_long(argc, argv, "c:dvVh", opts, &li)) != -1) { + switch (c) + { + case 'c': + config_fn = strdup(optarg); + break; + case 'd': + daemonize = 1; + break; + case 'v': + verbose = 1; + break; + case 'V': + printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION); + return 0; + case 'h': + case '?': + default: + help(argc, argv); + return 1; + } + } + + // Now check if we want to daemonize + if (daemonize) { + if (daemon(1, 0) != 0) { + fprintf(stderr, "Daemonization failed, " + "shutting down...\n"); + return 1; + } + } + + // Register service and signal handler + struct sigaction emptyset; + emptyset.sa_handler = interrupt_handle; + sigemptyset(&emptyset.sa_mask); + emptyset.sa_flags = 0; + sigaction(SIGALRM, &emptyset, NULL); // Interrupt + + // Setup event queue + evqueue_set(evqueue_new()); + + // Initialize log + log_init(); + + // Verbose mode + if (verbose) { + int mask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG); + log_levels_add(LOGT_STDOUT, LOG_ANY, mask); + } + + // Initialize pseudorandom number generator + srand(time(0)); + + // Create server + server_t *server = server_create(); + + // Initialize configuration + conf_read_lock(); + conf_add_hook(conf(), CONF_LOG, log_conf_hook, 0); + conf_add_hook(conf(), CONF_LOG, zones_ns_conf_hook, server->nameserver); + conf_add_hook(conf(), CONF_LOG, server_conf_hook, server); + conf_read_unlock(); + + // Find implicit configuration file + if (!config_fn) { + config_fn = conf_find_default(); + } + + // Find absolute path for config file + if (config_fn[0] != '/') + { + // Get absolute path to cwd + size_t cwbuflen = 64; + char *cwbuf = malloc((cwbuflen + 2) * sizeof(char)); + while (getcwd(cwbuf, cwbuflen) == 0) { + cwbuflen *= 2; + cwbuf = realloc(cwbuf, (cwbuflen + 2) * sizeof(char)); + } + cwbuflen = strlen(cwbuf); + + // Append ending slash + if (cwbuf[cwbuflen - 1] != '/') { + cwbuf = strcat(cwbuf, "/"); + } + + // Assemble path to config file + char *abs_cfg = strcdup(cwbuf, config_fn); + free(config_fn); + free(cwbuf); + config_fn = abs_cfg; + } + + // Open configuration + log_server_info("Parsing configuration '%s' ...\n", config_fn); + if (conf_open(config_fn) != KNOTD_EOK) { + + log_server_error("Failed to parse configuration file '%s'.\n", + config_fn); + server_destroy(&server); + free(config_fn); + return 1; + } else { + log_server_info("Configured %d interfaces and %d zones.\n", + conf()->ifaces_count, conf()->zones_count); + } + log_server_info("\n"); + + // Create server instance + char* pidfile = pid_filename(); + + // Run server + int res = 0; + log_server_info("Starting server...\n"); + if ((res = server_start(server)) == KNOTD_EOK) { + + // Save PID + int has_pid = 1; + int rc = pid_write(pidfile); + if (rc < 0) { + has_pid = 0; + log_server_warning("Failed to create " + "PID file '%s'.\n", pidfile); + } + + // Change directory if daemonized + if (daemonize) { + log_server_info("Server started as a daemon, " + "PID = %ld\n", (long)getpid()); + res = chdir("/"); + } else { + log_server_info("Server started in foreground, " + "PID = %ld\n", (long)getpid()); + } + if (has_pid) { + log_server_info("PID stored in %s\n", pidfile); + } else { + log_server_warning("Server running without PID file.\n"); + } + size_t zcount = server->nameserver->zone_db->zone_count; + if (!zcount) { + log_server_warning("Server started, but no zones served.\n"); + } + + // Setup signal handler + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = interrupt_handle; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sa.sa_flags = 0; + pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL); + + /* Run event loop. */ + for(;;) { + pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL); + int ret = evqueue_poll(evqueue(), 0, 0); + pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL); + + /* Interrupts. */ + /*! \todo More robust way to exit evloop. + * Event loop should exit with a special + * event. + */ + if (sig_req_stop) { + sig_req_stop = 0; + server_stop(server); + break; + } + if (sig_req_reload) { + log_server_info("Reloading configuration...\n"); + sig_req_reload = 0; + int cf_ret = cf_ret = conf_open(config_fn); + switch (cf_ret) { + case KNOTD_EOK: + log_server_info("Configuration " + "reloaded.\n"); + break; + case KNOTD_ENOENT: + log_server_error("Configuration " + "file '%s' " + "not found.\n", + conf()->filename); + break; + default: + log_server_error("Configuration " + "reload failed.\n"); + break; + } + } + + /* Events. */ + if (ret > 0) { + event_t ev; + if (evqueue_get(evqueue(), &ev) == 0) { + dbg_server_verb("Event: " + "received new event.\n"); + if (ev.cb) { + ev.cb(&ev); + } + } + } + } + pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL); + + if ((res = server_wait(server)) != KNOTD_EOK) { + log_server_error("An error occured while " + "waiting for server to finish.\n"); + } else { + log_server_info("Server finished.\n"); + } + + } else { + log_server_fatal("An error occured while " + "starting the server.\n"); + } + + // Stop server and close log + server_destroy(&server); + + // Remove PID file + if (pid_remove(pidfile) < 0) { + log_server_warning("Failed to remove PID file.\n"); + } + + log_server_info("Shut down.\n"); + log_close(); + free(pidfile); + + // Destroy event loop + evqueue_t *q = evqueue(); + evqueue_free(&q); + + // Free default config filename if exists + free(config_fn); + + if (!daemonize) { + fflush(stdout); + fflush(stderr); + } + + return res; +} diff --git a/src/knot/other/debug.h b/src/knot/other/debug.h new file mode 100644 index 0000000..aa80373 --- /dev/null +++ b/src/knot/other/debug.h @@ -0,0 +1,426 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file other/debug.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Debugging facility, uses log.h. + * + * \addtogroup debugging + * @{ + */ + +#ifndef _KNOTD_DEBUG_H_ +#define _KNOTD_DEBUG_H_ + +#include "config.h" /* autoconf generated */ + +#include "knot/other/log.h" +#include "common/print.h" + +/*! \todo Set these during configure as well. */ +//#define KNOTD_SERVER_DEBUG +//#define KNOTD_THREADS_DEBUG +//#define KNOTD_JOURNAL_DEBUG +//#define KNOTD_NET_DEBUG +//#define KNOTD_ZONES_DEBUG +//#define KNOTD_XFR_DEBUG +//#define KNOTD_NOTIFY_DEBUG +//#define KNOTD_ZDUMP_DEBUG +//#define KNOTD_ZLOAD_DEBUG + +/******************************************************************************/ + +#ifdef KNOTD_NOTIFY_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_notify(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_notify_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_notify(msg...) +#define dbg_notify_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_notify_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_notify_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_notify_verb(msg...) +#define dbg_notify_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_notify_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_notify_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_notify_detail(msg...) +#define dbg_notify_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_notify(msg...) +#define dbg_notify_hex(data, len) +#define dbg_notify_verb(msg...) +#define dbg_notify_hex_verb(data, len) +#define dbg_notify_detail(msg...) +#define dbg_notify_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_SERVER_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_server(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_server_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_server(msg...) +#define dbg_server_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_server_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_server_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_server_verb(msg...) +#define dbg_server_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_server_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_server_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_server_detail(msg...) +#define dbg_server_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_server(msg...) +#define dbg_server_hex(data, len) +#define dbg_server_verb(msg...) +#define dbg_server_hex_verb(data, len) +#define dbg_server_detail(msg...) +#define dbg_server_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_NET_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_net(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_net_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_net(msg...) +#define dbg_net_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_net_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_net_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_net_verb(msg...) +#define dbg_net_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_net_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_net_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_net_detail(msg...) +#define dbg_net_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_net(msg...) +#define dbg_net_hex(data, len) +#define dbg_net_verb(msg...) +#define dbg_net_hex_verb(data, len) +#define dbg_net_detail(msg...) +#define dbg_net_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_THREADS_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_dt(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_dt_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_dt(msg...) +#define dbg_dt_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_dt_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_dt_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_dt_verb(msg...) +#define dbg_dt_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_dt_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_dt_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_dt_detail(msg...) +#define dbg_dt_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_dt(msg...) +#define dbg_dt_hex(data, len) +#define dbg_dt_verb(msg...) +#define dbg_dt_hex_verb(data, len) +#define dbg_dt_detail(msg...) +#define dbg_dt_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_JOURNAL_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_journal(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_journal_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_journal(msg...) +#define dbg_journal_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_journal_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_journal_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_journal_verb(msg...) +#define dbg_journal_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_journal_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_journal_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_journal_detail(msg...) +#define dbg_journal_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_journal(msg...) +#define dbg_journal_hex(data, len) +#define dbg_journal_verb(msg...) +#define dbg_journal_hex_verb(data, len) +#define dbg_journal_detail(msg...) +#define dbg_journal_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_ZONES_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zones(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zones_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#define dbg_zones_exec(cmds) do { cmds } while (0) +#else +#define dbg_zones(msg...) +#define dbg_zones_hex(data, len) +#define dbg_zones_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zones_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zones_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#define dbg_zones_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_zones_verb(msg...) +#define dbg_zones_hex_verb(data, len) +#define dbg_zones_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zones_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zones_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#define dbg_zones_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_zones_detail(msg...) +#define dbg_zones_hex_detail(data, len) +#define dbg_zones_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_zones(msg...) +#define dbg_zones_hex(data, len) +#define dbg_zones_verb(msg...) +#define dbg_zones_hex_verb(data, len) +#define dbg_zones_detail(msg...) +#define dbg_zones_hex_detail(data, len) +#define dbg_zones_exec(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_XFR_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_xfr(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_xfr_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_xfr(msg...) +#define dbg_xfr_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_xfr_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_xfr_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_xfr_verb(msg...) +#define dbg_xfr_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_xfr_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_xfr_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_xfr_detail(msg...) +#define dbg_xfr_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_xfr(msg...) +#define dbg_xfr_hex(data, len) +#define dbg_xfr_verb(msg...) +#define dbg_xfr_hex_verb(data, len) +#define dbg_xfr_detail(msg...) +#define dbg_xfr_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_ZDUMP_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zdump(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zdump_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zdump(msg...) +#define dbg_zdump_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zdump_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zdump_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zdump_verb(msg...) +#define dbg_zdump_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zdump_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zdump_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zdump_detail(msg...) +#define dbg_zdump_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_zdump(msg...) +#define dbg_zdump_hex(data, len) +#define dbg_zdump_verb(msg...) +#define dbg_zdump_hex_verb(data, len) +#define dbg_zdump_detail(msg...) +#define dbg_zdump_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOTD_ZLOAD_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zload(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zload_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zload(msg...) +#define dbg_zload_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zload_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zload_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zload_verb(msg...) +#define dbg_zload_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zload_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zload_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zload_detail(msg...) +#define dbg_zload_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_zload(msg...) +#define dbg_zload_hex(data, len) +#define dbg_zload_verb(msg...) +#define dbg_zload_hex_verb(data, len) +#define dbg_zload_detail(msg...) +#define dbg_zload_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#endif /* _KNOTD_DEBUG_H_ */ + +/*! @} */ diff --git a/src/knot/other/error.c b/src/knot/other/error.c new file mode 100644 index 0000000..a149966 --- /dev/null +++ b/src/knot/other/error.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "knot/other/error.h" +#include "common/errors.h" + +const error_table_t knotd_error_msgs[] = { + + /* Mapped errors. */ + {KNOTD_EOK, "OK"}, + {KNOTD_ENOMEM, "Not enough memory."}, + {KNOTD_EINVAL, "Invalid parameter passed."}, + {KNOTD_ENOTSUP, "Parameter not supported."}, + {KNOTD_EBUSY, "Requested resource is busy."}, + {KNOTD_EAGAIN, "The system lacked the necessary resource, try again."}, + {KNOTD_EACCES, "Permission to perform requested operation is denied."}, + {KNOTD_ECONNREFUSED, "Connection is refused."}, + {KNOTD_EISCONN, "Already connected."}, + {KNOTD_EADDRINUSE, "Address already in use."}, + {KNOTD_ENOENT, "Resource not found."}, + {KNOTD_ERANGE, "Value is out of range."}, + + /* Custom errors. */ + {KNOTD_ERROR, "Generic error."}, + {KNOTD_EZONEINVAL, "Invalid zone file."}, + {KNOTD_ENOTRUNNING, "Resource is not running."}, + {KNOTD_EPARSEFAIL, "Parser failed."}, + {KNOTD_ENOIPV6, "IPv6 support disabled."}, + {KNOTD_EMALF, "Malformed data."}, + {KNOTD_ESPACE, "Not enough space provided."}, + {KNOTD_EEXPIRED, "Resource is expired."}, + {KNOTD_ERROR, 0} +}; diff --git a/src/knot/other/error.h b/src/knot/other/error.h new file mode 100644 index 0000000..65c51cf --- /dev/null +++ b/src/knot/other/error.h @@ -0,0 +1,99 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file other/error.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Error codes and function for getting error message. + * + * \addtogroup utils + * @{ + */ + +#ifndef _KNOTD__ERROR_H_ +#define _KNOTD__ERROR_H_ + +#include <errno.h> + +#include "common/errors.h" + +/*! + * \brief Error codes used in the server. + * + * Some viable errors are directly mapped + * to libc errno codes. + */ +enum knot_error_t { + + /* Directly mapped error codes. */ + KNOTD_EOK = 0, + KNOTD_ENOMEM = -ENOMEM, /*!< \brief Out of memory. */ + KNOTD_EINVAL = -EINVAL, /*!< \brief Invalid parameter passed. */ + KNOTD_ENOTSUP = -ENOTSUP, /*!< \brief Parameter not supported. */ + KNOTD_EBUSY = -EBUSY, /*!< \brief Requested resource is busy. */ + KNOTD_EAGAIN = -EAGAIN, /*!< \brief OS lacked necessary resources. */ + KNOTD_EACCES = -EACCES, /*!< \brief Permission is denied. */ + KNOTD_ECONNREFUSED = -ECONNREFUSED, /*!< \brief Connection is refused. */ + KNOTD_EISCONN = -EISCONN, /*!< \brief Already connected. */ + KNOTD_EADDRINUSE = -EADDRINUSE, /*!< \brief Address already in use. */ + KNOTD_ENOENT = -ENOENT, /*!< \brief Resource not found. */ + KNOTD_ERANGE = -ERANGE, /*!< \brief Value is out of range. */ + + /* Custom error codes. */ + KNOTD_ERROR = -16384, /*!< \brief Generic error. */ + KNOTD_EZONEINVAL, /*!< \brief Invalid zone file. */ + KNOTD_ENOTRUNNING, /*!< \brief Resource is not running. */ + KNOTD_EPARSEFAIL, /*!< \brief Parser fail. */ + KNOTD_ENOIPV6, /*!< \brief No IPv6 support. */ + KNOTD_EMALF, /*!< \brief Malformed data. */ + KNOTD_ESPACE, /*!< \brief Not enough space provided. */ + KNOTD_EEXPIRED, /*!< \brief Resource is expired. */ + + KNOTD_ERROR_COUNT = 21 +}; + +/*! \brief Table linking error messages to error codes. */ +extern const error_table_t knotd_error_msgs[KNOTD_ERROR_COUNT]; + +/*! + * \brief Returns error message for the given error code. + * + * \param code Error code. + * + * \return String containing the error message. + */ +static inline const char *knotd_strerror(int code) +{ + return error_to_str((const error_table_t*)knotd_error_msgs, code); +} + +/*! + * \brief errno mapper that automatically prepends fallback value. + * + * \see map_errno() + * + * \param err POSIX errno. + * \param ... List of handled codes. + * + * \return Mapped error code. + */ +#define knot_map_errno(err...) map_errno(KNOTD_ERROR, err); + +#endif /* _KNOTD__ERROR_H_ */ + +/*! @} */ diff --git a/src/knot/other/log.c b/src/knot/other/log.c new file mode 100644 index 0000000..9318d5f --- /dev/null +++ b/src/knot/other/log.c @@ -0,0 +1,305 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "knot/common.h" +#include "knot/other/error.h" +#include "knot/other/log.h" +#include "common/lists.h" +#include "knot/conf/conf.h" + +/*! Log source table. */ +static uint8_t *LOG_FCL = 0; +static volatile size_t LOG_FCL_SIZE = 0; +static FILE** LOG_FDS = 0; +static ssize_t LOG_FDS_OPEN = 0; + +#define facility_at(i) (LOG_FCL + ((i) << LOG_SRC_BITS)) +#define facility_next(f) (f) += (1 << LOG_SRC_BITS) +#define facility_levels(f, i) *((f) + (i)) + +int log_setup(int logfiles) +{ + /* Check facilities count. */ + if (logfiles < 0) { + return KNOTD_EINVAL; + } + + /* Ensure minimum facilities count. */ + int facilities = LOGT_FILE + logfiles; + + /* Reserve space for facilities. */ + size_t new_size = facilities << LOG_SRC_BITS; + LOG_FDS = 0; + LOG_FDS_OPEN = 0; + LOG_FCL = 0; + LOG_FCL_SIZE = 0; + LOG_FCL = malloc(new_size); + if (!LOG_FCL) { + return KNOTD_ENOMEM; + } + + /* Reserve space for logfiles. */ + if (logfiles > 0) { + LOG_FDS = malloc(sizeof(FILE*) * logfiles); + if (!LOG_FDS) { + free(LOG_FCL); + LOG_FCL = 0; + return KNOTD_ENOMEM; + } + memset(LOG_FDS, 0, sizeof(FILE*) * logfiles); + } + + memset(LOG_FCL, 0, new_size); + LOG_FCL_SIZE = new_size; // Assign only when all is set + return KNOTD_EOK; +} + + + +int log_init() +{ + /* Initialize globals. */ + LOG_FCL = 0; + LOG_FCL_SIZE = 0; + LOG_FDS = 0; + LOG_FDS_OPEN = 0; + + /* Setup initial state. */ + int ret = KNOTD_EOK; + int emask = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR)|LOG_MASK(LOG_FATAL); + int imask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_NOTICE); + + /* Add debug messages. */ + emask |= LOG_MASK(LOG_DEBUG); + + ret = log_setup(0); + log_levels_set(LOGT_SYSLOG, LOG_ANY, emask); + log_levels_set(LOGT_STDERR, LOG_ANY, emask); + log_levels_set(LOGT_STDOUT, LOG_ANY, imask); + + /// \todo May change to LOG_DAEMON. + setlogmask(LOG_UPTO(LOG_DEBUG)); + openlog(PACKAGE_NAME, LOG_PID, LOG_DAEMON); + return ret; +} + +void log_close() +{ + log_truncate(); + closelog(); +} + +void log_truncate() +{ + LOG_FCL_SIZE = 0; + if (LOG_FCL) { + free(LOG_FCL); + LOG_FCL = 0; + } + if (LOG_FDS) { + + /* Close open logfiles. */ + for (int i = 0; i < LOG_FDS_OPEN; ++i) { + fclose(LOG_FDS[i]); + } + + free(LOG_FDS); + LOG_FDS = 0; + LOG_FDS_OPEN = 0; + } +} + +int log_isopen() +{ + return LOG_FCL_SIZE; +} + +int log_open_file(const char* filename) +{ + // Check facility + if (unlikely(!LOG_FCL_SIZE || LOGT_FILE + LOG_FDS_OPEN >= LOG_FCL_SIZE)) { + return KNOTD_ERROR; + } + + // Open file + LOG_FDS[LOG_FDS_OPEN] = fopen(filename, "w"); + if (!LOG_FDS[LOG_FDS_OPEN]) { + return KNOTD_EINVAL; + } + + // Disable buffering + setvbuf(LOG_FDS[LOG_FDS_OPEN], (char *)0, _IONBF, 0); + + return LOGT_FILE + LOG_FDS_OPEN++; +} + +uint8_t log_levels(int facility, logsrc_t src) +{ + // Check facility + if (unlikely(!LOG_FCL_SIZE || facility >= LOG_FCL_SIZE)) { + return 0; + } + + return *(LOG_FCL + (facility << LOG_SRC_BITS) + src); +} + +int log_levels_set(int facility, logsrc_t src, uint8_t levels) +{ + // Check facility + if (unlikely(!LOG_FCL_SIZE || facility >= LOG_FCL_SIZE)) { + return KNOTD_EINVAL; + } + + // Get facility pointer from offset + uint8_t *lp = LOG_FCL + (facility << LOG_SRC_BITS); + + // Assign level if not multimask + if (src != LOG_ANY) { + *(lp + src) = levels; + } else { + // Any == set to all sources + for (int i = 0; i <= LOG_ANY; ++i) { + *(lp + i) = levels; + } + } + + return KNOTD_EOK; +} + +int log_levels_add(int facility, logsrc_t src, uint8_t levels) +{ + uint8_t new_levels = log_levels(facility, src) | levels; + return log_levels_set(facility, src, new_levels); +} + +static int _log_msg(logsrc_t src, int level, const char *msg) +{ + if(!log_isopen()) { + return KNOTD_ERROR; + } + + int ret = 0; + FILE *stream = stdout; + uint8_t *f = facility_at(LOGT_SYSLOG); + + // Syslog + if (facility_levels(f, src) & LOG_MASK(level)) { + syslog(level, "%s", msg); + ret = 1; // To prevent considering the message as ignored. + } + + // Convert level to mask + level = LOG_MASK(level); + + // Log streams + for (int i = LOGT_STDERR; i < LOGT_FILE + LOG_FDS_OPEN; ++i) { + + // Check facility levels mask + f = facility_at(i); + if (facility_levels(f, src) & level) { + + // Select stream + switch(i) { + case LOGT_STDERR: stream = stderr; break; + case LOGT_STDOUT: stream = stdout; break; + default: stream = LOG_FDS[i - LOGT_FILE]; break; + } + + // Print + ret = fprintf(stream, "%s", msg); + if (stream == stdout) { + fflush(stream); + } + } + } + + if (ret < 0) { + return KNOTD_EINVAL; + } + + return ret; +} + +int log_msg(logsrc_t src, int level, const char *msg, ...) +{ + /* Buffer for log message. */ + char sbuf[4096]; + char *buf = sbuf; + int buflen = sizeof(sbuf) - 1; + + /* Prefix error level. */ + const char *prefix = ""; + switch (level) { + case LOG_DEBUG: break; + case LOG_INFO: break; + case LOG_NOTICE: prefix = "notice: "; break; + case LOG_WARNING: prefix = "warning: "; break; + case LOG_ERR: prefix = "error: "; break; + case LOG_FATAL: prefix = "fatal: "; break; + default: break; + } + + /* Prepend prefix. */ + int plen = strlen(prefix); + if (plen > 0) { + strcpy(buf, prefix); + buf += plen; + buflen -= plen; + } + + /* Compile log message. */ + int ret = 0; + va_list ap; + va_start(ap, msg); + ret = vsnprintf(buf, buflen, msg, ap); + va_end(ap); + + /* Send to logging facilities. */ + if (ret > 0) { + ret = _log_msg(src, level, sbuf); + } + + return ret; +} + +int log_vmsg(logsrc_t src, int level, const char *msg, va_list ap) +{ + int ret = 0; + char buf[2048]; + ret = vsnprintf(buf, sizeof(buf) - 1, msg, ap); + + if (ret > 0) { + ret = _log_msg(src, level, buf); + } + + return ret; +} + +void hex_log(int source, const char *data, int length) +{ + int ptr = 0; + for (; ptr < length; ptr++) { + log_msg(source, LOG_DEBUG, "0x%02x ", + (unsigned char)*(data + ptr)); + } + log_msg(source, LOG_DEBUG, "\n"); +} diff --git a/src/knot/other/log.h b/src/knot/other/log.h new file mode 100644 index 0000000..305020c --- /dev/null +++ b/src/knot/other/log.h @@ -0,0 +1,208 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file log.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Logging facility. + * + * \note Loglevel defined in syslog.h, may be redefined in other backend, but + * keep naming. LOG_FATAL, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG + * + * In standard mode, only LOG_FATAL, LOG_ERR and LOG_WARNING is logged. + * Verbose mode enables LOG_NOTICE and LOG_INFO for additional information. + * + * \addtogroup logging + * @{ + */ + +#ifndef _KNOTD_LOG_H_ +#define _KNOTD_LOG_H_ + +/* + */ +#include <syslog.h> +#include <stddef.h> +#include <stdint.h> +#include <stdarg.h> + +/*! \brief Log facility types. */ +typedef enum { + LOGT_SYSLOG = 0, /*!< Logging to syslog(3) facility. */ + LOGT_STDERR = 1, /*!< Print log messages to the stderr. */ + LOGT_STDOUT = 2, /*!< Print log messages to the stdout. */ + LOGT_FILE = 3 /*!< Generic logging to (unbuffered) file on the disk. */ +} logtype_t; + +/*! \brief Log sources width (bits). */ +#define LOG_SRC_BITS 3 + +/*! \brief Log sources (max. LOG_SRC_BITS bits). */ +typedef enum { + LOG_SERVER = 0, /*!< Server module. */ + LOG_ANSWER = 1, /*!< Query answering module. */ + LOG_ZONE = 2, /*!< Zone manipulation module. */ + LOG_ANY = 7 /*!< Any module. */ +} logsrc_t; + +/*! \brief Severity mapping. */ +#define LOG_FATAL LOG_CRIT /*!< Fatal errors cannot be masked. */ + +/* Logging facility setup. */ + +/*! + * \brief Create logging facilities respecting their + * canonical order. + * + * Facilities ordering: Syslog, Stderr, Stdout, File0... + * \see logtype_t + * + * \param logfiles Number of extra logfiles. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid number of logfiles (negative). + */ +int log_setup(int logfiles); + +/*! + * \brief Setup logging subsystem. + * + * \see syslog.h + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ENOMEM out of memory error. + */ +int log_init(); + +/*! + * \brief Close and deinitialize log. + */ +void log_close(); + +/*! + * \brief Truncate current log setup. + */ +void log_truncate(); + +/*! + * \brief Return positive number if open. + * + * \return 1 if open (boolean true) + * \return 0 if closed (boolean false) + */ +int log_isopen(); + +/*! + * \brief Open file as a logging facility. + * + * \param filename File path. + * + * \retval associated facility index on success. + * \retval KNOTD_EINVAL filename cannot be opened for writing. + * \retval KNOTD_ERROR unspecified error. + */ +int log_open_file(const char* filename); + +/*! + * \brief Return log levels for a given facility. + * + * \param facility Given log facility index. + * \param src Given log source in the context of current facility. + * + * \retval Associated log level flags on success. + * \retval 0 on error. + */ +uint8_t log_levels(int facility, logsrc_t src); + +/*! + * \brief Set log levels for given facility. + * + * \param facility Logging facility index (LOGT_SYSLOG...). + * \param src Logging source (LOG_SERVER...LOG_ANY). + * \param levels Bitmask of specified log levels. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters (facility out of range). + */ +int log_levels_set(int facility, logsrc_t src, uint8_t levels); + +/*! + * \brief Add log levels to a given facility. + * + * New levels are added on top of existing, the resulting + * levels set is "old_levels OR new_levels". + * + * \param facility Logging facility index (LOGT_SYSLOG...). + * \param src Logging source (LOG_SERVER...LOG_ANY). + * \param levels Bitmask of specified log levels. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters (facility out of range). + */ +int log_levels_add(int facility, logsrc_t src, uint8_t levels); + +/*! + * \brief Log message. + * + * Function follows printf() format. + * + * \param src Origin of the message. + * \param level Message error level. + * \param msg Content of the logged message. + * + * \retval Number of logged bytes on success. + * \retval 0 When the message is ignored. + * \retval KNOTD_EINVAL invalid parameters. + * \retval KNOTD_ERROR unspecified error. + */ +int log_msg(logsrc_t src, int level, const char *msg, ...) + __attribute__((format(printf, 3, 4))); + +/*! + * \brief Log message for stdarg. + * + * \see log_msg + */ +int log_vmsg(logsrc_t src, int level, const char *msg, va_list ap); + +void hex_log(int source, const char *data, int length); + +/* Convenient logging. */ +#define log_server_fatal(msg...) log_msg(LOG_SERVER, LOG_FATAL, msg) +#define log_server_error(msg...) log_msg(LOG_SERVER, LOG_ERR, msg) +#define log_server_warning(msg...) log_msg(LOG_SERVER, LOG_WARNING, msg) +#define log_server_notice(msg...) log_msg(LOG_SERVER, LOG_NOTICE, msg) +#define log_server_info(msg...) log_msg(LOG_SERVER, LOG_INFO, msg) +#define log_server_debug(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) + +#define log_answer_fatal(msg...) log_msg(LOG_ANSWER, LOG_FATAL, msg) +#define log_answer_error(msg...) log_msg(LOG_ANSWER, LOG_ERR, msg) +#define log_answer_warning(msg...) log_msg(LOG_ANSWER, LOG_WARNING, msg) +#define log_answer_notice(msg...) log_msg(LOG_ANSWER, LOG_NOTICE, msg) +#define log_answer_info(msg...) log_msg(LOG_ANSWER, LOG_INFO, msg) +#define log_answer_debug(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg) + +#define log_zone_fatal(msg...) log_msg(LOG_ZONE, LOG_FATAL, msg) +#define log_zone_error(msg...) log_msg(LOG_ZONE, LOG_ERR, msg) +#define log_zone_warning(msg...) log_msg(LOG_ZONE, LOG_WARNING, msg) +#define log_zone_notice(msg...) log_msg(LOG_ZONE, LOG_NOTICE, msg) +#define log_zone_info(msg...) log_msg(LOG_ZONE, LOG_INFO, msg) +#define log_zone_debug(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) + +#endif /* _KNOTD_LOG_H_ */ + +/*! @} */ diff --git a/src/knot/server/dthreads.c b/src/knot/server/dthreads.c new file mode 100644 index 0000000..9707e57 --- /dev/null +++ b/src/knot/server/dthreads.c @@ -0,0 +1,1006 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> + +#include "knot/common.h" +#include "knot/server/dthreads.h" +#include "knot/other/log.h" +#include "knot/other/error.h" + +/*! \brief Lock thread state for R/W. */ +static inline void lock_thread_rw(dthread_t *thread) +{ + pthread_mutex_lock(&thread->_mx); +} +/*! \brief Unlock thread state for R/W. */ +static inline void unlock_thread_rw(dthread_t *thread) +{ + pthread_mutex_unlock(&thread->_mx); +} + +/*! \brief Signalize thread state change. */ +static inline void unit_signalize_change(dt_unit_t *unit) +{ + pthread_mutex_lock(&unit->_report_mx); + pthread_cond_signal(&unit->_report); + pthread_mutex_unlock(&unit->_report_mx); +} + +/*! + * \brief Update thread state with notification. + * \param thread Given thread. + * \param state New state for thread. + * \retval 0 on success. + * \retval <0 on error (EINVAL, ENOTSUP). + */ +static inline int dt_update_thread(dthread_t *thread, int state) +{ + // Check + if (thread == 0) { + return KNOTD_EINVAL; + } + + // Cancel with lone thread + dt_unit_t *unit = thread->unit; + if (unit == 0) { + return KNOTD_ENOTSUP; + } + + // Cancel current runnable if running + pthread_mutex_lock(&unit->_notify_mx); + lock_thread_rw(thread); + if (thread->state & (ThreadIdle | ThreadActive)) { + + // Update state + thread->state = state; + unlock_thread_rw(thread); + + // Notify thread + dt_signalize(thread, SIGALRM); + pthread_cond_broadcast(&unit->_notify); + pthread_mutex_unlock(&unit->_notify_mx); + } else { + /* Unable to update thread, it is already dead. */ + unlock_thread_rw(thread); + pthread_mutex_unlock(&unit->_notify_mx); + return KNOTD_EINVAL; + } + + return KNOTD_EOK; +} + +/*! + * \brief Thread entrypoint function. + * + * When a thread is created and started, it immediately enters this function. + * Depending on thread state, it either enters runnable or + * blocks until it is awakened. + * + * This function also handles "ThreadIdle" state to quickly suspend and resume + * threads and mitigate thread creation costs. Also, thread runnable may + * be changed to alter the thread behavior on runtime + */ +static void *thread_ep(void *data) +{ + // Check data + dthread_t *thread = (dthread_t *)data; + if (thread == 0) { + return 0; + } + + // Check if is a member of unit + dt_unit_t *unit = thread->unit; + if (unit == 0) { + return 0; + } + + // Ignore specific signals (except SIGALRM) + sigset_t ignset; + sigemptyset(&ignset); + sigaddset(&ignset, SIGINT); + sigaddset(&ignset, SIGTERM); + sigaddset(&ignset, SIGHUP); + pthread_sigmask(SIG_BLOCK, &ignset, 0); /*! \todo Review under BSD. */ + + dbg_dt("dthreads: [%p] entered ep\n", thread); + + // Run loop + for (;;) { + + // Check thread state + lock_thread_rw(thread); + if (thread->state == ThreadDead) { + dbg_dt("dthreads: [%p] marked as dead\n", thread); + unlock_thread_rw(thread); + break; + } + + // Update data + thread->data = thread->_adata; + runnable_t _run = thread->run; + + // Start runnable if thread is marked Active + if ((thread->state == ThreadActive) && (thread->run != 0)) { + unlock_thread_rw(thread); + dbg_dt("dthreads: [%p] entering runnable\n", thread); + _run(thread); + dbg_dt("dthreads: [%p] exited runnable\n", thread); + } else { + unlock_thread_rw(thread); + } + + // If the runnable was cancelled, start new iteration + lock_thread_rw(thread); + if (thread->state & ThreadCancelled) { + dbg_dt("dthreads: [%p] cancelled\n", thread); + thread->state &= ~ThreadCancelled; + unlock_thread_rw(thread); + continue; + } + unlock_thread_rw(thread); + + // Runnable finished without interruption, mark as Idle + pthread_mutex_lock(&unit->_notify_mx); + lock_thread_rw(thread); + if (thread->state & ThreadActive) { + thread->state &= ~ThreadActive; + thread->state |= ThreadIdle; + } + + // Go to sleep if idle + if (thread->state & ThreadIdle) { + unlock_thread_rw(thread); + + // Signalize state change + unit_signalize_change(unit); + + // Wait for notification from unit + dbg_dt("dthreads: [%p] going idle\n", thread); + /*! \todo Check return value. */ + pthread_cond_wait(&unit->_notify, &unit->_notify_mx); + pthread_mutex_unlock(&unit->_notify_mx); + dbg_dt("dthreads: [%p] resumed from idle\n", thread); + } else { + unlock_thread_rw(thread); + pthread_mutex_unlock(&unit->_notify_mx); + } + } + + // Report thread state change + dbg_dt("dthreads: [%p] thread finished\n", thread); + unit_signalize_change(unit); + dbg_dt("dthreads: [%p] thread exited ep\n", thread); + lock_thread_rw(thread); + thread->state |= ThreadJoinable; + unlock_thread_rw(thread); + + // Return + return 0; +} + +/*! + * \brief Create single thread. + * \retval New thread instance on success. + * \retval NULL on error. + */ +static dthread_t *dt_create_thread(dt_unit_t *unit) +{ + // Alloc thread + dthread_t *thread = malloc(sizeof(dthread_t)); + if (thread == 0) { + return 0; + } + + memset(thread, 0, sizeof(dthread_t)); + + // Blank thread state + thread->state = ThreadJoined; + pthread_mutex_init(&thread->_mx, 0); + + // Set membership in unit + thread->unit = unit; + + // Initialize attribute + pthread_attr_t *attr = &thread->_attr; + pthread_attr_init(attr); + pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED); + pthread_attr_setschedpolicy(attr, SCHED_OTHER); + return thread; +} + +/*! \brief Delete single thread. */ +static void dt_delete_thread(dthread_t **thread) +{ + // Check + if (thread == 0) { + return; + } + if (*thread == 0) { + return; + } + + dthread_t* thr = *thread; + thr->unit = 0; + *thread = 0; + + // Delete attribute + pthread_attr_destroy(&(thr)->_attr); + + // Delete mutex + pthread_mutex_destroy(&(thr)->_mx); + + // Free memory + free(thr); +} + +/* + * Public APIs. + */ + +dt_unit_t *dt_create(int count) +{ + // Check count + if (count <= 0) { + return 0; + } + + dt_unit_t *unit = malloc(sizeof(dt_unit_t)); + if (unit == 0) { + return 0; + } + + // Initialize conditions + if (pthread_cond_init(&unit->_notify, 0) != 0) { + free(unit); + return 0; + } + if (pthread_cond_init(&unit->_report, 0) != 0) { + pthread_cond_destroy(&unit->_notify); + free(unit); + return 0; + } + + // Initialize mutexes + if (pthread_mutex_init(&unit->_notify_mx, 0) != 0) { + pthread_cond_destroy(&unit->_notify); + pthread_cond_destroy(&unit->_report); + free(unit); + return 0; + } + if (pthread_mutex_init(&unit->_report_mx, 0) != 0) { + pthread_cond_destroy(&unit->_notify); + pthread_cond_destroy(&unit->_report); + pthread_mutex_destroy(&unit->_notify_mx); + free(unit); + return 0; + } + if (pthread_mutex_init(&unit->_mx, 0) != 0) { + pthread_cond_destroy(&unit->_notify); + pthread_cond_destroy(&unit->_report); + pthread_mutex_destroy(&unit->_notify_mx); + pthread_mutex_destroy(&unit->_report_mx); + free(unit); + return 0; + } + + // Save unit size + unit->size = count; + + // Alloc threads + unit->threads = malloc(count * sizeof(dthread_t *)); + if (unit->threads == 0) { + pthread_cond_destroy(&unit->_notify); + pthread_cond_destroy(&unit->_report); + pthread_mutex_destroy(&unit->_notify_mx); + pthread_mutex_destroy(&unit->_report_mx); + pthread_mutex_destroy(&unit->_mx); + free(unit); + return 0; + } + + // Initialize threads + int init_success = 1; + for (int i = 0; i < count; ++i) { + unit->threads[i] = dt_create_thread(unit); + if (unit->threads[i] == 0) { + init_success = 0; + break; + } + } + + // Check thread initialization + if (!init_success) { + + // Delete created threads + for (int i = 0; i < count; ++i) { + dt_delete_thread(&unit->threads[i]); + } + + // Free rest of the unit + pthread_cond_destroy(&unit->_notify); + pthread_cond_destroy(&unit->_report); + pthread_mutex_destroy(&unit->_notify_mx); + pthread_mutex_destroy(&unit->_report_mx); + pthread_mutex_destroy(&unit->_mx); + free(unit->threads); + free(unit); + return 0; + } + + return unit; +} + +dt_unit_t *dt_create_coherent(int count, runnable_t runnable, void *data) +{ + // Check count + if (count <= 0) { + return 0; + } + + // Create unit + dt_unit_t *unit = dt_create(count); + if (unit == 0) { + return 0; + } + + // Set threads common purpose + pthread_mutex_lock(&unit->_notify_mx); + dt_unit_lock(unit); + + for (int i = 0; i < count; ++i) { + dthread_t *thread = unit->threads[i]; + lock_thread_rw(thread); + thread->run = runnable; + thread->_adata = data; + unlock_thread_rw(thread); + } + + dt_unit_unlock(unit); + pthread_mutex_unlock(&unit->_notify_mx); + + return unit; +} + +void dt_delete(dt_unit_t **unit) +{ + /* + * All threads must be stopped or idle at this point, + * or else the behavior is undefined. + * Sorry. + */ + + // Check + if (unit == 0) { + return; + } + if (*unit == 0) { + return; + } + + // Compact and reclaim idle threads + dt_unit_t *d_unit = *unit; + dt_compact(d_unit); + + // Delete threads + for (int i = 0; i < d_unit->size; ++i) { + dt_delete_thread(&d_unit->threads[i]); + } + + // Deinit mutexes + pthread_mutex_destroy(&d_unit->_notify_mx); + pthread_mutex_destroy(&d_unit->_report_mx); + + // Deinit conditions + pthread_cond_destroy(&d_unit->_notify); + pthread_cond_destroy(&d_unit->_report); + + // Free memory + free(d_unit->threads); + free(d_unit); + *unit = 0; +} + +int dt_resize(dt_unit_t *unit, int size) +{ + // Check input + if (unit == 0 || size <= 0) { + return KNOTD_EINVAL; + } + + // Evaluate delta + int delta = unit->size - size; + + // Same size + if (delta == 0) { + return 0; + } + + // Unit expansion + if (delta < 0) { + + // Lock unit + pthread_mutex_lock(&unit->_notify_mx); + dt_unit_lock(unit); + + // Realloc threads + dbg_dt("dthreads: growing from %d to %d threads\n", + unit->size, size); + + dthread_t **threads = realloc(unit->threads, + size * sizeof(dthread_t *)); + if (threads == NULL) { + dt_unit_unlock(unit); + pthread_mutex_unlock(&unit->_notify_mx); + return -1; + } + + // Reassign + unit->threads = threads; + + // Create new threads + for (int i = unit->size; i < size; ++i) { + threads[i] = dt_create_thread(unit); + } + + // Update unit + unit->size = size; + dt_unit_unlock(unit); + pthread_mutex_unlock(&unit->_notify_mx); + return 0; + } + + + // Unit shrinking + int remaining = size; + dbg_dt("dthreads: shrinking from %d to %d threads\n", + unit->size, size); + + // New threads vector + dthread_t **threads = malloc(size * sizeof(dthread_t *)); + if (threads == 0) { + return KNOTD_ENOMEM; + } + + // Lock unit + pthread_mutex_lock(&unit->_notify_mx); + dt_unit_lock(unit); + + // Iterate while there is space in new unit + memset(threads, 0, size * sizeof(dthread_t *)); + int threshold = ThreadActive; + for (;;) { + + // Find threads matching given criterias + int inspected = 0; + for (int i = 0; i < unit->size; ++i) { + + // Get thread + dthread_t *thread = unit->threads[i]; + if (thread == 0) { + continue; + } + + // Count thread as inspected + ++inspected; + + lock_thread_rw(thread); + + // Populate with matching threads + if ((remaining > 0) && + (!threshold || (thread->state & threshold))) { + + // Append to new vector + threads[size - remaining] = thread; + --remaining; + + // Invalidate in old vector + unit->threads[i] = 0; + dbg_dt_verb("dthreads: [%p] dt_resize: elected\n", + thread); + + } else if (remaining <= 0) { + + // Not enough space, delete thread + if (thread->state & ThreadDead) { + unlock_thread_rw(thread); + --inspected; + continue; + } + + // Signalize thread to stop + thread->state = ThreadDead | ThreadCancelled; + dt_signalize(thread, SIGALRM); + dbg_dt_verb("dthreads: [%p] dt_resize: " + "is discarded\n", thread); + } + + // Unlock thread and continue + unlock_thread_rw(thread); + } + + // Finished inspecting running threads + if (inspected == 0) { + break; + } + + // Lower threshold + switch (threshold) { + case ThreadActive: + threshold = ThreadIdle; + break; + case ThreadIdle: + threshold = ThreadDead; + break; + default: + threshold = ThreadJoined; + break; + } + } + + // Notify idle threads to wake up + pthread_cond_broadcast(&unit->_notify); + pthread_mutex_unlock(&unit->_notify_mx); + + // Join discarded threads + for (int i = 0; i < unit->size; ++i) { + + // Get thread + dthread_t *thread = unit->threads[i]; + if (thread == 0) { + continue; + } + + pthread_join(thread->_thr, 0); + thread->state = ThreadJoined; + + // Delete thread + dt_delete_thread(&thread); + unit->threads[i] = 0; + } + + // Reassign unit threads vector + unit->size = size; + free(unit->threads); + unit->threads = threads; + + // Unlock unit + dt_unit_unlock(unit); + + return 0; +} + +int dt_start(dt_unit_t *unit) +{ + // Check input + if (unit == 0) { + return KNOTD_EINVAL; + } + + // Lock unit + pthread_mutex_lock(&unit->_notify_mx); + dt_unit_lock(unit); + for (int i = 0; i < unit->size; ++i) { + + dthread_t *thread = unit->threads[i]; + int res = dt_start_id(thread); + if (res != 0) { + dbg_dt("dthreads: failed to create thread '%d'.", i); + dt_unit_unlock(unit); + pthread_mutex_unlock(&unit->_notify_mx); + return res; + } + + dbg_dt("dthreads: [%p] %s: thread started\n", + thread, __func__); + } + + // Unlock unit + dt_unit_unlock(unit); + pthread_cond_broadcast(&unit->_notify); + pthread_mutex_unlock(&unit->_notify_mx); + return 0; +} + +int dt_start_id(dthread_t *thread) +{ + // Check input + if (thread == 0) { + return KNOTD_EINVAL; + } + + lock_thread_rw(thread); + + // Update state + int prev_state = thread->state; + thread->state |= ThreadActive; + thread->state &= ~ThreadIdle; + thread->state &= ~ThreadDead; + thread->state &= ~ThreadJoined; + thread->state &= ~ThreadJoinable; + + // Do not re-create running threads + if (prev_state != ThreadJoined) { + dbg_dt("dthreads: [%p] %s: refused to recreate thread\n", + thread, __func__); + unlock_thread_rw(thread); + return 0; + } + + // Start thread + int res = pthread_create(&thread->_thr, /* pthread_t */ + &thread->_attr, /* pthread_attr_t */ + thread_ep, /* routine: thread_ep */ + thread); /* passed object: dthread_t */ + + // Unlock thread + unlock_thread_rw(thread); + return res; +} + +int dt_signalize(dthread_t *thread, int signum) +{ + // Check input + if (thread == 0) { + return KNOTD_EINVAL; + } + + int ret = pthread_kill(thread->_thr, signum); + + /* Not thread id found or invalid signum. */ + if (ret == EINVAL || ret == ESRCH) { + return KNOTD_EINVAL; + } + + /* Generic error. */ + if (ret < 0) { + return KNOTD_ERROR; + } + + return KNOTD_EOK; +} + +int dt_join(dt_unit_t *unit) +{ + // Check input + if (unit == 0) { + return KNOTD_EINVAL; + } + + for (;;) { + + // Lock unit + pthread_mutex_lock(&unit->_report_mx); + dt_unit_lock(unit); + + // Browse threads + int active_threads = 0; + for (int i = 0; i < unit->size; ++i) { + + // Count active or cancelled but pending threads + dthread_t *thread = unit->threads[i]; + lock_thread_rw(thread); + if (thread->state & (ThreadActive|ThreadCancelled)) { + ++active_threads; + } + + // Reclaim dead threads, but only fast + if (thread->state & ThreadJoinable) { + unlock_thread_rw(thread); + dbg_dt_verb("dthreads: [%p] %s: reclaiming\n", + thread, __func__); + pthread_join(thread->_thr, 0); + dbg_dt("dthreads: [%p] %s: reclaimed\n", + thread, __func__); + thread->state = ThreadJoined; + } else { + unlock_thread_rw(thread); + } + } + + // Unlock unit + dt_unit_unlock(unit); + + // Check result + if (active_threads == 0) { + pthread_mutex_unlock(&unit->_report_mx); + break; + } + + // Wait for a thread to finish + pthread_cond_wait(&unit->_report, &unit->_report_mx); + pthread_mutex_unlock(&unit->_report_mx); + } + + return KNOTD_EOK; +} + +int dt_stop_id(dthread_t *thread) +{ + // Check input + if (thread == 0) { + return KNOTD_EINVAL; + } + + // Signalize active thread to stop + lock_thread_rw(thread); + if (thread->state & (ThreadIdle | ThreadActive)) { + thread->state = ThreadDead | ThreadCancelled; + dt_signalize(thread, SIGALRM); + } + unlock_thread_rw(thread); + + // Broadcast notification + dt_unit_t *unit = thread->unit; + if (unit != 0) { + pthread_mutex_lock(&unit->_notify_mx); + pthread_cond_broadcast(&unit->_notify); + pthread_mutex_unlock(&unit->_notify_mx); + } + + return KNOTD_EOK; +} + +int dt_stop(dt_unit_t *unit) +{ + // Check unit + if (unit == 0) { + return KNOTD_EINVAL; + } + + // Lock unit + pthread_mutex_lock(&unit->_notify_mx); + dt_unit_lock(unit); + + // Signalize all threads to stop + for (int i = 0; i < unit->size; ++i) { + + // Lock thread + dthread_t *thread = unit->threads[i]; + lock_thread_rw(thread); + if (thread->state & (ThreadIdle | ThreadActive)) { + thread->state = ThreadDead | ThreadCancelled; + dbg_dt("dthreads: [%p] %s: stopping thread\n", + thread, __func__); + dt_signalize(thread, SIGALRM); + } + unlock_thread_rw(thread); + } + + // Unlock unit + dt_unit_unlock(unit); + + // Broadcast notification + pthread_cond_broadcast(&unit->_notify); + pthread_mutex_unlock(&unit->_notify_mx); + + return KNOTD_EOK; +} + +int dt_setprio(dthread_t *thread, int prio) +{ + // Check input + if (thread == 0) { + return KNOTD_EINVAL; + } + + // Clamp priority + int policy = SCHED_FIFO; + prio = MIN(MAX(sched_get_priority_min(policy), prio), + sched_get_priority_max(policy)); + + // Update scheduler policy + int ret = pthread_attr_setschedpolicy(&thread->_attr, policy); + + // Update priority + if (ret >= 0) { + struct sched_param sp; + sp.sched_priority = prio; + ret = pthread_attr_setschedparam(&thread->_attr, &sp); + } + + /* Map error codes. */ + if (ret < 0) { + dbg_dt("dthreads: [%p] %s(%d): failed", + thread, __func__, prio); + + /* Map "not supported". */ + if (ret == ENOTSUP) { + return KNOTD_ENOTSUP; + } + + return KNOTD_EINVAL; + } + + return KNOTD_EOK; +} + +int dt_repurpose(dthread_t *thread, runnable_t runnable, void *data) +{ + // Check + if (thread == 0) { + return KNOTD_EINVAL; + } + + // Stop here if thread isn't a member of a unit + dt_unit_t *unit = thread->unit; + if (unit == 0) { + lock_thread_rw(thread); + thread->state = ThreadActive | ThreadCancelled; + unlock_thread_rw(thread); + return KNOTD_ENOTSUP; + } + + // Lock thread state changes + pthread_mutex_lock(&unit->_notify_mx); + lock_thread_rw(thread); + + // Repurpose it's object and runnable + thread->run = runnable; + thread->_adata = data; + + // Cancel current runnable if running + if (thread->state & (ThreadIdle | ThreadActive)) { + + // Update state + thread->state = ThreadActive | ThreadCancelled; + unlock_thread_rw(thread); + + // Notify thread + pthread_cond_broadcast(&unit->_notify); + pthread_mutex_unlock(&unit->_notify_mx); + } else { + unlock_thread_rw(thread); + pthread_mutex_unlock(&unit->_notify_mx); + } + + return KNOTD_EOK; +} + +int dt_activate(dthread_t *thread) +{ + return dt_update_thread(thread, ThreadActive); +} + +int dt_cancel(dthread_t *thread) +{ + return dt_update_thread(thread, ThreadIdle | ThreadCancelled); +} + +int dt_compact(dt_unit_t *unit) +{ + // Check input + if (unit == 0) { + return KNOTD_EINVAL; + } + + // Lock unit + pthread_mutex_lock(&unit->_notify_mx); + dt_unit_lock(unit); + + // Reclaim all Idle threads + for (int i = 0; i < unit->size; ++i) { + + // Locked state update + dthread_t *thread = unit->threads[i]; + lock_thread_rw(thread); + if (thread->state & (ThreadIdle)) { + thread->state = ThreadDead | ThreadCancelled; + dt_signalize(thread, SIGALRM); + } + unlock_thread_rw(thread); + } + + // Notify all threads + pthread_cond_broadcast(&unit->_notify); + pthread_mutex_unlock(&unit->_notify_mx); + + // Join all threads + for (int i = 0; i < unit->size; ++i) { + + // Reclaim all dead threads + dthread_t *thread = unit->threads[i]; + lock_thread_rw(thread); + if (thread->state & (ThreadDead)) { + dbg_dt_verb("dthreads: [%p] %s: reclaiming thread\n", + thread, __func__); + unlock_thread_rw(thread); + pthread_join(thread->_thr, 0); + dbg_dt("dthreads: [%p] %s: thread reclaimed\n", + thread, __func__); + thread->state = ThreadJoined; + } else { + unlock_thread_rw(thread); + } + } + + dbg_dt_verb("dthreads: compact: joined all threads\n"); + + // Unlock unit + dt_unit_unlock(unit); + + return KNOTD_EOK; +} + +int dt_optimal_size() +{ +#ifdef _SC_NPROCESSORS_ONLN + int ret = (int) sysconf(_SC_NPROCESSORS_ONLN); + if (ret >= 1) { + return ret + CPU_ESTIMATE_MAGIC; + } +#endif + dbg_dt("dthreads: failed to fetch the number of online CPUs."); + return DEFAULT_THR_COUNT; +} + +/*! + * \todo Use memory barriers or asynchronous read-only access, locking + * poses a thread performance decrease by 1.31%. + */ + +int dt_is_cancelled(dthread_t *thread) +{ + // Check input + if (thread == 0) { + return 0; + } + + lock_thread_rw(thread); + int ret = thread->state & ThreadCancelled; + unlock_thread_rw(thread); + return ret; +} + +int dt_unit_lock(dt_unit_t *unit) +{ + // Check input + if (unit == 0) { + return KNOTD_EINVAL; + } + + int ret = pthread_mutex_lock(&unit->_mx); + + /* Map errors. */ + if (ret < 0) { + return knot_map_errno(EINVAL, EAGAIN); + } + + return KNOTD_EOK; +} + +int dt_unit_unlock(dt_unit_t *unit) +{ + // Check input + if (unit == 0) { + return KNOTD_EINVAL; + } + + int ret = pthread_mutex_unlock(&unit->_mx); + + /* Map errors. */ + if (ret < 0) { + return knot_map_errno(EINVAL, EAGAIN); + } + + return KNOTD_EOK; +} diff --git a/src/knot/server/dthreads.h b/src/knot/server/dthreads.h new file mode 100644 index 0000000..8a5e2b4 --- /dev/null +++ b/src/knot/server/dthreads.h @@ -0,0 +1,353 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file dthreads.h + * + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief Threading API. + * + * Dynamic threads provide: + * - coherent and incoherent threading capabilities + * - thread repurposing + * - thread prioritization + * - on-the-fly changing of threading unit size + * + * Coherent threading unit is when all threads execute + * the same runnable function. + * + * Incoherent function is when at least one thread executes + * a different runnable than the others. + * + * \addtogroup threading + * @{ + */ + +#ifndef _KNOTD_DTHREADS_H_ +#define _KNOTD_DTHREADS_H_ + +#include <pthread.h> + +/* Forward decls */ +struct dthread_t; +struct dt_unit_t; + +/*! + * \brief Thread state enumeration. + */ +typedef enum { + ThreadJoined = 1 << 0, /*!< Thread is finished and joined. */ + ThreadJoinable = 1 << 1, /*!< Thread is waiting to be reclaimed. */ + ThreadCancelled = 1 << 2, /*!< Thread is cancelled, finishing task. */ + ThreadDead = 1 << 3, /*!< Thread is finished, exiting. */ + ThreadIdle = 1 << 4, /*!< Thread is idle, waiting for purpose. */ + ThreadActive = 1 << 5 /*!< Thread is active, working on a task. */ + +} dt_state_t; + +/*! + * \brief Thread runnable prototype. + * + * Runnable is basically a pointer to function which is called on active + * thread runtime. + * + * \note When implementing a runnable, keep in mind to check thread state as + * it may change, and implement a cooperative cancellation point. + * + * Implement this by checking dt_is_cancelled() and return + * as soon as possible. + */ +typedef int (*runnable_t)(struct dthread_t *); + +/*! + * \brief Single thread descriptor public API. + */ +typedef struct dthread_t { + volatile unsigned state; /*!< Bitfield of dt_flag flags. */ + runnable_t run; /*!< Runnable function or 0. */ + void *data; /*!< Currently active data */ + struct dt_unit_t *unit; /*!< Reference to assigned unit. */ + void *_adata; /* Thread-specific data. */ + pthread_t _thr; /* Thread */ + pthread_attr_t _attr; /* Thread attributes */ + pthread_mutex_t _mx; /* Thread state change lock. */ +} dthread_t; + +/*! + * \brief Thread unit descriptor API. + * + * Thread unit consists of 1..N threads. + * Unit is coherent if all threads execute + * the same runnable. + */ +typedef struct dt_unit_t { + int size; /*!< Unit width (number of threads) */ + struct dthread_t **threads; /*!< Array of threads */ + pthread_cond_t _notify; /* Notify thread */ + pthread_mutex_t _notify_mx; /* Condition mutex */ + pthread_cond_t _report; /* Report thread state */ + pthread_mutex_t _report_mx; /* Condition mutex */ + pthread_mutex_t _mx; /* Unit lock */ +} dt_unit_t; + +/*! + * \brief Create a set of threads with no initial runnable. + * + * \note All threads are created with Dead state. + * This means, they're not physically created unit dt_start() is called. + * + * \param count Requested thread count. + * + * \retval New instance if successful + * \retval NULL on error + */ +dt_unit_t *dt_create(int count); + +/*! + * \brief Create a set of coherent threads. + * + * Coherent means, that the threads will share a common runnable and the data. + * + * \param count Requested thread count. + * \param runnable Runnable function for all threads. + * \param data Any data passed onto threads. + * + * \retval New instance if successful + * \retval NULL on error + */ +dt_unit_t *dt_create_coherent(int count, runnable_t runnable, void *data); + +/*! + * \brief Free unit. + * + * \warning Behavior is undefined if threads are still active, make sure + * to call dt_join() first. + * + * \param unit Unit to be deleted. + */ +void dt_delete(dt_unit_t **unit); + +/*! + * \brief Resize unit to given number. + * + * \note Newly created dthreads will have no runnable or data, their state + * will be ThreadJoined (that means no thread will be physically created + * until the next dt_start()). + * + * \warning Be careful when shrinking unit, joined and idle threads are + * reclaimed first, but it may kill your active threads + * as a last resort. + * Threads will stop at their nearest cancellation point, + * so this is potentially an expensive and blocking operation. + * + * \param unit Unit to be resized. + * \param size New unit size. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOMEM out of memory error. + */ +int dt_resize(dt_unit_t *unit, int size); + +/*! + * \brief Start all threads in selected unit. + * + * \param unit Unit to be started. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters (unit is null). + */ +int dt_start(dt_unit_t *unit); + +/*! + * \brief Start given thread. + * + * \param thread Target thread instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_start_id(dthread_t *thread); + +/*! + * \brief Send given signal to thread. + * + * \note This is useful to interrupt some blocking I/O as well, for example + * with SIGALRM, which is handled by default. + * \note Signal handler may be overriden in runnable. + * + * \param thread Target thread instance. + * \param signum Signal code. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ERROR unspecified error. + */ +int dt_signalize(dthread_t *thread, int signum); + +/*! + * \brief Wait for all thread in unit to finish. + * + * \param unit Unit to be joined. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_join(dt_unit_t *unit); + +/*! + * \brief Stop thread from running. + * + * Active thread is interrupted at the nearest runnable cancellation point. + * + * \param thread Target thread instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_stop_id(dthread_t *thread); + +/*! + * \brief Stop all threads in unit. + * + * Thread is interrupted at the nearest runnable cancellation point. + * + * \param unit Unit to be stopped. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_stop(dt_unit_t *unit); + +/*! + * \brief Modify thread priority. + * + * \param thread Target thread instance. + * \param prio Requested priority (positive integer, default is 0). + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_setprio(dthread_t *thread, int prio); + +/*! + * \brief Set thread to execute another runnable. + * + * \param thread Target thread instance. + * \param runnable Runnable function for target thread. + * \param data Data passed to target thread. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOTSUP operation not supported. + */ +int dt_repurpose(dthread_t *thread, runnable_t runnable, void *data); + +/*! + * \brief Wake up thread from idle state. + * + * Thread is awoken from idle state and reenters runnable. + * This function only affects idle threads. + * + * \note Unit needs to be started with dt_start() first, as the function + * doesn't affect dead threads. + * + * \param thread Target thread instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOTSUP operation not supported. + */ +int dt_activate(dthread_t *thread); + +/*! + * \brief Put thread to idle state, cancells current runnable function. + * + * Thread is flagged with Cancel flag and returns from runnable at the nearest + * cancellation point, which requires complying runnable function. + * + * \note Thread isn't disposed, but put to idle state until it's requested + * again or collected by dt_compact(). + * + * \param thread Target thread instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_cancel(dthread_t *thread); + +/*! + * \brief Collect and dispose idle threads. + * + * \param unit Target unit instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_compact(dt_unit_t *unit); + +/*! + * \brief Return optimal number of threads for instance. + * + * It is estimated as NUM_CPUs + 1. + * Fallback is DEFAULT_THR_COUNT (\see common.h). + * + * \return Number of threads. + */ +int dt_optimal_size(); + +/*! + * \brief Return true if thread is cancelled. + * + * Synchronously check for ThreadCancelled flag. + * + * \param thread Target thread instance. + * + * \retval 1 if cancelled. + * \retval 0 if not cancelled. + */ +int dt_is_cancelled(dthread_t *thread); + +/*! + * \brief Lock unit to prevent parallel operations which could alter unit + * at the same time. + * + * \param unit Target unit instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_EAGAIN lack of resources to lock unit, try again. + * \retval KNOTD_ERROR unspecified error. + */ +int dt_unit_lock(dt_unit_t *unit); + +/*! + * \brief Unlock unit. + * + * \see dt_unit_lock() + * + * \param unit Target unit instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_EAGAIN lack of resources to unlock unit, try again. + * \retval KNOTD_ERROR unspecified error. + */ +int dt_unit_unlock(dt_unit_t *unit); + +#endif // _KNOTD_DTHREADS_H_ + +/*! @} */ diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c new file mode 100644 index 0000000..651f0f3 --- /dev/null +++ b/src/knot/server/journal.c @@ -0,0 +1,636 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "knot/other/error.h" +#include "knot/other/debug.h" +#include "journal.h" + +/*! \brief Infinite file size limit. */ +#define FSLIMIT_INF (~((size_t)0)) + +/*! \brief Node classification macros. */ +#define jnode_flags(j, i) ((j)->nodes[(i)].flags) + +/*! \brief Next node. */ +#define jnode_next(j, i) (((i) + 1) % (j)->max_nodes) + +/*! \brief Previous node. */ +#define jnode_prev(j, i) (((i) == 0) ? (j)->max_nodes - 1 : (i) - 1) + +static inline int sfread(void *dst, size_t len, int fd) +{ + return read(fd, dst, len) == len; +} + +static inline int sfwrite(const void *src, size_t len, int fd) +{ + return write(fd, src, len) == len; +} + +/*! \brief Equality compare function. */ +static inline int journal_cmp_eq(uint64_t k1, uint64_t k2) +{ + if (k1 == k2) { + return 0; + } + + if (k1 < k2) { + return -1; + } + + return 1; +} + +/*! \brief Recover metadata from journal. */ +static int journal_recover(journal_t *j) +{ + /* Attempt to recover queue. */ + int qstate[2] = { -1, -1 }; + unsigned c = 0, p = j->max_nodes - 1; + while (1) { + + /* Fetch previous and current node. */ + journal_node_t *np = j->nodes + p; + journal_node_t *nc = j->nodes + c; + + /* Check flags + * p c (0 = free, 1 = non-free) + * 0 0 - in free segment + * 0 1 - c-node is qhead + * 1 0 - c-node is qtail + * 1 1 - in full segment + */ + unsigned c_set = (nc->flags > JOURNAL_FREE); + unsigned p_set = (np->flags > JOURNAL_FREE); + if (!p_set && c_set && qstate[0] < 0) { + qstate[0] = c; /* Recovered qhead. */ + dbg_journal_verb("journal: recovered qhead=%u\n", + qstate[0]); + } + if (p_set && !c_set && qstate[1] < 0) {\ + qstate[1] = c; /* Recovered qtail. */ + dbg_journal_verb("journal: recovered qtail=%u\n", + qstate[1]); + } + + /* Both qstates set. */ + if (qstate[0] > -1 && qstate[1] > -1) { + break; + } + + /* Set prev and next. */ + p = c; + c = (c + 1) % j->max_nodes; + + /* All nodes probed. */ + if (c == 0) { + dbg_journal("journal: failed to recover node queue\n"); + break; + } + } + + /* Evaluate */ + if (qstate[0] < 0 || qstate[1] < 0) { + return KNOTD_ERANGE; + } + + /* Write back. */ + lseek(j->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (!sfwrite(qstate, 2 * sizeof(uint16_t), j->fd)) { + dbg_journal("journal: failed to write back queue state\n"); + return KNOTD_ERROR; + } + + /* Reset queue state. */ + j->qhead = qstate[0]; + j->qtail = qstate[1]; + dbg_journal("journal: node queue=<%u,%u> recovered\n", + qstate[0], qstate[1]); + + + return KNOTD_EOK; +} + +int journal_create(const char *fn, uint16_t max_nodes) +{ + /* File lock. */ + struct flock fl; + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + + /* Create journal file. */ + int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG); + if (fd < 0) { + dbg_journal("journal: failed to create file '%s'\n", fn); + return KNOTD_EINVAL; + } + + /* Lock. */ + fcntl(fd, F_SETLKW, &fl); + fl.l_type = F_UNLCK; + + /* Create journal header. */ + dbg_journal("journal: creating header\n"); + if (!sfwrite(&max_nodes, sizeof(uint16_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + remove(fn); + return KNOTD_ERROR; + } + + /* Create node queue head + tail. + * qhead points to least recent node + * qtail points to next free node + * qhead == qtail means empty queue + */ + uint16_t zval = 0; + if (!sfwrite(&zval, sizeof(uint16_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + remove(fn); + return KNOTD_ERROR; + } + + if (!sfwrite(&zval, sizeof(uint16_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + remove(fn); + return KNOTD_ERROR; + } + + dbg_journal_verb("journal: creating free segment descriptor\n"); + + /* Create free segment descriptor. */ + journal_node_t jn; + memset(&jn, 0, sizeof(journal_node_t)); + jn.id = 0; + jn.flags = JOURNAL_VALID; + jn.pos = JOURNAL_HSIZE + (max_nodes + 1) * sizeof(journal_node_t); + jn.len = 0; + if (!sfwrite(&jn, sizeof(journal_node_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + remove(fn); + return KNOTD_ERROR; + } + + /* Create nodes. */ + dbg_journal("journal: creating node table, size=%u\n", max_nodes); + memset(&jn, 0, sizeof(journal_node_t)); + for(uint16_t i = 0; i < max_nodes; ++i) { + if (!sfwrite(&jn, sizeof(journal_node_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + remove(fn); + return KNOTD_ERROR; + } + } + + /* Unlock and close. */ + fcntl(fd, F_SETLK, &fl); + close(fd); + + /* Journal file created. */ + dbg_journal("journal: file '%s' initialized\n", fn); + return KNOTD_EOK; +} + +journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags) +{ + /*! \todo Memory mapping may be faster than stdio? */ + + /* File lock. */ + struct flock fl; + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + + /* Check file. */ + struct stat st; + if (stat(fn, &st) < 0) { + return 0; + } + + /* Open journal file for r/w. */ + int fd = open(fn, O_RDWR); + if (fd < 0) { + dbg_journal("journal: failed to open file '%s'\n", fn); + return 0; + } + + /* Attempt to lock. */ + dbg_journal_verb("journal: locking journal %s\n", fn); + int ret = fcntl(fd, F_SETLK, &fl); + + /* Lock. */ + if (ret < 0) { + struct flock efl; + memcpy(&efl, &fl, sizeof(struct flock)); + fcntl(fd, F_GETLK, &efl); + log_server_warning("Journal file '%s' is locked by process " + "PID=%d, waiting for process to " + "release lock.\n", + fn, efl.l_pid); + ret = fcntl(fd, F_SETLKW, &fl); + } + fl.l_type = F_UNLCK; + dbg_journal("journal: locked journal %s (returned %d)\n", fn, ret); + + /* Read maximum number of entries. */ + uint16_t max_nodes = 512; + if (!sfread(&max_nodes, sizeof(uint16_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + return 0; + } + + /* Allocate journal structure. */ + const size_t node_len = sizeof(journal_node_t); + journal_t *j = malloc(sizeof(journal_t) + max_nodes * node_len); + if (!j) { + fcntl(fd, F_SETLK, &fl); + close(fd); + return 0; + } + j->qhead = j->qtail = 0; + j->fd = fd; + j->max_nodes = max_nodes; + j->bflags = bflags; + + /* Load node queue state. */ + if (!sfread(&j->qhead, sizeof(uint16_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + free(j); + return 0; + } + + /* Load queue tail. */ + if (!sfread(&j->qtail, sizeof(uint16_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + free(j); + return 0; + } + + /* Load empty segment descriptor. */ + if (!sfread(&j->free, node_len, fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + free(j); + return 0; + } + + /* Read journal descriptors table. */ + if (!sfread(&j->nodes, max_nodes * node_len, fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + free(j); + return 0; + } + + /* Set file size. */ + j->fsize = st.st_size; + if (fslimit == 0) { + j->fslimit = FSLIMIT_INF; + } else { + j->fslimit = (size_t)fslimit; + } + + dbg_journal("journal: opened journal size=%u, queue=<%u, %u>, fd=%d\n", + max_nodes, j->qhead, j->qtail, j->fd); + + /* Check node queue. */ + unsigned qtail_free = (jnode_flags(j, j->qtail) <= JOURNAL_FREE); + unsigned qhead_free = j->max_nodes - 1; /* Left of qhead must be free.*/ + if (j->qhead > 0) { + qhead_free = (j->qhead - 1); + } + qhead_free = (jnode_flags(j, qhead_free) <= JOURNAL_FREE); + if ((j->qhead != j->qtail) && (!qtail_free || !qhead_free)) { + log_server_warning("Recovering journal '%s' metadata " + "after crash.\n", + fn); + ret = journal_recover(j); + if (ret != KNOTD_EOK) { + log_server_error("Journal file '%s' is unrecoverable, " + "metadata corrupted - %s\n", + fn, knotd_strerror(ret)); + fcntl(fd, F_SETLK, &fl); + close(fd); + free(j); + return 0; + } + } + + /* Save file lock. */ + fl.l_type = F_WRLCK; + memcpy(&j->fl, &fl, sizeof(struct flock)); + + return j; +} + +int journal_fetch(journal_t *journal, uint64_t id, + journal_cmp_t cf, journal_node_t** dst) +{ + if (journal == 0 || dst == 0) { + return KNOTD_EINVAL; + } + + /* Check compare function. */ + if (!cf) { + cf = journal_cmp_eq; + } + + /*! \todo Organize journal descriptors in btree? */ + size_t i = jnode_prev(journal, journal->qtail); + size_t endp = jnode_prev(journal, journal->qhead); + for(; i != endp; i = jnode_prev(journal, i)) { + if (cf(journal->nodes[i].id, id) == 0) { + *dst = journal->nodes + i; + return KNOTD_EOK; + } + } + + return KNOTD_ENOENT; +} + +int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst) +{ + if (journal == 0 || dst == 0) { + return KNOTD_EINVAL; + } + + journal_node_t *n = 0; + if(journal_fetch(journal, id, cf, &n) != 0) { + dbg_journal("journal: failed to fetch node with id=%llu\n", + (unsigned long long)id); + return KNOTD_ENOENT; + } + + /* Check valid flag. */ + if (!(n->flags & JOURNAL_VALID)) { + dbg_journal("journal: node with id=%llu is invalid " + "(flags=0x%hx)\n", (unsigned long long)id, n->flags); + return KNOTD_EINVAL; + } + + dbg_journal("journal: reading node with id=%llu, data=<%u, %u>, flags=0x%hx\n", + (unsigned long long)id, n->pos, n->pos + n->len, n->flags); + + /* Seek journal node. */ + lseek(journal->fd, n->pos, SEEK_SET); + + /* Read journal node content. */ + if (!sfread(dst, n->len, journal->fd)) { + return KNOTD_ERROR; + } + + return KNOTD_EOK; +} + +int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size) +{ + if (journal == 0 || src == 0) { + return KNOTD_EINVAL; + } + + const size_t node_len = sizeof(journal_node_t); + + /* Find next free node. */ + uint16_t jnext = (journal->qtail + 1) % journal->max_nodes; + + dbg_journal("journal: will write id=%llu, node=%u, size=%zu, fsize=%zu\n", + (unsigned long long)id, journal->qtail, size, journal->fsize); + + /* Calculate remaining bytes to reach file size limit. */ + size_t fs_remaining = journal->fslimit - journal->fsize; + + /* Increase free segment if on the end of file. */ + journal_node_t *n = journal->nodes + journal->qtail; + if (journal->free.pos + journal->free.len == journal->fsize) { + + dbg_journal_verb("journal: * is last node\n"); + + /* Grow journal file until the size limit. */ + if(journal->free.len < size && size <= fs_remaining) { + size_t diff = size - journal->free.len; + dbg_journal("journal: * growing by +%zu, pos=%u, " + "new fsize=%zu\n", + diff, journal->free.pos, + journal->fsize + diff); + journal->fsize += diff; /* Appending increases file size. */ + journal->free.len += diff; + + } + + /* Rewind if resize is needed, but the limit is reached. */ + if(journal->free.len < size && size > fs_remaining) { + journal_node_t *head = journal->nodes + journal->qhead; + journal->fsize = journal->free.pos; + journal->free.pos = head->pos; + journal->free.len = 0; + dbg_journal_verb("journal: * fslimit reached, " + "rewinding to %u\n", + head->pos); + dbg_journal_verb("journal: * file size trimmed to %zu\n", + journal->fsize); + } + } + + /* Evict occupied nodes if necessary. */ + while (journal->free.len < size || + journal->nodes[jnext].flags > JOURNAL_FREE) { + + /* Evict least recent node if not empty. */ + journal_node_t *head = journal->nodes + journal->qhead; + + /* Check if it has been synced to disk. */ + if (head->flags & JOURNAL_DIRTY) { + return KNOTD_EAGAIN; + } + + /* Write back evicted node. */ + head->flags = JOURNAL_FREE; + lseek(journal->fd, JOURNAL_HSIZE + (journal->qhead + 1) * node_len, SEEK_SET); + if (!sfwrite(head, node_len, journal->fd)) { + return KNOTD_ERROR; + } + + dbg_journal("journal: * evicted node=%u, growing by +%u\n", + journal->qhead, head->len); + + /* Write back query state. */ + journal->qhead = (journal->qhead + 1) % journal->max_nodes; + uint16_t qstate[2] = {journal->qhead, journal->qtail}; + lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) { + return KNOTD_ERROR; + } + + /* Increase free segment. */ + journal->free.len += head->len; + } + + /* Invalidate node and write back. */ + n->id = id; + n->pos = journal->free.pos; + n->len = size; + n->flags = JOURNAL_FREE; + journal_update(journal, n); + + /* Write data to permanent storage. */ + lseek(journal->fd, n->pos, SEEK_SET); + if (!sfwrite(src, size, journal->fd)) { + return KNOTD_ERROR; + } + + /* Mark node as valid and write back. */ + n->flags = JOURNAL_VALID | journal->bflags; + journal_update(journal, n); + + /* Handle free segment on node rotation. */ + if (journal->qtail > jnext && journal->fslimit == FSLIMIT_INF) { + /* Trim free space. */ + journal->fsize -= journal->free.len; + dbg_journal_verb("journal: * trimmed filesize to %zu\n", + journal->fsize); + + /* Rewind free segment. */ + journal_node_t *n = journal->nodes + jnext; + journal->free.pos = n->pos; + journal->free.len = 0; + + } else { + /* Mark used space. */ + journal->free.pos += size; + journal->free.len -= size; + } + dbg_journal("journal: finished node=%u, data=<%u, %u> free=<%u, %u>\n", + journal->qtail, n->pos, n->pos + n->len, + journal->free.pos, + journal->free.pos + journal->free.len); + + /* Write back free segment state. */ + lseek(journal->fd, JOURNAL_HSIZE, SEEK_SET); + if (!sfwrite(&journal->free, node_len, journal->fd)) { + /* Node is marked valid and failed to shrink free space, + * node will be overwritten on the next write. Return error. + */ + dbg_journal("journal: failed to write back " + "free segment descriptor\n"); + return KNOTD_ERROR; + } + + /* Node write successful. */ + journal->qtail = jnext; + + /* Write back queue state, not essential as it may be recovered. + * qhead - lowest valid node identifier (least recent) + * qtail - highest valid node identifier (most recently used) + */ + uint16_t qstate[2] = {journal->qhead, journal->qtail}; + lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) { + dbg_journal("journal: failed to write back queue state\n"); + return KNOTD_ERROR; + } + + /*! \todo Delayed write-back? */ + dbg_journal_verb("journal: write of finished, nqueue=<%u, %u>\n", + journal->qhead, journal->qtail); + + return KNOTD_EOK; +} + +int journal_walk(journal_t *journal, journal_apply_t apply) +{ + int ret = KNOTD_EOK; + size_t i = journal->qhead; + for(; i != journal->qtail; i = (i + 1) % journal->max_nodes) { + /* Apply function. */ + ret = apply(journal, journal->nodes + i); + } + + return ret; +} + +int journal_update(journal_t *journal, journal_node_t *n) +{ + if (!journal || !n) { + return KNOTD_EINVAL; + } + + /* Calculate node offset. */ + const size_t node_len = sizeof(journal_node_t); + size_t i = n - journal->nodes; + if (i > journal->max_nodes) { + return KNOTD_EINVAL; + } + + /* Calculate node position in permanent storage. */ + long jn_fpos = JOURNAL_HSIZE + (i + 1) * node_len; + + dbg_journal("journal: syncing journal node=%zu at %ld\n", + i, jn_fpos); + + /* Write back. */ + lseek(journal->fd, jn_fpos, SEEK_SET); + if (!sfwrite(n, node_len, journal->fd)) { + dbg_journal("journal: failed to writeback node=%llu to %ld\n", + (unsigned long long)n->id, jn_fpos); + return KNOTD_ERROR; + } + + return KNOTD_EOK; +} + +int journal_close(journal_t *journal) +{ + /* Check journal. */ + if (!journal) { + return KNOTD_EINVAL; + } + + /* Unlock journal file. */ + journal->fl.l_type = F_UNLCK; + fcntl(journal->fd, F_SETLK, &journal->fl); + dbg_journal("journal: unlocked journal %p\n", journal); + + /* Close file. */ + close(journal->fd); + + dbg_journal("journal: closed journal %p\n", journal); + + /* Free allocated resources. */ + free(journal); + + return KNOTD_EOK; +} diff --git a/src/knot/server/journal.h b/src/knot/server/journal.h new file mode 100644 index 0000000..321b591 --- /dev/null +++ b/src/knot/server/journal.h @@ -0,0 +1,243 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file journal.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Journal for storing transactions on permanent storage. + * + * Journal stores entries on a permanent storage. + * Each written entry is guaranteed to persist until + * the maximum file size or node count is reached. + * Entries are removed from the least recent. + * + * Journal file structure + * <pre> + * uint16_t node_count + * uint16_t node_queue_head + * uint16_t node_queue_tail + * journal_entry_t free_segment + * node_count *journal_entry_t + * ...data... + * </pre> + * \addtogroup utils + * @{ + */ + +#ifndef _KNOTD_JOURNAL_H_ +#define _KNOTD_JOURNAL_H_ + +#include <stdint.h> +#include <fcntl.h> + +/*! + * \brief Journal entry flags. + */ +typedef enum journal_flag_t { + JOURNAL_NULL = 0 << 0, /*!< Invalid journal entry. */ + JOURNAL_FREE = 1 << 0, /*!< Free journal entry. */ + JOURNAL_VALID = 1 << 1, /*!< Valid journal entry. */ + JOURNAL_DIRTY = 1 << 2 /*!< Journal entry cannot be evicted. */ +} journal_flag_t; + +/*! + * \brief Journal node structure. + * + * Each node represents journal entry and points + * to position of the data in the permanent storage. + */ +typedef struct journal_node_t +{ + uint64_t id; /*!< Node ID. */ + uint16_t flags; /*!< Node flags. */ + uint32_t pos; /*!< Position in journal file. */ + uint32_t len; /*!< Entry data length. */ +} journal_node_t; + +/*! + * \brief Journal structure. + * + * Journal organizes entries as nodes. + * Nodes are stored in-memory for fast lookup and also + * backed by a permanent storage. + * Each journal has a fixed number of nodes. + * + * \todo Organize nodes in an advanced structure, like + * btree or hash table to improve lookup time. + */ +typedef struct journal_t +{ + int fd; + struct flock fl; /*!< File lock. */ + uint16_t max_nodes; /*!< Number of nodes. */ + uint16_t qhead; /*!< Node queue head. */ + uint16_t qtail; /*!< Node queue tail. */ + uint16_t bflags; /*!< Initial flags for each written node. */ + size_t fsize; /*!< Journal file size. */ + size_t fslimit; /*!< File size limit. */ + journal_node_t free; /*!< Free segment. */ + journal_node_t nodes[]; /*!< Array of nodes. */ +} journal_t; + +/*! + * \brief Entry identifier compare function. + * + * \retval -n if k1 < k2 + * \retval +n if k1 > k2 + * \retval 0 if k1 == k2 + */ +typedef int (*journal_cmp_t)(uint64_t k1, uint64_t k2); + +/*! + * \brief Function prototype for journal_walk() function. + * + * \param j Associated journal. + * \param n Pointer to target node. + */ +typedef int (*journal_apply_t)(journal_t *j, journal_node_t *n); + +/* + * Journal defaults and constants. + */ +#define JOURNAL_NCOUNT 1024 /*!< Default node count. */ +#define JOURNAL_HSIZE (sizeof(uint16_t) * 3) /*!< max_entries, qhead, qtail */ + +/*! + * \brief Create new journal. + * + * \param fn Journal file name, will be created if not exist. + * \param max_nodes Maximum number of nodes in journal. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_EINVAL if the file with given name cannot be created. + * \retval KNOTD_ERROR on I/O error. + */ +int journal_create(const char *fn, uint16_t max_nodes); + +/*! + * \brief Open journal file for read/write. + * + * \param fn Journal file name. + * \param fslimit File size limit (0 for no limit). + * \param bflags Initial flags for each written node. + * + * \retval new journal instance if successful. + * \retval NULL on error. + */ +journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags); + +/*! + * \brief Fetch entry node for given identifier. + * + * \param journal Associated journal. + * \param id Entry identifier. + * \param cf Compare function (NULL for equality). + * \param dst Destination for journal entry. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_ENOENT if not found. + */ +int journal_fetch(journal_t *journal, uint64_t id, + journal_cmp_t cf, journal_node_t** dst); + +/*! + * \brief Read journal entry data. + * + * \param journal Associated journal. + * \param id Entry identifier. + * \param cf Compare function (NULL for equality). + * \param dst Pointer to destination memory. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_ENOENT if the entry cannot be found. + * \retval KNOTD_EINVAL if the entry is invalid. + * \retval KNOTD_ERROR on I/O error. + */ +int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst); + +/*! + * \brief Write journal entry data. + * + * \param journal Associated journal. + * \param id Entry identifier. + * \param src Pointer to source data. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_EAGAIN if no free node is available, need to remove dirty nodes. + * \retval KNOTD_ERROR on I/O error. + */ +int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size); + +/*! + * \brief Return least recent node (journal head). + * + * \param journal Associated journal. + * + * \retval node if successful. + * \retval NULL if empty. + */ +static inline journal_node_t *journal_head(journal_t *journal) { + return journal->nodes + journal->qhead; +} + +/*! + * \brief Return node after most recent node (journal tail). + * + * \param journal Associated journal. + * + * \retval node if successful. + * \retval NULL if empty. + */ +static inline journal_node_t *journal_end(journal_t *journal) { + return journal->nodes + journal->qtail; +} + +/*! + * \brief Apply function to each node. + * + * \param journal Associated journal. + * \param apply Function to apply to each node. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int journal_walk(journal_t *journal, journal_apply_t apply); + +/*! + * \brief Sync node state to permanent storage. + * + * \note May be used for journal_walk(). + * + * \param journal Associated journal. + * \param n Pointer to node (must belong to associated journal). + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int journal_update(journal_t *journal, journal_node_t *n); + +/*! + * \brief Close journal file. + * + * \param journal Associated journal. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameter. + */ +int journal_close(journal_t *journal); + +#endif /* _KNOTD_JOURNAL_H_ */ diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c new file mode 100644 index 0000000..3966b26 --- /dev/null +++ b/src/knot/server/notify.c @@ -0,0 +1,327 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "knot/server/notify.h" + +#include "libknot/dname.h" +#include "libknot/packet/packet.h" +#include "libknot/rrset.h" +#include "libknot/packet/response.h" +#include "libknot/packet/query.h" +#include "libknot/consts.h" +#include "knot/other/error.h" +#include "libknot/zone/zonedb.h" +#include "libknot/common.h" +#include "libknot/util/error.h" +#include "libknot/util/wire.h" +#include "knot/server/zones.h" +#include "common/acl.h" +#include "common/evsched.h" +#include "knot/other/debug.h" +#include "knot/server/server.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ + +static int notify_request(const knot_rrset_t *rrset, + uint8_t *buffer, size_t *size) +{ + knot_packet_t *pkt = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + CHECK_ALLOC_LOG(pkt, KNOTD_ENOMEM); + + /*! \todo Get rid of the numeric constant. */ + int rc = knot_packet_set_max_size(pkt, 512); + if (rc != KNOT_EOK) { + knot_packet_free(&pkt); + return KNOTD_ERROR; + } + + rc = knot_query_init(pkt); + if (rc != KNOT_EOK) { + knot_packet_free(&pkt); + return KNOTD_ERROR; + } + + knot_question_t question; + + // this is ugly!! + question.qname = rrset->owner; + question.qtype = rrset->type; + question.qclass = rrset->rclass; + + rc = knot_query_set_question(pkt, &question); + if (rc != KNOT_EOK) { + knot_packet_free(&pkt); + return KNOTD_ERROR; + } + + /* Set random query ID. */ + knot_packet_set_random_id(pkt); + knot_wire_set_id(pkt->wireformat, pkt->header.id); + + /*! \todo add the SOA RR to the Answer section as a hint */ + /*! \todo this should not use response API!! */ +// rc = knot_response_add_rrset_answer(pkt, rrset, 0, 0, 0); +// if (rc != KNOT_EOK) { +// knot_packet_free(&pkt); +// return rc; +// } + + /*! \todo this should not use response API!! */ + knot_response_set_aa(pkt); + + knot_query_set_opcode(pkt, KNOT_OPCODE_NOTIFY); + + /*! \todo OPT RR ?? */ + + uint8_t *wire = NULL; + size_t wire_size = 0; + rc = knot_packet_to_wire(pkt, &wire, &wire_size); + if (rc != KNOT_EOK) { + knot_packet_free(&pkt); + return KNOTD_ERROR; + } + + if (wire_size > *size) { + knot_packet_free(&pkt); + return KNOTD_ESPACE; + } + + memcpy(buffer, wire, wire_size); + *size = wire_size; + + knot_packet_dump(pkt); + + knot_packet_free(&pkt); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int notify_create_response(knot_packet_t *request, uint8_t *buffer, + size_t *size) +{ + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + CHECK_ALLOC_LOG(response, KNOTD_ENOMEM); + + /* Set maximum packet size. */ + knot_packet_set_max_size(response, *size); + knot_response_init_from_query(response, request); + + // TODO: copy the SOA in Answer section + uint8_t *wire = NULL; + size_t wire_size = 0; + int rc = knot_packet_to_wire(response, &wire, &wire_size); + if (rc != KNOT_EOK) { + knot_packet_free(&response); + return rc; + } + + if (wire_size > *size) { + knot_packet_free(&response); + return KNOTD_ESPACE; + } + + memcpy(buffer, wire, wire_size); + *size = wire_size; + + knot_packet_dump(response); + knot_packet_free(&response); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +int notify_create_request(const knot_zone_contents_t *zone, uint8_t *buffer, + size_t *size) +{ + const knot_rrset_t *soa_rrset = knot_node_rrset( + knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); + if (soa_rrset == NULL) { + return KNOTD_ERROR; + } + + return notify_request(soa_rrset, buffer, size); +} + +/*----------------------------------------------------------------------------*/ + +static int notify_check_and_schedule(knot_nameserver_t *nameserver, + const knot_zone_t *zone, + sockaddr_t *from) +{ + if (zone == NULL || from == NULL || knot_zone_data(zone) == NULL) { + return KNOTD_EINVAL; + } + + /* Check ACL for notify-in. */ + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + if (from) { + if (acl_match(zd->notify_in, from) == ACL_DENY) { + /* rfc1996: Ignore request and report incident. */ + char straddr[SOCKADDR_STRLEN]; + sockaddr_tostr(from, straddr, sizeof(straddr)); + log_zone_notice("Unauthorized NOTIFY query " + "from %s:%d to zone '%s'.\n", + straddr, sockaddr_portnum(from), + zd->conf->name); + return KNOT_ERROR; + } else { + dbg_notify("notify: authorized NOTIFY query.\n"); + } + } + + /*! \todo Packet may contain updated RRs. */ + + /* Cancel REFRESH/RETRY timer. */ + evsched_t *sched = ((server_t *)knot_ns_get_data(nameserver))->sched; + event_t *refresh_ev = zd->xfr_in.timer; + if (refresh_ev) { + dbg_notify("notify: expiring REFRESH timer\n"); + evsched_cancel(sched, refresh_ev); + + /* Set REFRESH timer for now. */ + evsched_schedule(sched, refresh_ev, 0); + } + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int notify_process_request(knot_nameserver_t *ns, + knot_packet_t *notify, + sockaddr_t *from, + uint8_t *buffer, size_t *size) +{ + /*! \todo Most of this function is identical to xfrin_transfer_needed() + * - it will be fine to merge the code somehow. + */ + + if (notify == NULL || ns == NULL || buffer == NULL + || size == NULL || from == NULL) { + dbg_notify("notify: invalid parameters for %s()\n", + "notify_process_request"); + return KNOTD_EINVAL; + } + + int ret = KNOTD_EOK; + + dbg_notify("notify: parsing rest of the packet\n"); + if (notify->parsed < notify->size) { + ret = knot_packet_parse_rest(notify); + if (ret != KNOT_EOK) { + dbg_notify("notify: failed to parse NOTIFY query\n"); + knot_ns_error_response(ns, knot_packet_id(notify), + KNOT_RCODE_FORMERR, buffer, + size); + return KNOTD_EOK; + } + } + + // create NOTIFY response + dbg_notify("notify: creating response\n"); + ret = notify_create_response(notify, buffer, size); + if (ret != KNOTD_EOK) { + dbg_notify("notify: failed to create NOTIFY response\n"); + knot_ns_error_response(ns, knot_packet_id(notify), + KNOT_RCODE_SERVFAIL, buffer, + size); + return KNOTD_EOK; + } + + // find the zone + const knot_dname_t *qname = knot_packet_qname(notify); + const knot_zone_t *z = knot_zonedb_find_zone_for_name( + ns->zone_db, qname); + if (z == NULL) { + dbg_notify("notify: failed to find zone by name\n"); + knot_ns_error_response(ns, knot_packet_id(notify), + KNOT_RCODE_REFUSED, buffer, + size); + return KNOTD_EOK; + } + + notify_check_and_schedule(ns, z, from); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int notify_process_response(knot_nameserver_t *nameserver, + knot_packet_t *notify, + sockaddr_t *from, + uint8_t *buffer, size_t *size) +{ + if (nameserver == NULL || notify == NULL || from == NULL + || buffer == NULL || size == NULL) { + return KNOTD_EINVAL; + } + + /* Assert no response size. */ + *size = 0; + + /* Find matching zone. */ + const knot_dname_t *zone_name = knot_packet_qname(notify); + knot_zone_t *zone = knot_zonedb_find_zone(nameserver->zone_db, + zone_name); + if (!zone) { + return KNOTD_ENOENT; + } + if (!knot_zone_data(zone)) { + return KNOTD_ENOENT; + } + + /* Match ID against awaited. */ + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + pthread_mutex_lock(&zd->lock); + uint16_t pkt_id = knot_packet_id(notify); + notify_ev_t *ev = 0, *match = 0; + WALK_LIST(ev, zd->notify_pending) { + if ((int)pkt_id == ev->msgid) { + match = ev; + break; + } + } + + /* Found waiting NOTIFY query? */ + if (!match) { + log_server_notice("No pending NOTIFY query found for ID=%u\n", + pkt_id); + return KNOTD_ERROR; + } + + /* NOTIFY is now finished. */ + zones_cancel_notify(zd, match); + + /* Zone was removed/reloaded. */ + pthread_mutex_unlock(&zd->lock); + + log_server_info("Received response for pending NOTIFY query ID=%u\n", + pkt_id); + + return KNOTD_EOK; +} + diff --git a/src/knot/server/notify.h b/src/knot/server/notify.h new file mode 100644 index 0000000..c1bebb8 --- /dev/null +++ b/src/knot/server/notify.h @@ -0,0 +1,128 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file notify.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief NOTIFY request/reply API. + * + * \addtogroup query_processing + * @{ + */ + +#ifndef _KNOTD_NOTIFY_H_ +#define _KNOTD_NOTIFY_H_ + +#include <stdint.h> +#include <string.h> + +#include "libknot/zone/zone.h" +#include "libknot/packet/packet.h" +#include "libknot/zone/zonedb.h" +#include "common/lists.h" +#include "common/sockaddr.h" +#include "libknot/nameserver/name-server.h" + +/*! + * \brief Pending NOTIFY event. + * \see knot_zone_t.notify_pending + */ +typedef struct notify_ev_t { + node n; + int timeout; /*!< Timeout for events. */ + int retries; /*!< Number of retries. */ + int msgid; /*!< ID of pending NOTIFY. */ + sockaddr_t addr; /*!< Slave server address. */ + struct event_t *timer; /*!< Event timer. */ + knot_zone_t *zone; /*!< Associated zone. */ +} notify_ev_t; + +/*! + * \brief Creates a NOTIFY request message for SOA RR of the given zone. + * + * \param zone Zone from which to take the SOA RR. + * \param buffer Buffer to fill the message in. + * \param size In: available space in the buffer. Out: actual size of the + * message in bytes. + * + * \retval KNOTD_EOK + * \retval KNOTD_ESPACE + * \retval KNOTD_ERROR + */ +int notify_create_request(const knot_zone_contents_t *zone, uint8_t *buffer, + size_t *size); + +/*! + * \brief Creates a response for NOTIFY query. + * + * Valid NOTIFY query expires REFRESH timer for received qname. + * + * \see RFC1996 for query and response format. + * + * \param nameserver Name server structure to provide the needed data. + * \param query Response structure with parsed query. + * \param response_wire Place for the response in wire format. + * \param rsize Input: maximum acceptable size of the response. Output: real + * size of the response. + * + * \retval KNOTD_EOK if a valid response was created. + * \retval KNOTD_EACCES sender is not authorized to request NOTIFY. + * \retval KNOTD_EMALF if an error occured and the response is not valid. + */ +/*! + * \brief Evaluates incoming NOTIFY request and produces a reply. + * + * \param notify (Partially) parsed packet with the NOTIFY request. + * \param zonedb Zone database of the server. + * \param zone Zone which is probably out-of-date or NULL if there either is no + * zone corresponding to the request or if the zone is up-to-date. + * \param buffer Buffer to fill the message in. + * \param size In: available space in the buffer. Out: actual size of the + * response message in bytes. + * + * \retval KNOTD_EOK + * \retval KNOTD_EINVAL + * \retval KNOTD_EMALF + * \retval KNOTD_ERROR + */ +int notify_process_request(knot_nameserver_t *nameserver, + knot_packet_t *notify, + sockaddr_t *from, + uint8_t *buffer, size_t *size); + +/*! + * \brief Processes NOTIFY response packet. + * + * \param nameserver Name server structure to provide the needed data. + * \param from Address of the response sender. + * \param packet Parsed response packet. + * \param response_wire Place for the response in wire format. + * \param rsize Input: maximum acceptable size of the response. Output: real + * size of the response. + * + * \retval KNOTD_EOK if a valid response was created. + * \retval KNOTD_EINVAL on invalid parameters or packet. + * \retval KNOTD_EMALF if an error occured and the response is not valid. + */ +int notify_process_response(knot_nameserver_t *nameserver, + knot_packet_t *notify, + sockaddr_t *from, + uint8_t *buffer, size_t *size); + +#endif /* _KNOTD_NOTIFY_H_ */ + +/*! @} */ diff --git a/src/knot/server/server.c b/src/knot/server/server.c new file mode 100644 index 0000000..80db35d --- /dev/null +++ b/src/knot/server/server.c @@ -0,0 +1,730 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <errno.h> +#include <openssl/evp.h> +#include <assert.h> + +#include "knot/common.h" +#include "knot/other/error.h" +#include "knot/server/server.h" +#include "knot/server/udp-handler.h" +#include "knot/server/tcp-handler.h" +#include "knot/server/xfr-handler.h" +#include "libknot/nameserver/name-server.h" +#include "knot/stat/stat.h" +#include "libknot/zone/zonedb.h" +#include "knot/zone/zone-load.h" +#include "libknot/dname.h" +#include "knot/conf/conf.h" +#include "knot/server/zones.h" + +/*! \brief Event scheduler loop. */ +static int evsched_run(dthread_t *thread) +{ + iohandler_t *sched_h = (iohandler_t *)thread->data; + evsched_t *s = (evsched_t*)sched_h->data; + if (!s) { + return KNOTD_EINVAL; + } + + /* Run event loop. */ + event_t *ev = 0; + while((ev = evsched_next(s))) { + + /* Error. */ + if (!ev) { + return KNOTD_ERROR; + } + + /* Process termination event. */ + if (ev->type == EVSCHED_TERM) { + evsched_event_finished(s); + evsched_event_free(s, ev); + break; + } + + /* Process event. */ + if (ev->type == EVSCHED_CB && ev->cb) { + ev->cb(ev); + evsched_event_finished(s); + } else { + evsched_event_finished(s); + evsched_event_free(s, ev); + } + + /* Check for thread cancellation. */ + if (dt_is_cancelled(thread)) { + break; + } + } + + return KNOTD_EOK; +} + +/*! \brief List item for generic pointers. */ +typedef struct pnode_t { + struct node *next, *prev; /* Keep the ordering for lib/lists.h */ + void *p; /*!< \brief Useful data pointer. */ +} pnode_t; + +/*! \brief Unbind and dispose given interface. */ +static void server_remove_iface(iface_t *iface) +{ + /* Free UDP handler. */ + iohandler_t *handler = iface->handler[UDP_ID]; + if (handler) { + server_remove_handler(handler->server, handler); + } else { + if (iface->fd[UDP_ID] > -1) { + close(iface->fd[UDP_ID]); + } + } + + /* Free TCP handler. */ + handler = iface->handler[TCP_ID]; + if (handler) { + server_remove_handler(handler->server, handler); + } else { + if (iface->fd[TCP_ID] > -1) { + close(iface->fd[TCP_ID]); + } + } + + /* Free interface. */ + free(iface->addr); + free(iface); +} + +/*! + * \brief Initialize new interface from config value. + * + * Both TCP and UDP sockets will be created for the interface. + * + * \param new_if Allocated memory for the interface. + * \param cfg_if Interface template from config. + * + * \retval 0 if successful (EOK). + * \retval <0 on errors (EACCES, EINVAL, ENOMEM, EADDRINUSE). + */ +static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if) +{ + /* Initialize interface. */ + char errbuf[128]; + int opt = 1024 * 1024; + int snd_opt = 1024 * 1024; + memset(new_if, 0, sizeof(iface_t)); + + /* Create UDP socket. */ + int sock = socket_create(cfg_if->family, SOCK_DGRAM); + if (sock <= 0) { + strerror_r(errno, errbuf, sizeof(errbuf)); + log_server_error("Could not create UDP socket: %s.\n", + errbuf); + return sock; + } + if (socket_bind(sock, cfg_if->family, + cfg_if->address, cfg_if->port) < 0) { + socket_close(sock); + log_server_error("Could not bind to " + "UDP interface %s port %d.\n", + cfg_if->address, cfg_if->port); + return knot_map_errno(EACCES, EINVAL, ENOMEM); + } + + new_if->fd[UDP_ID] = sock; + new_if->type[UDP_ID] = cfg_if->family; + + /* Set socket options - voluntary. */ + if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_opt, sizeof(snd_opt)) < 0) { + // log_server_warning("Failed to configure socket " + // "write buffers.\n"); + } + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { + // log_server_warning("Failed to configure socket read buffers.\n"); + } + + /* Create TCP socket. */ + int ret = 0; + sock = socket_create(cfg_if->family, SOCK_STREAM); + if (sock <= 0) { + socket_close(new_if->fd[UDP_ID]); + strerror_r(errno, errbuf, sizeof(errbuf)); + log_server_error("Could not create TCP socket: %s.\n", + errbuf); + return sock; + } + + ret = socket_bind(sock, cfg_if->family, cfg_if->address, cfg_if->port); + if (ret < 0) { + socket_close(new_if->fd[UDP_ID]); + socket_close(sock); + log_server_error("Could not bind to " + "TCP interface %s port %d.\n", + cfg_if->address, cfg_if->port); + return ret; + } + + ret = socket_listen(sock, TCP_BACKLOG_SIZE); + if (ret < 0) { + socket_close(new_if->fd[UDP_ID]); + socket_close(sock); + log_server_error("Failed to listen on " + "TCP interface %s port %d.\n", + cfg_if->address, cfg_if->port); + return ret; + } + + new_if->fd[TCP_ID] = sock; + new_if->type[TCP_ID] = cfg_if->family; + new_if->port = cfg_if->port; + new_if->addr = strdup(cfg_if->address); + return KNOTD_EOK; +} + +/*! + * \brief Update bound sockets according to configuration. + * + * \param server Server instance. + * \return number of added sockets. + */ +static int server_bind_sockets(server_t *server) +{ + /*! \todo This requires locking to disable parallel updates. */ + + /* Lock configuration. */ + conf_read_lock(); + + /* Prepare helper lists. */ + int bound = 0; + node *m = 0; + list *newlist, unmatched; + newlist = malloc(sizeof(list)); + init_list(newlist); + init_list(&unmatched); + + /* Duplicate current list. */ + /*! \note Pointers to addr, handlers etc. will be shared. */ + list_dup(&unmatched, server->ifaces, sizeof(iface_t)); + + /* Update pointers. */ + WALK_LIST(m, unmatched) { + + /* Interfaces. */ + iface_t *m_if = (iface_t*)m; + for (int i = 0; i <= TCP_ID; ++i) { + iohandler_t *h = m_if->handler[i]; + if (h) { + h->iface = m_if; + } + + } + } + + /* Update bound interfaces. */ + node *n = 0; + WALK_LIST(n, conf()->ifaces) { + + /* Find already matching interface. */ + int found_match = 0; + conf_iface_t *cfg_if = (conf_iface_t*)n; + WALK_LIST(m, unmatched) { + iface_t *srv_if = (iface_t*)m; + + /* Matching port and address. */ + if (cfg_if->port == srv_if->port) { + if (strcmp(cfg_if->address, srv_if->addr) == 0) { + found_match = 1; + break; + } + } + } + + /* Found already bound interface. */ + if (found_match) { + rem_node(m); + } else { + + /* Create new interface. */ + m = malloc(sizeof(iface_t)); + if (server_init_iface((iface_t*)m, cfg_if) < 0) { + free(m); + m = 0; + } + + log_server_info("Binding to interface %s port %d.\n", + cfg_if->address, cfg_if->port); + } + + /* Move to new list. */ + if (m) { + add_tail(newlist, m); + ++bound; + } + } + + /* Unlock configuration. */ + conf_read_unlock(); + + /* Publish new list. */ + list* oldlist = rcu_xchg_pointer(&server->ifaces, newlist); + + /* Ensure no one is reading old interfaces. */ + synchronize_rcu(); + + /* Remove deprecated interfaces. */ + WALK_LIST_DELSAFE(n, m, unmatched) { + iface_t *rm_if = (iface_t*)n; + log_server_info("Removing interface %s port %d.\n", + rm_if->addr, rm_if->port); + server_remove_iface(rm_if); + } + + /* Free original list. */ + WALK_LIST_DELSAFE(n, m, *oldlist) { + /*! \note Need to keep internal pointers, as they are shared + * with the newly published list. */ + free(n); + } + free(oldlist); + + return bound; +} + +/*! + * \brief Update socket handlers according to configuration. + * + * \param server Server instance. + * \retval 0 if successful (EOK). + * \retval <0 on errors (EINVAL). + */ +static int server_bind_handlers(server_t *server) +{ + if (!server || !server->ifaces) { + return KNOTD_EINVAL; + } + + /* Lock config. */ + conf_read_lock(); + + /* Estimate number of threads/manager. */ + int thr_count = 0; + int tcp_unit_size = 0; + if (conf()->workers < 1) { + thr_count = dt_optimal_size(); + tcp_unit_size = (thr_count * 2) + 1; /* Will be always odd. */ + } else { + thr_count = conf()->workers; + tcp_unit_size = thr_count + 1; /* Force configured value. */ + } + + dbg_server("server: configured %d worker%s per UDP iface\n", + thr_count, thr_count > 1 ? "s" : ""); + dbg_server("server: configured %d worker%s per TCP iface\n", + tcp_unit_size - 1, (tcp_unit_size - 1) > 1 ? "s" : ""); + + /* Create socket handlers. */ + node *n = 0; + iohandler_t* h = 0; + WALK_LIST(n, *server->ifaces) { + + iface_t *iface = (iface_t*)n; + + /* Create UDP handlers. */ + dt_unit_t *unit = 0; + if (!iface->handler[UDP_ID]) { + unit = dt_create_coherent(thr_count, &udp_master, 0); + h = server_create_handler(server, iface->fd[UDP_ID], unit); + h->type = iface->type[UDP_ID]; + h->iface = iface; + + /* Save pointer. */ + rcu_set_pointer(&iface->handler[UDP_ID], h); + dbg_server("server: creating UDP socket handlers for '%s:%d'\n", + iface->addr, iface->port); + + } + + /* Create TCP handlers. */ + if (!iface->handler[TCP_ID]) { + unit = dt_create(tcp_unit_size); + h = server_create_handler(server, iface->fd[TCP_ID], unit); + tcp_loop_unit(h, unit); + h->type = iface->type[TCP_ID]; + h->iface = iface; + + /* Save pointer. */ + rcu_set_pointer(&iface->handler[TCP_ID], h); + dbg_server("server: creating TCP socket handlers for '%s:%d'\n", + iface->addr, iface->port); + } + + } + + /* Unlock config. */ + conf_read_unlock(); + + return KNOTD_EOK; +} + +server_t *server_create() +{ + // Create server structure + server_t *server = malloc(sizeof(server_t)); + if (server == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + server->state = ServerIdle; + init_list(&server->handlers); + server->ifaces = malloc(sizeof(list)); + init_list(server->ifaces); + + // Create event scheduler + dbg_server("server: creating event scheduler\n"); + server->sched = evsched_new(); + dt_unit_t *unit = dt_create_coherent(1, evsched_run, 0); + iohandler_t *h = server_create_handler(server, -1, unit); + h->data = server->sched; + + // Create name server + dbg_server("server: creating Name Server structure\n"); + server->nameserver = knot_ns_create(); + if (server->nameserver == NULL) { + free(server); + return NULL; + } + knot_ns_set_data(server->nameserver, server); + dbg_server("server: initializing OpenSSL\n"); + OpenSSL_add_all_digests(); + + // Create XFR handler + server->xfr_h = xfr_create(XFR_THREADS_COUNT, server->nameserver); + if (!server->xfr_h) { + knot_ns_destroy(&server->nameserver); + free(server); + return NULL; + } + + dbg_server("server: created server instance\n"); + return server; +} + +iohandler_t *server_create_handler(server_t *server, int fd, dt_unit_t *unit) +{ + // Create new worker + iohandler_t *handler = malloc(sizeof(iohandler_t)); + if (handler == 0) { + ERR_ALLOC_FAILED; + return 0; + } + + // Initialize + handler->fd = fd; + handler->type = 0; + handler->state = ServerIdle; + handler->server = server; + handler->unit = unit; + handler->iface = 0; + handler->data = 0; + handler->interrupt = 0; + + // Update unit data object + for (int i = 0; i < unit->size; ++i) { + dthread_t *thread = unit->threads[i]; + if (thread->run) { + dt_repurpose(thread, thread->run, handler); + } + } + + /*! \todo This requires either RCU compatible ptr swap or locking. */ + + /* Lock RCU. */ + rcu_read_lock(); + + // Update list + add_tail(&server->handlers, (node*)handler); + + /* Unlock RCU. */ + rcu_read_unlock(); + + return handler; +} + +int server_remove_handler(server_t *server, iohandler_t *h) +{ + // Check + if (h == 0) { + return KNOTD_EINVAL; + } + + /* Lock RCU. */ + rcu_read_lock(); + + /*! \todo This requires either RCU compatible ptr swap or locking. */ + + // Remove node + rem_node((node*)h); + + // Wait for dispatcher to finish + if (h->state & ServerRunning) { + h->state = ServerIdle; + dt_stop(h->unit); + + /* Call interrupt handler. */ + if (h->interrupt) { + h->interrupt(h); + } + + dt_join(h->unit); + } + + // Close socket + if (h->fd >= 0) { + socket_close(h->fd); + h->fd = -1; + } + + // Update interface + if (h->iface) { + int id = UDP_ID; + if (h->iface->handler[TCP_ID] == h) { + id = TCP_ID; + } + + h->iface->fd[id] = h->fd; + h->iface->handler[id] = 0; + } + + /* Unlock RCU. */ + rcu_read_unlock(); + + /* RCU synchronize. */ + synchronize_rcu(); + + // Destroy dispatcher and worker + dt_delete(&h->unit); + free(h); + return KNOTD_EOK; +} + +int server_start(server_t *server) +{ + // Check server + if (server == 0) { + return KNOTD_EINVAL; + } + + dbg_server("server: starting server instance\n"); + + /* Start XFR handler. */ + xfr_start(server->xfr_h); + + /* Lock configuration. */ + conf_read_lock(); + + // Start dispatchers + int ret = KNOTD_EOK; + server->state |= ServerRunning; + iohandler_t *h = 0; + WALK_LIST(h, server->handlers) { + + /* Already running. */ + if (h->state & ServerRunning) { + continue; + } + + h->state = ServerRunning; + ret = dt_start(h->unit); + if (ret < 0) { + break; + } + } + + /* Unlock configuration. */ + conf_read_unlock(); + + dbg_server("server: server started\n"); + + return ret; +} + +int server_wait(server_t *server) +{ + /* Join threading unit. */ + xfr_join(server->xfr_h); + + /* Lock RCU. */ + rcu_read_lock(); + + // Wait for handlers to finish + int ret = 0; + iohandler_t *h = 0, *nxt = 0; + WALK_LIST_DELSAFE(h, nxt, server->handlers) { + + /* Unlock RCU. */ + rcu_read_unlock(); + + /* Remove handler. */ + int dret = dt_join(h->unit); + if (dret < 0) { + ret = dret; + } + server_remove_handler(server, h); + + /* Relock RCU. */ + rcu_read_lock(); + } + + /* Unlock RCU. */ + rcu_read_unlock(); + + return ret; +} + +void server_stop(server_t *server) +{ + dbg_server("server: stopping server\n"); + + /* Wait for XFR master. */ + xfr_stop(server->xfr_h); + + /* Interrupt XFR handler execution. */ + if (server->xfr_h->interrupt) { + server->xfr_h->interrupt(server->xfr_h); + } + + /* Send termination event. */ + evsched_schedule_term(server->sched, 0); + + /* Lock RCU. */ + rcu_read_lock(); + + /* Notify servers to stop. */ + log_server_info("Stopping server...\n"); + server->state &= ~ServerRunning; + iohandler_t *h = 0; + WALK_LIST(h, server->handlers) { + h->state = ServerIdle; + dt_stop(h->unit); + + /* Call interrupt handler. */ + if (h->interrupt) { + h->interrupt(h); + } + } + + /* Unlock RCU. */ + rcu_read_unlock(); +} + +void server_destroy(server_t **server) +{ + // Check server + if (!server) { + return; + } + if (!*server) { + return; + } + + dbg_server("server: destroying server instance\n"); + + // Free XFR master + xfr_free((*server)->xfr_h); + + // Free interfaces + node *n = 0, *nxt = 0; + if ((*server)->ifaces) { + WALK_LIST_DELSAFE(n, nxt, *(*server)->ifaces) { + iface_t *iface = (iface_t*)n; + server_remove_iface(iface); + } + free((*server)->ifaces); + } + + stat_static_gath_free(); + knot_ns_destroy(&(*server)->nameserver); + + // Delete event scheduler + evsched_delete(&(*server)->sched); + + free(*server); + + EVP_cleanup(); + + *server = NULL; +} + +int server_conf_hook(const struct conf_t *conf, void *data) +{ + server_t *server = (server_t *)data; + + if (!server) { + return KNOTD_EINVAL; + } + + /* Update bound sockets. */ + int ret = KNOTD_EOK; + if ((ret = server_bind_sockets(server)) < 0) { + log_server_error("Failed to bind configured " + "interfaces.\n"); + return KNOTD_ERROR; + } + + /* Update handlers. */ + if ((ret = server_bind_handlers(server)) < 0) { + log_server_error("Failed to create handlers for " + "configured interfaces.\n"); + return ret; + } + + /* Exit if the server is not running. */ + if (!(server->state & ServerRunning)) { + return KNOTD_ENOTRUNNING; + } + + /* Lock configuration. */ + conf_read_lock(); + + /* Start new handlers. */ + iohandler_t *h = 0; + WALK_LIST(h, server->handlers) { + if (!(h->state & ServerRunning)) { + h->state = ServerRunning; + ret = dt_start(h->unit); + if (ret < 0) { + log_server_error("Handler for %s:%d " + "has failed to start.\n", + h->iface->addr, + h->iface->port); + break; + } + } + } + + /* Unlock config. */ + conf_read_unlock(); + + return ret; +} + diff --git a/src/knot/server/server.h b/src/knot/server/server.h new file mode 100644 index 0000000..480219b --- /dev/null +++ b/src/knot/server/server.h @@ -0,0 +1,211 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file server.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Core server functions. + * + * Contains the main high-level server structure (server_t) and interface + * to functions taking care of proper initialization of the server and clean-up + * when terminated. + * + * As of now, the server supports only one zone file and only in a special + * format. + * + * \see zone-parser.h + * + * \addtogroup server + * @{ + */ + +#ifndef _KNOTD_SERVER_H_ +#define _KNOTD_SERVER_H_ + +#include "knot/common.h" +#include "libknot/nameserver/name-server.h" +#include "knot/server/xfr-handler.h" +#include "knot/server/socket.h" +#include "knot/server/dthreads.h" +#include "libknot/zone/zonedb.h" +#include "common/evsched.h" +#include "common/lists.h" + +/* Forwad declarations. */ +struct iface_t; +struct iohandler_t; +struct server_t; +struct conf_t; + +/*! \brief I/O handler structure. + */ +typedef struct iohandler_t { + struct node *next, *prev; + int fd; /*!< I/O filedescriptor */ + int type; /*!< Descriptor type/family. */ + unsigned state; /*!< Handler state */ + dt_unit_t *unit; /*!< Threading unit */ + struct iface_t *iface; /*!< Reference to associated interface. */ + struct server_t *server; /*!< Reference to server */ + void *data; /*!< Persistent data for I/O handler. */ + void (*interrupt)(struct iohandler_t *h); /*!< Interrupt handler. */ + +} iohandler_t; + +/*! \brief Round-robin mechanism of switching. + */ +#define get_next_rr(current, count) \ + (((current) + 1) % (count)) + +/*! \brief Server state flags. + */ +typedef enum { + ServerIdle = 0 << 0, /*!< Server is idle. */ + ServerRunning = 1 << 0 /*!< Server is running. */ +} server_state; + +/*! + * \brief Server interface structure. + */ +typedef struct iface_t { + struct node *next, *prev; + int fd[2]; /*!< \brief Socket filedescriptors (UDP, TCP). */ + int type[2]; /*!< \brief Socket type. */ + int port; /*!< \brief Socket port. */ + char* addr; /*!< \brief Socket address. */ + iohandler_t* handler[2]; /*!< \brief Associated I/O handlers. */ +} iface_t; + +/* Interface indexes. */ +#define UDP_ID 0 +#define TCP_ID 1 + +/*! + * \brief Main server structure. + * + * Keeps references to all important structures needed for operation. + */ +typedef struct server_t { + + /*! \brief Server state tracking. */ + volatile unsigned state; + + /*! \brief Reference to the name server structure. */ + knot_nameserver_t *nameserver; + + /*! \brief XFR handler. */ + xfrhandler_t *xfr_h; + + /*! \brief Event scheduler. */ + evsched_t *sched; + + /*! \brief I/O handlers list. */ + list handlers; + + /*! \brief List of interfaces. */ + list* ifaces; + +} server_t; + +/*! + * \brief Allocates and initializes the server structure. + * + * Creates all other main structures. + * + * \retval New instance if successful. + * \retval NULL If an error occured. + */ +server_t *server_create(); + +/*! + * \brief Create and bind handler to given filedescriptor. + * + * Pointer to handler instance is used as native unique identifier. + * This requests instance not to be reallocated. + * + * \param server Server structure to be used for operation. + * \param fd I/O filedescriptor. + * \param unit Threading unit to serve given filedescriptor. + * + * \retval Handler instance if successful. + * \retval NULL If an error occured. + */ +iohandler_t *server_create_handler(server_t *server, int fd, dt_unit_t *unit); + +/*! + * \brief Delete handler. + * + * \param server Server structure to be used for operation. + * \param ref I/O handler instance. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int server_remove_handler(server_t *server, iohandler_t *ref); + +/*! + * \brief Starts the server. + * + * \param server Server structure to be used for operation. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * + * \todo When a module for configuration is added, the filename parameter will + * be removed. + */ +int server_start(server_t *server); + +/*! + * \brief Waits for the server to finish. + * + * \param server Server structure to be used for operation. + * + * \retval 0 On success (EOK). + * \retval <0 If an error occured (EINVAL). + */ +int server_wait(server_t *server); + +/*! + * \brief Requests server to stop. + * + * \param server Server structure to be used for operation. + */ +void server_stop(server_t *server); + +/*! + * \brief Properly destroys the server structure. + * + * \param server Server structure to be used for operation. + */ +void server_destroy(server_t **server); + +/*! + * \brief Server config hook. + * + * Routine for dynamic server reconfiguration. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ENOTRUNNING if the server is not running. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ERROR unspecified error. + */ +int server_conf_hook(const struct conf_t *conf, void *data); + +#endif // _KNOTD_SERVER_H_ + +/*! @} */ diff --git a/src/knot/server/socket.c b/src/knot/server/socket.c new file mode 100644 index 0000000..d3dd664 --- /dev/null +++ b/src/knot/server/socket.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <netdb.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> + +#include "knot/other/error.h" +#include "knot/common.h" +#include "knot/server/socket.h" + +int socket_create(int family, int type) +{ + /* Create socket. */ + int ret = socket(family, type, 0); + if (ret < 0) { + return knot_map_errno(EACCES, EINVAL, ENOMEM); + } + + return ret; +} + +int socket_connect(int fd, const char *addr, unsigned short port) +{ + /* NULL address => any */ + if (!addr) { + addr = "0.0.0.0"; + } + + /* Resolve address. */ + int ret = KNOTD_EOK; + struct addrinfo hints, *res; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ((ret = getaddrinfo(addr, NULL, &hints, &res)) != 0) { + return KNOTD_EINVAL; + } + + /* Evaluate address type. */ + struct sockaddr *saddr = 0; + socklen_t addrlen = 0; +#ifndef DISABLE_IPV6 + if (res->ai_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res->ai_addr; + ipv6->sin6_port = htons(port); + saddr = (struct sockaddr*)ipv6; + addrlen = sizeof(struct sockaddr_in6); + } +#endif + if (res->ai_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in*)res->ai_addr; + ipv4->sin_port = htons(port); + saddr = (struct sockaddr*)ipv4; + addrlen = sizeof(struct sockaddr_in); + } + + /* Connect. */ + ret = -1; + if (addr) { + ret = connect(fd, saddr, addrlen); + if (ret < 0) { + ret = knot_map_errno(EACCES, EADDRINUSE, EAGAIN, + ECONNREFUSED, EISCONN); + } + } else { + ret = KNOTD_EINVAL; + } + + + /* Free addresses. */ + freeaddrinfo(res); + + return ret; +} + +int socket_bind(int socket, int family, const char *addr, unsigned short port) +{ + /* Check address family. */ + struct sockaddr* paddr = 0; + socklen_t addrlen = 0; + struct sockaddr_in saddr; +#ifndef DISABLE_IPV6 + struct sockaddr_in6 saddr6; +#endif + if (family == AF_INET) { + + /* Initialize socket address. */ + paddr = (struct sockaddr*)&saddr; + addrlen = sizeof(saddr); + if (getsockname(socket, paddr, &addrlen) < 0) { + return KNOTD_EINVAL; + } + + /* Set address and port. */ + saddr.sin_port = htons(port); + if (inet_pton(family, addr, &saddr.sin_addr) < 0) { + saddr.sin_addr.s_addr = INADDR_ANY; + char buf[INET_ADDRSTRLEN]; + inet_ntop(family, &saddr.sin_addr, buf, sizeof(buf)); + log_server_error("Address '%s' is invalid, " + "using '%s' instead.\n", + addr, buf); + + } + + } else { + +#ifdef DISABLE_IPV6 + log_server_error("ipv6 support disabled\n"); + return KNOTD_ENOIPV6; +#else + /* Initialize socket address. */ + paddr = (struct sockaddr*)&saddr6; + addrlen = sizeof(saddr6); + if (getsockname(socket, paddr, &addrlen) < 0) { + return KNOTD_EINVAL; + } + + /* Set address and port. */ + saddr6.sin6_port = htons(port); + if (inet_pton(family, addr, &saddr6.sin6_addr) < 0) { + memcpy(&saddr6.sin6_addr, &in6addr_any, sizeof(in6addr_any)); + char buf[INET6_ADDRSTRLEN]; + inet_ntop(family, &saddr6.sin6_addr, buf, sizeof(buf)); + log_server_error("Address '%s' is invalid, " + "using '%s' instead\n", + addr, buf); + + } +#endif + } + + /* Reuse old address if taken. */ + int flag = 1; + int ret = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, + &flag, sizeof(flag)); + if (ret < 0) { + return KNOTD_EINVAL; + } + + /* Bind to specified address. */ + int res = bind(socket, paddr, addrlen); + if (res < 0) { + log_server_error("Cannot bind to socket (%d).\n", + errno); + return knot_map_errno(EADDRINUSE, EINVAL, EACCES, ENOMEM); + } + + return KNOTD_EOK; +} + +int socket_listen(int socket, int backlog_size) +{ + int ret = listen(socket, backlog_size); + if (ret < 0) { + return knot_map_errno(EADDRINUSE); + } + + return KNOTD_EOK; +} + +int socket_close(int socket) +{ + if (close(socket) < 0) { + return KNOTD_EINVAL; + } + + return KNOTD_EOK; +} + diff --git a/src/knot/server/socket.h b/src/knot/server/socket.h new file mode 100644 index 0000000..dff5216 --- /dev/null +++ b/src/knot/server/socket.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file socket.h + * + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief Generic sockets APIs. + * + * This file provides platform-independent sockets. + * Functions work on sockets created via system socket(2) functions. + * + * You can use standard I/O functions send(), sendto(), recv(), recvfrom() + * like you would with a normal sockets. + * + * \addtogroup network + * @{ + */ + +#ifndef _KNOTD_SOCKET_H_ +#define _KNOTD_SOCKET_H_ + +/* POSIX only. */ +#include <sys/socket.h> +#include "common/sockaddr.h" + +/*! \brief Socket-related constants. */ +typedef enum { + SOCKET_MTU_SZ = 8192, /*!< \todo Determine UDP MTU size. */ +} socket_const_t; + +/*! + * \brief Create socket. + * + * \param family Socket family (PF_INET, PF_IPX, PF_PACKET, PF_UNIX). + * \param type Socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW). + * + * \retval new socket filedescriptor on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOMEM out of memory error. + * \retval KNOTD_EACCES process does not have appropriate privileges. + * \retval KNOTD_ERROR unspecified error. + */ +int socket_create(int family, int type); + +/*! + * \brief Connect to remote host. + * + * \param fd Socket filedescriptor. + * \param addr Requested address. + * \param port Requested port. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + * \retval KNOTD_EACCES process does not have appropriate privileges. + * \retval KNOTD_EAGAIN lack of resources, try again. + * \retval KNOTD_EADDRINUSE address already in use. + * \retval KNOTD_ECONNREFUSED connection refused. + * \retval KNOTD_EISCONN already connected. + * \retval KNOTD_ERROR unspecified error. + */ +int socket_connect(int fd, const char *addr, unsigned short port); + +/*! + * \brief Listen on given socket. + * + * \param fd Socket filedescriptor. + * \param family Socket family. + * \param addr Requested address. + * \param port Requested port. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + * \retval KNOTD_EACCES process does not have appropriate privileges. + * \retval KNOTD_EADDRINUSE address already in use. + * \retval KNOTD_ENOMEM out of memory error. + * \retval KNOTD_ENOIPV6 IPv6 support is not available. + * \retval KNOTD_ERROR unspecified error. + */ +int socket_bind(int fd, int family, const char *addr, unsigned short port); + +/*! + * \brief Listen on given TCP socket. + * + * \param fd Socket filedescriptor. + * \param backlog_size Requested TCP backlog size. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EADDRINUSE address already in use. + * \retval KNOTD_ERROR unspecified error. + */ +int socket_listen(int fd, int backlog_size); + +/*! + * \brief Close and deinitialize socket. + * + * \param fd Socket filedescriptor. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + */ +int socket_close(int fd); + + +#endif // _KNOTD_SOCKET_H_ + +/*! @} */ diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c new file mode 100644 index 0000000..db58fef --- /dev/null +++ b/src/knot/server/tcp-handler.c @@ -0,0 +1,511 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <netinet/tcp.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "common/sockaddr.h" +#include "common/skip-list.h" +#include "common/fdset.h" +#include "knot/common.h" +#include "knot/server/tcp-handler.h" +#include "knot/server/xfr-handler.h" +#include "libknot/nameserver/name-server.h" +#include "knot/other/error.h" +#include "knot/stat/stat.h" +#include "libknot/util/wire.h" +#include "knot/server/zones.h" + +/*! \brief TCP worker data. */ +typedef struct tcp_worker_t { + iohandler_t *ioh; /*!< Shortcut to I/O handler. */ + fdset_t *fdset; /*!< File descriptor set. */ + int pipe[2]; /*!< Master-worker signalization pipes. */ +} tcp_worker_t; + +/* + * Forward decls. + */ + +/*! \brief Wrapper for TCP send. */ +static int xfr_send_cb(int session, sockaddr_t *addr, uint8_t *msg, size_t msglen) +{ + UNUSED(addr); + return tcp_send(session, msg, msglen); +} + +/*! + * \brief TCP event handler function. + * + * Handle single TCP event. + * + * \param w Associated I/O event. + * \param revents Returned events. + */ +static void tcp_handle(tcp_worker_t *w, int fd) +{ + if (fd < 0 || !w || !w->ioh) { + dbg_net("tcp: tcp_handle(%p, %d) - invalid parameters\n", w, fd); + return; + } + + dbg_net("tcp: handling TCP event on fd=%d in thread %p.\n", + fd, (void*)pthread_self()); + + knot_nameserver_t *ns = w->ioh->server->nameserver; + xfrhandler_t *xfr_h = w->ioh->server->xfr_h; + + /* Check address type. */ + sockaddr_t addr; + if (sockaddr_init(&addr, w->ioh->type) != KNOTD_EOK) { + log_server_error("Socket type %d is not supported, " + "IPv6 support is probably disabled.\n", + w->ioh->type); + return; + } + + /* Receive data. */ + uint8_t qbuf[65535]; /*! \todo This may be problematic. */ + size_t qbuf_maxlen = sizeof(qbuf); + int n = tcp_recv(fd, qbuf, qbuf_maxlen, &addr); + if (n <= 0) { + dbg_net("tcp: client on fd=%d disconnected\n", fd); + fdset_remove(w->fdset, fd); + close(fd); + return; + } + + /* Parse query. */ +// knot_response_t *resp = knot_response_new(qbuf_maxlen); + size_t resp_len = qbuf_maxlen; // 64K + + /* Parse query. */ + knot_packet_type_t qtype = KNOT_QUERY_NORMAL; + + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + if (packet == NULL) { + uint16_t pkt_id = knot_wire_get_id(qbuf); + knot_ns_error_response(ns, pkt_id, KNOT_RCODE_SERVFAIL, + qbuf, &resp_len); + return; + } + + int res = knot_ns_parse_packet(qbuf, n, packet, &qtype); + if (unlikely(res != KNOTD_EOK)) { + + /* Send error response on dnslib RCODE. */ + if (res > 0) { + uint16_t pkt_id = knot_wire_get_id(qbuf); + knot_ns_error_response(ns, pkt_id, res, + qbuf, &resp_len); + } + +// knot_response_free(&resp); + knot_packet_free(&packet); + return; + } + + /* Handle query. */ + knot_ns_xfr_t xfr; + res = KNOTD_ERROR; + switch(qtype) { + + /* Query types. */ + case KNOT_QUERY_NORMAL: + res = knot_ns_answer_normal(ns, packet, qbuf, &resp_len); + break; + case KNOT_QUERY_IXFR: + res = xfr_request_init(&xfr, XFR_TYPE_IOUT, XFR_FLAG_TCP, packet); + if (res != KNOTD_EOK) { + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_SERVFAIL, qbuf, + &resp_len); + res = KNOTD_EOK; + break; + } + xfr.send = xfr_send_cb; + xfr.session = fd; + memcpy(&xfr.addr, &addr, sizeof(sockaddr_t)); + xfr_request(xfr_h, &xfr); + dbg_net("tcp: enqueued IXFR query on fd=%d\n", fd); + return; + case KNOT_QUERY_AXFR: + res = xfr_request_init(&xfr, XFR_TYPE_AOUT, XFR_FLAG_TCP, packet); + if (res != KNOTD_EOK) { + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_SERVFAIL, qbuf, + &resp_len); + res = KNOTD_EOK; + break; + } + xfr.send = xfr_send_cb; + xfr.session = fd; + memcpy(&xfr.addr, &addr, sizeof(sockaddr_t)); + xfr_request(xfr_h, &xfr); + dbg_net("tcp: enqueued AXFR query on fd=%d\n", fd); + return; + + /*! \todo Implement query notify/update. */ + case KNOT_QUERY_UPDATE: + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_NOTIMPL, qbuf, + &resp_len); + res = KNOTD_EOK; + break; + + /* Unhandled opcodes. */ + case KNOT_QUERY_NOTIFY: /*!< Only in UDP. */ + case KNOT_RESPONSE_NOTIFY: /*!< Only in UDP. */ + case KNOT_RESPONSE_NORMAL: /*!< TCP handler doesn't send queries. */ + case KNOT_RESPONSE_AXFR: /*!< Processed in XFR handler. */ + case KNOT_RESPONSE_IXFR: /*!< Processed in XFR handler. */ + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_REFUSED, qbuf, + &resp_len); + res = KNOTD_EOK; + break; + + /* Unknown opcodes. */ + default: + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_FORMERR, qbuf, + &resp_len); + res = KNOTD_EOK; + break; + } + + knot_packet_free(&packet); + + /* Send answer. */ + if (res == KNOTD_EOK) { + + dbg_net("tcp: got answer of size %zd.\n", + resp_len); + + assert(resp_len > 0); + res = tcp_send(fd, qbuf, resp_len); + + /* Check result. */ + if (res != (int)resp_len) { + dbg_net("tcp: %s: failed: %d - %d.\n", + "socket_send()", + res, errno); + } + } else { + dbg_net("tcp: failed to respond to query type=%d on fd=%d - %s\n", + qtype, fd, knotd_strerror(res));; + } + + return; +} + +static int tcp_accept(int fd) +{ + /* Accept incoming connection. */ + int incoming = accept(fd, 0, 0); + + /* Evaluate connection. */ + if (incoming < 0) { + if (errno != EINTR) { + log_server_error("Cannot accept connection " + "(%d).\n", errno); + } + } else { + dbg_net("tcp: accepted connection fd=%d\n", incoming); + } + + return incoming; +} + +tcp_worker_t* tcp_worker_create() +{ + tcp_worker_t *w = malloc(sizeof(tcp_worker_t)); + if (!w) { + dbg_net("tcp: out of memory when creating worker\n"); + return 0; + } + + /* Create signal pipes. */ + memset(w, 0, sizeof(tcp_worker_t)); + if (pipe(w->pipe) < 0) { + free(w); + return 0; + } + + /* Create fdset. */ + w->fdset = fdset_new(); + if (!w->fdset) { + close(w->pipe[0]); + close(w->pipe[1]); + free(w); + } + + fdset_add(w->fdset, w->pipe[0], OS_EV_READ); + + return w; +} + +void tcp_worker_free(tcp_worker_t* w) +{ + if (!w) { + return; + } + + /* Destroy fdset. */ + fdset_destroy(w->fdset); + + /* Close pipe write end and worker. */ + close(w->pipe[0]); + close(w->pipe[1]); + free(w); +} + +/* + * Public APIs. + */ + +int tcp_send(int fd, uint8_t *msg, size_t msglen) +{ + + /*! \brief TCP corking. + * \see http://vger.kernel.org/~acme/unbehaved.txt + */ +#ifdef TCP_CORK + int cork = 1; + setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); +#endif + + /* Send message size. */ + unsigned short pktsize = htons(msglen); + int sent = send(fd, &pktsize, sizeof(pktsize), 0); + if (sent < 0) { + return KNOTD_ERROR; + } + + /* Send message data. */ + sent = send(fd, msg, msglen, 0); + if (sent < 0) { + return KNOTD_ERROR; + } + +#ifdef TCP_CORK + /* Uncork. */ + cork = 0; + setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); +#endif + return sent; +} + +int tcp_recv(int fd, uint8_t *buf, size_t len, sockaddr_t *addr) +{ + /* Receive size. */ + unsigned short pktsize = 0; + int n = recv(fd, &pktsize, sizeof(unsigned short), MSG_WAITALL); + if (n < 0) { + return KNOTD_ERROR; + } + + pktsize = ntohs(pktsize); + + // Check packet size for NULL + if (pktsize == 0) { + return KNOTD_ERROR; + } + + dbg_net("tcp: incoming packet size=%hu on fd=%d\n", + pktsize, fd); + + // Check packet size + if (len < pktsize) { + return KNOTD_ENOMEM; + } + + /* Receive payload. */ + n = recv(fd, buf, pktsize, MSG_WAITALL); + + /* Get peer name. */ + if (addr) { + socklen_t alen = addr->len; + getpeername(fd, addr->ptr, &alen); + } + + dbg_net("tcp: received packet size=%d on fd=%d\n", + n, fd); + + return n; +} + +int tcp_loop_master(dthread_t *thread) +{ + iohandler_t *handler = (iohandler_t *)thread->data; + dt_unit_t *unit = thread->unit; + tcp_worker_t **workers = handler->data; + + /* Check socket. */ + if (!handler || handler->fd < 0 || !workers) { + dbg_net("tcp: failed to initialize master thread\n"); + return KNOTD_EINVAL; + } + + /* Accept connections. */ + int id = 0; + dbg_net("tcp: created 1 master with %d workers, backend is '%s' \n", + unit->size - 1, fdset_method()); + while(1) { + /* Check for cancellation. */ + if (dt_is_cancelled(thread)) { + break; + } + + /* Accept client. */ + int client = tcp_accept(handler->fd); + if (client < 0) { + continue; + } + + /* Add to worker in RR fashion. */ + if (write(workers[id]->pipe[1], &client, sizeof(int)) < 0) { + dbg_net("tcp: failed to register fd=%d to worker=%d\n", + client, id); + close(client); + continue; + } + id = get_next_rr(id, unit->size - 1); + } + + dbg_net("tcp: master thread finished\n"); + free(workers); + + return KNOTD_EOK; +} + +int tcp_loop_worker(dthread_t *thread) +{ + tcp_worker_t *w = thread->data; + if (!w) { + return KNOTD_EINVAL; + } + + /* Accept clients. */ + dbg_net_verb("tcp: worker %p started\n", w); + for (;;) { + + /* Cancellation point. */ + if (dt_is_cancelled(thread)) { + break; + } + + /* Wait for events. */ + int nfds = fdset_wait(w->fdset); + if (nfds <= 0) { + continue; + } + + /* Process incoming events. */ + dbg_net_verb("tcp: worker %p registered %d events\n", + w, nfds); + fdset_it_t it; + fdset_begin(w->fdset, &it); + while(1) { + + /* Handle incoming clients. */ + if (it.fd == w->pipe[0]) { + int client = 0; + if (read(it.fd, &client, sizeof(int)) < 0) { + continue; + } + + dbg_net_verb("tcp: worker %p registered " + "client %d\n", + w, client); + fdset_add(w->fdset, client, OS_EV_READ); + } else { + /* Handle other events. */ + tcp_handle(w, it.fd); + } + + /* Check if next exists. */ + if (fdset_next(w->fdset, &it) != 0) { + break; + } + } + + } + + /* Stop whole unit. */ + dbg_net_verb("tcp: worker %p finished\n", w); + tcp_worker_free(w); + return KNOTD_EOK; +} + +int tcp_loop_unit(iohandler_t *ioh, dt_unit_t *unit) +{ + if (unit->size < 1) { + return KNOTD_EINVAL; + } + + /* Create unit data. */ + tcp_worker_t **workers = malloc((unit->size - 1) * + sizeof(tcp_worker_t *)); + if (!workers) { + dbg_net("tcp: cannot allocate list of workers\n"); + return KNOTD_EINVAL; + } + + /* Prepare worker data. */ + unsigned allocated = 0; + for (unsigned i = 0; i < unit->size - 1; ++i) { + workers[i] = tcp_worker_create(); + if (workers[i] == 0) { + break; + } + workers[i]->ioh = ioh; + ++allocated; + } + + /* Check allocated workers. */ + if (allocated != unit->size - 1) { + for (unsigned i = 0; i < allocated; ++i) { + tcp_worker_free(workers[i]); + } + + free(workers); + dbg_net("tcp: cannot create workers\n"); + return KNOTD_EINVAL; + } + + /* Store worker data. */ + ioh->data = workers; + + /* Repurpose workers. */ + for (unsigned i = 0; i < allocated; ++i) { + dt_repurpose(unit->threads[i + 1], tcp_loop_worker, workers[i]); + } + + /* Repurpose first thread as master (unit controller). */ + dt_repurpose(unit->threads[0], tcp_loop_master, ioh); + + return KNOTD_EOK; +} diff --git a/src/knot/server/tcp-handler.h b/src/knot/server/tcp-handler.h new file mode 100644 index 0000000..f5fd17a --- /dev/null +++ b/src/knot/server/tcp-handler.h @@ -0,0 +1,103 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file tcp-handler.h + * + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief TCP sockets threading model. + * + * The master socket distributes incoming connections among + * the worker threads ("buckets"). Each threads processes it's own + * set of sockets, and eliminates mutual exclusion problem by doing so. + * + * \todo Improve documentation of TCP pool API and use proper error codes. + * + * \addtogroup server + * @{ + */ + +#ifndef _KNOTD_TCPHANDLER_H_ +#define _KNOTD_TCPHANDLER_H_ + +#include <stdint.h> + +#include "knot/server/socket.h" +#include "knot/server/server.h" +#include "knot/server/dthreads.h" + +/*! + * \brief Send TCP message. + * + * \param fd Associated socket. + * \param msg Buffer for a query wireformat. + * \param msglen Buffer maximum size. + * + * \retval Number of sent data on success. + * \retval KNOTD_ERROR on error. + */ +int tcp_send(int fd, uint8_t *msg, size_t msglen); + +/*! + * \brief Send TCP message. + * + * \param fd Associated socket. + * \param buf Buffer for incoming bytestream. + * \param len Buffer maximum size. + * \param addr Source address. + * + * \retval Number of read bytes on success. + * \retval KNOTD_ERROR on error. + * \retval KNOTD_ENOMEM on potential buffer overflow. + */ +int tcp_recv(int fd, uint8_t *buf, size_t len, sockaddr_t *addr); + +/*! + * \brief TCP event loop for accepting connections. + * + * \param thread Associated thread from DThreads unit. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + */ +int tcp_loop_master(dthread_t *thread); + +/*! + * \brief TCP event loop for processing requests. + * + * \param thread Associated thread from DThreads unit. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + */ +int tcp_loop_worker(dthread_t *thread); + +/*! + * \brief Create TCP event handler from threading unit. + * + * Set-up threading unit for processing TCP requests. + * + * \param ioh Associated I/O handler. + * \param thread Associated thread from DThreads unit. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + */ +int tcp_loop_unit(iohandler_t *ioh, dt_unit_t *unit); + +#endif // _KNOTD_TCPHANDLER_H_ + +/*! @} */ diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c new file mode 100644 index 0000000..f7ae550 --- /dev/null +++ b/src/knot/server/udp-handler.c @@ -0,0 +1,438 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <netinet/in.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "common/sockaddr.h" +#include "knot/common.h" +#include "knot/other/error.h" +#include "knot/server/udp-handler.h" +#include "libknot/nameserver/name-server.h" +#include "knot/stat/stat.h" +#include "knot/server/server.h" +#include "libknot/util/wire.h" +#include "libknot/consts.h" +#include "libknot/packet/packet.h" +#include "knot/server/zones.h" +#include "knot/server/notify.h" + +///*! \brief Wrapper for UDP send. */ +//static int xfr_send_udp(int session, sockaddr_t *addr, uint8_t *msg, size_t msglen) +//{ +// return sendto(session, msg, msglen, 0, addr->ptr, addr->len); +//} + +int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, + sockaddr_t* addr, knot_nameserver_t *ns) +{ + dbg_net("udp: fd=%d received %zd bytes.\n", fd, qbuflen); + + knot_packet_type_t qtype = KNOT_QUERY_NORMAL; + *resp_len = SOCKET_MTU_SZ; + + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + if (packet == NULL) { + dbg_net("udp: failed to create packet on fd=%d\n", fd); + uint16_t pkt_id = knot_wire_get_id(qbuf); + knot_ns_error_response(ns, pkt_id, KNOT_RCODE_SERVFAIL, + qbuf, resp_len); + return KNOTD_EOK; /* Created error response. */ + } + + /* Parse query. */ + int res = knot_ns_parse_packet(qbuf, qbuflen, packet, &qtype); + if (unlikely(res != KNOTD_EOK)) { + dbg_net("udp: failed to parse packet on fd=%d\n", fd); + /* Send error response on dnslib RCODE. */ + if (res > 0) { + uint16_t pkt_id = knot_wire_get_id(qbuf); + knot_ns_error_response(ns, pkt_id, res, + qbuf, resp_len); + } + + knot_packet_free(&packet); + return KNOTD_EOK; /* Created error response. */ + } + + /* Handle query. */ +// server_t *srv = (server_t *)knot_ns_get_data(ns); +// knot_ns_xfr_t xfr; + res = KNOTD_ERROR; + switch(qtype) { + + /* Response types. */ + case KNOT_RESPONSE_NORMAL: + res = zones_process_response(ns, addr, packet, + qbuf, resp_len); + break; + case KNOT_RESPONSE_NOTIFY: + res = notify_process_response(ns, packet, addr, + qbuf, resp_len); + break; + + /* Query types. */ + case KNOT_QUERY_NORMAL: + res = knot_ns_answer_normal(ns, packet, qbuf, + resp_len); + break; + case KNOT_QUERY_AXFR: + /* RFC1034, p.28 requires reliable transfer protocol. + * Bind responds with FORMERR. + */ + /*! \todo Draft exists for AXFR/UDP, but has not been standardized. */ + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_FORMERR, qbuf, + resp_len); + res = KNOTD_EOK; + break; + +// /* Process AXFR over UDP. */ +// res = xfr_request_init(&xfr, XFR_TYPE_AOUT, XFR_FLAG_UDP, packet); +// if (res != KNOTD_EOK) { +// knot_ns_error_response(ns, knot_packet_id(packet), +// KNOT_RCODE_SERVFAIL, qbuf, +// resp_len); +// res = KNOTD_EOK; +// break; +// } +// xfr.send = xfr_send_udp; +// xfr.session = dup(fd); +// memcpy(&xfr.addr, addr, sizeof(sockaddr_t)); +// xfr_request(srv->xfr_h, &xfr); +// dbg_net("udp: enqueued AXFR query on fd=%d\n", xfr.session); +// *resp_len = 0; +// return KNOTD_EOK; + case KNOT_QUERY_IXFR: + /* According to RFC1035, respond with SOA. + * Draft proposes trying to fit response into one packet, + * but I have found no tool or slave server to actually attempt + * IXFR/UDP. + */ + knot_packet_set_qtype(packet, KNOT_RRTYPE_SOA); + res = knot_ns_answer_normal(ns, packet, qbuf, + resp_len); + break; +// /* Process IXFR over UDP. */ +// res = xfr_request_init(&xfr, XFR_TYPE_IOUT, XFR_FLAG_UDP, packet); +// if (res != KNOTD_EOK) { +// knot_ns_error_response(ns, knot_packet_id(packet), +// KNOT_RCODE_SERVFAIL, qbuf, +// resp_len); +// res = KNOTD_EOK; +// break; +// } +// xfr.send = xfr_send_udp; +// xfr.session = dup(fd); +// memcpy(&xfr.addr, addr, sizeof(sockaddr_t)); +// xfr_request(srv->xfr_h, &xfr); +// dbg_net("udp: enqueued IXFR query on fd=%d\n", xfr.session); +// *resp_len = 0; +// return KNOTD_EOK; + case KNOT_QUERY_NOTIFY: + res = notify_process_request(ns, packet, addr, + qbuf, resp_len); + break; + + /*! \todo Implement query notify/update. */ + case KNOT_QUERY_UPDATE: + dbg_net("udp: UPDATE query on fd=%d not implemented\n", fd); + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_NOTIMPL, qbuf, + resp_len); + res = KNOTD_EOK; + break; + + /* Unhandled opcodes. */ + case KNOT_RESPONSE_AXFR: /*!< Processed in XFR handler. */ + case KNOT_RESPONSE_IXFR: /*!< Processed in XFR handler. */ + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_REFUSED, qbuf, + resp_len); + res = KNOTD_EOK; + break; + + /* Unknown opcodes */ + default: + knot_ns_error_response(ns, knot_packet_id(packet), + KNOT_RCODE_FORMERR, qbuf, + resp_len); + res = KNOTD_EOK; + break; + } + + knot_packet_free(&packet); + + return res; +} + +static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat) +{ + iohandler_t *h = (iohandler_t *)thread->data; + knot_nameserver_t *ns = h->server->nameserver; + int sock = dup(h->fd); + + sockaddr_t addr; + if (sockaddr_init(&addr, h->type) != KNOTD_EOK) { + log_server_error("Socket type %d is not supported, " + "IPv6 support is probably disabled.\n", + h->type); + return KNOTD_ENOTSUP; + } + + uint8_t qbuf[SOCKET_MTU_SZ]; + struct msghdr msg; + memset(&msg, 0, sizeof(struct msghdr)); + struct iovec iov; + memset(&iov, 0, sizeof(struct iovec)); + iov.iov_base = qbuf; + iov.iov_len = SOCKET_MTU_SZ; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_name = addr.ptr; + msg.msg_namelen = addr.len; + + /* Loop until all data is read. */ + ssize_t n = 0; + while (n >= 0) { + + /* Receive packet. */ + n = recvmsg(sock, &msg, 0); + + /* Cancellation point. */ + if (dt_is_cancelled(thread)) { + break; + } + + /* Error and interrupt handling. */ + if (unlikely(n <= 0)) { + if (errno != EINTR && errno != 0) { + dbg_net("udp: recvmsg() failed: %d\n", + errno); + } + + if (!(h->state & ServerRunning)) { + break; + } else { + continue; + } + } + + /* Handle received pkt. */ + size_t resp_len = 0; + int rc = udp_handle(sock, qbuf, n, &resp_len, &addr, ns); + + /* Send response. */ + if (rc == KNOTD_EOK && resp_len > 0) { + + dbg_net("udp: on fd=%d, sending answer size=%zd.\n", + sock, resp_len); + + // Send datagram + rc = sendto(sock, qbuf, resp_len, + 0, addr.ptr, addr.len); + + // Check result + if (rc != (int)resp_len) { + dbg_net("udp: sendto(): failed: %d - %d.\n", + rc, errno); + } + } + } + + /* Free allocd resources. */ + close(sock); + + return KNOTD_EOK; +} + +#ifdef ENABLE_RECVMMSG +#ifdef MSG_WAITFORONE +static inline int udp_master_recvmmsg(dthread_t *thread, stat_t *thread_stat) +{ + iohandler_t *h = (iohandler_t *)thread->data; + knot_nameserver_t *ns = h->server->nameserver; + int sock = dup(h->fd); + + /* Allocate batch for N packets. */ + char *iobuf = malloc(SOCKET_MTU_SZ * RECVMMSG_BATCHLEN); + sockaddr_t *addrs = malloc(sizeof(sockaddr_t) * RECVMMSG_BATCHLEN); + struct iovec *iov = malloc(sizeof(struct iovec) * RECVMMSG_BATCHLEN); + struct mmsghdr *msgs = malloc(sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN); + + /* Prepare batch. */ + memset(msgs, 0, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN); + for (unsigned i = 0; i < RECVMMSG_BATCHLEN; ++i) { + sockaddr_init(addrs + i, h->type); + iov[i].iov_base = iobuf + i * SOCKET_MTU_SZ; + iov[i].iov_len = SOCKET_MTU_SZ; + msgs[i].msg_hdr.msg_iov = iov + i; + msgs[i].msg_hdr.msg_iovlen = 1; + msgs[i].msg_hdr.msg_name = addrs[i].ptr; + msgs[i].msg_hdr.msg_namelen = addrs[i].len; + } + + /* Loop until all data is read. */ + ssize_t n = 0; + while (n >= 0) { + + /* Receive multiple messages. */ + n = recvmmsg(sock, msgs, RECVMMSG_BATCHLEN, MSG_WAITFORONE, 0); + + /* Cancellation point. */ + if (dt_is_cancelled(thread)) { + break; + } + + /* Error and interrupt handling. */ + if (unlikely(n <= 0)) { + if (errno != EINTR && errno != 0) { + dbg_net("udp: recvmmsg() failed: %d\n", + errno); + } + + if (!(h->state & ServerRunning)) { + break; + } else { + continue; + } + } + + /* Handle each received msg. */ + int ret = 0; + for (unsigned i = 0; i < n; ++i) { + struct iovec *cvec = msgs[i].msg_hdr.msg_iov; + size_t resp_len = msgs[i].msg_len; + ret = udp_handle(sock, cvec->iov_base, resp_len, &resp_len, + addrs + i, ns); + if (ret == KNOTD_EOK) { + msgs[i].msg_len = resp_len; + } else { + msgs[i].msg_len = 0; + } + + } + + /* Gather results. */ + /*! \todo Implement with sendmmsg() when it's ready. */ + for (unsigned i = 0; i < n; ++i) { + const size_t resp_len = msgs[i].msg_len; + if (resp_len > 0) { + dbg_net("udp: on fd=%d, sending answer size=%zd.\n", + sock, resp_len); + + // Send datagram + sockaddr_t *addr = addrs + i; + struct iovec *cvec = msgs[i].msg_hdr.msg_iov; + int res = sendto(sock, cvec->iov_base, resp_len, + 0, addr->ptr, addr->len); + + // Check result + if (res != (int)resp_len) { + dbg_net("udp: sendto(): failed: %d - %d.\n", + res, errno); + } + } + } + } + + /* Free allocd resources. */ + free(iobuf); + free(addrs); + free(iov); + free(msgs); + close(sock); + return KNOTD_EOK; +} +#endif +#endif + +int udp_master(dthread_t *thread) +{ + iohandler_t *handler = (iohandler_t *)thread->data; + int sock = handler->fd; + + /* Check socket. */ + if (sock < 0) { + dbg_net("udp: null socket recevied, finishing.\n"); + return KNOTD_EINVAL; + } + + /* Set socket options. */ + int flag = 1; +#ifndef DISABLE_IPV6 +# + if (handler->type == AF_INET6) { + /* Disable dual-stack for performance reasons. */ + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)); + + /* UDP packets will not exceed a minimum MTU size. */ + /*flag = IPV6_MIN_MTU; + setsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &flag, sizeof(flag)); + flag = 1; */ + } +#endif + if (handler->type == AF_INET) { + +//#ifdef IP_PMTUDISC_DONT +// /* Disable fragmentation. */ +// flag = IP_PMTUDISC_DONT; +// setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)); +// flag = 1; +//#endif + } + + /* in case of STAT_COMPILE the following code will declare thread_stat + * variable in following fashion: stat_t *thread_stat; + */ + + stat_t *thread_stat = 0; + STAT_INIT(thread_stat); //XXX new stat instance every time. + stat_set_protocol(thread_stat, stat_UDP); + + /* Execute proper handler. */ + dbg_net_verb("udp: thread started (worker %p).\n", thread); + int ret = KNOTD_EOK; + +#ifdef ENABLE_RECVMMSG + +/* Check if MSG_WAITFORONE is supported. */ +#ifdef MSG_WAITFORONE + ret = udp_master_recvmmsg(thread, thread_stat); +#else /* Don't have MSG_WAITFORONE */ + ret = udp_master_recvfrom(thread, thread_stat); +#endif + +#else /* Don't have ENABLE_RECVMMSG */ + ret = udp_master_recvfrom(thread, thread_stat); +#endif + + + stat_free(thread_stat); + dbg_net_verb("udp: worker %p finished.\n", thread); + return ret; +} + diff --git a/src/knot/server/udp-handler.h b/src/knot/server/udp-handler.h new file mode 100644 index 0000000..f5fcd04 --- /dev/null +++ b/src/knot/server/udp-handler.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file udp-handler.h + * + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief UDP sockets threading model. + * + * The master socket locks one worker thread at a time + * and saves events in it's own backing store for asynchronous processing. + * The worker threads work asynchronously in thread pool. + * + * \addtogroup server + * @{ + */ + +#ifndef _KNOTD_UDPHANDLER_H_ +#define _KNOTD_UDPHANDLER_H_ + +#include "knot/server/socket.h" +#include "knot/server/server.h" +#include "knot/server/dthreads.h" + +/*! + * \brief Handle single packet. + * + * Function processses packet and prepares answer to qbuf, + * response length is set to resp_len. + * + * \param sock + * \param qbuf + * \param qbuflen + * \param resp_len + * \param addr + * \param ns + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ERROR + * \retval KNOTD_ENOMEM + */ +int udp_handle(int sock, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, + sockaddr_t* addr, knot_nameserver_t *ns); + +/*! + * \brief UDP handler thread runnable. + * + * Listen to DNS datagrams in a loop on a UDP socket and + * reply to them. This runnable is designed to be used as coherent + * and implements cancellation point. + * + * \param thread Associated thread from DThreads unit. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + */ +int udp_master(dthread_t *thread); + +#endif + +/*! @} */ diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c new file mode 100644 index 0000000..45817cb --- /dev/null +++ b/src/knot/server/xfr-handler.c @@ -0,0 +1,1296 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <netinet/tcp.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <urcu.h> + +#include "knot/common.h" +#include "knot/server/xfr-handler.h" +#include "libknot/nameserver/name-server.h" +#include "knot/other/error.h" +#include "knot/server/socket.h" +#include "knot/server/udp-handler.h" +#include "knot/server/tcp-handler.h" +#include "libknot/updates/xfr-in.h" +#include "knot/server/zones.h" +#include "libknot/util/error.h" +#include "libknot/tsig-op.h" +#include "common/evsched.h" + +void xfr_interrupt(xfrhandler_t *h) +{ + for(unsigned i = 0; i < h->unit->size; ++i) { + evqueue_write(h->workers[i]->q, "", 1); + } +} + +/*! + * \brief SOA query timeout handler. + */ +static int xfr_udp_timeout(event_t *e) +{ + knot_ns_xfr_t *data = (knot_ns_xfr_t *)e->data; + if (!data) { + return KNOTD_EINVAL; + } + + sockaddr_update(&data->addr); + char r_addr[SOCKADDR_STRLEN]; + sockaddr_tostr(&data->addr, r_addr, sizeof(r_addr)); + int r_port = sockaddr_portnum(&data->addr); + + /* Close socket. */ + knot_zone_t *z = data->zone; + if (z && knot_zone_get_contents(z) && knot_zone_data(z)) { + zonedata_t *zd = (zonedata_t *)knot_zone_data(z); + log_zone_info("%s '%s' query to %s:%d - timeout exceeded.\n", + data->type == XFR_TYPE_SOA ? "SOA" : "NOTIFY", + zd->conf->name, + r_addr, r_port); + } + + knot_ns_xfr_t cr = {}; + cr.type = XFR_TYPE_CLOSE; + cr.session = data->session; + cr.data = data; + cr.zone = data->zone; + xfrworker_t *w = (xfrworker_t *)data->owner; + if (w) { + evqueue_write(w->q, &cr, sizeof(knot_ns_xfr_t)); + } + + return KNOTD_EOK; +} + +/*! + * \brief Query reponse event handler function. + * + * Handle single query response event. + * + * \param loop Associated event pool. + * \param w Associated socket watcher. + * \param revents Returned events. + */ +static int xfr_process_udp_query(xfrworker_t *w, int fd, knot_ns_xfr_t *data) +{ + /* Prepare msg header. */ + struct msghdr msg; + memset(&msg, 0, sizeof(struct msghdr)); + struct iovec iov; + memset(&iov, 0, sizeof(struct iovec)); + iov.iov_base = data->wire; + iov.iov_len = data->wire_size; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_name = data->addr.ptr; + msg.msg_namelen = data->addr.len; + + /* Receive msg. */ + ssize_t n = recvmsg(data->session, &msg, 0); + size_t resp_len = data->wire_size; + if (n > 0) { + udp_handle(fd, data->wire, n, &resp_len, &data->addr, w->ns); + } + + /* Disable timeout. */ + evsched_t *sched = + ((server_t *)knot_ns_get_data(w->ns))->sched; + event_t *ev = (event_t *)data->data; + if (ev) { + dbg_xfr("xfr: cancelling UDP query timeout\n"); + evsched_cancel(sched, ev); + ev = (event_t *)data->data; + if (ev) { + evsched_event_free(sched, ev); + data->data = 0; + } + + /* Close after receiving response. */ + knot_ns_xfr_t cr = {}; + cr.type = XFR_TYPE_CLOSE; + cr.session = data->session; + cr.data = data; + cr.zone = data->zone; + evqueue_write(w->q, &cr, sizeof(knot_ns_xfr_t)); + } + + return KNOTD_EOK; +} + +/*! \todo Document me. */ +static void xfr_free_task(knot_ns_xfr_t *task) +{ + if (!task) { + return; + } + + xfrworker_t *w = (xfrworker_t *)task->owner; + if (!w) { + free(task); + return; + } + + /* Remove from fdset. */ + if (w->fdset) { + dbg_xfr("xfr_free_task: freeing fd=%d.\n", task->session); + fdset_remove(w->fdset, task->session); + } + + /* Unlock if XFR/IN.*/ + if (task->type == XFR_TYPE_AIN || task->type == XFR_TYPE_IIN) { + knot_zone_t *zone = task->zone; + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + if (zd) { + zd->xfr_in.wrkr = 0; + pthread_mutex_unlock(&zd->xfr_in.lock); + } + } + + /* Remove fd-related data. */ + xfrhandler_t *h = w->master; + pthread_mutex_lock(&h->tasks_mx); + skip_remove(h->tasks, (void*)((size_t)task->session), 0, 0); + pthread_mutex_unlock(&h->tasks_mx); + + /*! \todo Free data. */ + close(task->session); + free(task); +} + +/*! \todo Document me. */ +static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, knot_ns_xfr_t *req) +{ + knot_ns_xfr_t *t = malloc(sizeof(knot_ns_xfr_t)); + if (!t) { + return 0; + } + + memcpy(t, req, sizeof(knot_ns_xfr_t)); + sockaddr_update(&t->addr); + + /* Update request. */ + t->wire = 0; /* Invalidate shared buffer. */ + t->wire_size = 0; + t->data = 0; /* New zone will be built. */ + + /* Register data. */ + xfrhandler_t * h = w->master; + pthread_mutex_lock(&h->tasks_mx); + skip_insert(h->tasks, (void*)((ssize_t)t->session), t, 0); + pthread_mutex_unlock(&h->tasks_mx); + + /* Add to set. */ + fdset_add(w->fdset, t->session, OS_EV_READ); + t->owner = w; + return t; +} + +/*! + * \brief Clean pending transfer data. + */ +static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data) +{ + int ret = KNOTD_EOK; + knot_changesets_t *chs = 0; + + switch(data->type) { + case XFR_TYPE_AIN: + if (data->data) { + knot_zone_contents_deep_free( + (knot_zone_contents_t **)&data->data, 0); + data->data = 0; + } + break; + case XFR_TYPE_IIN: + if (data->data) { + chs = (knot_changesets_t *)data->data; + knot_free_changesets(&chs); + } + break; + } + + return ret; +} + +/*! + * \brief Finalize XFR/IN transfer. + * + * \param w XFR worker. + * \param data Associated data. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ERROR + */ +static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) +{ + knot_zone_t *zone = (knot_zone_t *)data->zone; + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + const char *zorigin = zd->conf->name; + + /* CLEANUP */ +// // get the zone name from Question +// dbg_xfr_verb("Query: %p, response: %p\n", data->query, data->response); +// const knot_dname_t *qname = knot_packet_qname(data->query); +// char *zorigin = "(unknown)"; +// if (qname != NULL) { +// zorigin = knot_dname_to_str(qname); +// } + + int ret = KNOTD_EOK; + + switch(data->type) { + case XFR_TYPE_AIN: + dbg_xfr("xfr: AXFR/IN saving new zone\n"); + ret = zones_save_zone(data); + if (ret != KNOTD_EOK) { + xfr_xfrin_cleanup(w, data); + log_zone_error("AXFR failed to save " + "transferred zone '%s/IN' - %s\n", + zorigin, knotd_strerror(ret)); + } else { + dbg_xfr("xfr: AXFR/IN new zone saved.\n"); + ret = knot_ns_switch_zone(w->ns, data); + if (ret != KNOTD_EOK) { + log_zone_error("AXFR failed to " + "switch in-memory zone " + "'%s/IN' - %s\n", + zorigin, + knotd_strerror(ret)); + } + } + log_zone_info("AXFR transfer of zone '%s/IN' " + "%s.\n", zorigin, + ret == KNOTD_EOK ? "finished" : "failed"); + break; + case XFR_TYPE_IIN: + /* Save changesets. */ + dbg_xfr("xfr: IXFR/IN saving changesets\n"); + ret = zones_store_changesets(data); + if (ret != KNOTD_EOK) { + log_zone_error("IXFR failed to save " + "transferred changesets " + "for zone '%s/IN' - %s\n", + zorigin, knotd_strerror(ret)); + } else { + /* Update zone. */ + ret = zones_apply_changesets(data); + if (ret != KNOTD_EOK) { + log_zone_error("IXFR failed to " + "apply changesets to " + "zone '%s/IN' - %s\n", + zorigin, + knotd_strerror(ret)); + } + } + /* Free changesets, but not the data. */ + knot_changesets_t *chs = (knot_changesets_t *)data->data; + knot_free_changesets(&chs); + /* CLEANUP */ +// free(chs->sets); +// free(chs); + data->data = 0; + log_zone_info("IXFR transfer of zone '%s/IN' " + "%s.\n", zorigin, + ret == KNOTD_EOK ? "finished" : "failed"); + break; + default: + ret = KNOTD_EINVAL; + break; + } + + /* CLEANUP */ +// if (qname != NULL) { +// free(zorigin); +// } + + return ret; +} + +/*! + * \brief Prepare TSIG for XFR. + */ +static int xfr_prepare_tsig(knot_ns_xfr_t *xfr, knot_key_t *key) +{ + int ret = KNOT_EOK; + xfr->tsig_key = 0; /*key;*/ /*!< \todo [TSIG] DISABLED */ +// xfr->tsig_size = tsig_wire_maxsize(key); +// xfr->digest_max_size = tsig_alg_digest_length( +// key->algorithm); +// xfr->digest = malloc(xfr->digest_max_size); +// memset(xfr->digest, 0 , xfr->digest_max_size); +// dbg_xfr("xfr: found TSIG key (MAC len=%zu), adding to transfer\n", +// xfr->digest_max_size); + + return ret; +} + +/*! + * \brief Check TSIG if exists. + */ +static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) +{ + /*!< \todo [TSIG] DISABLED */ + return knot_packet_parse_rest(xfr->query); + +// /* Parse rest of the packet. */ +// int ret = KNOT_EOK; +// knot_packet_t *qry = xfr->query; +// knot_key_t *key = 0; +// const knot_rrset_t *tsig_rr = 0; +// ret = knot_packet_parse_rest(qry); +// if (ret == KNOT_EOK) { + +// /* Find TSIG key name from query. */ +// const knot_dname_t* kname = 0; +// int tsig_pos = knot_packet_additional_rrset_count(qry) - 1; +// if (tsig_pos >= 0) { +// tsig_rr = knot_packet_additional_rrset(qry, tsig_pos); +// if (knot_rrset_type(tsig_rr) == KNOT_RRTYPE_TSIG) { +// dbg_xfr("xfr: found TSIG in AR\n"); +// kname = knot_rrset_owner(tsig_rr); +// ret = KNOT_TSIG_EBADKEY; +// } +// } +// if (!kname) { +// dbg_xfr("xfr: TSIG not found in AR\n"); +// } + +// /* Find configured key for claimed key name. */ +// conf_key_t *ck = 0; +// WALK_LIST(ck, conf()->keys) { +// if (!kname) { +// break; +// } +// /* Compare stored keys to claimed. */ +// if (knot_dname_compare(ck->k.name, +// kname) == 0) { +// dbg_xfr("xfr: found claimed " +// "TSIG key for " +// "comparison\n"); +// key = &ck->k; +// break; +// } +// } + +// /* Validate with TSIG. */ +// if (key) { +// /* Prepare variables for TSIG */ +// xfr_prepare_tsig(xfr, key); + +// /* Copy MAC from query. */ +// dbg_xfr("xfr: validating TSIG from query\n"); +// const uint8_t* mac = tsig_rdata_mac(tsig_rr); +// size_t mac_len = tsig_rdata_mac_length(tsig_rr); +// if (mac_len > xfr->digest_max_size) { +// ret = KNOT_EMALF; +// dbg_xfr("xfr: MAC length %zu exceeds digest " +// "maximum size %zu\n", +// mac_len, xfr->digest_max_size); +// } else { +// memcpy(xfr->digest, mac, mac_len); +// xfr->digest_size = mac_len; + +// /* Check query TSIG. */ +// ret = knot_tsig_server_check( +// tsig_rr, +// knot_packet_wireformat(qry), +// knot_packet_size(qry), +// key); +// dbg_xfr("knot_tsig_server_check() returned %s\n", +// knot_strerror(ret)); +// } + +// /* Evaluate TSIG check results. */ +// switch(ret) { +// case KNOT_EOK: +// *rcode = KNOT_RCODE_NOERROR; +// break; +// case KNOT_TSIG_EBADKEY: +// case KNOT_TSIG_EBADSIG: +// // delete the TSIG key so that the error +// // response is not signed +// xfr->tsig_key = NULL; +// case KNOT_TSIG_EBADTIME: +// /*! \note [TSIG] Set TSIG rcode in TSIG RR. */ + +// *rcode = KNOT_RCODE_NOTAUTH; +// break; +// case KNOT_EMALF: +// *rcode = KNOT_RCODE_FORMERR; +// break; +// default: +// *rcode = KNOT_RCODE_SERVFAIL; +// } +// } else { +// dbg_xfr("xfr: no claimed key configured, " +// "treating as bad key\n"); +// } +// } else { +// dbg_xfr("xfr: failed to parse rest of the packet\n"); +// *rcode = KNOT_RCODE_FORMERR; +// } + +// return ret; +} + +/*! + * \brief XFR-IN event handler function. + * + * Handle single XFR client event. + * + * \param w Associated XFR worker. + * \param fd Associated file descriptor. + * \param data Transfer data. + */ +int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data) +{ + /* Buffer for answering. */ + uint8_t buf[65535]; + + /* Update xfer state. */ + data->wire = buf; + data->wire_size = sizeof(buf); + + /* Handle SOA/NOTIFY responses. */ + if (data->type == XFR_TYPE_NOTIFY || data->type == XFR_TYPE_SOA) { + return xfr_process_udp_query(w, fd, data); + } + + /* Read DNS/TCP packet. */ + int ret = 0; + int rcvd = tcp_recv(fd, buf, sizeof(buf), 0); + data->wire_size = rcvd; + if (rcvd <= 0) { + data->wire_size = 0; + ret = KNOT_ECONN; + } else { + + /*! + * \todo [TSIG] Somewhere before this fetch the query digest and the TSIG + * associated with this transfer and save them to 'data'. + */ + + /* Process incoming packet. */ + switch(data->type) { + case XFR_TYPE_AIN: + ret = knot_ns_process_axfrin(w->ns, data); + break; + case XFR_TYPE_IIN: + ret = knot_ns_process_ixfrin(w->ns, data); + break; + default: + ret = KNOT_EBADARG; + break; + } + } + + /* AXFR-style IXFR. */ + if (ret == KNOT_ENOIXFR) { + dbg_xfr("xfr: Fallback to AXFR/IN.\n"); + assert(data->type == XFR_TYPE_IIN); + data->type = XFR_TYPE_AIN; + ret = knot_ns_process_axfrin(w->ns, data); + } + + /* Check return code for errors. */ + dbg_xfr_verb("xfr: processed incoming XFR packet (res = %d)\n", ret); + + /* Finished xfers. */ + int xfer_finished = 0; + if (ret != KNOT_EOK) { + xfer_finished = 1; + } + + /* IXFR refused, try again with AXFR. */ + knot_zone_t *zone = (knot_zone_t *)data->zone; + if (zone && data->type == XFR_TYPE_IIN && ret == KNOT_EXFRREFUSED) { + log_server_notice("IXFR/IN failed, attempting to use " + "AXFR/IN instead.\n"); + size_t bufsize = sizeof(buf); + data->wire_size = sizeof(buf); /* Reset maximum bufsize */ + ret = xfrin_create_axfr_query(zone->name, data, + &bufsize, 1); + /* Send AXFR/IN query. */ + if (ret == KNOTD_EOK) { + ret = data->send(data->session, &data->addr, + data->wire, bufsize); + /* Switch to AIN type XFR and return now. */ + if (ret == bufsize) { + data->type = XFR_TYPE_AIN; + return KNOTD_EOK; + } + } + } + + /* Handle errors. */ + if (ret < 0 && ret != KNOT_ENOXFR) { + log_server_error("%cXFR/IN request failed - %s\n", + data->type == XFR_TYPE_AIN ? 'A' : 'I', + knot_strerror(ret)); + } + + /* Check finished zone. */ + if (xfer_finished) { + + knot_zone_t *zone = (knot_zone_t *)data->zone; + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + const char *zorigin = zd->conf->name; + + /* Only for successful xfers. */ + if (ret > 0) { + ret = xfr_xfrin_finalize(w, data); + + /* AXFR bootstrap timeout. */ + rcu_read_lock(); + if (!knot_zone_contents(zone) && data->type == XFR_TYPE_AIN) { + /* Schedule request (60 - 90s random delay). */ + int tmr_s = AXFR_BOOTSTRAP_RETRY; + tmr_s += (30.0 * 1000) * (rand() / (RAND_MAX + 1.0)); + zd->xfr_in.bootstrap_retry = tmr_s; + log_zone_info("Another attempt to AXFR bootstrap " + "zone '%s' in %d seconds.\n", + zorigin, tmr_s/1000); + } + rcu_read_unlock(); + + /* Update timers. */ + server_t *server = (server_t *)knot_ns_get_data(w->ns); + zones_timers_update(zone, zd->conf, server->sched); + + } else { + /* Cleanup */ + xfr_xfrin_cleanup(w, data); + } + + /* Free TSIG buffers. */ + if (data->digest) { + free(data->digest); + data->digest = 0; + data->digest_size = 0; + } + if (data->tsig_data) { + free(data->tsig_data); + data->tsig_data = 0; + data->tsig_data_size = 0; + } + + /* Disconnect. */ + ret = KNOTD_ECONNREFUSED; /* Make it disconnect. */ + } else { + ret = KNOTD_EOK; + } + + return ret; +} + +/*! \todo Document me. + */ +static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) +{ + /* Fetch associated zone. */ + knot_zone_t *zone = (knot_zone_t *)data->zone; + if (!zone) { + return KNOTD_EINVAL; + } + + /* Check if not already processing. */ + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + if (!zd) { + return KNOTD_EINVAL; + } + + /* Enqueue to worker that has zone locked for XFR/IN. */ + int ret = pthread_mutex_trylock(&zd->xfr_in.lock); + if (ret != 0) { + dbg_xfr_verb("xfr: XFR/IN switching to another thread, " + "zone '%s' is already in transfer\n", + zd->conf->name); + xfrworker_t *nextw = (xfrworker_t *)zd->xfr_in.wrkr; + if (nextw == 0) { + nextw = w; + } + evqueue_write(nextw->q, data, sizeof(knot_ns_xfr_t)); + return KNOTD_EOK; + } else { + zd->xfr_in.wrkr = w; + } + + /* Update address. */ + sockaddr_update(&data->addr); + char r_addr[SOCKADDR_STRLEN]; + sockaddr_tostr(&data->addr, r_addr, sizeof(r_addr)); + int r_port = sockaddr_portnum(&data->addr); + + /* Connect to remote. */ + if (data->session <= 0) { + int fd = socket_create(data->addr.family, SOCK_STREAM); + if (fd < 0) { + log_server_warning("Failed to create socket " + "(type=%s, family=%s).\n", + "SOCK_STREAM", + data->addr.family == AF_INET ? + "AF_INET" : "AF_INET6"); + return KNOTD_ERROR; + } + ret = connect(fd, data->addr.ptr, data->addr.len); + if (ret < 0) { + log_server_warning("Failed to connect to %cXFR master " + "at %s:%d.\n", + data->type == XFR_TYPE_AIN ? 'A' : 'I', + r_addr, r_port); + if (!knot_zone_contents(zone)) { + /* Reschedule request (120 - 240s random delay). */ + int tmr_s = AXFR_BOOTSTRAP_RETRY * 2; /* Malus x2 */ + tmr_s += (int)((120.0 * 1000) * + (rand() / (RAND_MAX + 1.0))); + event_t *ev = zd->xfr_in.timer; + if (ev) { + evsched_cancel(ev->parent, ev); + evsched_schedule(ev->parent, ev, tmr_s); + } + log_zone_notice("Zone AXFR bootstrap failed, " + "another attempt in %d seconds." + "\n", tmr_s / 1000); + } + return KNOTD_ERROR; + } + + /* Store new socket descriptor. */ + data->session = fd; + } else { + /* Duplicate existing socket descriptor. */ + data->session = dup(data->session); + } + + /* Fetch zone contents. */ + rcu_read_lock(); + const knot_zone_contents_t *contents = knot_zone_contents(zone); + if (!contents && data->type == XFR_TYPE_IIN) { + rcu_read_unlock(); + log_server_warning("Failed start IXFR on zone with no " + "contents\n"); + return KNOTD_ERROR; + } + + /*! \todo [TSIG] Somewhere before this determine if the server should + * use TSIG for this transfer and set appropriate fields + * in 'data'. + */ + int add_tsig = 0; + if (data->tsig_key) { + if (xfr_prepare_tsig(data, data->tsig_key) == KNOT_EOK) { + size_t data_bufsize = KNOT_NS_TSIG_DATA_MAX_SIZE; + data->tsig_data = malloc(data_bufsize); + if (data->tsig_data) { + dbg_xfr("xfr: using TSIG for XFR/IN\n"); + add_tsig = 1; + data->tsig_data_size = data_bufsize; + } else { + dbg_xfr("xfr: failed to allocate TSIG data " + "buffer (%zu kB)\n", + data_bufsize / 1024); + } + } + } + + /* Create XFR query. */ + size_t bufsize = data->wire_size; + switch(data->type) { + case XFR_TYPE_AIN: + ret = xfrin_create_axfr_query(zone->name, data, &bufsize, add_tsig); + break; + case XFR_TYPE_IIN: + ret = xfrin_create_ixfr_query(contents, data, &bufsize, add_tsig); + break; + default: + ret = KNOTD_EINVAL; + break; + } + + /* Handle errors. */ + if (ret != KNOT_EOK) { + dbg_xfr("xfr: failed to create XFR query type %d: %s\n", + data->type, knot_strerror(ret)); + return ret; + } + + /* Unlock zone contents. */ + rcu_read_unlock(); + + /* Add to pending transfers. */ + knot_ns_xfr_t *task = xfr_register_task(w, data); + + ret = data->send(data->session, &data->addr, data->wire, bufsize); + if (ret != bufsize) { + log_server_notice("Failed to send %cXFR query.", + data->type == XFR_TYPE_AIN ? 'A' : 'I'); + xfr_free_task(task); + return KNOTD_ERROR; + } + + /* Send XFR query. */ + log_server_info("%cXFR transfer of zone '%s/IN' with %s:%d started.\n", + data->type == XFR_TYPE_AIN ? 'A' : 'I', + zd->conf->name, + r_addr, r_port); + + return KNOTD_EOK; +} + +static int xfr_fd_compare(void *k1, void *k2) +{ + if (k1 < k2) { + return -1; + } + + if (k1 > k2) { + return 1; + } + + return 0; +} + +/* + * Public APIs. + */ + +static xfrworker_t* xfr_worker_create(xfrhandler_t *h, knot_nameserver_t *ns) +{ + xfrworker_t *w = malloc(sizeof(xfrworker_t)); + if(!w) { + return 0; + } + + /* Set nameserver and master. */ + w->ns = ns; + w->master = h; + + /* Create event queue. */ + w->q = evqueue_new(); + if (!w->q) { + free(w); + return 0; + } + + /* Create fdset. */ + w->fdset = fdset_new(); + if (!w->fdset) { + evqueue_free(&w->q); + free(w); + return 0; + } + + /* Add evqueue to fdset. */ + fdset_add(w->fdset, evqueue_pollfd(w->q), OS_EV_READ); + + return w; +} + +static void xfr_worker_free(xfrworker_t *w) { + if (w) { + evqueue_free(&w->q); + fdset_destroy(w->fdset); + free(w); + } +} + +xfrhandler_t *xfr_create(size_t thrcount, knot_nameserver_t *ns) +{ + /* Create XFR handler data. */ + xfrhandler_t *data = malloc(sizeof(xfrhandler_t)); + if (!data) { + return 0; + } + memset(data, 0, sizeof(xfrhandler_t)); + + /* Create RR mutex. */ + pthread_mutex_init(&data->rr_mx, 0); + + /* Create tasks structure and mutex. */ + pthread_mutex_init(&data->tasks_mx, 0); + data->tasks = skip_create_list(xfr_fd_compare); + + /* Initialize threads. */ + data->workers = malloc(thrcount * sizeof(xfrhandler_t*)); + if(data->workers == 0) { + pthread_mutex_destroy(&data->rr_mx); + free(data); + } + + /* Create threading unit. */ + dt_unit_t *unit = dt_create(thrcount); + if (!unit) { + pthread_mutex_destroy(&data->rr_mx); + free(data->workers); + free(data); + return 0; + } + data->unit = unit; + + /* Create worker threads. */ + unsigned initialized = 0; + for (unsigned i = 0; i < thrcount; ++i) { + data->workers[i] = xfr_worker_create(data, ns); + if(data->workers[i] == 0) { + break; + } + ++initialized; + } + + /* Check for initialized. */ + if (initialized != thrcount) { + for (unsigned i = 0; i < initialized; ++i) { + xfr_worker_free(data->workers[i]); + } + pthread_mutex_destroy(&data->rr_mx); + free(data->workers); + free(data->unit); + free(data); + return 0; + } + + /* Assign worker threads. */ + for (unsigned i = 0; i < thrcount; ++i) { + dt_repurpose(unit->threads[i], xfr_worker, data->workers[i]); + } + + data->interrupt = xfr_interrupt; + + return data; +} + +int xfr_free(xfrhandler_t *handler) +{ + if (!handler) { + return KNOTD_EINVAL; + } + + /* Free RR mutex. */ + pthread_mutex_destroy(&handler->rr_mx); + + /* Free tasks and mutex. */ + skip_destroy_list(&handler->tasks, 0, + (void(*)(void*))xfr_free_task); + pthread_mutex_destroy(&handler->tasks_mx); + + /* Free workers. */ + for (unsigned i = 0; i < handler->unit->size; ++i) { + xfr_worker_free(handler->workers[i]); + } + free(handler->workers); + + /* Delete unit. */ + dt_delete(&handler->unit); + free(handler); + + return KNOTD_EOK; +} + +int xfr_stop(xfrhandler_t *handler) +{ + /* Break loop. */ + dt_stop(handler->unit); + return KNOTD_EOK; +} + +int xfr_join(xfrhandler_t *handler) { + return dt_join(handler->unit); +} + +int xfr_request_init(knot_ns_xfr_t *r, int type, int flags, knot_packet_t *pkt) +{ + if (!r || type < 0 || flags < 0) { + return KNOTD_EINVAL; + } + + /* Blank and init. */ + memset(r, 0, sizeof(knot_ns_xfr_t)); + r->type = type; + r->flags = flags; + + /* Copy packet if applicable. */ + if (pkt != 0) { + uint8_t *wire_copy = malloc(sizeof(uint8_t) * pkt->size); + if (!wire_copy) { + ERR_ALLOC_FAILED; + return KNOTD_ENOMEM; + } + memcpy(wire_copy, pkt->wireformat, pkt->size); + pkt->wireformat = wire_copy; + r->query = pkt; + } + + return KNOTD_EOK; +} + +int xfr_request(xfrhandler_t *handler, knot_ns_xfr_t *req) +{ + if (!handler || !req) { + return KNOTD_EINVAL; + } + + /* Get next worker in RR fashion */ + pthread_mutex_lock(&handler->rr_mx); + evqueue_t *q = handler->workers[handler->rr]->q; + handler->rr = get_next_rr(handler->rr, handler->unit->size); + pthread_mutex_unlock(&handler->rr_mx); + + /* Delegate request. */ + int ret = evqueue_write(q, req, sizeof(knot_ns_xfr_t)); + if (ret < 0) { + return KNOTD_ERROR; + } + + return KNOTD_EOK; +} + +static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) +{ + /* Read single request. */ + knot_ns_xfr_t xfr = {}; + int ret = evqueue_read(w->q, &xfr, sizeof(knot_ns_xfr_t)); + if (ret != sizeof(knot_ns_xfr_t)) { + dbg_xfr_verb("xfr: evqueue_read() returned %d.\n", ret); + return KNOTD_ENOTRUNNING; + } + + /* Update request. */ + sockaddr_update(&xfr.addr); + xfr.wire = buf; + xfr.wire_size = buflen; + char r_addr[SOCKADDR_STRLEN]; + sockaddr_tostr(&xfr.addr, r_addr, sizeof(r_addr)); + int r_port = sockaddr_portnum(&xfr.addr); + + conf_read_lock(); + + /* Handle request. */ + knot_ns_xfr_t *task = 0; + evsched_t *sch = 0; + const char *req_type = ""; + knot_rcode_t rcode = 0; + char *zname = "(unknown)"; + + /* XFR request state tracking. */ + int init_failed = 0; + const char *errstr = ""; + const knot_dname_t *qname = NULL; + + dbg_xfr_verb("Query ptr: %p\n", xfr.query); + + dbg_xfr_verb("xfr: processing request type '%d'\n", xfr.type); + switch(xfr.type) { + case XFR_TYPE_AOUT: + req_type = "AXFR/OUT"; + ret = knot_ns_init_xfr(w->ns, &xfr); + init_failed = (ret != KNOT_EOK); + errstr = knot_strerror(ret); + + // use the QNAME as the zone name to get names also for + // zones that are not in the server + qname = knot_packet_qname(xfr.query); + if (qname != NULL) { + zname = knot_dname_to_str(qname); + } + + /* Check requested zone. */ + if (!init_failed) { + ret = zones_xfr_check_zone(&xfr, &rcode); + init_failed = (ret != KNOTD_EOK); + errstr = knotd_strerror(ret); + } + + /* Check TSIG. */ + if (!init_failed) { + ret = xfr_check_tsig(&xfr, &rcode); + init_failed = (ret != KNOT_EOK); + errstr = knot_strerror(ret); + } + + /* Evaluate progress and answer if passed. */ + if (init_failed) { + knot_ns_xfr_send_error(w->ns, &xfr, rcode); + socket_close(xfr.session); + log_server_notice("AXFR transfer of zone '%s/OUT' " + "%s:%d failed: %s\n", + zname, + r_addr, r_port, + errstr); + } else { + ret = knot_ns_answer_axfr(w->ns, &xfr); + dbg_xfr("xfr: ns_answer_axfr() = %d.\n", ret); + if (ret != KNOTD_EOK) { + socket_close(xfr.session); + } else { + log_server_info("AXFR transfer of zone '%s/OUT' " + "to %s:%d successful.\n", + zname, + r_addr, r_port); + } + } + + if (xfr.digest) { + free(xfr.digest); + xfr.digest_max_size = 0; + xfr.digest = 0; + } + free(xfr.query->wireformat); + xfr.query->wireformat = 0; + knot_packet_free(&xfr.query); /* Free query. */ + + if (qname != NULL) { + free(zname); + } + + break; + case XFR_TYPE_IOUT: + req_type = "IXFR/OUT"; + ret = knot_ns_init_xfr(w->ns, &xfr); + init_failed = (ret != KNOT_EOK); + errstr = knot_strerror(ret); + + qname = knot_packet_qname(xfr.query); + if (qname != NULL) { + zname = knot_dname_to_str(qname); + } + + /* Check requested zone. */ + if (!init_failed) { + ret = zones_xfr_check_zone(&xfr, &rcode); + init_failed = (ret != KNOTD_EOK); + errstr = knotd_strerror(ret); + } + + /* Check TSIG. */ + if (!init_failed) { + ret = xfr_check_tsig(&xfr, &rcode); + init_failed = (ret != KNOT_EOK); + errstr = knot_strerror(ret); + } + + uint32_t serial_from = 0; + uint32_t serial_to = 0; + + // Check serial differeces + if (!init_failed) { + dbg_xfr_verb("Loading serials for IXFR.\n"); + ret = ns_ixfr_load_serials(&xfr, &serial_from, + &serial_to); + dbg_xfr_detail("Loaded serials: from: %u, to: %u\n", + serial_from, serial_to); + init_failed = (ret != KNOT_EOK); + errstr = knot_strerror(ret); + } + + /* Load changesets from journal. */ + if (!init_failed) { + dbg_xfr_verb("Loading changesets from journal.\n"); + ret = zones_xfr_load_changesets(&xfr, serial_from, + serial_to); + if (ret != KNOTD_EOK) { + /* History cannot be reconstructed, fallback to AXFR. */ + if (ret == KNOTD_ERANGE || ret == KNOTD_ENOENT) { + log_server_info("IXFR transfer of zone '%s/OUT'" + " - failed to load data from journal: %s." + " Fallback to AXFR.\n", + knotd_strerror(ret), zname); + xfr.type = XFR_TYPE_AOUT; + xfr_request(w->master, &xfr); + conf_read_unlock(); + return KNOTD_EOK; + } else if (ret == KNOTD_EMALF) { + rcode = KNOT_RCODE_FORMERR; + } else { + rcode = KNOT_RCODE_SERVFAIL; + } + init_failed = (ret != KNOTD_EOK); + errstr = knotd_strerror(ret); + } + } + + /* Evaluate progress and answer if passed. */ + if (init_failed) { + knot_ns_xfr_send_error(w->ns, &xfr, rcode); + log_server_notice("IXFR transfer of zone '%s/OUT' " + "%s:%d failed: %s\n", + zname, + r_addr, r_port, + errstr); + ret = KNOTD_ERROR; + } else { + ret = knot_ns_answer_ixfr(w->ns, &xfr); + dbg_xfr("xfr: ns_answer_ixfr() = %d.\n", ret); + if (ret != KNOTD_EOK) { + socket_close(xfr.session); + } else { + log_server_info("IXFR transfer of zone '%s/OUT'" + " - not enough data in journal," + " fallback to AXFR.\n", + zname); + xfr.type = XFR_TYPE_AOUT; + xfr_request(w->master, &xfr); + return KNOTD_EOK; + } + } + if (xfr.digest) { + free(xfr.digest); + xfr.digest = 0; + xfr.digest_max_size = 0; + } + free(xfr.query->wireformat); + knot_packet_free(&xfr.query); /* Free query. */ + + if (qname) { + free(zname); + } + + break; + case XFR_TYPE_AIN: + req_type = "AXFR/IN"; + case XFR_TYPE_IIN: + if (xfr.type == XFR_TYPE_IIN) { + req_type = "IXFR/IN"; + } + + ret = xfr_client_start(w, &xfr); + + /* Report. */ + if (ret != KNOTD_EOK && ret != KNOTD_EACCES) { + log_server_error("%s request from %s:%d failed: %s\n", + req_type, r_addr, r_port, + knotd_strerror(ret)); + } + break; + case XFR_TYPE_SOA: + case XFR_TYPE_NOTIFY: + /* Register task. */ + task = xfr_register_task(w, &xfr); + if (!task) { + ret = KNOTD_ENOMEM; + break; + } + + req_type = "SOA or NOTIFY"; + dbg_xfr("xfr: waiting for %s query response\n", + xfr.type == XFR_TYPE_SOA ? "SOA" : "NOTIFY"); + + /* Add timeout. */ + sch = ((server_t *)knot_ns_get_data(w->ns))->sched; + task->data = evsched_schedule_cb(sch, xfr_udp_timeout, + task, SOA_QRY_TIMEOUT); + ret = KNOTD_EOK; + break; + /* Socket close event. */ + case XFR_TYPE_CLOSE: + xfr_free_task((knot_ns_xfr_t *)xfr.data); + ret = KNOTD_EOK; + default: + break; + } + + conf_read_unlock(); + + return ret; +} + +int xfr_worker(dthread_t *thread) +{ + xfrworker_t *w = (xfrworker_t *)thread->data; + + /* Check data. */ + if (w < 0) { + dbg_xfr("xfr: NULL worker data, worker cancelled\n"); + return KNOTD_EINVAL; + } + + /* Buffer for answering. */ + uint8_t buf[65535]; + + /* Accept requests. */ + int ret = 0; + dbg_xfr_verb("xfr: worker=%p starting\n", w); + for (;;) { + + /* Check for cancellation. */ + if (dt_is_cancelled(thread)) { + break; + } + + /* Poll fdset. */ + int nfds = fdset_wait(w->fdset); + if (nfds <= 0) { + continue; + } + + /* Check for cancellation. */ + if (dt_is_cancelled(thread)) { + break; + } + + /* Iterate fdset. */ + xfrhandler_t *h = w->master; + knot_ns_xfr_t *data = 0; + int rfd = evqueue_pollfd(w->q); + fdset_it_t it; + fdset_begin(w->fdset, &it); + while(1) { + + /* Check if it request. */ + if (it.fd == rfd) { + dbg_xfr_verb("xfr: worker=%p processing request\n", + w); + ret = xfr_process_request(w, buf, sizeof(buf)); + if (ret == KNOTD_ENOTRUNNING) { + break; + } + } else { + /* Find data. */ + pthread_mutex_lock(&h->tasks_mx); + data = skip_find(h->tasks, (void*)((size_t)it.fd)); + pthread_mutex_unlock(&h->tasks_mx); + dbg_xfr_verb("xfr: worker=%p processing event on " + "fd=%d data=%p.\n", + w, it.fd, data); + ret = xfr_process_event(w, it.fd, data); + if (ret != KNOTD_EOK) { + xfr_free_task(data); + } + } + + /* Next fd. */ + if (fdset_next(w->fdset, &it) < 0) { + break; + } + } + } + + + /* Stop whole unit. */ + dbg_xfr_verb("xfr: worker=%p finished.\n", w); + thread->data = 0; + return KNOTD_EOK; +} diff --git a/src/knot/server/xfr-handler.h b/src/knot/server/xfr-handler.h new file mode 100644 index 0000000..3587d93 --- /dev/null +++ b/src/knot/server/xfr-handler.h @@ -0,0 +1,163 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file xfr-handler.h + * + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief XFR requests handler. + * + * \addtogroup server + * @{ + */ + +#ifndef _KNOTD_XFRHANDLER_H_ +#define _KNOTD_XFRHANDLER_H_ + +#include "knot/server/dthreads.h" +#include "libknot/nameserver/name-server.h" +#include "common/evqueue.h" +#include "common/fdset.h" +#include "common/skip-list.h" /*!< \todo Consider another data struct. */ + +struct xfrhandler_t; + +/*! + * \brief XFR worker structure. + */ +typedef struct xfrworker_t +{ + knot_nameserver_t *ns; /*!< \brief Pointer to nameserver.*/ + evqueue_t *q; /*!< \brief Shared XFR requests queue.*/ + fdset_t *fdset; /*!< \brief File descriptor set. */ + struct xfrhandler_t *master; /*! \brief Worker master. */ +} xfrworker_t; + +/*! + * \brief XFR handler structure. + */ +typedef struct xfrhandler_t +{ + dt_unit_t *unit; /*!< \brief Threading unit. */ + xfrworker_t **workers; /*!< \brief Workers. */ + skip_list_t *tasks; /*!< \brief Pending tasks. */ + pthread_mutex_t tasks_mx; /*!< \brief Tasks synchronisation. */ + void (*interrupt)(struct xfrhandler_t *h); /*!< Interrupt handler. */ + unsigned rr; /*!< \brief Round-Robin counter. */ + pthread_mutex_t rr_mx; /*!< \brief RR mutex. */ +} xfrhandler_t; + +/*! + * \brief Create XFR threading unit. + * + * Unit can be controlled by standard DThreads API. + * Unit is created in Idle mode. + * + * \param thrcount Requested number of threads. + * \param ns Pointer to nameserver. + * + * \retval New handler on success. + * \retval NULL on error. + */ +xfrhandler_t *xfr_create(size_t thrcount, knot_nameserver_t *ns); + +/*! + * \brief Delete XFR handler. + * + * \warning Threading unit must be stopped and joined. + * + * \param handler XFR handler. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on NULL handler. + * \retval KNOTD_ERROR on error. + */ +int xfr_free(xfrhandler_t *handler); + +/*! + * \brief Start XFR handler. + * + * \param handler XFR handler. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ERROR on error. + */ +static inline int xfr_start(xfrhandler_t *handler) { + return dt_start(handler->unit); +} + +/*! + * \brief Stop XFR handler. + * + * \param handler XFR handler. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ERROR on error. + */ +int xfr_stop(xfrhandler_t *handler); + +/*! + * \brief Wait for XFR handler to finish. + * + * \param handler XFR handler. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_ERROR on error. + */ +int xfr_join(xfrhandler_t *handler); + +/*! + * \brief Prepare XFR request. + * + * \param r XFR request. + * \param type Request type. + * \param flags Request flags. + * \param pkt Query packet or NULL. + * + * \retval KNOTD_EOK + * \retval KNOTD_ENOMEM + * \retval KNOTD_EINVAL + */ +int xfr_request_init(knot_ns_xfr_t *r, int type, int flags, knot_packet_t *pkt); + +/*! + * \brief Enqueue XFR request. + * + * \param handler XFR handler instance. + * \param req XFR request. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on NULL handler or request. + * \retval KNOTD_ERROR on error. + */ +int xfr_request(xfrhandler_t *handler, knot_ns_xfr_t *req); + +/*! + * \brief XFR master runnable. + * + * Processes incoming AXFR/IXFR requests asynchonously. + * When no thread is available at the moment, request is enqueued. + * + * \param thread Associated thread from DThreads unit. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL invalid parameters. + */ +int xfr_worker(dthread_t *thread); + +#endif // _KNOTD_XFRHANDLER_H_ + +/*! @} */ diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c new file mode 100644 index 0000000..4456dac --- /dev/null +++ b/src/knot/server/zones.c @@ -0,0 +1,2352 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/stat.h> + +#include "common/lists.h" +#include "libknot/dname.h" +#include "libknot/util/wire.h" +#include "knot/zone/zone-dump-text.h" +#include "knot/zone/zone-load.h" +#include "libknot/zone/zone.h" +#include "libknot/zone/zonedb.h" +#include "knot/conf/conf.h" +#include "knot/other/debug.h" +#include "knot/other/error.h" +#include "knot/other/log.h" +#include "knot/server/notify.h" +#include "knot/server/server.h" +#include "libknot/updates/xfr-in.h" +#include "knot/server/zones.h" +#include "libknot/util/error.h" +#include "knot/zone/zone-dump.h" +#include "libknot/nameserver/name-server.h" +#include "libknot/updates/changesets.h" + +static const size_t XFRIN_CHANGESET_BINARY_SIZE = 100; +static const size_t XFRIN_CHANGESET_BINARY_STEP = 100; + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Wrapper for TCP send. + * \todo Implement generic fd pool properly with callbacks. + */ +#include "knot/server/tcp-handler.h" +static int zones_send_cb(int fd, sockaddr_t *addr, uint8_t *msg, size_t msglen) +{ + return tcp_send(fd, msg, msglen); +} + +/*----------------------------------------------------------------------------*/ + +/*! \brief Zone data destructor function. */ +static int zonedata_destroy(knot_zone_t *zone) +{ + dbg_zones_verb("zones: zonedata_destroy(%p) called\n", zone); + + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + if (!zd) { + return KNOTD_EINVAL; + } + + /* Cancel REFRESH timer. */ + if (zd->xfr_in.timer) { + evsched_t *sch = zd->xfr_in.timer->parent; + evsched_cancel(sch, zd->xfr_in.timer); + evsched_event_free(sch, zd->xfr_in.timer); + zd->xfr_in.timer = 0; + } + + /* Cancel EXPIRE timer. */ + if (zd->xfr_in.expire) { + evsched_t *sch = zd->xfr_in.expire->parent; + evsched_cancel(sch, zd->xfr_in.expire); + evsched_event_free(sch, zd->xfr_in.expire); + zd->xfr_in.expire = 0; + } + + /* Remove list of pending NOTIFYs. */ + pthread_mutex_lock(&zd->lock); + notify_ev_t *ev = 0, *evn = 0; + WALK_LIST_DELSAFE(ev, evn, zd->notify_pending) { + zones_cancel_notify(zd, ev); + } + pthread_mutex_unlock(&zd->lock); + + /* Cancel IXFR DB sync timer. */ + if (zd->ixfr_dbsync) { + evsched_t *sch = zd->ixfr_dbsync->parent; + evsched_cancel(sch, zd->ixfr_dbsync); + evsched_event_free(sch, zd->ixfr_dbsync); + zd->ixfr_dbsync = 0; + } + + /* Destroy mutex. */ + pthread_mutex_destroy(&zd->lock); + pthread_mutex_destroy(&zd->xfr_in.lock); + + acl_delete(&zd->xfr_in.acl); + acl_delete(&zd->xfr_out); + acl_delete(&zd->notify_in); + acl_delete(&zd->notify_out); + + /* Close IXFR db. */ + journal_close(zd->ixfr_db); + + free(zd); + + /* Invalidate. */ + zone->dtor = 0; + zone->data = 0; + + return KNOTD_EOK; +} + +/*! \brief Zone data constructor function. */ +static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) +{ + zonedata_t *zd = malloc(sizeof(zonedata_t)); + if (!zd) { + return KNOTD_ENOMEM; + } + + /* Link to config. */ + zd->conf = cfg; + zd->server = 0; + + /* Initialize mutex. */ + pthread_mutex_init(&zd->lock, 0); + + /* Initialize ACLs. */ + zd->xfr_out = 0; + zd->notify_in = 0; + zd->notify_out = 0; + + /* Initialize XFR-IN. */ + sockaddr_init(&zd->xfr_in.master, -1); + zd->xfr_in.timer = 0; + zd->xfr_in.expire = 0; + zd->xfr_in.next_id = -1; + zd->xfr_in.acl = 0; + zd->xfr_in.wrkr = 0; + zd->xfr_in.bootstrap_retry = 0; + pthread_mutex_init(&zd->xfr_in.lock, 0); + + /* Initialize NOTIFY. */ + init_list(&zd->notify_pending); + + /* Initialize IXFR database. */ + zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit, + JOURNAL_DIRTY); + if (!zd->ixfr_db) { + int ret = journal_create(cfg->ixfr_db, JOURNAL_NCOUNT); + if (ret != KNOTD_EOK) { + log_server_error("Failed to create journal file " + "'%s'\n", cfg->ixfr_db); + } + zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit, + JOURNAL_DIRTY); + } + + if (zd->ixfr_db == 0) { + log_server_error("Failed to open journal file " + "'%s'\n", cfg->ixfr_db); + } + + /* Initialize IXFR database syncing event. */ + zd->ixfr_dbsync = 0; + + /* Set and install destructor. */ + zone->data = zd; + zone->dtor = zonedata_destroy; + + /* Set zonefile SOA serial. */ + const knot_rrset_t *soa_rrs = 0; + const knot_rdata_t *soa_rr = 0; + + /* Load serial. */ + zd->zonefile_serial = 0; + const knot_zone_contents_t *contents = knot_zone_contents(zone); + if (contents) { + soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents), + KNOT_RRTYPE_SOA); + soa_rr = knot_rrset_rdata(soa_rrs); + int64_t serial = knot_rdata_soa_serial(soa_rr); + zd->zonefile_serial = (uint32_t)serial; + if (serial < 0) { + return KNOTD_EINVAL; + } + } + + return KNOTD_EOK; +} + +/*! + * \brief Return SOA timer value. + * + * \param zone Pointer to zone. + * \param rr_func RDATA specificator. + * \return Timer in miliseconds. + */ +static uint32_t zones_soa_timer(knot_zone_t *zone, + uint32_t (*rr_func)(const knot_rdata_t*)) +{ + if (!zone) { + dbg_zones_verb("zones: zones_soa_timer() called " + "with NULL zone\n"); + } + + uint32_t ret = 0; + + /* Retrieve SOA RDATA. */ + const knot_rrset_t *soa_rrs = 0; + const knot_rdata_t *soa_rr = 0; + knot_zone_contents_t * zc = knot_zone_get_contents((zone)); + if (!zc) { + return 0; + } + + soa_rrs = knot_node_rrset(knot_zone_contents_apex(zc), + KNOT_RRTYPE_SOA); + soa_rr = knot_rrset_rdata(soa_rrs); + ret = rr_func(soa_rr); + + /* Convert to miliseconds. */ + return ret * 1000; +} + +/*! + * \brief Return SOA REFRESH timer value. + * + * \param zone Pointer to zone. + * \return REFRESH timer in miliseconds. + */ +static uint32_t zones_soa_refresh(knot_zone_t *zone) +{ + return zones_soa_timer(zone, knot_rdata_soa_refresh); +} + +/*! + * \brief Return SOA RETRY timer value. + * + * \param zone Pointer to zone. + * \return RETRY timer in miliseconds. + */ +static uint32_t zones_soa_retry(knot_zone_t *zone) +{ + return zones_soa_timer(zone, knot_rdata_soa_retry); +} + +/*! + * \brief Return SOA EXPIRE timer value. + * + * \param zone Pointer to zone. + * \return EXPIRE timer in miliseconds. + */ +static uint32_t zones_soa_expire(knot_zone_t *zone) +{ + return zones_soa_timer(zone, knot_rdata_soa_expire); +} + +/*! + * \brief XFR/IN expire event handler. + */ +static int zones_expire_ev(event_t *e) +{ + rcu_read_lock(); + dbg_zones("zones: EXPIRE timer event\n"); + knot_zone_t *zone = (knot_zone_t *)e->data; + if (!zone) { + return KNOTD_EINVAL; + } + if (!zone->data) { + return KNOTD_EINVAL; + } + + zonedata_t *zd = (zonedata_t *)zone->data; + + /* Won't accept any pending SOA responses. */ + zd->xfr_in.next_id = -1; + + /* Mark the zone as expired. This will remove the zone contents. */ + knot_zone_contents_t *contents = knot_zonedb_expire_zone( + zd->server->nameserver->zone_db, zone->name); + + if (contents == NULL) { + log_server_warning("Non-existent zone expired. Ignoring.\n"); + rcu_read_unlock(); + return 0; + } + + + rcu_read_unlock(); + + dbg_zones_verb("zones: zone %s expired, waiting for xfers to finish\n", + zd->conf->name); + pthread_mutex_lock(&zd->xfr_in.lock); + dbg_zones_verb("zones: zone %s locked, no xfers are running\n", + zd->conf->name); + + synchronize_rcu(); + pthread_mutex_unlock(&zd->xfr_in.lock); + + log_server_info("Zone '%s' expired.\n", zd->conf->name); + + /* Early finish this event to prevent lockup during cancellation. */ + dbg_zones("zones: zone expired, removing from database\n"); + evsched_event_finished(e->parent); + + /* Cancel REFRESH timer. */ + if (zd->xfr_in.timer) { + evsched_cancel(e->parent, zd->xfr_in.timer); + evsched_event_free(e->parent, zd->xfr_in.timer); + zd->xfr_in.timer = 0; + } + + /* Free EXPIRE timer. */ + if (zd->xfr_in.expire) { + evsched_event_free(e->parent, zd->xfr_in.expire); + zd->xfr_in.expire = 0; + } + + knot_zone_contents_deep_free(&contents, 0); + + return 0; +} + +/*! + * \brief Zone REFRESH or RETRY event. + */ +static int zones_refresh_ev(event_t *e) +{ + dbg_zones("zones: REFRESH or RETRY timer event\n"); + knot_zone_t *zone = (knot_zone_t *)e->data; + if (!zone) { + return KNOTD_EINVAL; + } + + /* Cancel pending timers. */ + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + if (!zd) { + return KNOTD_EINVAL; + } + + /* Prepare buffer for query. */ + uint8_t qbuf[SOCKET_MTU_SZ]; + size_t buflen = SOCKET_MTU_SZ; + + /* Lock RCU. */ + rcu_read_lock(); + + /* Check for contents. */ + if (!knot_zone_contents(zone)) { + + /* Bootstrap from XFR master. */ + knot_ns_xfr_t xfr_req; + memset(&xfr_req, 0, sizeof(knot_ns_xfr_t)); + memcpy(&xfr_req.addr, &zd->xfr_in.master, sizeof(sockaddr_t)); + xfr_req.data = (void *)zone; + xfr_req.send = zones_send_cb; + + /* Select transfer method. */ + xfr_req.type = XFR_TYPE_AIN; + xfr_req.zone = zone; + + /* Select TSIG key. */ + /*!< \todo [TSIG] DISABLED */ + xfr_req.tsig_key = 0; +// if (zd->xfr_in.tsig_key.name) { +// xfr_req.tsig_key = &zd->xfr_in.tsig_key; +// } + + /* Unlock zone contents. */ + rcu_read_unlock(); + + /* Enqueue XFR request. */ + int locked = pthread_mutex_trylock(&zd->xfr_in.lock); + if (locked != 0) { + dbg_zones("zones: already bootstrapping '%s'\n", + zd->conf->name); + return KNOTD_EOK; + } else { + log_zone_info("Attempting to bootstrap zone %s from master\n", + zd->conf->name); + pthread_mutex_unlock(&zd->xfr_in.lock); + } + + return xfr_request(zd->server->xfr_h, &xfr_req); + } + + /* Do not issue SOA query if transfer is pending. */ + int locked = pthread_mutex_trylock(&zd->xfr_in.lock); + if (locked != 0) { + dbg_zones("zones: zone '%s' is being transferred, " + "deferring SOA query\n", + zd->conf->name); + + /* Reschedule as RETRY timer. */ + evsched_schedule(e->parent, e, zones_soa_retry(zone)); + dbg_zones("zones: RETRY of '%s' after %u seconds\n", + zd->conf->name, zones_soa_retry(zone) / 1000); + + /* Unlock RCU. */ + rcu_read_unlock(); + return KNOTD_EOK; + } else { + pthread_mutex_unlock(&zd->xfr_in.lock); + } + + /* Create query. */ + /*! \todo API for retrieval of name. */ + + /*! \todo [TSIG] CHANGE!!! only for compatibility now. */ + knot_ns_xfr_t xfr_req; + memset(&xfr_req, 0, sizeof(knot_ns_xfr_t)); + xfr_req.wire = qbuf; + + int ret = xfrin_create_soa_query(zone->name, &xfr_req, &buflen); + if (ret == KNOT_EOK) { + + sockaddr_t *master = &zd->xfr_in.master; + + /* Create socket on random port. */ + int sock = socket_create(master->family, SOCK_DGRAM); + + /* Send query. */ + ret = -1; + if (sock > -1) { + ret = sendto(sock, qbuf, buflen, 0, + master->ptr, master->len); + } + + /* Store ID of the awaited response. */ + if (ret == buflen) { + zd->xfr_in.next_id = knot_wire_get_id(qbuf); + dbg_zones("zones: expecting SOA response " + "ID=%d for '%s'\n", + zd->xfr_in.next_id, zd->conf->name); + } + + /* Watch socket. */ + knot_ns_xfr_t req; + memset(&req, 0, sizeof(req)); + req.session = sock; + req.type = XFR_TYPE_SOA; + req.zone = zone; + memcpy(&req.addr, master, sizeof(sockaddr_t)); + sockaddr_update(&req.addr); + xfr_request(zd->server->xfr_h, &req); + } else { + ret = KNOTD_ERROR; + } + + /* Schedule EXPIRE timer on first attempt. */ + if (!zd->xfr_in.expire) { + uint32_t expire_tmr = zones_soa_expire(zone); + zd->xfr_in.expire = evsched_schedule_cb( + e->parent, + zones_expire_ev, + zone, expire_tmr); + dbg_zones("zones: EXPIRE of '%s' after %u seconds\n", + zd->conf->name, expire_tmr / 1000); + } + + /* Reschedule as RETRY timer. */ + evsched_schedule(e->parent, e, zones_soa_retry(zone)); + dbg_zones("zones: RETRY of '%s' after %u seconds\n", + zd->conf->name, zones_soa_retry(zone) / 1000); + + /* Unlock RCU. */ + rcu_read_unlock(); + + return ret; +} + +/*! + * \brief Send NOTIFY to slave server. + */ +static int zones_notify_send(event_t *e) +{ + dbg_notify("notify: NOTIFY timer event\n"); + + notify_ev_t *ev = (notify_ev_t *)e->data; + knot_zone_t *zone = ev->zone; + if (!zone) { + log_zone_error("notify: NOTIFY invalid event received\n"); + evsched_event_free(e->parent, e); + free(ev); + return KNOTD_EINVAL; + } + + /* Check for answered/cancelled query. */ + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + knot_zone_contents_t *contents = knot_zone_get_contents(zone); + + /* Reduce number of available retries. */ + --ev->retries; + + /* Check number of retries. */ + if (ev->retries < 0) { + log_server_notice("NOTIFY query maximum number of retries " + "for zone %s exceeded.\n", + zd->conf->name); + pthread_mutex_lock(&zd->lock); + rem_node(&ev->n); + evsched_event_free(e->parent, e); + free(ev); + pthread_mutex_unlock(&zd->lock); + return KNOTD_EMALF; + } + + /* Prepare buffer for query. */ + uint8_t qbuf[SOCKET_MTU_SZ]; + size_t buflen = sizeof(qbuf); + + /* RFC suggests 60s, but it is configurable. */ + int retry_tmr = ev->timeout * 1000; + + /* Reschedule. */ + conf_read_lock(); + evsched_schedule(e->parent, e, retry_tmr); + dbg_notify("notify: Query RETRY after %u secs (zone '%s')\n", + retry_tmr / 1000, zd->conf->name); + conf_read_unlock(); + + /* Create query. */ + int ret = notify_create_request(contents, qbuf, &buflen); + if (ret == KNOTD_EOK && zd->server) { + + /* Lock RCU. */ + rcu_read_lock(); + + /* Create socket on random port. */ + int sock = socket_create(ev->addr.family, SOCK_DGRAM); + + /* Send query. */ + ret = -1; + if (sock > -1) { + ret = sendto(sock, qbuf, buflen, 0, + ev->addr.ptr, ev->addr.len); + } + + /* Store ID of the awaited response. */ + if (ret == buflen) { + char r_addr[SOCKADDR_STRLEN]; + sockaddr_tostr(&ev->addr, r_addr, sizeof(r_addr)); + int r_port = sockaddr_portnum(&ev->addr); + ev->msgid = knot_wire_get_id(qbuf); + log_server_info("Issued NOTIFY query to %s:%d, expecting " + "response ID=%d\n", + r_addr, r_port, + ev->msgid); + + } + + /* Watch socket. */ + knot_ns_xfr_t req; + memset(&req, 0, sizeof(req)); + req.session = sock; + req.type = XFR_TYPE_NOTIFY; + req.zone = zone; + memcpy(&req.addr, &ev->addr, sizeof(sockaddr_t)); + xfr_request(zd->server->xfr_h, &req); + + /* Unlock RCU */ + rcu_read_unlock(); + } + + return ret; +} + +/*! \brief Function for marking nodes as synced and updated. */ +static int zones_ixfrdb_sync_apply(journal_t *j, journal_node_t *n) +{ + /* Check for dirty bit (not synced to permanent storage). */ + if (n->flags & JOURNAL_DIRTY) { + + /* Remove dirty bit. */ + n->flags = n->flags & ~JOURNAL_DIRTY; + + /* Sync. */ + journal_update(j, n); + } + + return KNOTD_EOK; +} + +/*! + * \brief Sync chagnes in zone to zonefile. + */ +static int zones_zonefile_sync_ev(event_t *e) +{ + dbg_zones("zones: IXFR database SYNC timer event\n"); + + /* Fetch zone. */ + knot_zone_t *zone = (knot_zone_t *)e->data; + if (!zone) { + return KNOTD_EINVAL; + } + + /* Fetch zone data. */ + zonedata_t *zd = (zonedata_t *)zone->data; + if (!zd) { + return KNOTD_EINVAL; + } + + /* Execute zonefile sync. */ + int ret = zones_zonefile_sync(zone); + if (ret == KNOTD_EOK) { + log_zone_info("Applied differences of '%s' to zonefile.\n", + zd->conf->name); + } else { + log_zone_warning("Failed to apply differences of '%s' " + "to zonefile.\n", + zd->conf->name); + } + + /* Reschedule. */ + conf_read_lock(); + evsched_schedule(e->parent, e, zd->conf->dbsync_timeout * 1000); + dbg_zones("zones: next IXFR database SYNC of '%s' in %d seconds\n", + zd->conf->name, zd->conf->dbsync_timeout); + conf_read_unlock(); + + return ret; +} + +/*! + * \brief Update ACL list from configuration. + * + * \param acl Pointer to existing or NULL ACL. + * \param acl_list List of remotes from configuration. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOMEM on failed memory allocation. + */ +static int zones_set_acl(acl_t **acl, list* acl_list) +{ + if (!acl || !acl_list) { + return KNOTD_EINVAL; + } + + /* Truncate old ACL. */ + acl_delete(acl); + + /* Create new ACL. */ + *acl = acl_new(ACL_DENY, 0); + if (!*acl) { + return KNOTD_ENOMEM; + } + + /* Load ACL rules. */ + conf_remote_t *r = 0; + WALK_LIST(r, *acl_list) { + + /* Initialize address. */ + /*! Port matching disabled, port = 0. */ + sockaddr_t addr; + conf_iface_t *cfg_if = r->remote; + int ret = sockaddr_set(&addr, cfg_if->family, + cfg_if->address, 0); + + /* Load rule. */ + if (ret > 0) { + acl_create(*acl, &addr, ACL_ACCEPT); + } + } + + return KNOTD_EOK; +} + +/*! + * \brief Load zone to zone database. + * + * \param zonedb Zone database to load the zone into. + * \param zone_name Zone name (owner of the apex node). + * \param source Path to zone file source. + * \param filename Path to requested compiled zone file. + * + * \retval KNOTD_EOK + * \retval KNOTD_EINVAL + * \retval KNOTD_EZONEINVAL + */ +static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name, + const char *source, const char *filename) +{ + knot_zone_t *zone = NULL; + + /* Check path */ + if (filename) { + dbg_zones("zones: parsing zone database '%s'\n", filename); + zloader_t *zl = 0; + int ret = knot_zload_open(&zl, filename); + switch(ret) { + case KNOT_EOK: + /* OK */ + break; + case KNOT_EFEWDATA: + log_server_error("Compiled zone db '%s' not exists.\n", + filename); + return KNOTD_EZONEINVAL; + case KNOT_ECRC: + log_server_error("Compiled zone db CRC mismatches, " + "db is corrupted or .crc file is " + "deleted.\n"); + return KNOTD_EZONEINVAL; + case KNOT_EMALF: + log_server_error("Compiled db '%s' is too old, " + " please recompile.\n", + filename); + return KNOTD_EZONEINVAL; + case KNOT_ERROR: + case KNOT_ENOMEM: + default: + log_server_error("Failed to read zone db file '%s'.\n", + filename); + return KNOTD_EZONEINVAL; + } + + /* Check if the db is up-to-date */ + int src_changed = strcmp(source, zl->source) != 0; + if (src_changed || knot_zload_needs_update(zl)) { + log_server_warning("Database for zone '%s' is not " + "up-to-date. Please recompile.\n", + zone_name); + } + + zone = knot_zload_load(zl); + + /* Check loaded name. */ + const knot_dname_t *dname = knot_zone_name(zone); + knot_dname_t *dname_req = 0; + dname_req = knot_dname_new_from_str(zone_name, + strlen(zone_name), 0); + if (knot_dname_compare(dname, dname_req) != 0) { + log_server_warning("Origin of the zone db file is " + "different than '%s'\n", + zone_name); + knot_zone_deep_free(&zone, 0); + zone = 0; + + } + knot_dname_free(&dname_req); + + /* CLEANUP */ + //knot_zone_contents_dump(zone->contents, 1); + + if (zone) { + /* save the timestamp from the zone db file */ + struct stat s; + stat(filename, &s); + knot_zone_set_version(zone, s.st_mtime); + + if (knot_zonedb_add_zone(zonedb, zone) != 0){ + knot_zone_deep_free(&zone, 0); + zone = 0; + } + } + + knot_zload_close(zl); + + if (!zone) { + log_server_error("Failed to load " + "db '%s' for zone '%s'.\n", + filename, zone_name); + return KNOTD_EZONEINVAL; + } + } else { + /* db is null. */ + return KNOTD_EINVAL; + } + + /* CLEANUP */ +// knot_zone_dump(zone, 1); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +/*! \brief Return 'serial_from' part of the key. */ +static inline uint32_t ixfrdb_key_from(uint64_t k) +{ + /* 64 32 0 + * key = [TO | FROM] + * Need: Least significant 32 bits. + */ + return (uint32_t)(k & ((uint64_t)0x00000000ffffffff)); +} + +/*----------------------------------------------------------------------------*/ + +/*! \brief Return 'serial_to' part of the key. */ +static inline uint32_t ixfrdb_key_to(uint64_t k) +{ + /* 64 32 0 + * key = [TO | FROM] + * Need: Most significant 32 bits. + */ + return (uint32_t)(k >> (uint64_t)32); +} + +/*----------------------------------------------------------------------------*/ + +/*! \brief Compare function to match entries with target serial. */ +static inline int ixfrdb_key_to_cmp(uint64_t k, uint64_t to) +{ + /* 64 32 0 + * key = [TO | FROM] + * Need: Most significant 32 bits. + */ + return ((uint64_t)ixfrdb_key_to(k)) - to; +} + +/*----------------------------------------------------------------------------*/ + +/*! \brief Compare function to match entries with starting serial. */ +static inline int ixfrdb_key_from_cmp(uint64_t k, uint64_t from) +{ + /* 64 32 0 + * key = [TO | FROM] + * Need: Least significant 32 bits. + */ + return ((uint64_t)ixfrdb_key_from(k)) - from; +} + +/*----------------------------------------------------------------------------*/ + +/*! \brief Make key for journal from serials. */ +static inline uint64_t ixfrdb_key_make(uint32_t from, uint32_t to) +{ + /* 64 32 0 + * key = [TO | FROM] + */ + return (((uint64_t)to) << ((uint64_t)32)) | ((uint64_t)from); +} + +/*----------------------------------------------------------------------------*/ + +static int zones_changesets_from_binary(knot_changesets_t *chgsets) +{ + assert(chgsets != NULL); + assert(chgsets->allocated >= chgsets->count); + /* + * Parses changesets from the binary format stored in chgsets->data + * into the changeset_t structures. + */ + knot_rrset_t *rrset = 0; + int ret = 0; + + for (int i = 0; i < chgsets->count; ++i) { + + /* Read initial changeset RRSet - SOA. */ + knot_changeset_t* chs = chgsets->sets + i; + size_t remaining = chs->size; + ret = knot_zload_rrset_deserialize(&rrset, chs->data, &remaining); + if (ret != KNOT_EOK) { + dbg_xfr("xfr: SOA: failed to deserialize data " + "from changeset, %s\n", knot_strerror(ret)); + return KNOTD_EMALF; + } + + /* in this special case (changesets loaded + * from journal) the SOA serial should already + * be set, check it. + */ + assert(knot_rrset_type(rrset) == KNOT_RRTYPE_SOA); + assert(chs->serial_from == + knot_rdata_soa_serial(knot_rrset_rdata(rrset))); + knot_changeset_store_soa(&chs->soa_from, &chs->serial_from, + rrset); + + dbg_xfr_verb("xfr: reading RRSets to REMOVE\n"); + + /* Read remaining RRSets */ + int in_remove_section = 1; + while (remaining > 0) { + + /* Parse next RRSet. */ + rrset = 0; + uint8_t *stream = chs->data + (chs->size - remaining); + ret = knot_zload_rrset_deserialize(&rrset, stream, &remaining); + if (ret != KNOT_EOK) { + dbg_xfr("xfr: failed to deserialize data " + "from changeset, %s\n", + knot_strerror(ret)); + return KNOTD_EMALF; + } + + /* Check for next SOA. */ + if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + + /* Move to ADD section if in REMOVE. */ + if (in_remove_section) { + knot_changeset_store_soa( + &chgsets->sets[i].soa_to, + &chgsets->sets[i].serial_to, + rrset); + dbg_xfr_verb("xfr: reading RRSets" + " to ADD\n"); + in_remove_section = 0; + } else { + /* Final SOA. */ + dbg_xfr_verb("xfr: extra SOA\n"); + knot_rrset_free(&rrset); + break; + } + } else { + /* Remove RRSets. */ + if (in_remove_section) { + ret = knot_changeset_add_rrset( + &chgsets->sets[i].remove, + &chgsets->sets[i].remove_count, + &chgsets->sets[i] + .remove_allocated, + rrset); + } else { + /* Add RRSets. */ + ret = knot_changeset_add_rrset( + &chgsets->sets[i].add, + &chgsets->sets[i].add_count, + &chgsets->sets[i].add_allocated, + rrset); + } + + /* Check result. */ + if (ret != KNOT_EOK) { + dbg_xfr("xfr: failed to add/remove " + "RRSet to changeset: %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; + } + } + } + + dbg_xfr_verb("xfr: read all RRSets in changeset\n"); + } + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int zones_load_changesets(const knot_zone_t *zone, + knot_changesets_t *dst, + uint32_t from, uint32_t to) +{ + if (!zone || !dst) { + dbg_zones_detail("Bad arguments: zone=%p, dst=%p\n", zone, dst); + return KNOTD_EINVAL; + } + if (!zone->data) { + dbg_zones_detail("Bad arguments: zone->data=%p\n", zone->data); + return KNOTD_EINVAL; + } + + dbg_xfr("Loading changesets from serial %u to %u\n", from, to); + + /* Fetch zone-specific data. */ + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + if (!zd->ixfr_db) { + dbg_zones_detail("Bad arguments: zd->ixfr_db=%p\n", zone->data); + return KNOTD_EINVAL; + } + + /* Read entries from starting serial until finished. */ + uint32_t found_to = from; + journal_node_t *n = 0; + int ret = journal_fetch(zd->ixfr_db, from, ixfrdb_key_from_cmp, &n); + if (ret != KNOTD_EOK) { + dbg_xfr("xfr: failed to fetch starting changeset: %s\n", + knotd_strerror(ret)); + return ret; + } + + while (n != 0 && n != journal_end(zd->ixfr_db)) { + + /* Check for history end. */ + if (to == found_to) { + break; + } + + /*! \todo Increment and decrement to reserve +1, + * but not incremented counter.*/ + /* Check changesets size if needed. */ + ++dst->count; + ret = knot_changesets_check_size(dst); + --dst->count; + if (ret != KNOT_EOK) { + --dst->count; + dbg_xfr("xfr: failed to check changesets size: %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; + } + + /* Initialize changeset. */ + dbg_xfr_detail("xfr: reading entry #%zu id=%llu\n", + dst->count, (unsigned long long)n->id); + knot_changeset_t *chs = dst->sets + dst->count; + chs->serial_from = ixfrdb_key_from(n->id); + chs->serial_to = ixfrdb_key_to(n->id); + chs->data = malloc(n->len); + if (!chs->data) { + return KNOTD_ENOMEM; + } + + /* Read journal entry. */ + ret = journal_read(zd->ixfr_db, n->id, + 0, (char*)chs->data); + if (ret != KNOTD_EOK) { + dbg_xfr("xfr: failed to read data from journal\n"); + free(chs->data); + return KNOTD_ERROR; + } + + /* Update changeset binary size. */ + chs->size = chs->allocated = n->len; + + /* Next node. */ + found_to = chs->serial_to; + ++dst->count; + ++n; + + /*! \todo Check consistency. */ + } + + dbg_xfr_detail("xfr: Journal entries read.\n"); + + /* Unpack binary data. */ + ret = zones_changesets_from_binary(dst); + if (ret != KNOT_EOK) { + dbg_xfr("xfr: failed to unpack changesets " + "from binary, %s\n", knot_strerror(ret)); + return KNOTD_ERROR; + } + + /* Check for complete history. */ + if (to != found_to) { + dbg_xfr_detail("Returning ERANGE\n"); + return KNOTD_ERANGE; + } + + /* History reconstructed. */ + dbg_xfr_detail("Returning EOK\n"); + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Apply changesets to zone from journal. + * + * \param zone Specified zone. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOENT if zone has no contents. + * \retval KNOTD_ERROR on unspecified error. + */ +static int zones_journal_apply(knot_zone_t *zone) +{ + /* Fetch zone. */ + if (!zone) { + return KNOTD_EINVAL; + } + + knot_zone_contents_t *contents = knot_zone_get_contents(zone); + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + if (!contents || !zd) { + return KNOTD_ENOENT; + } + + /* Fetch SOA serial. */ + const knot_rrset_t *soa_rrs = 0; + const knot_rdata_t *soa_rr = 0; + soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents), + KNOT_RRTYPE_SOA); + soa_rr = knot_rrset_rdata(soa_rrs); + int64_t serial_ret = knot_rdata_soa_serial(soa_rr); + if (serial_ret < 0) { + return KNOTD_EINVAL; + } + uint32_t serial = (uint32_t)serial_ret; + + /* Load all pending changesets. */ + dbg_zones_verb("zones: loading all changesets of '%s' from SERIAL %u\n", + zd->conf->name, serial); + knot_changesets_t* chsets = malloc(sizeof(knot_changesets_t)); + memset(chsets, 0, sizeof(knot_changesets_t)); + /*! \todo Check what should be the upper bound. */ + int ret = zones_load_changesets(zone, chsets, serial, serial - 1); + if (ret == KNOTD_EOK || ret == KNOTD_ERANGE) { + if (chsets->count > 0) { + /* Apply changesets. */ + log_server_info("Applying '%zu' changesets from journal " + "to zone '%s'.\n", + chsets->count, zd->conf->name); + ret = xfrin_apply_changesets_to_zone(zone, chsets); + if (ret != KNOT_EOK) { + log_server_error("Failed to apply changesets to " + "'%s' - %s\n", + zd->conf->name, + knot_strerror(ret)); + ret = KNOTD_ERROR; + } + } + } else { + dbg_zones("zones: failed to load changesets - %s\n", + knotd_strerror(ret)); + } + + /* Free changesets and return. */ + knot_free_changesets(&chsets); + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Fill the new database with zones. + * + * Zones that should be retained are just added from the old database to the + * new. New zones are loaded. + * + * \param ns Name server instance. + * \param zone_conf Zone configuration. + * \param db_old Old zone database. + * \param db_new New zone database. + * + * \return Number of inserted zones. + */ +static int zones_insert_zones(knot_nameserver_t *ns, + const list *zone_conf, + const knot_zonedb_t *db_old, + knot_zonedb_t *db_new) +{ + /*! \todo Change to zone contents. */ + + node *n = 0; + int inserted = 0; + /* for all zones in the configuration */ + WALK_LIST(n, *zone_conf) { + conf_zone_t *z = (conf_zone_t *)n; + + /* Convert the zone name into a domain name. */ + /* Local allocation, will be discarded. */ + knot_dname_t *zone_name = knot_dname_new_from_str(z->name, + strlen(z->name), NULL); + if (zone_name == NULL) { + log_server_error("Error creating domain name from zone" + " name\n"); + return inserted; + } + + dbg_zones_verb("zones: inserting zone %s into the new database.\n", + z->name); + + /* try to find the zone in the current zone db */ + knot_zone_t *zone = knot_zonedb_find_zone(db_old, + zone_name); + int reload = 0; + + /* Attempt to bootstrap if db or source does not exist. */ + struct stat s; + int stat_ret = stat(z->file, &s); + if (zone != NULL) { + /* if found, check timestamp of the file against the + * loaded zone + */ + if (knot_zone_version(zone) < s.st_mtime) { + /* the file is newer, reload! */ + reload = 1; + } + } else { + reload = 1; + } + + /* Reload zone file. */ + int ret = KNOTD_ERROR; + if (reload) { + /* Zone file not exists and has master set. */ + if (stat_ret < 0 && !EMPTY_LIST(z->acl.xfr_in)) { + + /* Create stub database. */ + dbg_zones_verb("zones: loading stub zone '%s' " + "for bootstrap.\n", + z->name); + knot_dname_t *owner = 0; + owner = knot_dname_deep_copy(zone_name); + knot_zone_t* sz = knot_zone_new_empty(owner); + if (sz) { + /* Add stub zone to db_new. */ + ret = knot_zonedb_add_zone(db_new, sz); + if (ret != KNOT_EOK) { + dbg_zones("zones: failed to add " + "stub zone '%s'.\n", + z->name); + knot_zone_deep_free(&sz, 0); + sz = 0; + ret = KNOTD_ERROR; + } else { + log_server_info("Will attempt to " + "bootstrap zone " + "%s from AXFR " + "master.\n", + z->name); + --inserted; + } + + } else { + dbg_zones("zones: failed to create " + "stub zone '%s'.\n", + z->name); + ret = KNOTD_ERROR; + } + + } else { + dbg_zones_verb("zones: loading zone '%s' " + "from '%s'\n", + z->name, + z->db); + ret = zones_load_zone(db_new, z->name, + z->file, z->db); + if (ret == KNOTD_EOK) { + log_server_info("Loaded zone '%s'\n", + z->name); + } else { + log_server_error("Failed to load zone " + "'%s' - %s\n", + z->name, + knotd_strerror(ret)); + } + } + + /* Find zone. */ + if (ret == KNOTD_EOK) { + /* Find the new zone */ + zone = knot_zonedb_find_zone(db_new, + zone_name); + ++inserted; + + dbg_zones_verb("zones: inserted '%s' into " + "database, initializing data\n", + z->name); + + /* Initialize zone-related data. */ + zonedata_init(z, zone); + + } + /* unused return value, if not loaded, just continue */ + } else { + /* just insert the zone into the new zone db */ + dbg_zones_verb("zones: found '%s' in old database, " + "copying to new.\n", + z->name); + log_server_info("Zone '%s' is up-to-date, no need " + "for reload.\n", z->name); + int ret = knot_zonedb_add_zone(db_new, zone); + if (ret != KNOT_EOK) { + log_server_error("Error adding known zone '%s' to" + " the new database - %s\n", + z->name, knot_strerror(ret)); + ret = KNOTD_ERROR; + } else { + ++inserted; + } + } + + /* Update zone data. */ + if (zone) { + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + + /* Update refs. */ + zd->conf = z; + + /* Update ACLs. */ + dbg_zones("Updating zone ACLs.\n"); + zones_set_acl(&zd->xfr_in.acl, &z->acl.xfr_in); + zones_set_acl(&zd->xfr_out, &z->acl.xfr_out); + zones_set_acl(&zd->notify_in, &z->acl.notify_in); + zones_set_acl(&zd->notify_out, &z->acl.notify_out); + + /* Update server pointer. */ + zd->server = (server_t *)knot_ns_get_data(ns); + + /* Update master server address. */ + memset(&zd->xfr_in.tsig_key, 0, sizeof(knot_key_t)); + sockaddr_init(&zd->xfr_in.master, -1); + if (!EMPTY_LIST(z->acl.xfr_in)) { + conf_remote_t *r = HEAD(z->acl.xfr_in); + conf_iface_t *cfg_if = r->remote; + sockaddr_set(&zd->xfr_in.master, + cfg_if->family, + cfg_if->address, + cfg_if->port); + /*!< \todo [TSIG] DISABLED */ +// if (cfg_if->key) { +// memcpy(&zd->xfr_in.tsig_key, +// cfg_if->key, +// sizeof(knot_key_t)); +// } + + dbg_zones("zones: using %s:%d as XFR master " + "for '%s'\n", + cfg_if->address, + cfg_if->port, + z->name); + } + + /* Apply changesets from journal. */ + zones_journal_apply(zone); + + /* Update events scheduled for zone. */ + zones_timers_update(zone, z, + ((server_t *)knot_ns_get_data(ns))->sched); + } + + /* CLEANUP */ +// knot_zone_contents_dump(knot_zone_get_contents(zone), 1); + + /* Directly discard zone. */ + knot_dname_free(&zone_name); + } + return inserted; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Remove zones present in the configuration from the old database. + * + * After calling this function, the old zone database should contain only zones + * that should be completely deleted. + * + * \param zone_conf Zone configuration. + * \param db_old Old zone database to remove zones from. + * + * \retval KNOTD_EOK + * \retval KNOTD_ERROR + */ +static int zones_remove_zones(const knot_zonedb_t *db_new, + knot_zonedb_t *db_old) +{ + const knot_zone_t **new_zones = knot_zonedb_zones(db_new); + if (new_zones == NULL) { + return KNOTD_ENOMEM; + } + + for (int i = 0; i < knot_zonedb_zone_count(db_new); ++i) { + /* try to find the new zone in the old DB + * if the pointers match, remove the zone from old DB + */ + /*! \todo Find better way of removing zone with given pointer.*/ + knot_zone_t *old_zone = knot_zonedb_find_zone( + db_old, knot_zone_name(new_zones[i])); + if (old_zone == new_zones[i]) { +dbg_zones_exec( + char *name = knot_dname_to_str(knot_zone_name(old_zone)); + dbg_zones_verb("zones: zone pointers match, removing zone %s " + "from database.\n", name); + free(name); +); + knot_zone_t * rm = knot_zonedb_remove_zone(db_old, + knot_zone_name(old_zone)); + assert(rm == old_zone); + } + } + + free(new_zones); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns, + knot_zonedb_t **db_old) +{ + /* Check parameters */ + if (conf == NULL || ns == NULL) { + return KNOTD_EINVAL; + } + + /* Lock RCU to ensure none will deallocate any data under our hands. */ + rcu_read_lock(); + + /* Grab a pointer to the old database */ + *db_old = ns->zone_db; + if (*db_old == NULL) { + log_server_error("Missing zone database in nameserver structure" + ".\n"); + return KNOTD_ERROR; + } + + /* Create new zone DB */ + knot_zonedb_t *db_new = knot_zonedb_new(); + if (db_new == NULL) { + return KNOTD_ERROR; + } + + log_server_info("Loading %d compiled zones...\n", conf->zones_count); + + /* Insert all required zones to the new zone DB. */ + int inserted = zones_insert_zones(ns, &conf->zones, *db_old, db_new); + + log_server_info("Loaded %d out of %d zones.\n", inserted, + conf->zones_count); + + if (inserted != conf->zones_count) { + log_server_warning("Not all the zones were loaded.\n"); + } + + dbg_zones_detail("zones: old db in nameserver: %p, old db stored: %p, new db: %p\n", + ns->zone_db, *db_old, db_new); + + /* Switch the databases. */ + (void)rcu_xchg_pointer(&ns->zone_db, db_new); + + dbg_zones_detail("db in nameserver: %p, old db stored: %p, new db: %p\n", + ns->zone_db, *db_old, db_new); + + /* + * Remove all zones present in the new DB from the old DB. + * No new thread can access these zones in the old DB, as the + * databases are already switched. + * + * Beware - only the exact same zones (same pointer) may be removed. + * All other have been loaded again so that the old must be destroyed. + */ + int ret = zones_remove_zones(db_new, *db_old); + if (ret != KNOTD_EOK) { + return ret; + } + + /* Unlock RCU, messing with any data will not affect us now */ + rcu_read_unlock(); + + return KNOTD_EOK; +} + +int zones_zonefile_sync(knot_zone_t *zone) +{ + if (!zone) { + return KNOTD_EINVAL; + } + if (!zone->data) { + return KNOTD_EINVAL; + } + + /* Fetch zone data. */ + zonedata_t *zd = (zonedata_t *)zone->data; + + /* Lock zone data. */ + pthread_mutex_lock(&zd->lock); + + knot_zone_contents_t *contents = knot_zone_get_contents(zone); + if (!contents) { + pthread_mutex_unlock(&zd->lock); + return KNOTD_EINVAL; + } + + /* Latest zone serial. */ + const knot_rrset_t *soa_rrs = 0; + const knot_rdata_t *soa_rr = 0; + soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents), + KNOT_RRTYPE_SOA); + soa_rr = knot_rrset_rdata(soa_rrs); + int64_t serial_ret = knot_rdata_soa_serial(soa_rr); + if (serial_ret < 0) { + return KNOTD_EINVAL; + } + uint32_t serial_to = (uint32_t)serial_ret; + + /* Check for difference against zonefile serial. */ + if (zd->zonefile_serial != serial_to) { + + /* Save zone to zonefile. */ + conf_read_lock(); + dbg_zones("zones: syncing '%s' differences to '%s' " + "(SOA serial %u)\n", + zd->conf->name, zd->conf->file, serial_to); + zone_dump_text(contents, zd->conf->file); + conf_read_unlock(); + + /* Update journal entries. */ + dbg_zones_verb("zones: unmarking all dirty nodes " + "in '%s' journal\n", + zd->conf->name); + journal_walk(zd->ixfr_db, zones_ixfrdb_sync_apply); + + /* Update zone file serial. */ + dbg_zones("zones: new '%s' zonefile serial is %u\n", + zd->conf->name, serial_to); + zd->zonefile_serial = serial_to; + } else { + dbg_zones_verb("zones: '%s' zonefile is in sync " + "with differences\n", zd->conf->name); + } + + /* Unlock zone data. */ + pthread_mutex_unlock(&zd->lock); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_xfr_check_zone(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) +{ + if (xfr == NULL || rcode == NULL) { + *rcode = KNOT_RCODE_SERVFAIL; + return KNOTD_EINVAL; + } + + /* Check if the zone is found. */ + if (xfr->zone == NULL) { + *rcode = KNOT_RCODE_REFUSED; + return KNOTD_EACCES; + } + + /* Check zone data. */ + zonedata_t *zd = (zonedata_t *)xfr->zone->data; + if (zd == NULL) { + dbg_zones("zones: invalid zone data for zone %p\n", xfr->zone); + *rcode = KNOT_RCODE_SERVFAIL; + return KNOTD_ERROR; + } + + /* Check zone contents. */ + if (knot_zone_contents(xfr->zone) == NULL) { + dbg_zones("zones: invalid zone contents for zone %p\n", xfr->zone); + *rcode = KNOT_RCODE_SERVFAIL; + return KNOTD_EEXPIRED; + } + + // Check xfr-out ACL + if (acl_match(zd->xfr_out, &xfr->addr) == ACL_DENY) { + log_answer_warning("Unauthorized request for XFR '%s/OUT'.\n", + zd->conf->name); + *rcode = KNOT_RCODE_REFUSED; + return KNOTD_EACCES; + } else { + dbg_zones("zones: authorized XFR '%s/OUT'\n", + zd->conf->name); + } + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_process_response(knot_nameserver_t *nameserver, + sockaddr_t *from, + knot_packet_t *packet, uint8_t *response_wire, + size_t *rsize) +{ + if (!packet || !rsize || nameserver == NULL || from == NULL || + response_wire == NULL) { + return KNOTD_EINVAL; + } + + /* Handle SOA query response, cancel EXPIRE timer + * and start AXFR transfer if needed. + * Reset REFRESH timer on finish. + */ + if (knot_packet_qtype(packet) == KNOT_RRTYPE_SOA) { + + if (knot_packet_rcode(packet) != KNOT_RCODE_NOERROR) { + /*! \todo Handle error response. */ + return KNOTD_ERROR; + } + + /* No response. */ + *rsize = 0; + + /* Find matching zone and ID. */ + const knot_dname_t *zone_name = knot_packet_qname(packet); + /*! \todo Change the access to the zone db. */ + knot_zone_t *zone = knot_zonedb_find_zone( + nameserver->zone_db, + zone_name); + + /* Get zone contents. */ + rcu_read_lock(); + const knot_zone_contents_t *contents = + knot_zone_contents(zone); + + if (!zone || !knot_zone_data(zone) || !contents) { + rcu_read_unlock(); + return KNOTD_EINVAL; + } + + /* Match ID against awaited. */ + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + uint16_t pkt_id = knot_packet_id(packet); + if ((int)pkt_id != zd->xfr_in.next_id) { + rcu_read_unlock(); + return KNOTD_ERROR; + } + + /* Check SOA SERIAL. */ + int ret = xfrin_transfer_needed(contents, packet); + dbg_zones_verb("xfrin_transfer_needed() returned %d\n", ret); + if (ret < 0) { + /* RETRY/EXPIRE timers running, do not interfere. */ + return KNOTD_ERROR; + } + + /* No updates available. */ + evsched_t *sched = + ((server_t *)knot_ns_get_data(nameserver))->sched; + if (ret == 0) { + log_zone_info("SOA query for zone '%s' answered, no " + "transfer needed.\n", zd->conf->name); + rcu_read_unlock(); + + /* Reinstall timers. */ + zones_timers_update(zone, zd->conf, sched); + return KNOTD_EOK; + } + + assert(ret > 0); + + /* Already transferring. */ + if (pthread_mutex_trylock(&zd->xfr_in.lock) != 0) { + /* Unlock zone contents. */ + dbg_zones("zones: SOA response received, but zone is " + "being transferred, refusing to start another " + "transfer\n"); + rcu_read_unlock(); + return KNOTD_EOK; + } else { + pthread_mutex_unlock(&zd->xfr_in.lock); + } + + /* Prepare XFR client transfer. */ + knot_ns_xfr_t xfr_req; + memset(&xfr_req, 0, sizeof(knot_ns_xfr_t)); + memcpy(&xfr_req.addr, from, sizeof(sockaddr_t)); + xfr_req.zone = (void *)zone; + xfr_req.send = zones_send_cb; + + /* Select transfer method. */ + xfr_req.type = zones_transfer_to_use(contents); + + /* Select TSIG key. */ + /*!< \todo [TSIG] DISABLED */ + xfr_req.tsig_key = 0; + /* CLEANUP */ +// if (zd->xfr_in.tsig_key.name) { +// xfr_req.tsig_key = &zd->xfr_in.tsig_key; +// } + + /* Unlock zone contents. */ + rcu_read_unlock(); + + /* Enqueue XFR request. */ + return xfr_request(((server_t *)knot_ns_get_data( + nameserver))->xfr_h, &xfr_req); + } + + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +knot_ns_xfr_type_t zones_transfer_to_use(const knot_zone_contents_t *zone) +{ + /*! \todo Implement. */ + return XFR_TYPE_IIN; +} + +/*----------------------------------------------------------------------------*/ + +static int zones_find_zone_for_xfr(const knot_zone_contents_t *zone, + const char **zonefile, const char **zonedb) +{ + /* find the zone file name and zone db file name for the zone */ + conf_t *cnf = conf(); + node *n = NULL; + WALK_LIST(n, cnf->zones) { + conf_zone_t *zone_conf = (conf_zone_t *)n; + knot_dname_t *zone_name = knot_dname_new_from_str( + zone_conf->name, strlen(zone_conf->name), NULL); + if (zone_name == NULL) { + return KNOTD_ENOMEM; + } + + int r = knot_dname_compare(zone_name, knot_node_owner( + knot_zone_contents_apex(zone))); + + /* Directly discard dname, won't be needed. */ + knot_dname_free(&zone_name); + + if (r == 0) { + /* found the right zone */ + *zonefile = zone_conf->file; + *zonedb = zone_conf->db; + return KNOTD_EOK; + } + } + + char *name = knot_dname_to_str(knot_node_owner( + knot_zone_contents_apex(zone))); + dbg_zones("zones: no zone found for the zone received by transfer " + "(%s).\n", name); + free(name); + + return KNOTD_ENOENT; +} + +/*----------------------------------------------------------------------------*/ + +static char *zones_find_free_filename(const char *old_name) +{ + /* find zone name not present on the disk */ + int free_name = 0; + size_t name_size = strlen(old_name); + + char *new_name = malloc(name_size + 3); + if (new_name == NULL) { + return NULL; + } + memcpy(new_name, old_name, name_size); + new_name[name_size] = '.'; + new_name[name_size + 2] = 0; + + dbg_zones_verb("zones: finding free name for the zone file.\n"); + int c = 48; + FILE *file; + while (!free_name && c < 58) { + new_name[name_size + 1] = c; + dbg_zones_verb("zones: trying file name %s\n", new_name); + if ((file = fopen(new_name, "r")) != NULL) { + fclose(file); + ++c; + } else { + free_name = 1; + } + } + + if (free_name) { + return new_name; + } else { + free(new_name); + return NULL; + } +} + +/*----------------------------------------------------------------------------*/ + +static int zones_dump_xfr_zone_text(knot_zone_contents_t *zone, + const char *zonefile) +{ + assert(zone != NULL && zonefile != NULL); + + /*! \todo new_zonefile may be created by another process, + * until the zone_dump_text is called. Needs to be opened in + * this function for writing. + * Use open() for exclusive open and fcntl() for locking. + */ + + char *new_zonefile = zones_find_free_filename(zonefile); + + if (new_zonefile == NULL) { + dbg_zones("zones: failed to find free filename for temporary " + "storage of the zone text file.\n"); + return KNOTD_ERROR; /*! \todo New error code? */ + } + + int rc = zone_dump_text(zone, new_zonefile); + + if (rc != KNOTD_EOK) { + dbg_zones("Failed to save the zone to text zone file '%s'.\n", + new_zonefile); + free(new_zonefile); + return KNOTD_ERROR; + } + + /*! \todo this would also need locking as well. */ + struct stat s; + rc = stat(zonefile, &s); + if (rc < 0 || remove(zonefile) == 0) { + if (rename(new_zonefile, zonefile) != 0) { + dbg_zones("Failed to replace old zonefile '%s'' with new" + " zone file '%s'.\n", zonefile, new_zonefile); + /*! \todo with proper locking, this shouldn't happen, + * revise it later on. + */ + zone_dump_text(zone, zonefile); + return KNOTD_ERROR; + } + } else { + dbg_zones("zones: failed to replace old zonefile '%s'.\n", + zonefile); + return KNOTD_ERROR; + } + + free(new_zonefile); + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int ns_dump_xfr_zone_binary(knot_zone_contents_t *zone, + const char *zonedb, + const char *zonefile) +{ + assert(zone != NULL && zonedb != NULL); + + /*! \todo new_zonedb may be created by another process, + * until the zone_dump_text is called. Needs to be opened in + * this function for writing. + * Use open() for exclusive open and fcntl() for locking. + */ + char *new_zonedb = zones_find_free_filename(zonedb); + + if (new_zonedb == NULL) { + dbg_zones("zones: failed to find free filename for temporary " + "storage of the zone binary file '%s'\n", + zonedb); + return KNOTD_ERROR; /*! \todo New error code? */ + } + + /*! \todo this would also need locking as well. */ + int rc = knot_zdump_dump_and_swap(zone, new_zonedb, zonedb, zonefile); + free(new_zonedb); + + if (rc != KNOT_EOK) { + return KNOTD_ERROR; + } + + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_save_zone(const knot_ns_xfr_t *xfr) +{ + if (xfr == NULL || xfr->data == NULL) { + return KNOTD_EINVAL; + } + + knot_zone_contents_t *zone = + (knot_zone_contents_t *)xfr->data; + + const char *zonefile = NULL; + const char *zonedb = NULL; + + int ret = zones_find_zone_for_xfr(zone, &zonefile, &zonedb); + if (ret != KNOTD_EOK) { + return ret; + } + + assert(zonefile != NULL && zonedb != NULL); + + /* dump the zone into text zone file */ + ret = zones_dump_xfr_zone_text(zone, zonefile); + if (ret != KNOTD_EOK) { + return KNOTD_ERROR; + } + /* dump the zone into binary db file */ + ret = ns_dump_xfr_zone_binary(zone, zonedb, zonefile); + if (ret != KNOTD_EOK) { + return KNOTD_ERROR; + } + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_ns_conf_hook(const struct conf_t *conf, void *data) +{ + knot_nameserver_t *ns = (knot_nameserver_t *)data; + dbg_zones_verb("zones: reconfiguring name server.\n"); + + knot_zonedb_t *old_db = 0; + + int ret = zones_update_db_from_config(conf, ns, &old_db); + if (ret != KNOTD_EOK) { + return ret; + } + /* Wait until all readers finish with reading the zones. */ + synchronize_rcu(); + + dbg_zones_verb("zones: nameserver's zone db: %p, old db: %p\n", + ns->zone_db, old_db); + + /* Delete all deprecated zones and delete the old database. */ + knot_zonedb_deep_free(&old_db); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int zones_check_binary_size(uint8_t **data, size_t *allocated, + size_t required) +{ + if (required <= *allocated) { + return KNOTD_EOK; + } + + /* Allocate new memory block. */ + size_t new_count = required; + uint8_t *new_data = malloc(new_count * sizeof(uint8_t)); + if (new_data == NULL) { + return KNOTD_ENOMEM; + } + + /* Clear memory block and copy old data. */ + memset(new_data, 0, new_count * sizeof(uint8_t)); + memcpy(new_data, *data, *allocated); + + /* Switch pointers and free old pointer. */ + free(*data); + *data = new_data; + *allocated = new_count; + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int zones_changeset_rrset_to_binary(uint8_t **data, size_t *size, + size_t *allocated, + knot_rrset_t *rrset) +{ + assert(data != NULL); + assert(size != NULL); + assert(allocated != NULL); + + /* + * In *data, there is the whole changeset in the binary format, + * the actual RRSet will be just appended to it + */ + + uint8_t *binary = NULL; + size_t actual_size = 0; + int ret = knot_zdump_rrset_serialize(rrset, &binary, &actual_size); + if (ret != KNOT_EOK) { + return KNOTD_ERROR; /*! \todo Other code? */ + } + + ret = zones_check_binary_size(data, allocated, *size + actual_size); + if (ret != KNOT_EOK) { + free(binary); + return KNOTD_ERROR; + } + + memcpy(*data + *size, binary, actual_size); + *size += actual_size; + free(binary); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int zones_changesets_to_binary(knot_changesets_t *chgsets) +{ + assert(chgsets != NULL); + assert(chgsets->allocated >= chgsets->count); + + /* + * Converts changesets to the binary format stored in chgsets->data + * from the changeset_t structures. + */ + int ret; + + for (int i = 0; i < chgsets->count; ++i) { + knot_changeset_t *ch = &chgsets->sets[i]; + assert(ch->data == NULL); + assert(ch->size == 0); + + /* 1) origin SOA */ + ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size, + &ch->allocated, ch->soa_from); + if (ret != KNOT_EOK) { + free(ch->data); + ch->data = NULL; + dbg_zones("zones_changeset_rrset_to_binary(): %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; + } + + int j; + + /* 2) remove RRsets */ + assert(ch->remove_allocated >= ch->remove_count); + for (j = 0; j < ch->remove_count; ++j) { + ret = zones_changeset_rrset_to_binary(&ch->data, + &ch->size, + &ch->allocated, + ch->remove[j]); + if (ret != KNOT_EOK) { + free(ch->data); + ch->data = NULL; + dbg_zones("zones_changeset_rrset_to_binary(): %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; + } + } + + /* 3) new SOA */ + ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size, + &ch->allocated, ch->soa_to); + if (ret != KNOT_EOK) { + free(ch->data); + ch->data = NULL; + dbg_zones("zones_changeset_rrset_to_binary(): %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; + } + + /* 4) add RRsets */ + assert(ch->add_allocated >= ch->add_count); + for (j = 0; j < ch->add_count; ++j) { + ret = zones_changeset_rrset_to_binary(&ch->data, + &ch->size, + &ch->allocated, + ch->add[j]); + if (ret != KNOT_EOK) { + free(ch->data); + ch->data = NULL; + dbg_zones("zones_changeset_rrset_to_binary(): %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; + } + } + } + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_store_changesets(knot_ns_xfr_t *xfr) +{ + if (xfr == NULL || xfr->data == NULL || xfr->zone == NULL) { + return KNOTD_EINVAL; + } + + knot_zone_t *zone = xfr->zone; + knot_changesets_t *src = (knot_changesets_t *)xfr->data; + + /*! \todo Convert to binary format. */ + + int ret = zones_changesets_to_binary(src); + if (ret != KNOTD_EOK) { + return ret; + } + + /* Fetch zone-specific data. */ + zonedata_t *zd = (zonedata_t *)zone->data; + if (!zd->ixfr_db) { + return KNOTD_EINVAL; + } + + /* Begin writing to journal. */ + for (unsigned i = 0; i < src->count; ++i) { + + /* Make key from serials. */ + knot_changeset_t* chs = src->sets + i; + uint64_t k = ixfrdb_key_make(chs->serial_from, chs->serial_to); + + /* Write entry. */ + int ret = journal_write(zd->ixfr_db, k, (const char*)chs->data, + chs->size); + + /* Check for errors. */ + while (ret != KNOTD_EOK) { + + /* Sync to zonefile may be needed. */ + if (ret == KNOTD_EAGAIN) { + + /* Cancel sync timer. */ + event_t *tmr = zd->ixfr_dbsync; + if (tmr) { + dbg_xfr_verb("xfr: cancelling zonefile " + "SYNC timer of '%s'\n", + zd->conf->name); + evsched_cancel(tmr->parent, tmr); + } + + /* Synchronize. */ + dbg_xfr_verb("xfr: forcing zonefile SYNC " + "of '%s'\n", + zd->conf->name); + ret = zones_zonefile_sync(zone); + if (ret != KNOTD_EOK) { + continue; + } + + /* Reschedule sync timer. */ + if (tmr) { + /* Fetch sync timeout. */ + conf_read_lock(); + int timeout = zd->conf->dbsync_timeout; + timeout *= 1000; /* Convert to ms. */ + conf_read_unlock(); + + /* Reschedule. */ + dbg_xfr_verb("xfr: resuming SYNC " + "of '%s'\n", + zd->conf->name); + evsched_schedule(tmr->parent, tmr, + timeout); + + } + + /* Attempt to write again. */ + ret = journal_write(zd->ixfr_db, k, + (const char*)chs->data, + chs->size); + } else { + /* Other errors. */ + return KNOTD_ERROR; + } + } + + /* Free converted binary data. */ + free(chs->data); + chs->data = 0; + chs->size = 0; + } + + /* Written changesets to journal. */ + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, + uint32_t serial_to) +{ + if (!xfr || !xfr->zone || !knot_zone_contents(xfr->zone)) { + dbg_zones_detail("Wrong parameters: xfr=%p," + " xfr->zone = %p\n", xfr, xfr->zone); + return KNOTD_EINVAL; + } + + knot_changesets_t *chgsets = (knot_changesets_t *) + calloc(1, sizeof(knot_changesets_t)); + CHECK_ALLOC_LOG(chgsets, KNOTD_ENOMEM); + + int ret = ns_serial_compare(serial_to, serial_from); + dbg_zones_verb("Compared serials, result: %d\n", ret); + + /* if serial_to is not larger than serial_from, do not load anything */ + if (ret <= 0) { + xfr->data = chgsets; + return KNOTD_EOK; + } + + dbg_zones("Loading changesets...\n"); + + ret = zones_load_changesets(xfr->zone, chgsets, + serial_from, serial_to); + if (ret != KNOTD_EOK) { + dbg_zones_verb("Loading changesets failed: %s\n", + knotd_strerror(ret)); + return ret; + } + + xfr->data = chgsets; + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_apply_changesets(knot_ns_xfr_t *xfr) +{ + if (xfr == NULL || xfr->zone == NULL || xfr->data == NULL) { + return KNOTD_EINVAL; + } + + return xfrin_apply_changesets_to_zone(xfr->zone, + (knot_changesets_t *)xfr->data); +} + +/*----------------------------------------------------------------------------*/ + +int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) +{ + if (!sch || !zone) { + return KNOTD_EINVAL; + } + + /* Fetch zone data. */ + zonedata_t *zd = (zonedata_t *)zone->data; + if (!zd) { + return KNOTD_EINVAL; + } + + /* Cancel REFRESH timer. */ + if (zd->xfr_in.timer) { + evsched_cancel(sch, zd->xfr_in.timer); + evsched_event_free(sch, zd->xfr_in.timer); + zd->xfr_in.timer = 0; + } + + /* Cancel EXPIRE timer. */ + if (zd->xfr_in.expire) { + evsched_cancel(sch, zd->xfr_in.expire); + evsched_event_free(sch, zd->xfr_in.expire); + zd->xfr_in.expire = 0; + } + + /* Remove list of pending NOTIFYs. */ + pthread_mutex_lock(&zd->lock); + notify_ev_t *ev = 0, *evn = 0; + WALK_LIST_DELSAFE(ev, evn, zd->notify_pending) { + zones_cancel_notify(zd, ev); + } + pthread_mutex_unlock(&zd->lock); + + /* Check XFR/IN master server. */ + if (zd->xfr_in.master.ptr) { + + /* Schedule REFRESH timer. */ + uint32_t refresh_tmr = 0; + if (knot_zone_contents(zone)) { + refresh_tmr = zones_soa_refresh(zone); + } else { + refresh_tmr = zd->xfr_in.bootstrap_retry; + } + zd->xfr_in.timer = evsched_schedule_cb(sch, zones_refresh_ev, + zone, refresh_tmr); + dbg_zones("zone: REFRESH set to %u\n", refresh_tmr); + } + + /* Schedule IXFR database syncing. */ + /*! \todo Sync timer should not be reset after each xfr. */ + int sync_timeout = cfzone->dbsync_timeout * 1000; /* Convert to ms. */ + if (zd->ixfr_dbsync) { + evsched_cancel(sch, zd->ixfr_dbsync); + evsched_event_free(sch, zd->ixfr_dbsync); + zd->ixfr_dbsync = 0; + } + if (zd->ixfr_db) { + zd->ixfr_dbsync = evsched_schedule_cb(sch, + zones_zonefile_sync_ev, + zone, sync_timeout); + } + + /* Do not issue NOTIFY queries if stub. */ + if (!knot_zone_contents(zone)) { + conf_read_unlock(); + return KNOTD_EOK; + } + + /* Schedule NOTIFY to slaves. */ + conf_remote_t *r = 0; + conf_read_lock(); + WALK_LIST(r, cfzone->acl.notify_out) { + + /* Fetch remote. */ + conf_iface_t *cfg_if = r->remote; + + /* Create request. */ + notify_ev_t *ev = malloc(sizeof(notify_ev_t)); + if (!ev) { + free(ev); + dbg_zones("notify: out of memory to create " + "NOTIFY query for %s\n", cfg_if->name); + continue; + } + + /* Parse server address. */ + int ret = sockaddr_set(&ev->addr, cfg_if->family, + cfg_if->address, + cfg_if->port); + if (ret < 1) { + free(ev); + dbg_zones("notify: NOTIFY slave %s has invalid " + "address\n", cfg_if->name); + continue; + } + + /* Prepare request. */ + ev->retries = cfzone->notify_retries + 1; /* first + N retries*/ + ev->msgid = 0; + ev->zone = zone; + ev->timeout = cfzone->notify_timeout; + + /* Schedule request (30 - 60s random delay). */ + int tmr_s = 30 + (int)(30.0 * (rand() / (RAND_MAX + 1.0))); + pthread_mutex_lock(&zd->lock); + ev->timer = evsched_schedule_cb(sch, zones_notify_send, ev, + tmr_s * 1000); + add_tail(&zd->notify_pending, &ev->n); + pthread_mutex_unlock(&zd->lock); + + log_server_info("Scheduled NOTIFY query after %d s to %s:%d\n", + tmr_s, cfg_if->address, cfg_if->port); + } + + conf_read_unlock(); + + return KNOTD_EOK; +} + +int zones_cancel_notify(zonedata_t *zd, notify_ev_t *ev) +{ + if (!zd || !ev || !ev->timer) { + return KNOTD_EINVAL; + } + + /* Wait for event to finish running. */ +#ifdef KNOTD_NOTIFY_DEBUG + int pkt_id = ev->msgid; /*< Do not optimize! */ +#endif + event_t *tmr = ev->timer; + ev->timer = 0; + pthread_mutex_unlock(&zd->lock); + evsched_cancel(tmr->parent, tmr); + + /* Re-lock and find again (if not deleted). */ + pthread_mutex_lock(&zd->lock); + int match_exists = 0; + notify_ev_t *tmpev = 0; + WALK_LIST(tmpev, zd->notify_pending) { + if (tmpev == ev) { + match_exists = 1; + break; + } + } + + /* Event deleted before cancelled. */ + if (!match_exists) { + dbg_notify("notify: NOTIFY event for query ID=%u was " + "deleted before cancellation.\n", + pkt_id); + return KNOTD_EOK; + + } + + /* Free event (won't be scheduled again). */ + dbg_notify("notify: NOTIFY query ID=%u event cancelled.\n", + pkt_id); + rem_node(&ev->n); + evsched_event_free(tmr->parent, tmr); + free(ev); + return KNOTD_EOK; +} diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h new file mode 100644 index 0000000..525a78a --- /dev/null +++ b/src/knot/server/zones.h @@ -0,0 +1,264 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file zones.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * Contains functions for updating zone database from configuration. + * + * \addtogroup server + * @{ + */ + +#ifndef _KNOTD_ZONES_H_ +#define _KNOTD_ZONES_H_ + +#include <stddef.h> + +#include "common/lists.h" +#include "common/acl.h" +#include "common/evsched.h" +#include "libknot/nameserver/name-server.h" +#include "libknot/zone/zonedb.h" +#include "knot/conf/conf.h" +#include "knot/server/notify.h" +#include "knot/server/server.h" +#include "knot/server/journal.h" +#include "libknot/zone/zone.h" +#include "libknot/updates/xfr-in.h" + +/* Constants. */ +#define SOA_QRY_TIMEOUT 10000 /*!< SOA query timeout (ms). */ +#define IXFR_DBSYNC_TIMEOUT (60*1000) /*!< Database sync timeout = 60s. */ +#define AXFR_BOOTSTRAP_RETRY (60*1000) /*!< Interval between AXFR BS retries. */ + +/*! + * \brief Zone-related data. + */ +typedef struct zonedata_t +{ + /*! \brief Shortcut to zone config entry. */ + conf_zone_t *conf; + + /*! \brief Shortcut to server instance. */ + server_t *server; + + /*! \brief Zone data lock for exclusive access. */ + pthread_mutex_t lock; + + /*! \brief Access control lists. */ + acl_t *xfr_out; /*!< ACL for xfr-out.*/ + acl_t *notify_in; /*!< ACL for notify-in.*/ + acl_t *notify_out; /*!< ACL for notify-out.*/ + + /*! \brief XFR-IN scheduler. */ + struct { + acl_t *acl; /*!< ACL for xfr-in.*/ + sockaddr_t master; /*!< Master server for xfr-in.*/ + knot_key_t tsig_key; /*!< Master TSIG key. */ + struct event_t *timer; /*!< Timer for REFRESH/RETRY. */ + struct event_t *expire; /*!< Timer for REFRESH. */ + int next_id; /*!< ID of the next awaited SOA resp.*/ + pthread_mutex_t lock; /*!< Pending XFR/IN lock. */ + void *wrkr; /*!< Pending XFR/IN worker. */ + uint32_t bootstrap_retry;/*!< AXFR/IN bootstrap retry. */ + } xfr_in; + + /*! \brief List of pending NOTIFY events. */ + list notify_pending; + + /*! \brief Zone IXFR history. */ + journal_t *ixfr_db; + struct event_t *ixfr_dbsync; /*!< Syncing IXFR db to zonefile. */ + uint32_t zonefile_serial; +} zonedata_t; + +/*! + * \brief Update zone database according to configuration. + * + * Creates a new database, copies references those zones from the old database + * which are still in the configuration, loads any new zones required and + * replaces the database inside the namserver. + * + * It also creates a list of deprecated zones that should be deleted once the + * function finishes. + * + * This function uses RCU mechanism to guard the access to the config and + * nameserver and to publish the new database in the nameserver. + * + * \param[in] conf Configuration. + * \param[in] ns Nameserver which holds the zone database. + * \param[out] db_old Old database, containing only zones which should be + * deleted afterwards. + * + * \retval KNOTD_EOK + * \retval KNOTD_EINVAL + * \retval KNOTD_ERROR + */ +int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns, + knot_zonedb_t **db_old); + +/*! + * \brief Sync zone data back to text zonefile. + * + * In case when SOA serial of the zonefile differs from the SOA serial of the + * loaded zone, zonefile needs to be updated. + * + * \note Current implementation rewrites the zone file. + * + * \param zone Evaluated zone. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_EINVAL on invalid parameter. + * \retval KNOTD_ERROR on unspecified error during processing. + */ +int zones_zonefile_sync(knot_zone_t *zone); + +int zones_xfr_check_zone(knot_ns_xfr_t *xfr, knot_rcode_t *rcode); + +/*! + * \brief Processes normal response packet. + * + * \param nameserver Name server structure to provide the needed data. + * \param from Address of the response sender. + * \param packet Parsed response packet. + * \param response_wire Place for the response in wire format. + * \param rsize Input: maximum acceptable size of the response. Output: real + * size of the response. + * + * \retval KNOTD_EOK if a valid response was created. + * \retval KNOTD_EINVAL on invalid parameters or packet. + * \retval KNOTD_EMALF if an error occured and the response is not valid. + */ +int zones_process_response(knot_nameserver_t *nameserver, + sockaddr_t *from, + knot_packet_t *packet, uint8_t *response_wire, + size_t *rsize); + +/*! + * \brief Decides what type of transfer should be used to update the given zone. + * + * \param nameserver Name server structure that uses the zone. + * \param zone Zone to be updated by the transfer. + * + * \retval + */ +knot_ns_xfr_type_t zones_transfer_to_use(const knot_zone_contents_t *zone); + +int zones_save_zone(const knot_ns_xfr_t *xfr); + +/*! + * \brief Name server config hook. + * + * Routine for dynamic name server reconfiguration. + * + * \param conf Current configuration. + * \param data Instance of the nameserver structure to update. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL + * \retval KNOTD_ERROR + */ +int zones_ns_conf_hook(const struct conf_t *conf, void *data); + +/*! + * \brief Store changesets in journal. + * + * Changesets will be stored on a permanent storage. + * Journal may be compacted, resulting in flattening changeset history. + * + * \param zone Zone associated with the changeset. + * \param src Changesets. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_EAGAIN if journal needs to be synced with zonefile first. + * + * \todo Expects the xfr structure to be initialized in some way. + */ +int zones_store_changesets(knot_ns_xfr_t *xfr); + +/*! + * \brief Load changesets from journal. + * + * Changesets will be stored on a permanent storage. + * Journal may be compacted, resulting in flattening changeset history. + * + * In case of KNOTD_ERANGE error, whole zone content should be sent instead, + * as the changeset history cannot be recovered. + * + * \param zone Zone containing a changeset journal. + * \param dst Container to be loaded. + * \param from Starting SOA serial (oldest). + * \param to Ending SOA serial (newest). + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ERANGE when changeset history cannot be reconstructed. + * + * \todo Expects the xfr structure to be initialized in some way. + */ +int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, + uint32_t serial_to); + +/*! + * \brief Apply changesets to zone. + * + * Applies a list of XFR-style changesets to the given zone. Also checks if the + * changesets are applicable (i.e. zone is right and has the right serial). + * + * \param zone Zone to which the changesets should be applied. + * \param chsets Changesets to be applied to the zone. + * + * \retval KNOTD_EOK + * \retval KNOTD_EINVAL + */ +int zones_apply_changesets(knot_ns_xfr_t *xfr); + +/*! + * \brief Update zone timers. + * + * REFRESH/RETRY/EXPIRE timers are updated according to SOA. + * + * \param sched Event scheduler. + * \param zone Related zone. + * \param cfzone Related zone contents. If NULL, configuration is + * reused. + * + * \retval KNOTD_EOK + * \retval KNOTD_EINVAL + * \retval KNOTD_ERROR + */ +int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch); + +/*! + * \brief Cancel pending NOTIFY timer. + * + * \warning Expects locked zonedata lock. + * + * \param zd Zone data. + * \param ev NOTIFY event. + * + * \retval KNOTD_EOK + * \retval KNOTD_ERROR + * \retval KNOTD_EINVAL + */ +int zones_cancel_notify(zonedata_t *zd, notify_ev_t *ev); + +#endif // _KNOTD_ZONES_H_ + +/*! @} */ diff --git a/src/knot/stat/gatherer.c b/src/knot/stat/gatherer.c new file mode 100644 index 0000000..e8048a1 --- /dev/null +++ b/src/knot/stat/gatherer.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <pthread.h> + +#include "knot/stat/stat-common.h" +#include "common/slab/malloc.h" +#include "knot/stat/gatherer.h" + +gatherer_t *new_gatherer() +{ + gatherer_t *ret; + + if ((ret = malloc(sizeof(gatherer_t))) == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + pthread_mutex_init(&ret->mutex_read, NULL); + + /* TODO check success */ + + for (int i = 0; i < FREQ_BUFFER_SIZE; i++) { + ret->freq_array[i] = 0; + ret->flow_array[i] = NULL; + } + + ret->qps = 0.0; + ret->udp_qps = 0.0; + ret->tcp_qps = 0.0; + + /* CLEANUP */ + /* currently disabled */ + /* ret->mean_latency = 0.0; + ret->udp_mean_latency = 0.0; + ret->tcp_mean_latency = 0.0; + + ret->udp_latency = 0; + ret->tcp_latency = 0; */ + + ret->udp_queries = 0; + ret->tcp_queries = 0; + + return ret; +} + +void gatherer_free(gatherer_t *gath) +{ + for (int i = 0; i < FREQ_BUFFER_SIZE; i++) { + if (gath->flow_array[i] != NULL) { + free(gath->flow_array[i]->addr); + free(gath->flow_array[i]); + } + } + + pthread_mutex_destroy(&(gath->mutex_read)); + + pthread_cancel(gath->sleeper_thread); + + pthread_join((gath->sleeper_thread), NULL); + + free(gath); +} diff --git a/src/knot/stat/gatherer.h b/src/knot/stat/gatherer.h new file mode 100644 index 0000000..62b3939 --- /dev/null +++ b/src/knot/stat/gatherer.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file gatherer.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief Contains gatherer structure and its API. + * + * \addtogroup statistics + * @{ + */ + +#ifndef _KNOTD_GATHERER_H_ +#define _KNOTD_GATHERER_H_ + +#include <stdint.h> + +/* The bigger this number, the better the performance of hashing. */ +enum fbs { FREQ_BUFFER_SIZE = 100000 }; + +/*! + * \brief Enum storing protocol codes. + */ +enum protocol { + stat_UDP, + stat_TCP +}; + +typedef enum protocol protocol_t; + +/*! + * \brief Structure used for backward mapping from a simple + * hash back to string representation. + */ +struct flow_data { + char *addr; /*!< IP adress in string format (IP4 only at this time). */ + uint16_t port; /*!< TCP/UDP port number. */ + protocol_t protocol; +}; + +typedef struct flow_data flow_data_t; + +/*! + * \brief Gatherer structure, used for gathering statistics from + * multiple threads. + */ +struct gatherer { + pthread_mutex_t mutex_read; /*!< Mutex used when reading values. */ + double qps; /*!< Queries per second. */ + double udp_qps; /*!< Queries per second - UDP. */ + double tcp_qps; /*!< Queries per second - TCP. */ + + /*!< \note latency currently disabled */ + /* double mean_latency; + double udp_mean_latency; + double tcp_mean_latency; + unsigned udp_latency; + unsigned tcp_latency; */ + + unsigned udp_queries; /*!< Total number of UDP queries for SLEEP_TIME. */ + unsigned tcp_queries; /*!< Total number of TCP queries for SLEEP_TIME. */ + /*! + * \brief this variable should be much bigger, preferably sparse array + * with 2**32 elements (for IPv4). It is an array with query + * query frequencies. + */ + unsigned freq_array[FREQ_BUFFER_SIZE]; + /*! + * \brief Used for backward mapping. + */ + flow_data_t *flow_array[FREQ_BUFFER_SIZE]; + /*! + * \brief Thread used for computation of statistics. + */ + pthread_t sleeper_thread; +}; + +typedef struct gatherer gatherer_t; + +/*! + * \brief Creates a new gatherer instance. + * + * \return Pointer to created structure, NULL otherwise. + */ +gatherer_t *new_gatherer(); + +/*! + * \brief Frees a gatherer instance. + * + * \param gatherer Gatherer instance to be freed. + */ +void gatherer_free(gatherer_t *gatherer); + +#endif /* _KNOTD_STAT_GATHERER_H_ */ + +/*! @} */ diff --git a/src/knot/stat/stat-common.h b/src/knot/stat/stat-common.h new file mode 100644 index 0000000..032e32b --- /dev/null +++ b/src/knot/stat/stat-common.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file stat-common.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Common macros for stat. + * + * \addtogroup statistics + * @{ + */ + +#ifndef _KNOTD_STAT_COMMON_H_ +#define _KNOTD_STAT_COMMON_H_ + +#include <stdio.h> + +//#define STAT_COMPILE +#define ST_DEBUG + +#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \ + __FILE__, __LINE__) + +#ifdef ST_DEBUG +#define dbg_st(msg...) fprintf(stderr, msg) +#else +#define dbg_st(msg...) +#endif + +#endif /* _KNOTD_STAT_COMMON_H_ */ + +/*! @} */ diff --git a/src/knot/stat/stat.c b/src/knot/stat/stat.c new file mode 100644 index 0000000..a473085 --- /dev/null +++ b/src/knot/stat/stat.c @@ -0,0 +1,270 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <time.h> +#include <pthread.h> +#include <unistd.h> +#include <stdbool.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <stdlib.h> + +#include "knot/stat/stat-common.h" +#include "knot/stat/stat.h" +#include "knot/stat/gatherer.h" + +#ifdef STAT_COMPILE + +/* Static local gatherer variable, to be used with all functions. */ +static gatherer_t *local_gath; + +/* CLEANUP */ +/* +static void stat_inc_latency( stat_t *stat, uint increment ) +{ + if (stat->protocol==stat_UDP) { + local_gath->udp_latency+=increment; + } else { + local_gath->tcp_latency+=increment; + } +}*/ +/* +static uint stat_last_query_time( stat_t *stat ) +{ + return (stat->t2).tv_nsec-(stat->t1).tv_nsec; +}*/ + +/*! + * \brief Increases query count in the local data gatherer. + * + * \param stat Current stat instance. + */ +static void stat_inc_query(stat_t *stat) +{ + if (stat->protocol == stat_UDP) { + local_gath->udp_queries++; + } else { + local_gath->tcp_queries++; + } +} + +/*! + * \brief Calculates very simple hash from IPv4 address and returns index to + * array. + * + * \param s_addr Socket address structure. + * \param protocol Used protocol. + * + * \return uint Calculated index. + */ +static uint return_index(struct sockaddr_in *s_addr , protocol_t protocol) +{ + /* TODO IPv6 */ + /* This is the first "hash" I could think of quickly. */ + uint ret = 0; + + char str[24]; + inet_ntop(AF_INET, &s_addr->sin_addr, str, 24); + + for (int i = 0; i < strlen(str); i++) { + if (str[i] != '.') { + ret += str[i]; + ret *= (i + 1); + } + } + + ret += s_addr->sin_port * 7; + if (protocol == stat_UDP) { + ret *= 3; + } else { + ret *= 7; + } + ret %= FREQ_BUFFER_SIZE; + /* Effectively uses only end of the hash, maybe hash the + * resulting number once again to get 0 <= n < 10000. */ + return ret; +} + +/*! + * \brief Adds data to local gatherer structure. + * + * \param stat Current stat variable. + * + * \retval 0 on success. + * \retval -1 on memory error. + */ +static int stat_gatherer_add_data(stat_t *stat) +{ + /* TODO IPv6*/ + uint index = return_index(stat->s_addr, stat->protocol); + if (!local_gath->freq_array[index]) { + char addr[24]; + inet_ntop(AF_INET, &stat->s_addr->sin_addr, addr, 24); + flow_data_t *tmp; + tmp = malloc(sizeof(flow_data_t)); + if (tmp == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + tmp->addr = malloc(sizeof(char) * 24); + if (tmp->addr == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + strcpy(tmp->addr, addr); + tmp->port = stat->s_addr->sin_port; + tmp->protocol = stat->protocol; + local_gath->flow_array[index] = tmp; + } + + //TODO add a check here, whether hashing fction performs well enough + + local_gath->freq_array[index] += 1; + + return 0; +} + +/*! + * \brief Resets logging array. + */ +static void stat_reset_gatherer_array() +{ + for (int i = 0; i < FREQ_BUFFER_SIZE; i++) { + local_gath->freq_array[i] = 0; + } +} + +/*! + * \brief Sleeps for given time and then runs all the computations, + * results of which are stored in local gatherer. + */ +static void stat_sleep_compute() +{ + while (1) { + sleep(SLEEP_TIME); + + for (int i = 0; i < FREQ_BUFFER_SIZE; i++) { + if (local_gath->freq_array[i] > + ACTIVE_FLOW_THRESHOLD) { + dbg_st("too much activity at index %d:" + " %d queries adress: %s port %d" + " protocol %d\n", + i, local_gath->freq_array[i], + local_gath->flow_array[i]->addr, + local_gath->flow_array[i]->port, + local_gath->flow_array[i]->protocol); + } + } + + pthread_mutex_lock(&(local_gath->mutex_read)); + + local_gath->udp_qps = local_gath->udp_queries / + (double)SLEEP_TIME; + local_gath->tcp_qps = local_gath->tcp_queries / + (double)SLEEP_TIME; + local_gath->qps = local_gath->udp_qps + local_gath->tcp_qps; + + /* following code needs usage of + * gettimeofday, which is currently disabled */ + /* CLEANUP */ +/* local_gath->udp_mean_latency=((double)local_gath->udp_latency/ + (double)local_gath->udp_queries); + local_gath->tcp_mean_latency=((double)local_gath->tcp_latency/ + (double)local_gath->tcp_queries); + local_gath->mean_latency = (local_gath->udp_mean_latency + + local_gath->tcp_mean_latency)/2; */ + + local_gath->udp_queries = 0; + local_gath->tcp_queries = 0; + + /* same thing as above applies here */ + +/* local_gath->tcp_latency = 0; + local_gath->udp_latency = 0; */ + + pthread_mutex_unlock(&(local_gath->mutex_read)); + + stat_reset_gatherer_array(local_gath); + + dbg_st("qps_udp: %f\n", local_gath->udp_qps); +/* dbg_st("mean_lat_udp: %f\n", local_gath->udp_mean_latency); */ + + dbg_st("qps_tcp: %f\n", local_gath->tcp_qps); +/* dbg_st("mean_lat_tcp: %f\n", local_gath->tcp_mean_latency); */ + + dbg_st("UDP/TCP ratio %f\n", + local_gath->udp_qps / local_gath->tcp_qps); + } +} + +stat_t *stat_new() +{ + stat_t *ret; + + if ((ret = malloc(sizeof(stat_t))) == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + return ret; +} + +void stat_set_protocol(stat_t *stat, int protocol) +{ + stat->protocol = protocol; +} + +void stat_get_first(stat_t *stat , struct sockaddr_in *s_addr) +{ + /* CLEANUP */ +// gettimeofday(&stat->t2, NULL); + stat->s_addr = s_addr; +// check if s_addr does not get overwritten +} + +void stat_get_second(stat_t *stat) +{ + /* CLEANUP */ +// gettimeofday(&stat->t2, NULL); + stat_inc_query(stat); +// stat_inc_latency(stat, stat_last_query_time(stat)); + stat_gatherer_add_data(stat); +} + +void stat_free(stat_t *stat) +{ + free(stat); +} + +void stat_static_gath_init() +{ + local_gath = new_gatherer(); +} + +void stat_static_gath_start() +{ + pthread_create(&(local_gath->sleeper_thread), NULL, + (void *) &stat_sleep_compute, NULL); +} + +void stat_static_gath_free() +{ + gatherer_free(local_gath); +} + +#endif /* STAT_COMPILE */ diff --git a/src/knot/stat/stat.h b/src/knot/stat/stat.h new file mode 100644 index 0000000..a82f130 --- /dev/null +++ b/src/knot/stat/stat.h @@ -0,0 +1,157 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file stat.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief Contains statistics structure and its API. + * + * \addtogroup statistics + * @{ + */ + +#ifndef _KNOTD_STAT_H_ +#define _KNOTD_STAT_H_ + +#include <time.h> +#include <stdbool.h> +#include <pthread.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "knot/stat/gatherer.h" + +#ifdef STAT_COMPILE +#define STAT_INIT(x) x = stat_new() +#else +#define STAT_INIT(x) x = NULL //UNUSED(x) +#endif /* STAT_COMPILE */ + +/* Determines how long until the sleeper thread + * wakes up and runs computations. + */ +static uint const SLEEP_TIME = 15; + +/* Sets threshold for active flow detection, will + * probably have to be changed. */ +static uint const ACTIVE_FLOW_THRESHOLD = 10; + +/*! + * \brief Statistics structure, unique for each UDP/TCP thread. + */ +struct stat_stat { +// struct timespec t1, t2; /* Currently disabled */ + protocol_t protocol; /*!< Flags. */ + struct sockaddr_in *s_addr; +// gatherer_t *gatherer; / * not needed when using static gatherer. */ +}; + +typedef struct stat_stat stat_t; + +/*! + * \brief Creates new stat_t structure. + * + * \return Newly allocated and initialized stat structure, NULL on errror. + */ +#ifdef STAT_COMPILE +stat_t *stat_new(); +#else +inline stat_t *stat_new() +{ + return NULL; +} +#endif /* STAT_COMPILE */ + +/*! + * \brief Sets a protocol for stat_t structure. Options are stat_UDP, stat_TCP. + * + * \param stat Stat_t instance (usually newly created). + * \param protocol Protocol to be assigned to stat structure. + */ +#ifdef STAT_COMPILE +void stat_set_protocol(stat_t *stat, int protocol); +#else +static inline void stat_set_protocol(stat_t *stat, int protocol) {} +#endif /* STAT_COMPILE */ + +/*! + * \brief Gets the time from a processing function. + * + * \param stat Current instance of stat_t. + * \param s_addr Sockaddr structure to be used later for statistics. + */ +#ifdef STAT_COMPILE +#warning "stat fixme: pass sockaddr* for generic _in and _in6 support" +void stat_get_first(stat_t *stat, struct sockaddr_in *s_addr); +#else +static inline void stat_get_first(stat_t *stat, struct sockaddr *s_addr) {} +#endif /* STAT_COMPILE */ + +/*! + * \brief Gets time from a processing fuction and changes + * the corresponding variables. + * + * \param stat Current stat_t instance. + */ +#ifdef STAT_COMPILE +void stat_get_second(stat_t *stat); +#else +static inline void stat_get_second(stat_t *stat) {} +#endif /* STAT_COMPILE */ + +/*! + * \brief Frees stat_t structure. + * + * \param stat Pointer to stat structure to be deallocated. + */ +#ifdef STAT_COMPILE +void stat_free(stat_t *stat); +#else +static inline void stat_free(stat_t *stat) {} +#endif /* STAT_COMPILE */ + +/*! + * \brief Initializes static gatherer. + */ +#ifdef STAT_COMPILE +void stat_static_gath_init(); +#else +static inline void stat_static_gath_init() {} +#endif /* STAT_COMPILE */ + +/*! + * \brief Starts static gatherer's sleeper thread. + */ +#ifdef STAT_COMPILE +void stat_static_gath_start(); +#else +static inline void stat_static_gath_start() {} +#endif /* STAT_COMPILE */ + +/*! + * \brief Frees static gatherer, calls gatherer_free(). + */ +#ifdef STAT_COMPILE +void stat_static_gath_free(); +#else +static inline void stat_static_gath_free() {} +#endif /* STAT_COMPILE */ + +#endif /* _KNOTD_STAT_H_ */ + +/*! @} */ diff --git a/src/knot/zone/zone-dump-text.c b/src/knot/zone/zone-dump-text.c new file mode 100644 index 0000000..f7899a1 --- /dev/null +++ b/src/knot/zone/zone-dump-text.c @@ -0,0 +1,1083 @@ +/*! + * \file zone-dump-text.c + * + * \author modifications (non-buffer implementation, zone-specific functions) + * by Jan Kadlec <jan.kadlec@nic.cz>, + * conversion functions by NLnet Labs, + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * b64ntop by ISC. + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> + +#include <ctype.h> +#include <assert.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include "libknot/libknot.h" +#include "libknot/common.h" +#include "common/skip-list.h" +#include "common/base32hex.h" + +/* TODO max length of alg */ + +enum uint_max_length { + U8_MAX_STR_LEN = 4, U16_MAX_STR_LEN = 6, + U32_MAX_STR_LEN = 11, MAX_RR_TYPE_LEN = 20, + MAX_NSEC_BIT_STR_LEN = 4096, + }; + +#define APL_NEGATION_MASK 0x80U +#define APL_LENGTH_MASK (~APL_NEGATION_MASK) + +/* RFC 4025 - codes for different types that IPSECKEY can hold. */ +#define IPSECKEY_NOGATEWAY 0 +#define IPSECKEY_IP4 1 +#define IPSECKEY_IP6 2 +#define IPSECKEY_DNAME 3 + +/* Following copyrights are only valid for b64_ntop function */ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int b64_ntop(uint8_t const *src, size_t srclength, char *target, + size_t targsize) { + size_t datalength = 0; + uint8_t input[3]; + uint8_t output[4]; + size_t i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* Taken from RFC 4398, section 2.1. */ +knot_lookup_table_t knot_dns_certificate_types[] = { +/* 0 Reserved */ + { 1, "PKIX" }, /* X.509 as per PKIX */ + { 2, "SPKI" }, /* SPKI cert */ + { 3, "PGP" }, /* OpenPGP packet */ + { 4, "IPKIX" }, /* The URL of an X.509 data object */ + { 5, "ISPKI" }, /* The URL of an SPKI certificate */ + { 6, "IPGP" }, /* The fingerprint and URL of an OpenPGP packet */ + { 7, "ACPKIX" }, /* Attribute Certificate */ + { 8, "IACPKIX" }, /* The URL of an Attribute Certificate */ + { 253, "URI" }, /* URI private */ + { 254, "OID" }, /* OID private */ +/* 255 Reserved */ +/* 256-65279 Available for IANA assignment */ +/* 65280-65534 Experimental */ +/* 65535 Reserved */ + { 0, NULL } +}; + +/* Taken from RFC 2535, section 7. */ +knot_lookup_table_t knot_dns_algorithms[] = { + { 1, "RSAMD5" }, /* RFC 2537 */ + { 2, "DH" }, /* RFC 2539 */ + { 3, "DSA" }, /* RFC 2536 */ + { 4, "ECC" }, + { 5, "RSASHA1" }, /* RFC 3110 */ + { 252, "INDIRECT" }, + { 253, "PRIVATEDNS" }, + { 254, "PRIVATEOID" }, + { 0, NULL } +}; + +static int get_bit(uint8_t bits[], size_t index) +{ + /* + * The bits are counted from left to right, so bit #0 is the + * left most bit. + */ + return bits[index / 8] & (1 << (7 - index % 8)); +} + +static inline uint8_t * rdata_item_data(knot_rdata_item_t item) +{ + return (uint8_t *)(item.raw_data + 1); +} + +static inline uint16_t rdata_item_size(knot_rdata_item_t item) +{ + return item.raw_data[0]; +} + +char *rdata_dname_to_string(knot_rdata_item_t item) +{ + return knot_dname_to_str(item.dname); +} + +char *rdata_dns_name_to_string(knot_rdata_item_t item) +{ + return knot_dname_to_str(item.dname); +} + +static char *rdata_txt_data_to_string(const uint8_t *data) +{ + uint8_t length = data[0]; + size_t i; + + if (length == 0) { + return NULL; + } + + /* + * 3 because: opening '"', closing '"', and \0 at the end. + * Times 2 because string can be all "double chars". + */ + size_t current_length = sizeof(char) * (length * 2 + 3); + char *ret = malloc(current_length); + if (ret == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + memset(ret, 0, sizeof(char) * (length * 2 + 3)); + + + strcat(ret, "\""); + + for (i = 1; i <= length; i++) { + char ch = (char) data[i]; + if (isprint((int)ch)) { + if (ch == '"' || ch == '\\') { + strcat(ret, "\""); + } + /* for the love of god, how to this better, + but w/o obscure self-made functions */ + char tmp_str[2]; + tmp_str[0] = ch; + tmp_str[1] = 0; + strcat(ret, tmp_str); + } else { + strcat(ret, "\\"); + char tmp_str[2]; + tmp_str[0] = ch - '0'; + tmp_str[1] = 0; + + strcat(ret, tmp_str); + } + } + strcat(ret, "\""); + + return ret; +} + +char *rdata_text_to_string(knot_rdata_item_t item) +{ + uint16_t size = item.raw_data[0]; + char *ret = malloc(sizeof(char) * size * 2) ; + if (ret == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + memset(ret, 0, sizeof(char) * size); + const uint8_t *data = (uint8_t *)(item.raw_data + 1); + size_t read_count = 0; + while (read_count < size) { + assert(read_count <= size); + char *txt = rdata_txt_data_to_string(data + read_count); + if (txt == NULL) { + free(ret); + return NULL; + } + read_count += strlen(txt) - 1; + /* Create delimiter. */ + char del[2]; + del[0] = ' '; + del[1] = '\0'; + strcat(ret, txt); + strcat(ret, del); + free(txt); + } + + return ret; +} + +char *rdata_byte_to_string(knot_rdata_item_t item) +{ + assert(item.raw_data[0] == 1); + uint8_t data = item.raw_data[1]; + char *ret = malloc(sizeof(char) * U8_MAX_STR_LEN); + snprintf(ret, U8_MAX_STR_LEN, "%d", (char) data); + return ret; +} + +char *rdata_short_to_string(knot_rdata_item_t item) +{ + uint16_t data = knot_wire_read_u16(rdata_item_data(item)); + char *ret = malloc(sizeof(char) * U16_MAX_STR_LEN); + snprintf(ret, U16_MAX_STR_LEN, "%u", data); + /* XXX Use proper macros - see response tests*/ + /* XXX check return value, return NULL on failure */ + return ret; +} + +char *rdata_long_to_string(knot_rdata_item_t item) +{ + uint32_t data = knot_wire_read_u32(rdata_item_data(item)); + char *ret = malloc(sizeof(char) * U32_MAX_STR_LEN); + /* u should be enough */ + snprintf(ret, U32_MAX_STR_LEN, "%u", data); + return ret; +} + +char *rdata_a_to_string(knot_rdata_item_t item) +{ + /* 200 seems like a little too much */ + char *ret = malloc(sizeof(char) * 200); + if (inet_ntop(AF_INET, rdata_item_data(item), ret, 200)) { + return ret; + } else { + return NULL; + } +} + +char *rdata_aaaa_to_string(knot_rdata_item_t item) +{ + char *ret = malloc(sizeof(char) * 200); + if (inet_ntop(AF_INET6, rdata_item_data(item), ret, 200)) { + return ret; + } else { + return NULL; + } +} + +char *rdata_rrtype_to_string(knot_rdata_item_t item) +{ + uint16_t type = knot_wire_read_u16(rdata_item_data(item)); + const char *tmp = knot_rrtype_to_string(type); + char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN); + strncpy(ret, tmp, MAX_RR_TYPE_LEN); + return ret; +} + +char *rdata_algorithm_to_string(knot_rdata_item_t item) +{ + uint8_t id = *rdata_item_data(item); + char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN); + knot_lookup_table_t *alg + = knot_lookup_by_id(knot_dns_algorithms, id); + if (alg) { + strncpy(ret, alg->name, MAX_RR_TYPE_LEN); + } else { + snprintf(ret, U8_MAX_STR_LEN, "%u", id); + } + + return ret; +} + +char *rdata_certificate_type_to_string(knot_rdata_item_t item) +{ + uint16_t id = knot_wire_read_u16(rdata_item_data(item)); + char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN); + knot_lookup_table_t *type + = knot_lookup_by_id(knot_dns_certificate_types, id); + if (type) { + strncpy(ret, type->name, MAX_RR_TYPE_LEN); + } else { + snprintf(ret, U16_MAX_STR_LEN, "%u", id); + } + + return ret; +} + +char *rdata_period_to_string(knot_rdata_item_t item) +{ + /* uint32 but read 16 XXX */ + uint32_t period = knot_wire_read_u32(rdata_item_data(item)); + char *ret = malloc(sizeof(char) * U32_MAX_STR_LEN); + snprintf(ret, U32_MAX_STR_LEN, "%u", period); + return ret; +} + +char *rdata_time_to_string(knot_rdata_item_t item) +{ + time_t time = (time_t) knot_wire_read_u32(rdata_item_data(item)); + struct tm tm_conv; + if (gmtime_r(&time, &tm_conv) == 0) { + return 0; + } + char *ret = malloc(sizeof(char) * 15); + if (strftime(ret, 15, "%Y%m%d%H%M%S", &tm_conv)) { + return ret; + } else { + free(ret); + return 0; + } +} + +char *rdata_base32_to_string(knot_rdata_item_t item) +{ + int length; + size_t size = rdata_item_size(item); + if (size == 0) { + char *ret = malloc(sizeof(char) * 2); + ret[0] = '-'; + ret[1] = '\0'; + return ret; + } + + size -= 1; // remove length byte from count + char *ret = NULL; + length = base32hex_encode_alloc((char *)rdata_item_data(item) + 1, + size, &ret); + if (length > 0) { + return ret; + } else { + free(ret); + return NULL; + } +} + +char *rdata_base64_to_string(knot_rdata_item_t item) +{ + int length; + size_t size = rdata_item_size(item); + char *ret = malloc((sizeof(char) * 2 * size) + 1 * sizeof(char)); + length = b64_ntop(rdata_item_data(item), size, + ret, (sizeof(char)) * (size * 2 + 1)); + if (length > 0) { + return ret; + } else { + free(ret); + return NULL; + } +} + +char *hex_to_string(const uint8_t *data, size_t size) +{ + static const char hexdigits[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + size_t i; + + char *ret = malloc(sizeof(char) * (size * 2 + 1)); + + for (i = 0; i < size * 2; i += 2) { + uint8_t octet = *data++; + ret[i] = hexdigits [octet >> 4]; + ret[i + 1] = hexdigits [octet & 0x0f]; + } + + ret[i] = '\0'; + + return ret; +} + +char *rdata_hex_to_string(knot_rdata_item_t item) +{ + return hex_to_string(rdata_item_data(item), rdata_item_size(item)); +} + +char *rdata_hexlen_to_string(knot_rdata_item_t item) +{ + if(rdata_item_size(item) <= 1) { + // NSEC3 salt hex can be empty + char *ret = malloc(sizeof(char) * 2); + ret[0] = '-'; + ret[1] = '\0'; + return ret; + } else { + return hex_to_string(rdata_item_data(item) + 1, + rdata_item_size(item) - 1); + } +} + +char *rdata_nsap_to_string(knot_rdata_item_t item) +{ + char *ret = malloc(sizeof(char) * (rdata_item_size(item) + 3)); + memcpy(ret, "0x", strlen("0x")); + char *converted = hex_to_string(rdata_item_data(item), + rdata_item_size(item)); + strcat(ret, converted); + free(converted); + return ret; +} + +char *rdata_apl_to_string(knot_rdata_item_t item) +{ + uint8_t *data = rdata_item_data(item); + uint16_t address_family = knot_wire_read_u16(data); + uint8_t prefix = data[2]; + uint8_t length = data[3]; + int negated = length & APL_NEGATION_MASK; + int af = -1; + + char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN); + + memset(ret, 0, MAX_NSEC_BIT_STR_LEN); + + length &= APL_LENGTH_MASK; + switch (address_family) { + case 1: af = AF_INET; break; + case 2: af = AF_INET6; break; + } + + if (af != -1) { + char text_address[1000]; + uint8_t address[128]; + memset(address, 0, sizeof(address)); + memcpy(address, data + 4, length); + if (inet_ntop(af, address, + text_address, + sizeof(text_address))) { + snprintf(ret, sizeof(text_address) + + U32_MAX_STR_LEN * 2, + "%s%d:%s/%d", + negated ? "!" : "", + (int) address_family, + text_address, + (int) prefix); + } + } + + return ret; + + /* + int result = 0; + buffer_type packet; + + buffer_create_from( + &packet, rdata_item_data(rdata), rdata_atom_size(rdata)); + + if (buffer_available(&packet, 4)) { + uint16_t address_family = buffer_read_u16(&packet); + uint8_t prefix = buffer_read_u8(&packet); + uint8_t length = buffer_read_u8(&packet); + int negated = length & APL_NEGATION_MASK; + int af = -1; + + length &= APL_LENGTH_MASK; + switch (address_family) { + case 1: af = AF_INET; break; + *case 2: af = AF_INET6; break; + } + if (af != -1 && buffer_available(&packet, length)) { + char text_address[1000]; + uint8_t address[128]; + memset(address, 0, sizeof(address)); + buffer_read(&packet, address, length); + if (inet_ntop(af, address, text_address, + sizeof(text_address))) { + buffer_printf(output, "%s%d:%s/%d", + negated ? "!" : "", + (int) address_family, + text_address, + (int) prefix); + result = 1; + } + } + } + return result; + */ + + +} + +char *rdata_services_to_string(knot_rdata_item_t item) +{ + uint8_t *data = rdata_item_data(item); + uint8_t protocol_number = data[0]; + ssize_t bitmap_size = rdata_item_size(item) - 1; + uint8_t *bitmap = data + 1; + struct protoent *proto = getprotobynumber(protocol_number); + + char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN); + + memset(ret, 0, MAX_NSEC_BIT_STR_LEN); + + if (proto) { + int i; + + strcpy(ret, proto->p_name); + + strcat(ret, " "); + + for (i = 0; i < bitmap_size * 8; ++i) { + if (get_bit(bitmap, i)) { + struct servent *service = + getservbyport((int)htons(i), + proto->p_name); + if (service) { + strcat(ret, service->s_name); + strcat(ret, " "); + } else { + char tmp[U32_MAX_STR_LEN]; + snprintf(tmp, U32_MAX_STR_LEN, + "%d ", i); + strcat(ret, tmp); + } + } + } + } + + return ret; + + /* + int result = 0; + uint8_t protocol_number = buffer_read_u8(&packet); + ssize_t bitmap_size = buffer_remaining(&packet); + uint8_t *bitmap = buffer_current(&packet); + struct protoent *proto = getprotobynumber(protocol_number); + + + if (proto) { + int i; + + strcpy(ret, proto->p_name); + + for (i = 0; i < bitmap_size * 8; ++i) { + if (get_bit(bitmap, i)) { + struct servent *service = + getservbyport((int)htons(i), + proto->p_name); + if (service) { + buffer_printf(output, " %s", + service->s_name); + } else { + buffer_printf(output, " %d", i); + } + } + } + result = 1; + } + return ret; + */ +} + +char *rdata_ipsecgateway_to_string(knot_rdata_item_t item, + const knot_rrset_t *rrset) +{ + const knot_rdata_item_t *gateway_type_item = + knot_rdata_item(knot_rrset_rdata(rrset), 1); + if (gateway_type_item == NULL) { + return NULL; + } + /* First two bytes store length. */ + int gateway_type = ((uint8_t *)(gateway_type_item->raw_data))[2]; + switch(gateway_type) { + case IPSECKEY_NOGATEWAY: { + char *ret = malloc(sizeof(char) * 4); + if (ret == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + memset(ret, 0, sizeof(char) * 4); + memcpy(ret, ".", 4); +/* ret[0] = '\"'; + ret[1] = '.'; + ret[2] = '\"'; + ret[3] = '\0'; */ + return ret; + } + case IPSECKEY_IP4: + return rdata_a_to_string(item); + case IPSECKEY_IP6: + return rdata_aaaa_to_string(item); + case IPSECKEY_DNAME: + return rdata_dname_to_string(item); + default: + return NULL; + } + + /* Flow *should* not get here. */ + return NULL; +} + +char *rdata_nxt_to_string(knot_rdata_item_t item) +{ + size_t i; + uint8_t *bitmap = rdata_item_data(item); + size_t bitmap_size = rdata_item_size(item); + + char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN); + + memset(ret, 0, MAX_NSEC_BIT_STR_LEN); + + for (i = 0; i < bitmap_size * 8; ++i) { + if (get_bit(bitmap, i)) { + strcat(ret, knot_rrtype_to_string(i)); + strcat(ret, " "); + } + } + + return ret; +} + + +char *rdata_nsec_to_string(knot_rdata_item_t item) +{ + /* CLEANUP */ +// int insert_space = 0; + + char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN); + + memset(ret, 0, MAX_NSEC_BIT_STR_LEN); + + uint8_t *data = rdata_item_data(item); + + int increment = 0; + + for (int i = 0; i < rdata_item_size(item); i += increment) { + increment = 0; + uint8_t window = data[i]; + increment++; + + uint8_t bitmap_size = data[i + increment]; + increment++; + + uint8_t *bitmap = malloc(sizeof(uint8_t) * bitmap_size); + + memcpy(bitmap, data + i + increment, + bitmap_size); + + increment += bitmap_size; + + for (int j = 0; j < bitmap_size * 8; j++) { + if (get_bit(bitmap, j)) { + strcat(ret, + knot_rrtype_to_string(j + + window * 256)); + strcat(ret, " "); + } + } + + free(bitmap); + } + + return ret; + + /* CLEANUP */ +/* while (buffer_available(&packet, 2)) { + uint8_t window = buffer_read_u8(&packet); + uint8_t bitmap_size = buffer_read_u8(&packet); + uint8_t *bitmap = buffer_current(&packet); + int i; + + if (!buffer_available(&packet, bitmap_size)) { + buffer_set_position(output, saved_position); + return 0; + } + + for (i = 0; i < bitmap_size * 8; ++i) { + if (get_bit(bitmap, i)) { + buffer_printf(output, + "%s%s", + insert_space ? " " : "", + rrtype_to_string( + window * 256 + i)); + insert_space = 1; + } + } + buffer_skip(&packet, bitmap_size); + } + + return 1; */ +} + +char *rdata_unknown_to_string(knot_rdata_item_t item) +{ + uint16_t size = rdata_item_size(item); + char *ret = + malloc(sizeof(char) * (rdata_item_size(item) + + strlen("\\# ") + U16_MAX_STR_LEN)); + snprintf(ret, strlen("\\# ") + U16_MAX_STR_LEN, "%lu", + (unsigned long) size); + char *converted = hex_to_string(rdata_item_data(item), size); + strcat(ret, converted); + free(converted); + return ret; +} + +char *rdata_loc_to_string(knot_rdata_item_t item) +{ + return rdata_unknown_to_string(item); +} + +typedef char * (*item_to_string_t)(knot_rdata_item_t); + +static item_to_string_t item_to_string_table[KNOT_RDATA_ZF_UNKNOWN + 1] = { + rdata_dname_to_string, + rdata_dns_name_to_string, + rdata_text_to_string, + rdata_byte_to_string, + rdata_short_to_string, + rdata_long_to_string, + rdata_a_to_string, + rdata_aaaa_to_string, + rdata_rrtype_to_string, + rdata_algorithm_to_string, + rdata_certificate_type_to_string, + rdata_period_to_string, + rdata_time_to_string, + rdata_base64_to_string, + rdata_base32_to_string, + rdata_hex_to_string, + rdata_hexlen_to_string, + rdata_nsap_to_string, + rdata_apl_to_string, + NULL, //rdata_ipsecgateway_to_string, + rdata_services_to_string, + rdata_nxt_to_string, + rdata_nsec_to_string, + rdata_loc_to_string, + rdata_unknown_to_string +}; + +char *rdata_item_to_string(knot_rdata_zoneformat_t type, + knot_rdata_item_t item) +{ + return item_to_string_table[type](item); +} + +/* CLEANUP */ +/*void knot_zone_tree_apply_inorder(knot_zone_t *zone, + void (*function)(knot_node_t *node, void *data), + void *data); */ + +void rdata_dump_text(const knot_rdata_t *rdata, uint16_t type, FILE *f, + const knot_rrset_t *rrset) +{ + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + char *item_str = NULL; + for (int i = 0; i < rdata->count; i++) { + /* Workaround for IPSec gateway. */ + if (desc->zoneformat[i] == KNOT_RDATA_ZF_IPSECGATEWAY) { + item_str = rdata_ipsecgateway_to_string(rdata->items[i], + rrset); + } else { + item_str = rdata_item_to_string(desc->zoneformat[i], + rdata->items[i]); + } + if (item_str == NULL) { + item_str = + rdata_item_to_string(KNOT_RDATA_ZF_UNKNOWN, + rdata->items[i]); + } + if (i != rdata->count - 1) { + fprintf(f, "%s ", item_str); + } else { + fprintf(f, "%s", item_str); + } + free(item_str); + } + fprintf(f, "\n"); +} + +void dump_rrset_header(const knot_rrset_t *rrset, FILE *f) +{ + char *name = knot_dname_to_str(rrset->owner); + fprintf(f, "%-20s ", name); + free(name); + fprintf(f, "%-5u ", rrset->ttl); + fprintf(f, "%-2s ", knot_rrclass_to_string(rrset->rclass)); + fprintf(f, "%-5s ", knot_rrtype_to_string(rrset->type)); +} + +void rrsig_set_dump_text(knot_rrset_t *rrsig, FILE *f) +{ + dump_rrset_header(rrsig, f); + knot_rdata_t *tmp = rrsig->rdata; + + while (tmp->next != rrsig->rdata) { + rdata_dump_text(tmp, KNOT_RRTYPE_RRSIG, f, rrsig); + dump_rrset_header(rrsig, f); + tmp = tmp->next; + } + + rdata_dump_text(tmp, KNOT_RRTYPE_RRSIG, f, rrsig); +} + + +void rrset_dump_text(const knot_rrset_t *rrset, FILE *f) +{ + dump_rrset_header(rrset, f); + knot_rdata_t *tmp = rrset->rdata; + + while (tmp->next != rrset->rdata) { + rdata_dump_text(tmp, rrset->type, f, rrset); + dump_rrset_header(rrset, f); + tmp = tmp->next; + } + + rdata_dump_text(tmp, rrset->type, f, rrset); + knot_rrset_t *rrsig_set = rrset->rrsigs; + if (rrsig_set != NULL) { + rrsig_set_dump_text(rrsig_set, f); + } +} + +struct dump_param { + FILE *f; + const knot_dname_t *origin; +}; + +void apex_node_dump_text(knot_node_t *node, FILE *f) +{ + knot_rrset_t dummy_rrset; + dummy_rrset.type = KNOT_RRTYPE_SOA; + knot_rrset_t *tmp_rrset = + (knot_rrset_t *)gen_tree_find(node->rrset_tree, + &dummy_rrset); + assert(tmp_rrset); + rrset_dump_text(tmp_rrset, f); + + const knot_rrset_t **rrsets = + knot_node_rrsets(node); + + for (int i = 0; i < node->rrset_count; i++) { + if (rrsets[i]->type != KNOT_RRTYPE_SOA) { + rrset_dump_text(rrsets[i], f); + } + } + + free(rrsets); +} + +void node_dump_text(knot_node_t *node, void *data) +{ + struct dump_param *param; + param = (struct dump_param *)data; + FILE *f = param->f; + const knot_dname_t *origin = param->origin; + + /* pointers should do in this case */ + if (node->owner == origin) { + apex_node_dump_text(node, f); + return; + } + + const knot_rrset_t **rrsets = + knot_node_rrsets(node); + + for (int i = 0; i < node->rrset_count; i++) { + rrset_dump_text(rrsets[i], f); + } + + free(rrsets); +} + +int zone_dump_text(knot_zone_contents_t *zone, const char *filename) +{ + FILE *f = fopen(filename, "w"); + if (f == NULL) { + return KNOT_EBADARG; + } + + fprintf(f, ";Dumped using %s v. %s\n", PACKAGE_NAME, PACKAGE_VERSION); + + struct dump_param param; + param.f = f; + assert(zone->apex != NULL && zone->apex->owner != NULL); + param.origin = knot_node_owner(knot_zone_contents_apex(zone)); + knot_zone_contents_tree_apply_inorder(zone, node_dump_text, ¶m); + knot_zone_contents_nsec3_apply_inorder(zone, node_dump_text, ¶m); + fclose(f); + + return KNOT_EOK; +} diff --git a/src/knot/zone/zone-dump-text.h b/src/knot/zone/zone-dump-text.h new file mode 100644 index 0000000..70dcff4 --- /dev/null +++ b/src/knot/zone/zone-dump-text.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file zone-dump-text.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief Functions for dumping zone to text file. + * + * \addtogroup dnslib + * @{ + */ + +#ifndef _KNOT_ZONE_DUMP_TEXT_H_ +#define _KNOT_ZONE_DUMP_TEXT_H_ + +#include "libknot/util/descriptor.h" +#include "libknot/zone/zone.h" + +/*! + * \brief Dumps given zone to text (BIND-like) file. + * + * \param zone Zone to be saved. + * \param filename Name of file to be created. + * + * \retval KNOT_EOK on success. + * \retval KNOT_EBADARG if the specified file is not valid for writing. + */ +int zone_dump_text(knot_zone_contents_t *zone, const char *filename); + +#endif // _KNOT_ZONE_DUMP_TEXT_H_ + +/*! @} */ diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c new file mode 100644 index 0000000..afc577d --- /dev/null +++ b/src/knot/zone/zone-dump.c @@ -0,0 +1,2301 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdint.h> +#include <assert.h> +#include <netinet/in.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include "libknot/common.h" +#include "knot/zone/zone-dump.h" +#include "libknot/libknot.h" +#include "knot/other/debug.h" +#include "common/skip-list.h" +#include "common/base32hex.h" +#include "common/crc.h" +#include "libknot/util/error.h" + +#define ZONECHECKS_VERBOSE + +/*! \note Contents of a dump file: + * MAGIC(knotxx) db_filename dname_table + * NUMBER_OF_NORMAL_NODES NUMBER_OF_NSEC3_NODES + * [normal_nodes] [nsec3_nodes] + * -------------------------------------------- + * dname_table is dumped as follows: + * NUMBER_OF_DNAMES [dname_wire_length dname_wire label_count dname_labels ID] + * node has following format: + * owner_id + * node_flags node_rrset_count [node_rrsets] + * rrset has following format: + * rrset_type rrset_class rrset_ttl rrset_rdata_count rrset_rrsig_count + * [rrset_rdata] [rrset_rrsigs] + * rdata can contain either dname ID, + * or raw data stored like this: data_len [data] + */ + +static const uint MAX_CNAME_CYCLE_DEPTH = 15; + +/*! + *\brief Internal error constants. General errors are added for convenience, + * so that code does not have to change if new errors are added. + */ +enum zonechecks_errors { + ZC_ERR_ALLOC = -40, + ZC_ERR_UNKNOWN, + + ZC_ERR_MISSING_SOA, + + ZC_ERR_GENERIC_GENERAL_ERROR, /* isn't there a better name? */ + + ZC_ERR_RRSIG_RDATA_TYPE_COVERED, + ZC_ERR_RRSIG_RDATA_TTL, + ZC_ERR_RRSIG_RDATA_LABELS, + ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER, + ZC_ERR_RRSIG_RDATA_SIGNED_WRONG, + ZC_ERR_RRSIG_NO_RRSIG, + ZC_ERR_RRSIG_SIGNED, + ZC_ERR_RRSIG_OWNER, + ZC_ERR_RRSIG_CLASS, + ZC_ERR_RRSIG_TTL, + ZC_ERR_RRSIG_NOT_ALL, + + ZC_ERR_RRSIG_GENERAL_ERROR, + + ZC_ERR_NO_NSEC, + ZC_ERR_NSEC_RDATA_BITMAP, + ZC_ERR_NSEC_RDATA_MULTIPLE, + ZC_ERR_NSEC_RDATA_CHAIN, + ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC, + + ZC_ERR_NSEC_GENERAL_ERROR, + + ZC_ERR_NSEC3_UNSECURED_DELEGATION, + ZC_ERR_NSEC3_NOT_FOUND, + ZC_ERR_NSEC3_UNSECURED_DELEGATION_OPT, + ZC_ERR_NSEC3_RDATA_TTL, + ZC_ERR_NSEC3_RDATA_CHAIN, + ZC_ERR_NSEC3_RDATA_BITMAP, + + ZC_ERR_NSEC3_GENERAL_ERROR, + + ZC_ERR_CNAME_CYCLE, + ZC_ERR_DNAME_CYCLE, + ZC_ERR_CNAME_EXTRA_RECORDS, + ZC_ERR_DNAME_EXTRA_RECORDS, + ZC_ERR_CNAME_EXTRA_RECORDS_DNSSEC, + ZC_ERR_CNAME_MULTIPLE, + ZC_ERR_DNAME_MULTIPLE, + + ZC_ERR_CNAME_GENERAL_ERROR, + + ZC_ERR_GLUE_NODE, + ZC_ERR_GLUE_RECORD, + + ZC_ERR_GLUE_GENERAL_ERROR, +}; + +static char *error_messages[(-ZC_ERR_ALLOC) + 1] = { + [-ZC_ERR_ALLOC] = "Memory allocation error!\n", + + [-ZC_ERR_MISSING_SOA] = "SOA record missing in zone!\n", + + [-ZC_ERR_RRSIG_RDATA_TYPE_COVERED] = + "RRSIG: Type covered rdata field is wrong!\n", + [-ZC_ERR_RRSIG_RDATA_TTL] = + "RRSIG: TTL rdata field is wrong!\n", + [-ZC_ERR_RRSIG_RDATA_LABELS] = + "RRSIG: Labels rdata field is wrong!\n", + [-ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER] = + "RRSIG: Signer name is different than in DNSKEY!\n", + [-ZC_ERR_RRSIG_RDATA_SIGNED_WRONG] = + "RRSIG: Key error!\n", + [-ZC_ERR_RRSIG_NO_RRSIG] = + "RRSIG: No RRSIG!\n", + [-ZC_ERR_RRSIG_SIGNED] = + "RRSIG: Signed RRSIG!\n", + [-ZC_ERR_RRSIG_OWNER] = + "RRSIG: Owner name rdata field is wrong!\n", + [-ZC_ERR_RRSIG_CLASS] = + "RRSIG: Class is wrong!\n", + [-ZC_ERR_RRSIG_TTL] = + "RRSIG: TTL is wrong!\n", + [-ZC_ERR_RRSIG_NOT_ALL] = + "RRSIG: Not all RRs are signed!\n", + + [-ZC_ERR_NO_NSEC] = + "NSEC: Missing NSEC record\n", + [-ZC_ERR_NSEC_RDATA_BITMAP] = + "NSEC: Wrong NSEC bitmap!\n", + [-ZC_ERR_NSEC_RDATA_MULTIPLE] = + "NSEC: Multiple NSEC records!\n", + [-ZC_ERR_NSEC_RDATA_CHAIN] = + "NSEC: NSEC chain is not coherent!\n", + [-ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC] = + "NSEC: NSEC chain is not cyclic!\n", + + [-ZC_ERR_NSEC3_UNSECURED_DELEGATION] = + "NSEC3: Zone contains unsecured delegation!\n", + [-ZC_ERR_NSEC3_NOT_FOUND] = + "NSEC3: Could not find previous NSEC3 record in the zone!\n", + [-ZC_ERR_NSEC3_UNSECURED_DELEGATION_OPT] = + "NSEC3: Unsecured delegation is not part " + "of the Opt-Out span!\n", + [-ZC_ERR_NSEC3_RDATA_TTL] = + "NSEC3: Original TTL rdata field is wrong!\n", + [-ZC_ERR_NSEC3_RDATA_CHAIN] = + "NSEC3: NSEC3 chain is not coherent!\n", + [-ZC_ERR_NSEC3_RDATA_BITMAP] = + "NSEC3: NSEC3 bitmap error!\n", + + [-ZC_ERR_CNAME_CYCLE] = + "CNAME: CNAME cycle!\n", + [-ZC_ERR_DNAME_CYCLE] = + "CNAME: DNAME cycle!\n", + [-ZC_ERR_CNAME_EXTRA_RECORDS] = + "CNAME: Node with CNAME record has other records!\n", + [-ZC_ERR_DNAME_EXTRA_RECORDS] = + "DNAME: Node with DNAME record has other records!\n", + [-ZC_ERR_CNAME_EXTRA_RECORDS_DNSSEC] = + "CNAME: Node with CNAME record has other " + "records than RRSIG and NSEC/NSEC3!\n", + [-ZC_ERR_CNAME_MULTIPLE] = "CNAME: Multiple CNAME records!\n", + [-ZC_ERR_DNAME_MULTIPLE] = "DNAME: Multiple DNAME records!\n", + + /* ^ + | Important errors (to be logged on first occurence and counted) */ + + + /* Below are errors of lesser importance, to be counted unless + specified otherwise */ + + [-ZC_ERR_GLUE_NODE] = + "GLUE: Node with Glue record missing!\n", + [-ZC_ERR_GLUE_RECORD] = + "GLUE: Record with Glue address missing\n", +}; + +/*! + * \brief Structure representing handle options. + */ +struct handler_options { + char log_cname; /*!< Log all CNAME related semantic errors. */ + char log_glue; /*!< Log all glue related semantic errors. */ + char log_rrsigs; /*!< Log all RRSIG related semantic errors. */ + char log_nsec; /*!< Log all NSEC related semantic errors. */ + char log_nsec3; /*!< Log all NSEC3 related semantic errors. */ +}; + +/*! + * \brief Structure for handling semantic errors. + */ +struct err_handler { + /* Consider moving error messages here */ + struct handler_options options; /*!< Handler options. */ + uint errors[(-ZC_ERR_ALLOC) + 1]; /*!< Array with error messages */ +}; + +typedef struct err_handler err_handler_t; + +/*! + * \brief Creates new semantic error handler. + * + * \param log_cname If true, log all CNAME related events. + * \param log_glue If true, log all Glue related events. + * \param log_rrsigs If true, log all RRSIGs related events. + * \param log_nsec If true, log all NSEC related events. + * \param log_nsec3 If true, log all NSEC3 related events. + * + * \return err_handler_t * Created error handler. + */ +static err_handler_t *handler_new(char log_cname, char log_glue, + char log_rrsigs, char log_nsec, + char log_nsec3) +{ + err_handler_t *handler = malloc(sizeof(err_handler_t)); + CHECK_ALLOC_LOG(handler, NULL); + + /* It should be initialized, but to be safe */ + memset(handler->errors, 0, sizeof(uint) * (-ZC_ERR_ALLOC + 1)); + + handler->options.log_cname = log_cname; + handler->options.log_glue = log_glue; + handler->options.log_rrsigs = log_rrsigs; + handler->options.log_nsec = log_nsec; + handler->options.log_nsec3 = log_nsec3; + + return handler; +} + +/*! + * \brief Prints error message with node information. + * + * \note If \a node is NULL, only total number of errors is printed. + * + * \param handler Error handler. + * \param node Node with semantic error in it. + * \param error Type of error. + */ +static void log_error_from_node(err_handler_t *handler, + const knot_node_t *node, + uint error) +{ + if (node != NULL) { + char *name = + knot_dname_to_str(knot_node_owner(node)); + fprintf(stderr, "Semantic warning in node: %s: ", name); + fprintf(stderr, "%s", error_messages[-error]); + free(name); + } else { + fprintf(stderr, "Total number of warnings is: %d for error: %s", + handler->errors[-error], + error_messages[-error]); + } +} + +/*! + * \brief Called when error has been encountered in node. Will either log error + * or print it, depending on handler's options. + * + * \param handler Error handler. + * \param node Node with semantic error in it. + * \param error Type of error. + * + * \retval KNOT_EOK on success. + * \retval ZC_ERR_UNKNOWN if unknown error. + * \retval ZC_ERR_ALLOC if memory error. + */ +static int err_handler_handle_error(err_handler_t *handler, + const knot_node_t *node, + uint error) +{ + assert(handler && node); + if ((error != 0) && + (error > ZC_ERR_GLUE_GENERAL_ERROR)) { + return ZC_ERR_UNKNOWN; + } + + if (error == ZC_ERR_ALLOC) { + ERR_ALLOC_FAILED; + return ZC_ERR_ALLOC; + } + + /* missing SOA can only occur once, so there + * needn't to be an option for it */ + + if ((error != 0) && + (error < ZC_ERR_GENERIC_GENERAL_ERROR)) { + /* The two errors before SOA were handled */ + log_error_from_node(handler, node, error); + + } else if ((error < ZC_ERR_RRSIG_GENERAL_ERROR) && + ((handler->errors[-error] == 0) || + (handler->options.log_rrsigs))) { + + log_error_from_node(handler, node, error); + + } else if ((error > ZC_ERR_RRSIG_GENERAL_ERROR) && + (error < ZC_ERR_NSEC_GENERAL_ERROR) && + ((handler->errors[-error] == 0) || + (handler->options.log_nsec))) { + + log_error_from_node(handler, node, error); + + } else if ((error > ZC_ERR_NSEC_GENERAL_ERROR) && + (error < ZC_ERR_NSEC3_GENERAL_ERROR) && + ((handler->errors[-error] == 0) || + (handler->options.log_nsec3))) { + + log_error_from_node(handler, node, error); + + } else if ((error > ZC_ERR_NSEC3_GENERAL_ERROR) && + (error < ZC_ERR_CNAME_GENERAL_ERROR) && + ((handler->errors[-error] == 0) || + (handler->options.log_cname))) { + + log_error_from_node(handler, node, error); + + } else if ((error > ZC_ERR_CNAME_GENERAL_ERROR) && + (error < ZC_ERR_GLUE_GENERAL_ERROR) && + handler->options.log_glue) { + + log_error_from_node(handler, node, error); + + } + + handler->errors[-error]++; + + return KNOT_EOK; +} + +/*! + * \brief This function prints all errors that occured in zone. + * + * \param handler Error handler containing found errors. + */ +static void err_handler_log_all(err_handler_t *handler) +{ + if (handler == NULL) { + return; + } + + for (int i = ZC_ERR_ALLOC; i < ZC_ERR_GLUE_GENERAL_ERROR; i++) { + if (handler->errors[-i] > 0) { + log_error_from_node(handler, NULL, i); + } + } +} + +/*! + * \brief Arguments to be used with tree traversal functions. Uses void pointers + * to be more versatile. + * + */ +struct arg { + void *arg1; /* FILE *f / zone */ + void *arg2; /* skip_list_t */ + void *arg3; /* zone */ + void *arg4; /* first node */ + void *arg5; /* last node */ + void *arg6; /* error handler */ + void *arg7; /* CRC */ +}; + +typedef struct arg arg_t; + +/*! + * \brief Semantic check - CNAME cycles. Uses constant value with maximum + * allowed CNAME chain depth. + * + * \param zone Zone containing the RRSet. + * \param rrset RRSet to be tested. + * + * \retval KNOT_EOK when there is no cycle. + * \retval ZC_ERR_CNAME_CYCLE when cycle is present. + */ +static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, + const knot_rrset_t *rrset) +{ + const knot_rrset_t *next_rrset = rrset; + assert(rrset); + const knot_rdata_t *tmp_rdata = knot_rrset_rdata(next_rrset); + const knot_node_t *next_node = NULL; + + uint i = 0; + + assert(tmp_rdata); + + const knot_dname_t *next_dname = + knot_rdata_cname_name(tmp_rdata); + + assert(next_dname); + + while (i < MAX_CNAME_CYCLE_DEPTH && next_dname != NULL) { + next_node = knot_zone_contents_get_node(zone, next_dname); + if (next_node == NULL) { + next_node = + knot_zone_contents_get_nsec3_node(zone, next_dname); + } + + if (next_node != NULL) { + next_rrset = knot_node_rrset(next_node, + KNOT_RRTYPE_CNAME); + if (next_rrset != NULL) { + next_dname = + knot_rdata_cname_name(next_rrset->rdata); + } else { + next_node = NULL; + next_dname = NULL; + } + } else { + next_dname = NULL; + } + i++; + } + + /* even if the length is 0, i will be 1 */ + if (i >= MAX_CNAME_CYCLE_DEPTH) { + return ZC_ERR_CNAME_CYCLE; + } + + return KNOT_EOK; +} + +/*! + * \brief Return raw data from rdata item structure (without length). + * + * \param item Item to get rdata from. + * \return uint16_t * raw data without length. + */ +static inline uint16_t *rdata_item_data(const knot_rdata_item_t *item) +{ + return (uint16_t *)(item->raw_data + 1); +} + +/*! + * \brief Returns type covered field from RRSIG RRSet's rdata. + * + * \param rdata RRSIG rdata. + * \return uint16_t Type covered. + */ +uint16_t type_covered_from_rdata(const knot_rdata_t *rdata) +{ + return ntohs(*(uint16_t *) rdata_item_data(&(rdata->items[0]))); +} + +/*! + * \brief Check whether DNSKEY rdata are valid. + * + * \param rdata DNSKEY rdata to be checked. + * + * \retval KNOT_EOK when rdata are OK. + * \retval ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER when rdata are not OK. + */ +static int check_dnskey_rdata(const knot_rdata_t *rdata) +{ + /* check that Zone key bit it set - position 7 in net order */ + /*! \todo FIXME: endian? I swear I've fixed this already, it was 7 i guesss*/ + uint16_t mask = 1 << 8; //0b0000000100000000; + + uint16_t flags = + knot_wire_read_u16((uint8_t *)rdata_item_data + (knot_rdata_item(rdata, 0))); + + if (flags & mask) { + return KNOT_EOK; + } else { + /* This error does not exactly fit, but it's better + * than a new one */ + return ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER; + } +} + +/*! + * \brief Calculates keytag for RSA/SHA algorithm. + * + * \param key Key wireformat. + * \param keysize Wireformat size. + * + * \return uint16_t Calculated keytag. + */ +static uint16_t keytag_1(uint8_t *key, uint16_t keysize) +{ + uint16_t ac = 0; + if (keysize > 4) { + memmove(&ac, key + keysize - 3, 2); + } + + ac = ntohs(ac); + return ac; +} + +/*! + * \brief Calculates keytag from key wire. + * + * \param key Key wireformat. + * \param keysize Wireformat size. + * + * \return uint16_t Calculated keytag. + */ +static uint16_t keytag(uint8_t *key, uint16_t keysize ) +{ + uint32_t ac = 0; /* assumed to be 32 bits or larger */ + + /* algorithm RSA/SHA */ + if (key[3] == 1) { + return keytag_1(key, keysize); + } else { + for(int i = 0; i < keysize; i++) { + ac += (i & 1) ? key[i] : key[i] << 8; + } + + ac += (ac >> 16) & 0xFFFF; + return (uint16_t)ac & 0xFFFF; + } +} + +/*! + * \brief Returns size of raw data item. + * + * \param item Raw data item. + * + * \return uint16_t Size of raw data item. + */ +static inline uint16_t rdata_item_size(const knot_rdata_item_t *item) +{ + return item->raw_data[0]; +} + +/*! + * \brief Converts DNSKEY rdata to wireformat. + * + * \param rdata DNSKEY rdata to be converted. + * \param wire Created wire. + * \param size Size of created wire. + * + * \retval KNOT_EOK on success. + * \retval KNOT_ENOMEM on memory error. + */ +static int dnskey_to_wire(const knot_rdata_t *rdata, uint8_t **wire, + uint *size) +{ + assert(*wire == NULL); + /* flags + algorithm + protocol + keysize */ + *size = 2 + 1 + 1 + knot_rdata_item(rdata, 3)->raw_data[0]; + *wire = malloc(sizeof(uint8_t) * *size); + CHECK_ALLOC_LOG(*wire, KNOT_ENOMEM); + + /* copy the wire octet by octet */ + + /* TODO check if we really have that many items */ + if (rdata->count < 4) { + return KNOT_ERROR; + } + + (*wire)[0] = ((uint8_t *)(knot_rdata_item(rdata, 0)->raw_data))[2]; + (*wire)[1] = ((uint8_t *)(knot_rdata_item(rdata, 0)->raw_data))[3]; + + (*wire)[2] = ((uint8_t *)(knot_rdata_item(rdata, 1)->raw_data))[2]; + (*wire)[3] = ((uint8_t *)(knot_rdata_item(rdata, 2)->raw_data))[2]; + + memcpy(*wire + 4, knot_rdata_item(rdata, 3)->raw_data + 1, + knot_rdata_item(rdata, 3)->raw_data[0]); + + return KNOT_EOK; +} + +/*! + * \brief Semantic check - RRSIG rdata. + * + * \param rdata_rrsig RRSIG rdata to be checked. + * \param rrset RRSet containing the rdata. + * \param dnskey_rrset RRSet containing zone's DNSKEY + * + * \retval KNOT_EOK if rdata are OK. + * + * \return Appropriate error code if error was found. + */ +static int check_rrsig_rdata(const knot_rdata_t *rdata_rrsig, + const knot_rrset_t *rrset, + const knot_rrset_t *dnskey_rrset) +{ + if (rdata_rrsig == NULL) { + return ZC_ERR_RRSIG_NO_RRSIG; + } + + if (type_covered_from_rdata(rdata_rrsig) != + knot_rrset_type(rrset)) { + /* zoneparser would not let this happen + * but to be on the safe side + */ + return ZC_ERR_RRSIG_RDATA_TYPE_COVERED; + } + + /* label number at the 2nd index should be same as owner's */ + uint16_t *raw_data = + rdata_item_data(knot_rdata_item(rdata_rrsig, 2)); + + uint8_t labels_rdata = ((uint8_t *)raw_data)[0]; + + int tmp = knot_dname_label_count(knot_rrset_owner(rrset)) - + labels_rdata; + + if (tmp != 0) { + /* if name has wildcard, label must not be included */ + if (!knot_dname_is_wildcard(knot_rrset_owner(rrset))) { + return ZC_ERR_RRSIG_RDATA_LABELS; + } else { + if (abs(tmp) != 1) { + return ZC_ERR_RRSIG_RDATA_LABELS; + } + } + } + + /* check original TTL */ + uint32_t original_ttl = + knot_wire_read_u32((uint8_t *)rdata_item_data( + knot_rdata_item(rdata_rrsig, 3))); + + if (original_ttl != knot_rrset_ttl(rrset)) { + return ZC_ERR_RRSIG_RDATA_TTL; + } + + /* signer's name is same as in the zone apex */ + knot_dname_t *signer_name = + knot_rdata_item(rdata_rrsig, 7)->dname; + + /* dnskey is in the apex node */ + if (knot_dname_compare(signer_name, + knot_rrset_owner(dnskey_rrset)) != 0) { + return ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER; + } + + /* Compare algorithm, key tag and signer's name with DNSKEY rrset + * one of the records has to match. Signer name has been checked + * before */ + char match = 0; + const knot_rdata_t *tmp_dnskey_rdata = + knot_rrset_rdata(dnskey_rrset); + do { + uint8_t alg = + ((uint8_t *)(knot_rdata_item(rdata_rrsig, 1)->raw_data))[2]; + uint8_t alg_dnskey = + ((uint8_t *)(knot_rdata_item(tmp_dnskey_rdata, + 2)->raw_data))[2]; + + raw_data = rdata_item_data(knot_rdata_item(rdata_rrsig, 6)); + uint16_t key_tag_rrsig = + knot_wire_read_u16((uint8_t *)raw_data); + +/* raw_data = + rdata_item_data(knot_rdata_item( + tmp_dnskey_rdata, 3)); + + uint16_t raw_length = rdata_item_size(knot_rdata_item( + tmp_dnskey_rdata, 3)); */ + + uint8_t *dnskey_wire = NULL; + uint dnskey_wire_size = 0; + + int ret = 0; + if ((ret = dnskey_to_wire(tmp_dnskey_rdata, &dnskey_wire, + &dnskey_wire_size)) != KNOT_EOK) { + return ret; + } + + uint16_t key_tag_dnskey = + keytag(dnskey_wire, dnskey_wire_size); + + free(dnskey_wire); + + match = (alg == alg_dnskey) && + (key_tag_rrsig == key_tag_dnskey) && + !check_dnskey_rdata(tmp_dnskey_rdata); + + } while (!match && + ((tmp_dnskey_rdata = + knot_rrset_rdata_next(dnskey_rrset, + tmp_dnskey_rdata)) + != NULL)); + + if (!match) { + return ZC_ERR_RRSIG_RDATA_SIGNED_WRONG; + } + + return KNOT_EOK; +} + +/*! + * \brief Semantic check - RRSet's RRSIG. + * + * \param rrset RRSet containing RRSIG. + * \param dnskey_rrset + * \param nsec3 NSEC3 active. + * + * \retval KNOT_EOK on success. + * + * \return Appropriate error code if error was found. + */ +static int check_rrsig_in_rrset(const knot_rrset_t *rrset, + const knot_rrset_t *dnskey_rrset, + char nsec3) +{ + assert(dnskey_rrset && rrset); + + const knot_rrset_t *rrsigs = knot_rrset_rrsigs(rrset); + + if (rrsigs == NULL) { + return ZC_ERR_RRSIG_NO_RRSIG; + } + + /* signed rrsig - nonsense */ + if (knot_rrset_rrsigs(rrsigs) != NULL) { + return ZC_ERR_RRSIG_SIGNED; + } + + /* Different owner, class, ttl */ + + if (knot_dname_compare(knot_rrset_owner(rrset), + knot_rrset_owner(rrsigs)) != 0) { + return ZC_ERR_RRSIG_OWNER; + } + + if (knot_rrset_class(rrset) != knot_rrset_class(rrsigs)) { + return ZC_ERR_RRSIG_CLASS; + } + + if (knot_rrset_ttl(rrset) != knot_rrset_ttl(rrset)) { + return ZC_ERR_RRSIG_TTL; + } + + /* Check whether all rrsets have their rrsigs */ + const knot_rdata_t *tmp_rdata = knot_rrset_rdata(rrset); + const knot_rdata_t *tmp_rrsig_rdata = knot_rrset_rdata(rrsigs); + + assert(tmp_rdata); + assert(tmp_rrsig_rdata); + int ret = 0; + char all_signed = tmp_rdata && tmp_rrsig_rdata; + do { + if ((ret = check_rrsig_rdata(tmp_rrsig_rdata, + rrset, + dnskey_rrset)) != 0) { + return ret; + } + + all_signed = tmp_rdata && tmp_rrsig_rdata; + } while (((tmp_rdata = knot_rrset_rdata_next(rrset, tmp_rdata)) + != NULL) && + ((tmp_rrsig_rdata = + knot_rrset_rdata_next(rrsigs, tmp_rrsig_rdata)) + != NULL)); + + if (!all_signed) { + return ZC_ERR_RRSIG_NOT_ALL; + } + + return KNOT_EOK; +} + +/*! + * \brief Returns bit on index from array in network order. Taken from NSD. + * + * \param bits Array in network order. + * \param index Index to return from array. + * + * \return int Bit on given index. + */ +static int get_bit(uint8_t *bits, size_t index) +{ + /* + * The bits are counted from left to right, so bit #0 is the + * leftmost bit. + */ + return bits[index / 8] & (1 << (7 - index % 8)); +} + +/*! + * \brief Converts NSEC bitmap to array of integers. (Inspired by NSD code) + * + * \param item Item containing the bitmap. + * \param array Array to be created. + * \param count Count of items in array. + * + * \retval KNOT_OK on success. + * \retval KNOT_NOMEM on memory error. + */ +static int rdata_nsec_to_type_array(const knot_rdata_item_t *item, + uint16_t **array, + uint *count) +{ + assert(*array == NULL); + + uint8_t *data = (uint8_t *)rdata_item_data(item); + + int increment = 0; + *count = 0; + + for (int i = 0; i < rdata_item_size(item); i += increment) { + increment = 0; + uint8_t window = data[i]; + increment++; + + uint8_t bitmap_size = data[i + increment]; + increment++; + + uint8_t *bitmap = + malloc(sizeof(uint8_t) * (bitmap_size)); + if (bitmap == NULL) { + ERR_ALLOC_FAILED; + free(*array); + return KNOT_ENOMEM; + } + + memcpy(bitmap, data + i + increment, + bitmap_size); + + increment += bitmap_size; + + for (int j = 0; j < bitmap_size * 8; j++) { + if (get_bit(bitmap, j)) { + (*count)++; + void *tmp = realloc(*array, + sizeof(uint16_t) * + *count); + if (tmp == NULL) { + ERR_ALLOC_FAILED; + free(bitmap); + free(*array); + return KNOT_ENOMEM; + } + *array = tmp; + (*array)[*count - 1] = j + window * 256; + } + } + free(bitmap); + } + + return KNOT_EOK; +} + +/* should write error, not return values !!! */ + +/*! + * \brief Semantic check - check node's NSEC node. + * + * \param zone Current zone. + * \param node Node to be checked. + * \param handler Error handler + * + * \retval KNOT_EOK if no error was found. + * + * \return Appropriate error code if error was found. + */ +static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, knot_node_t *node, + err_handler_t *handler) +{ + assert(handler); + const knot_node_t *nsec3_node = knot_node_nsec3_node(node, 0); + + if (nsec3_node == NULL) { + /* I know it's probably not what RFCs say, but it will have to + * do for now. */ + if (knot_node_rrset(node, KNOT_RRTYPE_DS) != NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC3_UNSECURED_DELEGATION); + } else { + /* Unsecured delegation, check whether it is part of + * opt-out span */ + const knot_node_t *nsec3_previous; + const knot_node_t *nsec3_node; + + if (knot_zone_contents_find_nsec3_for_name(zone, + knot_node_owner(node), + &nsec3_node, + &nsec3_previous, 0) != 0) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC3_NOT_FOUND); + } + + if (nsec3_node == NULL) { + /* Probably should not ever happen */ + return ZC_ERR_NSEC3_NOT_FOUND; + } + + assert(nsec3_previous); + + const knot_rrset_t *previous_rrset = + knot_node_rrset(nsec3_previous, + KNOT_RRTYPE_NSEC3); + + assert(previous_rrset); + + /* check for Opt-Out flag */ + uint8_t flags = + ((uint8_t *)(previous_rrset->rdata->items[1].raw_data))[2]; + + uint8_t opt_out_mask = 1; + + if (!(flags & opt_out_mask)) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC3_UNSECURED_DELEGATION_OPT); + } + } + } + + const knot_rrset_t *nsec3_rrset = + knot_node_rrset(nsec3_node, KNOT_RRTYPE_NSEC3); + + assert(nsec3_rrset); + + const knot_rrset_t *soa_rrset = + knot_node_rrset(knot_zone_contents_apex(zone), + KNOT_RRTYPE_SOA); + assert(soa_rrset); + + uint32_t minimum_ttl = + knot_wire_read_u32((uint8_t *) + rdata_item_data( + knot_rdata_item( + knot_rrset_rdata( + knot_node_rrset( + knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA)), 6))); + /* Are those getters even worth this? + * Now I have no idea what this code does. */ + + if (knot_rrset_ttl(nsec3_rrset) != minimum_ttl) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC3_RDATA_TTL); + } + + /* check that next dname is in the zone */ + uint8_t *next_dname_decoded = NULL; + size_t real_size = 0; + + if (((real_size = base32hex_encode_alloc(((char *) + rdata_item_data(&(nsec3_rrset->rdata->items[4]))) + 1, + rdata_item_size(&nsec3_rrset->rdata->items[4]) - 1, + (char **)&next_dname_decoded)) <= 0) || + (next_dname_decoded == NULL)) { + fprintf(stderr, "Could not encode base32 string!\n"); + return KNOT_ERROR; + } + + /* This is why we allocate maximum length of decoded string + 1 */ + memmove(next_dname_decoded + 1, next_dname_decoded, real_size); + next_dname_decoded[0] = real_size; + + /* Local allocation, will be discarded. */ + knot_dname_t *next_dname = + knot_dname_new_from_wire(next_dname_decoded, + real_size + 1, NULL); + CHECK_ALLOC_LOG(next_dname, KNOT_ENOMEM); + + free(next_dname_decoded); + + if (knot_dname_cat(next_dname, + knot_node_owner(knot_zone_contents_apex(zone))) == NULL) { + fprintf(stderr, "Could not concatenate dnames!\n"); + return KNOT_ERROR; + + } + + if (knot_zone_contents_find_nsec3_node(zone, next_dname) == NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC3_RDATA_CHAIN); + } + + /* Directly discard. */ + knot_dname_free(&next_dname); + + /* This is probably not sufficient, but again, it is covered in + * zone load time */ + + uint count; + uint16_t *array = NULL; + if (rdata_nsec_to_type_array( + knot_rdata_item( + knot_rrset_rdata(nsec3_rrset), 5), + &array, &count) != 0) { + err_handler_handle_error(handler, node, + ZC_ERR_ALLOC); + return KNOT_ERROR; + } + + uint16_t type = 0; + for (int j = 0; j < count; j++) { + /* test for each type's presence */ + type = array[j]; + if (type == KNOT_RRTYPE_RRSIG) { + continue; + } + if (knot_node_rrset(node, + type) == NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC3_RDATA_BITMAP); + break; +/* char *name = + knot_dname_to_str( + log_zone_error("Node %s does " + "not contain RRSet of type %s " + "but NSEC bitmap says " + "it does!\n", name, + knot_rrtype_to_string(type)); + free(name); */ + } + } + + free(array); + + return KNOT_EOK; +} + +/*! + * \brief Run semantic checks for node without DNSSEC-related types. + * + * \param zone Current zone. + * \param node Node to be checked. + * \param do_checks Level of checks to be done. + * \param handler Error handler. + * + * \retval KNOT_EOK if no error was found. + * + * \return Appropriate error code if error was found. + */ +static int semantic_checks_plain(knot_zone_contents_t *zone, + knot_node_t *node, + char do_checks, + err_handler_t *handler) +{ + assert(handler); + const knot_rrset_t *cname_rrset = + knot_node_rrset(node, KNOT_RRTYPE_CNAME); + if (cname_rrset != NULL) { + if (check_cname_cycles_in_zone(zone, cname_rrset) != + KNOT_EOK) { + err_handler_handle_error(handler, node, + ZC_ERR_CNAME_CYCLE); + } + + /* No DNSSEC and yet there is more than one rrset in node */ + if (do_checks == 1 && + knot_node_rrset_count(node) != 1) { + err_handler_handle_error(handler, node, + ZC_ERR_CNAME_EXTRA_RECORDS); + } else if (knot_node_rrset_count(node) != 1) { + /* With DNSSEC node can contain RRSIG or NSEC */ + if (!(knot_node_rrset(node, KNOT_RRTYPE_RRSIG) || + knot_node_rrset(node, KNOT_RRTYPE_NSEC)) || + knot_node_rrset_count(node) > 3) { + err_handler_handle_error(handler, node, + ZC_ERR_CNAME_EXTRA_RECORDS_DNSSEC); + } + } + + if (knot_rrset_rdata(cname_rrset)->next != + knot_rrset_rdata(cname_rrset)) { + err_handler_handle_error(handler, node, + ZC_ERR_CNAME_MULTIPLE); + } + } + + const knot_rrset_t *dname_rrset = + knot_node_rrset(node, KNOT_RRTYPE_DNAME); + if (dname_rrset != NULL) { + if (check_cname_cycles_in_zone(zone, dname_rrset) != + KNOT_EOK) { + err_handler_handle_error(handler, node, + ZC_ERR_DNAME_CYCLE); + } + + if (knot_node_rrset(node, KNOT_RRTYPE_CNAME)) { + err_handler_handle_error(handler, node, + ZC_ERR_DNAME_EXTRA_RECORDS); + } + + if (knot_rrset_rdata(dname_rrset)->next != + knot_rrset_rdata(dname_rrset)) { + err_handler_handle_error(handler, node, + ZC_ERR_DNAME_MULTIPLE); + } + } + + /* check for glue records at zone cuts */ + if (knot_node_is_deleg_point(node)) { + const knot_rrset_t *ns_rrset = + knot_node_rrset(node, KNOT_RRTYPE_NS); + assert(ns_rrset); + //FIXME this should be an error as well ! (i guess) + + const knot_dname_t *ns_dname = + knot_rdata_get_item(knot_rrset_rdata + (ns_rrset), 0)->dname; + + assert(ns_dname); + + const knot_node_t *glue_node = + knot_zone_contents_find_node(zone, ns_dname); + + if (knot_dname_is_subdomain(ns_dname, + knot_node_owner(knot_zone_contents_apex(zone)))) { + if (glue_node == NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_GLUE_NODE); + } else { + if ((knot_node_rrset(glue_node, + KNOT_RRTYPE_A) == NULL) && + (knot_node_rrset(glue_node, + KNOT_RRTYPE_AAAA) == NULL)) { + err_handler_handle_error(handler, node, + ZC_ERR_GLUE_RECORD); + } + } + } + } + return KNOT_EOK; +} + +/*! + * \brief Run semantic checks for node without DNSSEC-related types. + * + * \param zone Current zone. + * \param node Node to be checked. + * \param first_node First node in canonical order. + * \param last_node Last node in canonical order. + * \param handler Error handler. + * \param nsec3 NSEC3 used. + * + * \retval KNOT_EOK if no error was found. + * + * \return Appropriate error code if error was found. + */ +static int semantic_checks_dnssec(knot_zone_contents_t *zone, + knot_node_t *node, + knot_node_t *first_node, + knot_node_t **last_node, + err_handler_t *handler, + char nsec3) +{ + assert(handler); + assert(node); + char auth = !knot_node_is_non_auth(node); + char deleg = knot_node_is_deleg_point(node); + uint rrset_count = knot_node_rrset_count(node); + const knot_rrset_t **rrsets = knot_node_rrsets(node); + const knot_rrset_t *dnskey_rrset = + knot_node_rrset(knot_zone_contents_apex(zone), + KNOT_RRTYPE_DNSKEY); + + int ret = 0; + + for (int i = 0; i < rrset_count; i++) { + const knot_rrset_t *rrset = rrsets[i]; + if (auth && !deleg && + (ret = check_rrsig_in_rrset(rrset, dnskey_rrset, + nsec3)) != 0) { + /* CLEANUP */ +/* log_zone_error("RRSIG %d node %s\n", ret, + knot_dname_to_str(node->owner));*/ + + err_handler_handle_error(handler, node, ret); + } + + if (!nsec3 && auth) { + /* check for NSEC record */ + const knot_rrset_t *nsec_rrset = + knot_node_rrset(node, + KNOT_RRTYPE_NSEC); + + if (nsec_rrset == NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_NO_NSEC); + /* CLEANUP */ +/* char *name = + knot_dname_to_str(node->owner); + log_zone_error("Missing NSEC in node: " + "%s\n", name); + free(name); + return; */ + } else { + + /* check NSEC/NSEC3 bitmap */ + + uint count; + + uint16_t *array = NULL; + + if (rdata_nsec_to_type_array( + knot_rdata_item( + knot_rrset_rdata(nsec_rrset), + 1), + &array, &count) != 0) { + err_handler_handle_error(handler, + NULL, + ZC_ERR_ALLOC); + return ZC_ERR_ALLOC; /* ... */ + /*return; */ + } + + uint16_t type = 0; + for (int j = 0; j < count; j++) { + /* test for each type's presence */ + type = array[j]; + if (type == KNOT_RRTYPE_RRSIG) { + continue; + } + if (knot_node_rrset(node, + type) == NULL) { + err_handler_handle_error( + handler, + node, + ZC_ERR_NSEC_RDATA_BITMAP); + /* CLEANUP */ + /* char *name = + knot_dname_to_str( + knot_node_owner(node)); + + log_zone_error("Node %s does " + "not contain RRSet of type %s " + "but NSEC bitmap says " + "it does!\n", name, + knot_rrtype_to_string(type)); + + free(name); */ + } + } + free(array); + } + + /* Test that only one record is in the + * NSEC RRSet */ + + if ((nsec_rrset != NULL) && + knot_rrset_rdata(nsec_rrset)->next != + knot_rrset_rdata(nsec_rrset)) { + err_handler_handle_error(handler, + node, + ZC_ERR_NSEC_RDATA_MULTIPLE); + /* CLEANUP */ +/* char *name = + knot_dname_to_str( + knot_node_owner(node)); + log_zone_error("Node %s contains more " + "than one NSEC " + "record!\n", name); + knot_rrset_dump(nsec_rrset, 0); + free(name); */ + } + + /* + * Test that NSEC chain is coherent. + * We have already checked that every + * authoritative node contains NSEC record + * so checking should only be matter of testing + * the next link in each node. + */ + + if (nsec_rrset != NULL) { + knot_dname_t *next_domain = + knot_rdata_item( + knot_rrset_rdata(nsec_rrset), + 0)->dname; + + assert(next_domain); + + if (knot_zone_contents_find_node(zone, next_domain) == + NULL) { + err_handler_handle_error(handler, + node, + ZC_ERR_NSEC_RDATA_CHAIN); + /* CLEANUP */ +/* log_zone_error("NSEC chain is not " + "coherent!\n"); */ + } + + if (knot_dname_compare(next_domain, + knot_node_owner(knot_zone_contents_apex(zone))) + == 0) { + /* saving the last node */ + *last_node = node; + } + + } + } else if (nsec3 && (auth || deleg)) { /* nsec3 */ + int ret = check_nsec3_node_in_zone(zone, node, + handler); + if (ret != KNOT_EOK) { + free(rrsets); + return ret; + } + } + } + free(rrsets); + + return KNOT_EOK; +} + +/*! + * \brief Function called by zone traversal function. Used to call + * knot_zone_save_enclosers. + * + * \param node Node to be searched. + * \param data Arguments. + */ +static void do_checks_in_tree(knot_node_t *node, void *data) +{ + assert(data != NULL); + arg_t *args = (arg_t *)data; + + knot_rrset_t **rrsets = knot_node_get_rrsets(node); + short count = knot_node_rrset_count(node); + + assert(count == 0 || rrsets != NULL); + + knot_zone_contents_t *zone = (knot_zone_contents_t *)args->arg1; + + assert(zone); + + +/* for (int i = 0; i < count; ++i) { + assert(rrsets[i] != NULL); + knot_zone_save_enclosers_rrset(rrsets[i], + zone, + (skip_list_t *)args->arg2); + } */ + + knot_node_t *first_node = (knot_node_t *)args->arg4; + knot_node_t **last_node = (knot_node_t **)args->arg5; + + err_handler_t *handler = (err_handler_t *)args->arg6; + + char do_checks = *((char *)(args->arg3)); + + if (do_checks) { + semantic_checks_plain(zone, node, do_checks, handler); + } + + if (do_checks > 1) { + semantic_checks_dnssec(zone, node, first_node, last_node, + handler, do_checks == 3); + } + + free(rrsets); +} + +/*! + * \brief Helper function - wraps its arguments into arg_t structure and + * calls function that does the actual work. + * + * \param zone Zone to be searched / checked + * \param list Skip list of closests enclosers. + * \param do_checks Level of semantic checks. + * \param handler Semantic error handler. + * \param last_node Last checked node, which is part of NSEC(3) chain. + */ +void zone_do_sem_checks(knot_zone_contents_t *zone, char do_checks, + err_handler_t *handler, + knot_node_t **last_node) +{ + if (!do_checks) { + return; + } + + arg_t arguments; + arguments.arg1 = zone; + arguments.arg3 = &do_checks; + arguments.arg4 = NULL; + arguments.arg5 = last_node; + arguments.arg6 = handler; + + knot_zone_contents_tree_apply_inorder(zone, + do_checks_in_tree, + (void *)&arguments); +} + +static inline int fwrite_to_file_crc(const void *src, + size_t size, size_t n, FILE *f, + crc_t *crc) +{ + size_t rc = fwrite(src, size, n, f); + if (rc != n) { + fprintf(stderr, "fwrite: invalid write %zu (expected %zu)\n", rc, + n); + } + /* \todo this seems to be wrong, if you fwrite less than n items, you probably should not continue */ + + if (size * n > 0) { + *crc = + crc_update(*crc, (unsigned char *)src, + size * n); + } + + /* \todo the rc return is certainly wrong as it is used in the caller function */ +// return rc == n; + return (int)rc; + +} + +static inline int fwrite_to_stream(const void *src, + size_t size, size_t n, + uint8_t **stream, + size_t *stream_size) +{ + /* Resize the stream */ + void *tmp = realloc(*stream, + (*stream_size + (size * n)) * sizeof(uint8_t)); + if (tmp != NULL) { + *stream = tmp; + memcpy(*stream + *stream_size, src, + size * n); + *stream_size += (size * n) * sizeof(uint8_t); + return KNOT_EOK; + } else { + free(*stream); + return KNOT_ENOMEM; + } + + return KNOT_EOK; +} + +static int fwrite_wrapper(const void *src, + size_t size, size_t n, FILE *fp, + uint8_t **stream, size_t *stream_size, crc_t *crc) +{ + if (fp == NULL) { + assert(stream && stream_size); + assert(crc == NULL); + return fwrite_to_stream(src, size, n, stream, stream_size); + } else { + assert(stream == NULL && stream_size == NULL); + return fwrite_to_file_crc(src, size, n, fp, crc); + } +} + +/*! + * \brief Dumps dname labels in binary format to given file. + * + * \param dname Dname whose labels are to be dumped. + * \param f Output file. + */ +static void knot_labels_dump_binary(const knot_dname_t *dname, FILE *f, + uint8_t **stream, size_t *stream_size, + crc_t *crc) +{ + dbg_zdump("label count: %d\n", dname->label_count); + uint16_t label_count = dname->label_count; + /* \todo check the return value */ + fwrite_wrapper(&label_count, sizeof(label_count), 1, f, stream, + stream_size, crc); + /* \todo check the return value */ + fwrite_wrapper(dname->labels, sizeof(uint8_t), dname->label_count, f, + stream, stream_size, crc); +} + +/*! + * \brief Dumps dname in binary format to given file. + * + * \param dname Dname to be dumped. + * \param f Output file. + */ +static void knot_dname_dump_binary(const knot_dname_t *dname, FILE *f, + uint8_t **stream, size_t *stream_size, + crc_t *crc) +{ + uint32_t dname_size = dname->size; + /* \todo check the return value */ + fwrite_wrapper(&dname_size, sizeof(dname_size), 1, f, stream, + stream_size, crc); + /* \todo check the return value */ + fwrite_wrapper(dname->name, sizeof(uint8_t), dname->size, f, + stream, stream_size, crc); + dbg_zdump("dname size: %d\n", dname->size); + knot_labels_dump_binary(dname, f, stream, stream_size, crc); +} + +/*!< \todo some global variable indicating error! */ +static void dump_dname_with_id(const knot_dname_t *dname, FILE *f, + uint8_t **stream, size_t *stream_size, + crc_t *crc) +{ + uint32_t id = dname->id; + /* \todo check the return value */ + fwrite_wrapper(&id, sizeof(id), 1, f, stream, stream_size, crc); + knot_dname_dump_binary(dname, f, stream, stream_size, crc); +/* if (!fwrite_wrapper_safe(&dname->id, sizeof(dname->id), 1, f)) { + return KNOT_ERROR; + } */ +} + +/*! + * \brief Dumps given rdata in binary format to given file. + * + * \param rdata Rdata to be dumped. + * \param type Type of rdata. + * \param data Arguments to be propagated. + */ +static void knot_rdata_dump_binary(knot_rdata_t *rdata, + uint32_t type, void *data, int use_ids, + uint8_t **stream, size_t *stream_size, + crc_t *crc) +{ + FILE *f = (FILE *)((arg_t *)data)->arg1; + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + assert(desc != NULL); + + dbg_zdump("Dumping type: %d\n", type); + + if (desc->fixed_items) { + assert(desc->length == rdata->count); + } + + /* Write rdata count. */ + /* \todo check the return value */ + fwrite_wrapper(&(rdata->count), + sizeof(rdata->count), 1, f, stream, stream_size, crc); + + for (int i = 0; i < rdata->count; i++) { + if (&(rdata->items[i]) == NULL) { + dbg_zdump("Item n. %d is not set!\n", i); + continue; + } + dbg_zdump("Item n: %d\n", i); + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) { + /* some temp variables - this is way too long */ + assert(rdata->items[i].dname != NULL); + knot_dname_t *wildcard = NULL; + + if (rdata->items[i].dname->node != NULL && + rdata->items[i].dname->node->owner != + rdata->items[i].dname) { + wildcard = rdata->items[i].dname->node->owner; + } + + if (use_ids) { + /* Write ID. */ + dbg_zload("%s \n", + knot_dname_to_str(rdata->items[i].dname)); + assert(rdata->items[i].dname->id != 0); + + uint32_t id = rdata->items[i].dname->id; + /* \todo check the return value */ + fwrite_wrapper(&id, + sizeof(id), 1, f, stream, stream_size, + crc); + } else { +// assert(rdata->items[i].dname->id != 0); + dump_dname_with_id(rdata->items[i].dname, + f, stream, + stream_size, crc); + } + + /* Write in the zone bit */ + if (rdata->items[i].dname->node != NULL && !wildcard) { + /* \todo check the return value */ + fwrite_wrapper((uint8_t *)"\1", + sizeof(uint8_t), 1, f, stream, + stream_size, crc); + } else { + /* \todo check the return value */ + fwrite_wrapper((uint8_t *)"\0", sizeof(uint8_t), + 1, f, stream, stream_size, crc); + } + + if (use_ids && wildcard) { + /* \todo check the return value */ + fwrite_wrapper((uint8_t *)"\1", + sizeof(uint8_t), 1, f, stream, + stream_size, crc); + uint32_t wildcard_id = wildcard->id; + /* \todo check the return value */ + fwrite_wrapper(&wildcard_id, + sizeof(wildcard_id), 1, f, stream, + stream_size, crc); + } else { + /* \todo check the return value */ + fwrite_wrapper((uint8_t *)"\0", sizeof(uint8_t), + 1, f, stream, + stream_size, crc); + } + + } else { + dbg_zdump("Writing raw data. Item nr.: %d\n", + i); + assert(rdata->items[i].raw_data != NULL); + /* \todo check the return value */ + fwrite_wrapper(rdata->items[i].raw_data, + sizeof(uint8_t), + rdata->items[i].raw_data[0] + 2, f, + stream, stream_size, crc); + + dbg_zdump("Written %d long raw data\n", + rdata->items[i].raw_data[0]); + } + } +} + +/*! + * \brief Dumps RRSIG in binary format to given file. + * + * \param rrsig RRSIG to be dumped. + * \param data Arguments to be propagated. + */ +static void knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, arg_t *data, + int use_ids, + uint8_t **stream, size_t *stream_size, + crc_t *crc) +{ + dbg_zdump("Dumping rrset \\w owner: %s\n", + knot_dname_to_str(rrsig->owner)); + assert(rrsig->type == KNOT_RRTYPE_RRSIG); + assert(rrsig->rdata); + FILE *f = (FILE *)((arg_t *)data)->arg1; + /* \todo check the return value */ + fwrite_wrapper(&rrsig->type, sizeof(rrsig->type), 1, f, + stream, stream_size, crc); + fwrite_wrapper(&rrsig->rclass, sizeof(rrsig->rclass), 1, f, + stream, stream_size, crc); + fwrite_wrapper(&rrsig->ttl, sizeof(rrsig->ttl), 1, f, + stream, stream_size, crc); + + uint32_t rdata_count = 1; + /* Calculate rrset rdata count. */ + knot_rdata_t *tmp_rdata = rrsig->rdata; + while(tmp_rdata->next != rrsig->rdata) { + tmp_rdata = tmp_rdata->next; + rdata_count++; + } + + fwrite_wrapper(&rdata_count, sizeof(rdata_count), 1, f, + stream, stream_size, crc); + + tmp_rdata = rrsig->rdata; + while (tmp_rdata->next != rrsig->rdata) { + knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, data, + use_ids, stream, stream_size, crc); + tmp_rdata = tmp_rdata->next; + } + knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, data, use_ids, + stream, stream_size, crc); +} + +/*! + * \brief Dumps RRSet in binary format to given file. + * + * \param rrset RRSSet to be dumped. + * \param data Arguments to be propagated. + */ +static void knot_rrset_dump_binary(const knot_rrset_t *rrset, void *data, + int use_ids, + uint8_t **stream, size_t *stream_size, + crc_t *crc) +{ + FILE *f = (FILE *)((arg_t *)data)->arg1; + + if (!use_ids) { + dump_dname_with_id(rrset->owner, f, stream, stream_size, crc); + } + + /* \todo check the return value */ + fwrite_wrapper(&rrset->type, sizeof(rrset->type), 1, f, + stream, stream_size, crc); + fwrite_wrapper(&rrset->rclass, sizeof(rrset->rclass), 1, f, + stream, stream_size, crc); + fwrite_wrapper(&rrset->ttl, sizeof(rrset->ttl), 1, f, + stream, stream_size, crc); + + uint32_t rdata_count = 1; + uint8_t has_rrsig = rrset->rrsigs != NULL; + + /* Calculate rrset rdata count. */ + knot_rdata_t *tmp_rdata = rrset->rdata; + while(tmp_rdata->next != rrset->rdata) { + tmp_rdata = tmp_rdata->next; + rdata_count++; + } + + fwrite_wrapper(&rdata_count, sizeof(rdata_count), 1, f, + stream, stream_size, crc); + fwrite_wrapper(&has_rrsig, sizeof(has_rrsig), 1, f, + stream, stream_size, crc); + + tmp_rdata = rrset->rdata; + + while (tmp_rdata->next != rrset->rdata) { + knot_rdata_dump_binary(tmp_rdata, rrset->type, data, use_ids, + stream, stream_size, crc); + tmp_rdata = tmp_rdata->next; + } + knot_rdata_dump_binary(tmp_rdata, rrset->type, data, use_ids, + stream, stream_size, crc); + + /* This is now obsolete, although I'd rather not use recursion - that + * would probably not work */ + + if (rrset->rrsigs != NULL) { + knot_rrsig_set_dump_binary(rrset->rrsigs, data, use_ids, + stream, stream_size, crc); + } +} + +/*! + * \brief Dumps all RRSets in node to file in binary format. + * + * \param node Node to dumped. + * \param data Arguments to be propagated. + */ +static void knot_node_dump_binary(knot_node_t *node, void *data, + uint8_t **stream, size_t *stream_size, + crc_t *crc) +{ + arg_t *args = (arg_t *)data; + FILE *f = (FILE *)args->arg1; + +// node_count++; + /* first write dname */ + assert(node->owner != NULL); + + /* Write owner ID. */ + dbg_zdump("Dumping node owned by %s\n", + knot_dname_to_str(node->owner)); + assert(node->owner->id != 0); + uint32_t owner_id = node->owner->id; + /* \todo check the return value */ + fwrite_wrapper(&owner_id, sizeof(owner_id), 1, f, stream, stream_size, + crc); + + if (knot_node_parent(node, 0) != NULL) { + uint32_t parent_id = knot_dname_id( + knot_node_owner(knot_node_parent(node, 0))); + fwrite_wrapper(&parent_id, sizeof(parent_id), 1, f, + stream, stream_size, crc); + } else { + uint32_t parent_id = 0; + fwrite_wrapper(&parent_id, sizeof(parent_id), 1, f, + stream, stream_size, crc); + } + + fwrite_wrapper(&(node->flags), sizeof(node->flags), 1, f, + stream, stream_size, crc); + + dbg_zdump("Written flags: %u\n", node->flags); + + if (knot_node_nsec3_node(node, 0) != NULL) { + uint32_t nsec3_id = + knot_node_owner(knot_node_nsec3_node(node, 0))->id; + fwrite_wrapper(&nsec3_id, sizeof(nsec3_id), 1, f, + stream, stream_size, crc); + dbg_zdump("Written nsec3 node id: %u\n", + knot_node_owner(knot_node_nsec3_node(node, 0))->id); + } else { + uint32_t nsec3_id = 0; + fwrite_wrapper(&nsec3_id, sizeof(nsec3_id), 1, f, + stream, stream_size, crc); + } + + /* Now we need (or do we?) count of rrsets to be read + * but that number is yet unknown */ + + uint16_t rrset_count = node->rrset_count; + fwrite_wrapper(&rrset_count, sizeof(rrset_count), 1, f, + stream, stream_size, crc); + + /* CLEANUP */ +// const skip_node_t *skip_node = skip_first(node->rrsets); + + const knot_rrset_t **node_rrsets = knot_node_rrsets(node); + for (int i = 0; i < rrset_count; i++) + { + knot_rrset_dump_binary(node_rrsets[i], data, 1, + stream, stream_size, crc); + } + + /* CLEANUP */ +// if (skip_node == NULL) { +// /* we can return, count is set to 0 */ +// return; +// } + +// knot_rrset_t *tmp; + +// do { +// tmp = (knot_rrset_t *)skip_node->value; +// knot_rrset_dump_binary(tmp, data, 1); +// } while ((skip_node = skip_next(skip_node)) != NULL); + + free(node_rrsets); + + dbg_zdump("Position after all rrsets: %ld\n", ftell(f)); + dbg_zdump("Writing here: %ld\n", ftell(f)); + dbg_zdump("Function ends with: %ld\n\n", ftell(f)); +} + +/*! + * \brief Checks if zone uses DNSSEC and/or NSEC3 + * + * \param zone Zone to be checked. + * + * \retval 0 if zone is not secured. + * \retval 2 if zone uses NSEC3 + * \retval 1 if zone uses NSEC + */ +static int zone_is_secure(knot_zone_contents_t *zone) +{ + if (knot_node_rrset(knot_zone_contents_apex(zone), + KNOT_RRTYPE_DNSKEY) == NULL) { + return 0; + } else { + if (knot_node_rrset(knot_zone_contents_apex(zone), + KNOT_RRTYPE_NSEC3PARAM) != NULL) { + return 2; + } else { + return 1; + } + } +} + +/*! + * \brief Checks if last node in NSEC/NSEC3 chain points to first node in the + * chain and prints possible errors. + * + * \param handler Semantic error handler. + * \param zone Current zone. + * \param last_node Last node in NSEC/NSEC3 chain. + * \param do_checks Level of semantic checks. + */ +static void log_cyclic_errors_in_zone(err_handler_t *handler, + knot_zone_contents_t *zone, + knot_node_t *last_node, + const knot_node_t *first_nsec3_node, + const knot_node_t *last_nsec3_node, + char do_checks) +{ + if (do_checks == 3) { + /* Each NSEC3 node should only contain one RRSET. */ + assert(last_nsec3_node && first_nsec3_node); + const knot_rrset_t *nsec3_rrset = + knot_node_rrset(last_nsec3_node, + KNOT_RRTYPE_NSEC3); + if (nsec3_rrset == NULL) { + err_handler_handle_error(handler, last_nsec3_node, + ZC_ERR_NSEC3_RDATA_CHAIN); + return; + } + + /* check that next dname is in the zone */ + uint8_t *next_dname_decoded = NULL; + size_t real_size = 0; + + if (((real_size = base32hex_encode_alloc(((char *) + rdata_item_data(&(nsec3_rrset->rdata->items[4]))) + 1, + rdata_item_size(&nsec3_rrset->rdata->items[4]) - 1, + (char **)&next_dname_decoded)) <= 0) || + (next_dname_decoded == NULL)) { + fprintf(stderr, "Could not encode base32 string!\n"); + err_handler_handle_error(handler, last_nsec3_node, + ZC_ERR_NSEC3_RDATA_CHAIN); + return; + } + + /* This is why allocate maximum length of decoded string + 1 */ + memmove(next_dname_decoded + 1, next_dname_decoded, real_size); + next_dname_decoded[0] = real_size; + + /* Local allocation, will be discarded. */ + knot_dname_t *next_dname = + knot_dname_new_from_wire(next_dname_decoded, + real_size + 1, NULL); + if (next_dname == NULL) { + fprintf(stderr, "Could not allocate dname!\n"); + err_handler_handle_error(handler, last_nsec3_node, + ZC_ERR_ALLOC); + return; + } + + free(next_dname_decoded); + + /*! \todo Free result and dname! */ + if (knot_dname_cat(next_dname, + knot_node_owner(knot_zone_contents_apex(zone))) == + NULL) { + fprintf(stderr, "Could not concatenate dnames!\n"); + err_handler_handle_error(handler, last_nsec3_node, + ZC_ERR_NSEC3_RDATA_CHAIN); + return; + } + + /* Check it points somewhere first. */ + if (knot_zone_contents_find_nsec3_node(zone, next_dname) == NULL) { + err_handler_handle_error(handler, last_nsec3_node, + ZC_ERR_NSEC3_RDATA_CHAIN); + } + + /* Compare with the actual first NSEC3 node. */ + if (knot_dname_compare(first_nsec3_node->owner, + next_dname) != 0) { + err_handler_handle_error(handler, last_nsec3_node, + ZC_ERR_NSEC3_RDATA_CHAIN); + } + + /* Directly discard. */ + knot_dname_free(&next_dname); + + } else if (do_checks == 2 ) { + if (last_node == NULL) { + err_handler_handle_error(handler, last_node, + ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC); + return; + } else { + const knot_rrset_t *nsec_rrset = + knot_node_rrset(last_node, + KNOT_RRTYPE_NSEC); + + if (nsec_rrset == NULL) { + err_handler_handle_error(handler, last_node, + ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC); + return; + } + + const knot_dname_t *next_dname = + knot_rdata_item( + knot_rrset_rdata(nsec_rrset), 0)->dname; + assert(next_dname); + + const knot_dname_t *apex_dname = + knot_node_owner(knot_zone_contents_apex(zone)); + assert(apex_dname); + + if (knot_dname_compare(next_dname, apex_dname) !=0) { + err_handler_handle_error(handler, last_node, + ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC); + } + } + } +} + +/*! + * \brief Safe wrapper around fwrite. + * + * \param dst Destination pointer. + * \param size Size of element to be written. + * \param n Number of elements to be written. + * \param fp File to write to. + * + * \retval > 0 if succesfull. + * \retval 0 if failed. + */ +//static inline int fwrite_wrapper_safe(const void *src, +// size_t size, size_t n, FILE *fp) +//{ +// int rc = fwrite_wrapper(src, size, n, fp); +// if (rc != n) { +// fprintf(stderr, "fwrite_wrapper: invalid write %d (expected %zu)\n", rc, +// n); +// } + +// return rc == n; +//} + +static void dump_dname_from_tree(knot_dname_t *dname, + void *data) +{ + arg_t *arg = (arg_t *)data; + FILE *f = (FILE *)arg->arg1; + crc_t *crc = (crc_t*)arg->arg2; + dump_dname_with_id(dname, f, NULL, NULL, crc); +} + +static int knot_dump_dname_table(const knot_dname_table_t *dname_table, + FILE *f, crc_t *crc) +{ + arg_t arg; + arg.arg1 = f; + arg.arg2 = crc; + /* Go through the tree and dump each dname along with its ID. */ + knot_dname_table_tree_inorder_apply(dname_table, + dump_dname_from_tree, &arg); + /* CLEANUP */ +// TREE_FORWARD_APPLY(dname_table->tree, dname_table_node, avl, +// dump_dname_from_tree, (void *)f); + + return KNOT_EOK; +} + +static void save_node_from_tree(knot_node_t *node, void *data) +{ + arg_t *arg = (arg_t *)data; + /* Increment node count */ + (*((uint32_t *)(arg->arg1)))++; + /* Save the first node only */ + if (arg->arg2 == NULL) { + arg->arg2 = (void *)node; + } + arg->arg3 = (void *)node; +} + +static void dump_node_to_file(knot_node_t *node, void *data) +{ + arg_t *arg = (arg_t *)data; + knot_node_dump_binary(node, data, NULL, NULL, (crc_t *)arg->arg7); +} + +int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename, + int do_checks, const char *sfilename) +{ + /* Open .new file. */ + char new_path[strlen(filename) + strlen(".new") + 1]; + memcpy(new_path, filename, strlen(filename) + 1); + strcat(new_path, ".new"); + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + int fd = open(new_path, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (fd == -1) { + return KNOT_EBADARG; + } + + FILE *f = fdopen(fd, "wb"); + assert(f); + + /* CLEANUP */ +// skip_list_t *encloser_list = skip_create_list(compare_pointers); + arg_t arguments; + /* Memory to be derefenced in the save_node_from_tree function. */ + uint32_t node_count = 0; + arguments.arg1 = &node_count; + arguments.arg2 = NULL; + + /* Count number of normal nodes. */ + knot_zone_contents_tree_apply_inorder(zone, save_node_from_tree, &arguments); + /* arg1 is now count of normal nodes */ + uint32_t normal_node_count = *((uint32_t *)arguments.arg1); + + node_count = 0; + arguments.arg1 = &node_count; + arguments.arg2 = NULL; + + /* Count number of NSEC3 nodes. */ + knot_zone_contents_nsec3_apply_inorder(zone, save_node_from_tree, &arguments); + uint32_t nsec3_node_count = *((uint32_t *)arguments.arg1); + /* arg2 is the first NSEC3 node - used in sem checks. */ + /* arg3 is the last NSEC3 node - used in sem checks. */ + const knot_node_t *first_nsec3_node = (knot_node_t *)arguments.arg2; + const knot_node_t *last_nsec3_node = (knot_node_t *)arguments.arg3; + + if (do_checks && zone_is_secure(zone)) { + do_checks += zone_is_secure(zone); + } + + err_handler_t *handler = NULL; + + if (do_checks) { + handler = handler_new(1, 0, 1, 1, 1); + if (handler == NULL) { + /* disable checks and we can continue */ + do_checks = 0; + } else { /* Do check for SOA right now */ + if (knot_node_rrset(knot_zone_contents_apex(zone), + KNOT_RRTYPE_SOA) == NULL) { + err_handler_handle_error(handler, + knot_zone_contents_apex(zone), + ZC_ERR_MISSING_SOA); + } + } + + knot_node_t *last_node = NULL; + + zone_do_sem_checks(zone, do_checks, handler, &last_node); + log_cyclic_errors_in_zone(handler, zone, last_node, + first_nsec3_node, last_nsec3_node, + do_checks); + err_handler_log_all(handler); + free(handler); + } + + crc_t crc = crc_init(); + + /* Start writing header - magic bytes. */ + static const uint8_t MAGIC[MAGIC_LENGTH] = MAGIC_BYTES; + fwrite_wrapper(&MAGIC, sizeof(uint8_t), MAGIC_LENGTH, f, NULL, NULL, + &crc); + + /* Write source file length. */ + uint32_t sflen = 0; + if (sfilename) { + sflen = strlen(sfilename) + 1; + } + fwrite_wrapper(&sflen, sizeof(uint32_t), 1, f, NULL, NULL, &crc); + + /* Write source file. */ + fwrite_wrapper(sfilename, sflen, 1, f, NULL, NULL, &crc); + + /* Notice: End of header, + */ + + /* Start writing compiled data. */ + fwrite_wrapper(&normal_node_count, sizeof(normal_node_count), 1, f, + NULL, NULL, &crc); + fwrite_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, f, + NULL, NULL, &crc); + uint32_t auth_node_count = zone->node_count; + fwrite_wrapper(&auth_node_count, + sizeof(auth_node_count), 1, f, NULL, NULL, &crc); + + /* Write total number of dnames */ + assert(zone->dname_table); + uint32_t total_dnames = zone->dname_table->id_counter; + fwrite_wrapper(&total_dnames, + sizeof(total_dnames), 1, f, NULL, NULL, &crc); + + /* Write dname table. */ + if (knot_dump_dname_table(zone->dname_table, f, &crc) + != KNOT_EOK) { + return KNOT_ERROR; + } + + arguments.arg1 = (void *)f; + arguments.arg3 = zone; + arguments.arg7 = &crc; + + /* TODO is there a way how to stop the traversal upon error? */ + knot_zone_contents_tree_apply_inorder(zone, dump_node_to_file, + (void *)&arguments); + + knot_zone_contents_nsec3_apply_inorder(zone, dump_node_to_file, + (void *)&arguments); + fclose(f); + + crc = crc_finalize(crc); + /* Write CRC to separate .crc file. */ + /*!< \todo There is now function doing this. */ + char *crc_path = + malloc(sizeof(char) * (strlen(filename) + strlen(".crc") + 1)); + if (unlikely(!crc_path)) { + close(fd); + return KNOT_ENOMEM; + } + memset(crc_path, 0, + sizeof(char) * (strlen(filename) + strlen(".crc") + 1)); + memcpy(crc_path, filename, sizeof(char) * strlen(filename)); + + crc_path = strcat(crc_path, ".crc"); + FILE *f_crc = fopen(crc_path, "w"); + if (unlikely(!f_crc)) { + dbg_zload("knot_zload_open: failed to open '%s'\n", + crc_path); + close(fd); + free(crc_path); + return ENOENT; + } + free(crc_path); + + fprintf(f_crc, "%lu\n", (unsigned long)crc); + fclose(f_crc); + + close(fd); + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + fd = open(filename, O_WRONLY | O_CREAT, mode); + if (fd == -1) { + fprintf(stderr, "%s\n", strerror(errno)); + fprintf(stderr, "Could not open destination file! Use '%s' " + "file instead.\n", new_path); + return KNOT_ERROR; + } + + /* Try to obtain exclusive lock for originally given file. */ + if (fcntl(fd, F_SETLK, knot_file_lock(F_WRLCK, SEEK_SET)) == -1) { + fprintf(stderr, "Could not lock destination file for write! " + "Use '%s' file instead.\n", new_path); + close(fd); + return KNOT_ERROR; + } + + /* Move .new file to original file. */ + if (rename(new_path, filename) != 0) { + fprintf(stderr, "Could not move to originally given file! " + "Use '%s' file instead.\n", new_path); + close(fd); + return KNOT_ERROR; + } + + /* Release the lock. */ + if (fcntl(fd, F_SETLK, knot_file_lock(F_UNLCK, SEEK_SET)) == -1) { + fprintf(stderr, "Could not unlock destination file!\n"); + return KNOT_ERROR; + } + + close(fd); + + return KNOT_EOK; +} + +int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, + size_t *size) +{ + if (stream == NULL || *stream != NULL || rrset == NULL || + size == NULL) { + return KNOT_EBADARG; + } + + *size = 0; + arg_t arguments; + memset(&arguments, 0, sizeof(arg_t)); + + knot_rrset_dump_binary(rrset, &arguments, 0, stream, size, NULL); + + return KNOT_EOK; +} + +static char *knot_zdump_crc_file(const char* filename) +{ + char *crc_path = + malloc(sizeof(char) * (strlen(filename) + + strlen(".crc") + 1)); + CHECK_ALLOC_LOG(crc_path, NULL); + memset(crc_path, 0, + sizeof(char) * (strlen(filename) + + strlen(".crc") + 1)); + memcpy(crc_path, filename, + sizeof(char) * strlen(filename)); + crc_path = strcat(crc_path, ".crc"); + return crc_path; +} + +int knot_zdump_dump_and_swap(knot_zone_contents_t *zone, + const char *temp_zonedb, + const char *destination_zonedb, + const char *sfilename) +{ + int rc = knot_zdump_binary(zone, temp_zonedb, 0, sfilename); + + if (rc != KNOT_EOK) { + dbg_zdump("Failed to save the zone to binary zone db %s." + "\n", temp_zonedb); + return KNOT_ERROR; + } + + /*! \todo this would also need locking as well. */ + rc = remove(destination_zonedb); + if (rc == 0 || (rc != 0 && errno == ENOENT)) { + + /* Delete old CRC file. */ + char *destination_zonedb_crc = + knot_zdump_crc_file(destination_zonedb); + if (destination_zonedb_crc == NULL) { + return KNOT_ENOMEM; + } + remove(destination_zonedb_crc); + + /* Move CRC file. */ + char *temp_zonedb_crc = + knot_zdump_crc_file(temp_zonedb); + if (temp_zonedb_crc == NULL) { + return KNOT_ENOMEM; + } + + if (rename(temp_zonedb_crc, destination_zonedb_crc) != 0) { + dbg_zdump("Failed to replace old zonedb CRC %s " + "with new CRC zone file %s.\n", + destination_zonedb_crc, + temp_zonedb_crc); + return KNOT_ERROR; + } + free(temp_zonedb_crc); + free(destination_zonedb_crc); + + /* Rename zonedb. */ + if (rename(temp_zonedb, destination_zonedb) != 0) { + dbg_zdump("Failed to replace old zonedb %s " + "with new zone file %s.\n", + temp_zonedb, + destination_zonedb); + /*! \todo with proper locking, this shouldn't happen, + * revise it later on. + */ + return KNOT_ERROR; + } + } else { + dbg_zdump("Failed to replace old zonedb '%s'', %s.\n", + destination_zonedb, strerror(errno)); + return KNOT_ERROR; + } + + return KNOT_EOK; +} diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h new file mode 100644 index 0000000..daf6c18 --- /dev/null +++ b/src/knot/zone/zone-dump.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file zone-dump.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief Functions for dumping zone to binary file. + * + * \addtogroup dnslib + * @{ + */ + +#ifndef _KNOT_ZONEDUMP_H_ +#define _KNOT_ZONEDUMP_H_ + +#include "common/crc.h" +#include "libknot/zone/zone.h" + +/*! + * \brief Zone loader enums. + */ +enum { + MAGIC_LENGTH = 7 /*!< Compiled zone magic length. */ +}; + +/*! \brief Magic identifier: { "knot", maj_ver, min_ver, revision } */ +#define MAGIC_BYTES {'k', 'n', 'o', 't', '0', '8', '0'} + +/*! + * \brief Dumps given zone to binary file. + * + * \param zone Zone to be saved. + * \param filename Name of file to be created. + * \param do_checks Set to 1 to enable checking the zone for semantic errors. + * \param sfilename Source filename of the text zone file. + * + * \retval KNOT_EOK on success. + * \retval KNOT_EBADARG if the file cannot be opened for writing. + */ +int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename, + int do_checks, const char *sfilename); + +/*! + * \brief Serializes RRSet into binary stream. Expects NULL pointer, memory + * is handled inside function. + * + * \param rrset RRSet to be serialized. + * \param stream Stream containing serialized RRSet. + * \param size Length of created stream. + * + * \retval KNOT_EOK on success. + * \retval KNOT_EBADARG if wrong arguments are supplied. + * \retval KNOT_ENOMEM on memory error. + */ +int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, + size_t *size); + +/*! + * \brief Serializes RRSet into binary stream. Expects NULL pointer, memory + * is handled inside function. + * + * \param rrset RRSet to be serialized. + * \param stream Stream containing serialized RRSet. + * \param size Length of created stream. + * + * \retval KNOT_EOK on success. + * \retval KNOT_EBADARG if wrong arguments are supplied. + * \retval KNOT_ENOMEM on memory error. + */ +int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, + size_t *size); + +int knot_zdump_dump_and_swap(knot_zone_contents_t *zone, + const char *temp_zonedb, + const char *destination_zonedb, + const char *sfilename); + +#endif /* _KNOT_ZONEDUMP_H_ */ + +/*! @} */ diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c new file mode 100644 index 0000000..9ab0e8d --- /dev/null +++ b/src/knot/zone/zone-load.c @@ -0,0 +1,1209 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/stat.h> +#include <time.h> + +#include "common/crc.h" +#include "libknot/common.h" +#include "knot/other/debug.h" +#include "knot/zone/zone-load.h" +#include "knot/zone/zone-dump.h" +#include "libknot/libknot.h" + +/*! + * \brief Compares two time_t values. + * + * \param x First time_t value to be compared. + * \param y Second time_t value to be compared. + * + * \retval 0 when times are the some. + * \retval 1 when y < x. + * \retval -1 when x > y. + */ +static int timet_cmp(time_t x, time_t y) +{ + /* Calculate difference in the scale of seconds. */ + long diff = x - y; + + /* X and Y are equal. */ + if (diff == 0) { + return 0; + } + + /* X is newer. */ + if (diff > 0) { + return 1; + } + + /* Y is newer. */ + return -1; +} + +/*! + * \brief Safe wrapper around fread. + * + * \param dst Destination pointer. + * \param size Size of element to be read. + * \param n Number of elements to be read. + * \param fp File to read from. + * + * \retval > 0 if succesfull. + * \retval 0 if failed. + */ +static inline int fread_safe_from_file(void *dst, + size_t size, size_t n, FILE *fp) +{ + int rc = fread(dst, size, n, fp); + if (rc != n) { + fprintf(stderr, "fread: invalid read %d (expected %zu)\n", rc, + n); + } + + return rc == n; +} + +static uint8_t *knot_zload_stream = NULL; +static size_t knot_zload_stream_remaining = 0; +static size_t knot_zload_stream_size = 0; + +static inline int read_from_stream(void *dst, + size_t size, size_t n, FILE *fp) +{ + if (knot_zload_stream_remaining < (size * n)) { + return 0; + } + + memcpy(dst, + knot_zload_stream + + (knot_zload_stream_size - knot_zload_stream_remaining), + size * n); + knot_zload_stream_remaining -= size * n; + + return 1; +} + +static int (*fread_wrapper)(void *dst, size_t size, size_t n, FILE *fp); + +/*! \note Contents of dump file: + * MAGIC(knotxx) NUMBER_OF_NORMAL_NODES NUMBER_OF_NSEC3_NODES + * [normal_nodes] [nsec3_nodes] + * node has following format: + * owner_size owner_wire owner_label_size owner_labels owner_id + * node_flags node_rrset_count [node_rrsets] + * rrset has following format: + * rrset_type rrset_class rrset_ttl rrset_rdata_count rrset_rrsig_count + * [rrset_rdata] [rrset_rrsigs] + * rdata can either contain full dnames (that is with labels but without ID) + * or dname ID, if dname is in the zone + * or raw data stored like this: data_len [data] + */ + +enum { DNAME_MAX_WIRE_LENGTH = 256 }; + +/*! + * \brief Helper function. Frees rdata items and temporary array of items. + * + * \param rdata Rdata to be freed. + * \param items Items to be freed. + * \param count Current count of rdata items. + * \param type RRSet type. + */ +static void load_rdata_purge(knot_rdata_t *rdata, + knot_rdata_item_t *items, + int count, + knot_rrtype_descriptor_t *desc, + uint16_t type) +{ + /* Increase refcount manually, as the set_items() doesn't see the dname + * type and thus is unable to increment refcounter. + */ + for (int i = 0; i < count; ++i) { + switch(desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: + knot_dname_retain(items[i].dname); + break; + default: + break; + } + } + + /* Copy items to rdata and free the temporary rdata. */ + knot_rdata_set_items(rdata, items, count); + knot_rdata_deep_free(&rdata, type, 1); + free(items); +} + +static knot_dname_t *read_dname_with_id(FILE *f) +{ + knot_dname_t *ret = knot_dname_new(); + CHECK_ALLOC_LOG(ret, NULL); + + /* Read ID. */ + uint32_t dname_id = 0; + if (!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) { + knot_dname_release(ret); + return NULL; + } + + ret->id = dname_id; + dbg_zload("loaded: dname id: %u\n", dname_id); + + /* Read size of dname. */ + uint32_t dname_size = 0; + if (!fread_wrapper(&dname_size, sizeof(dname_size), 1, f)) { + knot_dname_release(ret); + return NULL; + } + ret->size = dname_size; + dbg_zload("loaded: dname length: %u\n", ret->size); + + assert(ret->size <= DNAME_MAX_WIRE_LENGTH); + + /* Read wireformat of dname. */ + ret->name = malloc(sizeof(uint8_t) * ret->size); + if (ret->name == NULL) { + ERR_ALLOC_FAILED; + knot_dname_release(ret); + return NULL; + } + + if (!fread_wrapper(ret->name, sizeof(uint8_t), ret->size, f)) { + knot_dname_release(ret); + return NULL; + } + + /* Read labels. */ + uint16_t label_count = 0; + if (!fread_wrapper(&label_count, sizeof(label_count), 1, f)) { + knot_dname_release(ret); + return NULL; + } + + ret->label_count = label_count; + + ret->labels = malloc(sizeof(uint8_t) * ret->label_count); + if (ret->labels == NULL) { + ERR_ALLOC_FAILED; + knot_dname_release(ret); + return NULL; + } + + if (!fread_wrapper(ret->labels, sizeof(uint8_t), ret->label_count, f)) { + free(ret->name); + free(ret); + return NULL; + } + + dbg_zload("loaded: %s (id: %d)\n", knot_dname_to_str(ret), + ret->id); + + return ret; +} + +/*! + * \brief Load rdata in binary format from file. + * + * \param type Type of RRSet containing read rdata. + * \param f File to read binary data from. + * + * \return Pointer to read and created rdata on success, NULL otherwise. + */ +static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, + knot_dname_t **id_array, + int use_ids) +{ + knot_rdata_t *rdata = knot_rdata_new(); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + assert(desc != NULL); + + + /* First, should read rdata count. */ + + uint32_t rdata_count = 0; + + if(!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { + return NULL; + } + + knot_rdata_item_t *items = + malloc(sizeof(knot_rdata_item_t) * rdata_count); + + if (desc->fixed_items) { + assert(desc->length == rdata_count); + } + + uint16_t raw_data_length; + + dbg_zload("Reading %d items\n", rdata_count); + + dbg_zload("current type: %s\n", knot_rrtype_to_string(type)); + + for (int i = 0; i < rdata_count; i++) { + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) { + + /* TODO maybe this does not need to be stored this big*/ + + uint32_t dname_id = 0; + uint8_t has_wildcard = 0; + uint8_t in_the_zone = 0; + + if (use_ids) { + if(!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) { + load_rdata_purge(rdata, items, i, desc, type); + return NULL; + } + + /* Store reference do dname. */ + knot_dname_retain(id_array[dname_id]); + items[i].dname = id_array[dname_id]; + } else { + items[i].dname = read_dname_with_id(f); + } + + if(!fread_wrapper(&in_the_zone, sizeof(in_the_zone), + 1, f)) { + load_rdata_purge(rdata, items, i, desc, type); + return NULL; + } + + if(!fread_wrapper(&has_wildcard, sizeof(uint8_t), + 1, f)) { + load_rdata_purge(rdata, items, i, desc, type); + return NULL; + } + + if (use_ids && has_wildcard) { + if(!fread_wrapper(&dname_id, sizeof(dname_id), + 1, f)) { + load_rdata_purge(rdata, items, + i, desc, type); + return NULL; + } + items[i].dname->node = + id_array[dname_id]->node; + } else if (use_ids && !in_the_zone) { /* destroy the node */ + if (id_array[dname_id]->node != NULL) { + knot_node_free(&id_array[dname_id]-> + node, 0, 0); + } + /* Also sets node to NULL! */ + } + assert(items[i].dname); + } else { + if (!fread_wrapper(&raw_data_length, + sizeof(raw_data_length), 1, f)) { + load_rdata_purge(rdata, items, i, desc, type); + return NULL; + } + + items[i].raw_data = + malloc(sizeof(uint8_t) * (raw_data_length + 2)); + items[i].raw_data[0] = raw_data_length; + + if (!fread_wrapper(items[i].raw_data + 1, sizeof(uint8_t), + raw_data_length, f)) { + load_rdata_purge(rdata, items, i + 1, desc, type); + return NULL; + } + dbg_zload("read raw_data len %d\n", raw_data_length); + } + } + + /* Each item has refcount already incremented for saving in rdata. */ + if (knot_rdata_set_items(rdata, items, rdata_count) != 0) { + fprintf(stderr, "zoneload: Could not set items " + "when loading rdata.\n"); + } + + free(items); + + dbg_zload("knot_load_rdata: all %d items read\n", + desc->length); + + assert(rdata->count == rdata_count); + + rdata->count = rdata_count; + + return rdata; +} + +/*! + * \brief Loads RRSIG from binary file. + * + * \param f File to read from. + * + * \return pointer to created and read RRSIG on success, NULL otherwise. + */ +static knot_rrset_t *knot_load_rrsig(FILE *f, knot_dname_t **id_array, + int use_ids) +{ + knot_rrset_t *rrsig; + + uint16_t rrset_type; + uint16_t rrset_class; + uint32_t rrset_ttl; + + uint32_t rdata_count; + + if (!fread_wrapper(&rrset_type, sizeof(rrset_type), 1, f)) { + return NULL; + } + + if (rrset_type != KNOT_RRTYPE_RRSIG) { + fprintf(stderr, "!! Error: rrsig has wrong type\n"); + return NULL; + } + dbg_zload("rrset type: %d\n", rrset_type); + if (!fread_wrapper(&rrset_class, sizeof(rrset_class), 1, f)) { + return NULL; + } + dbg_zload("rrset class %d\n", rrset_class); + + if (!fread_wrapper(&rrset_ttl, sizeof(rrset_ttl), 1, f)) { + return NULL; + } + dbg_zload("rrset ttl %d\n", rrset_ttl); + + if (!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { + return NULL; + } + + rrsig = knot_rrset_new(NULL, rrset_type, rrset_class, rrset_ttl); + + knot_rdata_t *tmp_rdata; + + dbg_zload("loading %d rdata entries\n", rdata_count); + + for (int i = 0; i < rdata_count; i++) { + tmp_rdata = knot_load_rdata(KNOT_RRTYPE_RRSIG, f, + id_array, use_ids); + if (tmp_rdata) { + knot_rrset_add_rdata(rrsig, tmp_rdata); + } else { + knot_rrset_deep_free(&rrsig, 0, 1, 1); + return NULL; + } + } + + return rrsig; +} + +/*! + * \brief Loads RRSet from binary file. + * + * \param f File to read from. + * + * \return pointer to created and read RRSet on success, NULL otherwise. + */ +static knot_rrset_t *knot_load_rrset(FILE *f, knot_dname_t **id_array, + int use_ids) +{ + knot_rrset_t *rrset = NULL; + + uint16_t rrset_type = 0; + uint16_t rrset_class = 0; + uint32_t rrset_ttl = 0; + + uint32_t rdata_count = 0; + uint8_t rrsig_count = 0; + + knot_dname_t *owner = NULL; + + if (!use_ids) { + dbg_zload("Loading owner of new RRSet from wire.\n"); + owner = read_dname_with_id(f); + } + + if (!fread_wrapper(&rrset_type, sizeof(rrset_type), 1, f)) { + return NULL; + } + dbg_zload("Zone load: rrset load: type: %u\n", rrset_type); + if (!fread_wrapper(&rrset_class, sizeof(rrset_class), 1, f)) { + return NULL; + } + dbg_zload("Zone load: rrset class: type: %u\n", rrset_class); + if (!fread_wrapper(&rrset_ttl, sizeof(rrset_ttl), 1, f)) { + return NULL; + } + dbg_zload("Zone load: rrset ttl: type: %u\n", rrset_ttl); + if (!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { + return NULL; + } + dbg_zload("Zone load: rrset load: rdata count: %u\n", rdata_count); + if (!fread_wrapper(&rrsig_count, sizeof(rrsig_count), 1, f)) { + return NULL; + } + dbg_zload("Zone load: rrset load: type: %u\n", rrset_type); + + dbg_zload("Loading RRSet owned by: %s\n", + knot_dname_to_str(owner)); + + rrset = knot_rrset_new(owner, rrset_type, rrset_class, rrset_ttl); + + if (!use_ids) { + /* Directly release if allocated locally. */ + knot_dname_release(owner); + owner = 0; + } + + dbg_zload("RRSet type: %d\n", rrset->type); + + knot_rdata_t *tmp_rdata = NULL; + + for (int i = 0; i < rdata_count; i++) { + tmp_rdata = knot_load_rdata(rrset->type, f, + id_array, use_ids); + if (tmp_rdata) { + knot_rrset_add_rdata(rrset, tmp_rdata); + } else { + knot_rrset_deep_free(&rrset, 0, 1, 1); + return NULL; + } + } + + knot_rrset_t *tmp_rrsig = NULL; + + dbg_zload("Reading: %d RRSIGs\n", rrsig_count); + if (rrsig_count) { + tmp_rrsig = knot_load_rrsig(f, id_array, use_ids); + if (!use_ids) { + knot_rrset_set_owner(tmp_rrsig, rrset->owner); + } + } + + knot_rrset_set_rrsigs(rrset, tmp_rrsig); + + dbg_zload("Finished loading RRSet %p\n", rrset); + + return rrset; +} + +/*! + * \brief Loads node from binary file. + * + * \param f File to read from. + * + * \return Pointer to created and read node on success, NULL otherwise. + */ +static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) +{ + uint8_t flags = 0; + knot_node_t *node = NULL; + uint32_t parent_id = 0; + uint32_t nsec3_node_id = 0; + uint16_t rrset_count = 0; + uint32_t dname_id = 0; + + /* At the beginning of node - just dname_id !!!.*/ + if (!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) { + return NULL; + } + + if (!fread_wrapper(&parent_id, sizeof(parent_id), 1, f)) { + return NULL; + } + + if (!fread_wrapper(&flags, sizeof(flags), 1, f)) { + return NULL; + } + + if (!fread_wrapper(&nsec3_node_id, sizeof(nsec3_node_id), 1, f)) { + return NULL; + } + + if (!fread_wrapper(&rrset_count, sizeof(rrset_count), 1, f)) { + return NULL; + } + knot_dname_t *owner = id_array[dname_id]; + + dbg_zload("Node owner id: %d\n", dname_id); + dbg_zload("Node owned by: %s\n", knot_dname_to_str(owner)); + dbg_zload("Number of RRSets in a node: %d\n", rrset_count); + + node = owner->node; + + if (node == NULL) { + fprintf(stderr, "zone: Could not create node.\n"); + return NULL; + } + /* XXX can it be 0, ever? I think not. */ + if (nsec3_node_id != 0) { + knot_node_set_nsec3_node(node, id_array[nsec3_node_id]->node); + /* CLEANUP */ +// node->nsec3_node = id_array[nsec3_node_id]->node; + } else { + knot_node_set_nsec3_node(node, NULL); + /* CLEANUP */ +// node->nsec3_node = NULL; + } + + /* Retain new owner while releasing replaced owner. */ + knot_node_set_owner(node, owner); + node->flags = flags; + + //XXX will have to be set already...canonical order should do it + + if (parent_id != 0) { + knot_node_set_parent(node, id_array[parent_id]->node); + assert(knot_node_parent(node, 0) != NULL); + } else { + knot_node_set_parent(node, NULL); + } + + knot_rrset_t *tmp_rrset; + + for (int i = 0; i < rrset_count; i++) { + if ((tmp_rrset = knot_load_rrset(f, id_array, 1)) == NULL) { + knot_node_free(&node, 1, 0); + //TODO what else to free? + fprintf(stderr, "zone: Could not load rrset.\n"); + return NULL; + } + /* Retain new owner while releasing replaced owner. */ + knot_rrset_set_owner(tmp_rrset, node->owner); + if (tmp_rrset->rrsigs != NULL) { + knot_rrset_set_owner(tmp_rrset->rrsigs, node->owner); + } + if (knot_node_add_rrset(node, tmp_rrset, 0) < 0) { + fprintf(stderr, "zone: Could not add rrset.\n"); + return NULL; + } + } + assert(node != NULL); + dbg_zload("Node loaded: %p\n", node); + return node; +} + +/*! + * \brief Finds and sets wildcard child for given node's owner. + * + * \param zone Current zone. + * \param node Node to be used. + * \param nsec3 Is NSEC3 node. + */ +static void find_and_set_wildcard_child(knot_zone_contents_t *zone, + knot_node_t *node, int nsec3) +{ + knot_dname_t *chopped = knot_dname_left_chop(node->owner); + assert(chopped); + knot_node_t *wildcard_parent; + if (!nsec3) { + wildcard_parent = + knot_zone_contents_get_node(zone, chopped); + } else { + wildcard_parent = + knot_zone_contents_get_nsec3_node(zone, chopped); + } + + /* Directly discard. */ + knot_dname_free(&chopped); + + assert(wildcard_parent); /* it *has* to be there */ + + knot_node_set_wildcard_child(wildcard_parent, node); +} + +/*! + * \brief Checks if magic string at the beginning of the file is the same + * as defined. + * + * \param f File to read magic string from. + * \param MAGIC Magic string. + * \param MAGIC_LENGTH Length of magic string. + * + * \retval 1 if magic is the same. + * \retval 0 otherwise. + */ +static int knot_check_magic(FILE *f, const uint8_t* MAGIC, uint MAGIC_LENGTH) +{ + uint8_t tmp_magic[MAGIC_LENGTH]; + + if (!fread_wrapper(&tmp_magic, sizeof(uint8_t), MAGIC_LENGTH, f)) { + return 0; + } + + for (int i = 0; i < MAGIC_LENGTH; i++) { + if (tmp_magic[i] != MAGIC[i]) { + return 0; + } + } + + return 1; +} + +static unsigned long calculate_crc(FILE *f) +{ + crc_t crc = crc_init(); + /* Get file size. */ + fseek(f, 0L, SEEK_END); + size_t file_size = ftell(f); + fseek(f, 0L, SEEK_SET); + + const size_t chunk_size = 1024; + /* read chunks of 1 kB */ + size_t read_bytes = 0; + /* Prealocate chunk */ + unsigned char *chunk = malloc(sizeof(unsigned char) * chunk_size); + CHECK_ALLOC_LOG(chunk, 0); + while ((file_size - read_bytes) > chunk_size) { + if (!fread_wrapper(chunk, sizeof(unsigned char), chunk_size, f)) { + free(chunk); + return 0; + } + crc = crc_update(crc, chunk, + sizeof(unsigned char) * chunk_size); + read_bytes += chunk_size; + } + + /* Read the rest of the file */ + if (!fread_wrapper(chunk, sizeof(unsigned char), file_size - read_bytes, + f)) { + free(chunk); + return 0; + } + + crc = crc_update(crc, chunk, + sizeof(unsigned char) * (file_size - read_bytes)); + free(chunk); + + fseek(f, 0L, SEEK_SET); + return (unsigned long)crc_finalize(crc); +} + +int knot_zload_open(zloader_t **dst, const char *filename) +{ + *dst = 0; + if (!dst || !filename) { + return KNOT_EBADARG; + } + + fread_wrapper = fread_safe_from_file; + + /* Open file for binary read. */ + FILE *f = fopen(filename, "rb"); + if (unlikely(!f)) { + dbg_zload("knot_zload_open: failed to open '%s'\n", + filename); + return KNOT_EFEWDATA; // No such file or directory (POSIX.1) + } + + /* Calculate CRC and compare with filename.crc file */ + unsigned long crc_calculated = calculate_crc(f); + + /* Read CRC from filename.crc file */ + char *crc_path = + malloc(sizeof(char) * (strlen(filename) + strlen(".crc") + 1)); + if (unlikely(!crc_path)) { + fclose(f); + return KNOT_ENOMEM; + } + memset(crc_path, 0, + sizeof(char) * (strlen(filename) + strlen(".crc") + 1)); + + memcpy(crc_path, filename, sizeof(char) * strlen(filename)); + + crc_path = strcat(crc_path, ".crc"); + FILE *f_crc = fopen(crc_path, "r"); + if (unlikely(!f_crc)) { + dbg_zload("knot_zload_open: failed to open '%s'\n", + crc_path); + fclose(f); + free(crc_path); + return KNOT_ECRC; + } + + unsigned long crc_from_file = 0; + if (fscanf(f_crc, "%lu\n", &crc_from_file) != 1) { + dbg_zload("knot_zload_open: could not read " + "CRC from file '%s'\n", + crc_path); + fclose(f_crc); + fclose(f); + free(crc_path); + return KNOT_ERROR; + } + free(crc_path); + fclose(f_crc); + + /* Compare calculated and read CRCs. */ + if (crc_from_file != crc_calculated) { + dbg_zload("knot_zload_open: CRC failed for " + "file '%s'\n", + filename); + fclose(f); + return KNOT_ECRC; + } + + /* Check magic sequence. */ + static const uint8_t MAGIC[MAGIC_LENGTH] = MAGIC_BYTES; + if (!knot_check_magic(f, MAGIC, MAGIC_LENGTH)) { + fclose(f); + dbg_zload("knot_zload_open: magic bytes " + "in don't match '%*s' " + "(%s)\n", + (int)MAGIC_LENGTH, (const char*)MAGIC, filename); + return KNOT_EMALF; // Illegal byte sequence (POSIX.1, C99) + } + + /* Read source file length. */ + uint32_t sflen = 0; + if (!fread_wrapper(&sflen, 1, sizeof(uint32_t), f)) { + dbg_zload("knot_zload_open: failed to read " + "sfile length\n"); + fclose(f); + return KNOT_ERROR; + } + + /* Read source file. */ + char *sfile = malloc(sflen); + if (!sfile) { + dbg_zload("knot_zload_open: invalid sfile " + "length %u\n", sflen); + fclose(f); + return KNOT_ENOMEM; + } + if (!fread_wrapper(sfile, 1, sflen, f)) { + dbg_zload("knot_zload_open: failed to read %uB " + "source file\n", + sflen); + free(sfile); + fclose(f); + return KNOT_ERROR; + } + + /* Allocate new loader. */ + zloader_t *zl = malloc(sizeof(zloader_t)); + if (!zl) { + free(sfile); + fclose(f); + return KNOT_ENOMEM; + } + + dbg_zload("knot_zload_open: opened '%s' as fp %p " + "(source is '%s')\n", + filename, f, sfile); + zl->filename = strdup(filename); + zl->source = sfile; + zl->fp = f; + *dst = zl; + + return KNOT_EOK; +} + +static void cleanup_id_array(knot_dname_t **id_array, + const uint from, const uint to) +{ + for (uint i = from; i < to; i++) { + knot_dname_release(id_array[i]); + } + + free(id_array); +} + +//static knot_dname_table_t *create_dname_table(FILE *f, uint max_id) +//{ +// if (f == NULL ) { +// return NULL; +// } + +// if (!fread_wrapper(&max_id, sizeof(max_id), 1, f)) { +// return NULL; +// } + +// knot_dname_table_t *dname_table = knot_dname_table_new(); +// if (dname_table == NULL) { +// return NULL; +// } + +// /* Create nodes containing dnames. */ +// for (uint i = 1; i < max_id; i++) { +// knot_dname_t *loaded_dname = read_dname_with_id(f); +// if (loaded_dname == NULL) { +// knot_dname_table_deep_free(&dname_table); +// return NULL; +// } +// if (knot_dname_table_add_dname(dname_table, +// loaded_dname) != KNOT_EOK) { + +// } +// } + +// return dname_table; +//} + +static knot_dname_table_t *create_dname_table_from_array( + knot_dname_t **array, uint max_id) +{ + if (array == NULL) { + /* should I set errno or what ... ? */ + dbg_zload("No array passed\n"); + return NULL; + } + + assert(array[0] == NULL); + + knot_dname_table_t *ret = knot_dname_table_new(); + CHECK_ALLOC_LOG(ret, NULL); + + /* Table will have max_id entries */ + for (uint i = 1; i < max_id; i++) { + assert(array[i]); + if (knot_dname_table_add_dname(ret, + array[i]) != KNOT_EOK) { + dbg_zload("Could not add: %s\n", + knot_dname_to_str(array[i])); + knot_dname_table_deep_free(&ret); + return NULL; + } + } + + return ret; +} + +static knot_dname_t **create_dname_array(FILE *f, uint max_id) +{ + if (f == NULL) { + return NULL; + } + + knot_dname_t **array = + malloc(sizeof(knot_dname_t *) * ( max_id + 1)); + memset(array, 0, sizeof(knot_dname_t *) * (max_id + 1)); + if (array == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + for (uint i = 0; i < max_id - 1; i++) { + knot_dname_t *read_dname = read_dname_with_id(f); + if (read_dname == NULL) { + cleanup_id_array(array, 0, i); + return NULL; + } + + if (read_dname->id < max_id) { + + /* Create new node from dname. */ + read_dname->node = knot_node_new(read_dname, NULL, 0); + + if (read_dname->node == NULL) { + ERR_ALLOC_FAILED; + + /* Release read dname. */ + knot_dname_release(read_dname); + cleanup_id_array(array, 0, i); + return NULL; + } + + /* Store reference to dname in array. */ + array[read_dname->id] = read_dname; + } else { + /* Release read dname. */ + knot_dname_release(read_dname); + cleanup_id_array(array, 0, i); + return NULL; + } + + } + + return array; +} + +knot_zone_t *knot_zload_load(zloader_t *loader) +{ + dbg_zload("Loading zone, loader: %p\n", loader); + if (!loader) { + dbg_zload("NULL loader!\n"); + return NULL; + } + + fread_wrapper = fread_safe_from_file; + + FILE *f = loader->fp; + + knot_node_t *tmp_node; + + /* Load the dname table. */ + /* CLEANUP */ +// const knot_dname_table_t *dname_table = +// create_dname_table(f, total_dnames); +// if (dname_table == NULL) { +// return NULL; +// } + + uint32_t node_count; + uint32_t nsec3_node_count; + uint32_t auth_node_count; + + if (!fread_wrapper(&node_count, sizeof(node_count), 1, f)) { + dbg_zload("wrong read!\n"); + return NULL; + } + + if (!fread_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, f)) { + dbg_zload("wrong read!\n"); + return NULL; + } + if (!fread_wrapper(&auth_node_count, + sizeof(auth_node_count), 1, f)) { + dbg_zload("wrong read!\n"); + return NULL; + } + dbg_zload("authoritative nodes: %u\n", auth_node_count); + + dbg_zload("loading %u nodes\n", node_count); + + uint32_t total_dnames = 0; + /* First, read number of dnames in dname table. */ + if (!fread_wrapper(&total_dnames, sizeof(total_dnames), 1, f)) { + return NULL; + } + + dbg_zload("total dname count: %d\n", total_dnames); + + /* Create id array. */ + knot_dname_t **id_array = create_dname_array(f, total_dnames); + if (id_array == NULL) { + return NULL; + } + + knot_dname_table_t *dname_table = + create_dname_table_from_array(id_array, total_dnames); + if (dname_table == NULL) { + ERR_ALLOC_FAILED; + cleanup_id_array(id_array, 1, total_dnames); + return NULL; + } + + knot_node_t *apex = knot_load_node(f, id_array); + + if (!apex) { + fprintf(stderr, "zone: Could not load apex node (in %s)\n", + loader->filename); + cleanup_id_array(id_array, 1, + node_count + nsec3_node_count + 1); + return NULL; + } + + dbg_zload("Apex node loaded: %p\n", apex); + + knot_zone_t *zone = knot_zone_new(apex, auth_node_count, 0); + if (zone == NULL) { + cleanup_id_array(id_array, 1, + node_count + nsec3_node_count + 1); + dbg_zload("Failed to create new zone from apex!\n"); + return NULL; + } + + knot_zone_contents_t *contents = knot_zone_get_contents(zone); + assert(contents); + + /* Assign dname table to the new zone. */ + contents->dname_table = dname_table; + + /* CLEANUP */ +// apex->prev = NULL; + knot_node_set_previous(apex, NULL); + + knot_node_t *last_node = 0; + + last_node = apex; + + for (uint i = 1; i < node_count; i++) { + tmp_node = knot_load_node(f, id_array); + + if (tmp_node != NULL) { + if (knot_zone_contents_add_node(contents, tmp_node, + 0, 0, 0) != 0) { + fprintf(stderr, "!! cannot add node\n"); + continue; + } + if (knot_dname_is_wildcard(tmp_node->owner)) { + find_and_set_wildcard_child(contents, + tmp_node, 0); + } + + knot_node_set_previous(tmp_node, last_node); + /* CLEANUP */ +// tmp_node->prev = last_node; + + if (tmp_node->rrset_count && + (knot_node_is_deleg_point(tmp_node) || + !knot_node_is_non_auth(tmp_node))) { + last_node = tmp_node; + } + + } else { + fprintf(stderr, "zone: Node error (in %s).\n", + loader->filename); + } + } + + assert(knot_node_previous(knot_zone_contents_apex(contents), 0) + == NULL); + + knot_node_set_previous(knot_zone_contents_get_apex(contents), + last_node); + + dbg_zload("loading %u nsec3 nodes\n", nsec3_node_count); + + knot_node_t *nsec3_first = NULL; + + if (nsec3_node_count > 0) { + nsec3_first = knot_load_node(f, id_array); + + assert(nsec3_first != NULL); + + if (knot_zone_contents_add_nsec3_node(contents, nsec3_first, 0, 0, 0) + != 0) { + fprintf(stderr, "!! cannot add first nsec3 node, " + "exiting.\n"); + knot_zone_deep_free(&zone, 0); + free(id_array); + /* TODO this will leak dnames from id_array that were + * not assigned. */ + return NULL; + } + + knot_node_set_previous(nsec3_first, NULL); + /* CLEANUP */ +// nsec3_first->prev = NULL; + + last_node = nsec3_first; + } + + for (uint i = 1; i < nsec3_node_count; i++) { + tmp_node = knot_load_node(f, id_array); + + if (tmp_node != NULL) { + if (knot_zone_contents_add_nsec3_node(contents, + tmp_node, 0, 0, 0) != 0) { + fprintf(stderr, "!! cannot add nsec3 node\n"); + continue; + } + + knot_node_set_previous(tmp_node, last_node); + /* CLEANUP */ +// tmp_node->prev = last_node; + + last_node = tmp_node; + } else { + fprintf(stderr, "zone: Node error (in %s).\n", + loader->filename); + } + } + + if (nsec3_node_count) { + assert(knot_node_previous(nsec3_first, 0) == NULL); + knot_node_set_previous(nsec3_first, last_node); + /* CLEANUP */ +// nsec3_first->prev = last_node; + } + + /* ID array is now useless */ + for (uint i = 1; i < total_dnames; i++) { + /* Added to table, may discard now. */ + knot_dname_release(id_array[i]); + } + free(id_array); + + dbg_zload("zone loaded, returning: %p\n", zone); + return zone; +} + +int knot_zload_needs_update(zloader_t *loader) +{ + if (!loader) { + return 1; + } + + /* Check if the source still exists. */ + struct stat st_src; + if (stat(loader->source, &st_src) != 0) { + return 1; + } + + /* Check if the compiled file still exists. */ + struct stat st_bin; + if (stat(loader->filename, &st_bin) != 0) { + return 1; + } + + /* Compare the mtime of the source and file. */ + /*! \todo Inspect types on Linux. */ + if (timet_cmp(st_bin.st_mtime, st_src.st_mtime) < 0) { + return 1; + } + + return 0; +} + +void knot_zload_close(zloader_t *loader) +{ + if (!loader) { + return; + } + + free(loader->filename); + free(loader->source); + fclose(loader->fp); + free(loader); +} + +int knot_zload_rrset_deserialize(knot_rrset_t **rrset, + uint8_t *stream, size_t *size) +{ + if (stream == NULL || size == 0) { + return KNOT_EBADARG; + } + + fread_wrapper = read_from_stream; + + knot_zload_stream = stream; + knot_zload_stream_remaining = knot_zload_stream_size = *size; + + knot_rrset_t *ret = knot_load_rrset(NULL, NULL, 0); + + if (ret == NULL) { + knot_zload_stream = NULL; + knot_zload_stream_remaining = 0; + knot_zload_stream_size = 0; + return KNOT_EMALF; + } + + *size = knot_zload_stream_remaining; + *rrset = ret; + + knot_zload_stream = NULL; + knot_zload_stream_remaining = 0; + knot_zload_stream_size = 0; + + return KNOT_EOK; +} + diff --git a/src/knot/zone/zone-load.h b/src/knot/zone/zone-load.h new file mode 100644 index 0000000..2fe318f --- /dev/null +++ b/src/knot/zone/zone-load.h @@ -0,0 +1,104 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file zone-load.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief Loader of previously parsed zone + * + * \addtogroup dnslib + * @{ + */ + +#ifndef _KNOT_ZONELOAD_H_ +#define _KNOT_ZONELOAD_H_ + +#include <stdio.h> + +#include "libknot/zone/zone.h" + +/*! + * \brief Zone loader structure. + */ +typedef struct zloader_t +{ + char *filename; /*!< Compiled zone filename. */ + char *source; /*!< Zone source file. */ + FILE *fp; /*!< Open filepointer to compiled zone. */ + +} zloader_t; + +/*! + * \brief Initializes zone loader from file.. + * + * \param filename File containing the compiled zone. + * \param loader Will create new loader in *loader. + * + * \retval Initialized loader on success. + * \retval NULL on error. + */ +int knot_zload_open(zloader_t **loader, const char *filename); + +/*! + * \brief Loads zone from a compiled and serialized zone file. + * + * \param loader Zone loader instance. + * + * \retval Loaded zone on success. + * \retval NULL otherwise. + */ +knot_zone_t *knot_zload_load(zloader_t *loader); + +/*! + * \brief Checks whether the compiled zone needs a recompilation. + * + * \param loader Zone loader instance. + * + * \retval 1 is if needs to be recompiled. + * \retval 0 if it is up to date. + */ +int knot_zload_needs_update(zloader_t *loader); + + +/*! + * \brief Free zone loader. + * + * \param loader Zone loader instance. + */ +void knot_zload_close(zloader_t *loader); + +/*! + * \brief Loads RRSet serialized by knot_zdump_rrset_serialize(). + * + * \param stream Stream containing serialized RRSet. + * \param size Size of stream. This variable will contain remaining length of + * stream, once the function has ended. + * \param rrset Place for created RRSet. + * + * \note If RRSet contains RRSIGs, their owners are not copies, but only links + * to the owner of RRSet. All RDATA dnames are copied. + * + * \retval KNOT_EOK on success. + * \retval KNOT_EBADAG on wrong arguments. + * \retval KNOT_EMALF when stream is malformed. + */ +int knot_zload_rrset_deserialize(knot_rrset_t **rrset, + uint8_t *stream, size_t *size); + +#endif /* _KNOTD_ZONELOAD_H_ */ + +/*! @} */ diff --git a/src/knotc.8 b/src/knotc.8 new file mode 100644 index 0000000..f2e7e40 --- /dev/null +++ b/src/knotc.8 @@ -0,0 +1,63 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4. +.TH KNOT "1" "November 2011" "Knot DNS, version 0.8" "User Commands" +.SH NAME +Knot \- manual page for Knot DNS, version 0.8 +.SH SYNOPSIS +.B knotc +[\fIparameters\fR] \fIstart|stop|restart|reload|running|compile\fR +.SH DESCRIPTION +.SS "Parameters:" +.HP +\fB\-c\fR [file], \fB\-\-config\fR=\fI[file]\fR Select configuration file. +.TP +\fB\-j\fR [num], \fB\-\-jobs\fR=\fI[num]\fR +Number of parallel tasks to run (only for 'compile'). +.TP +\fB\-f\fR, \fB\-\-force\fR +Force operation \- override some checks. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Verbose mode \- additional runtime information. +.TP +\fB\-V\fR, \fB\-\-version\fR +Print knot server version. +.TP +\fB\-w\fR, \fB\-\-wait\fR +Wait for the server to finish start/stop operations. +.TP +\fB\-i\fR, \fB\-\-interactive\fR +Interactive mode (do not daemonize). +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help and usage. +.SS "Actions:" +.TP +start +Start knot server zone (no\-op if running). +.TP +stop +Stop knot server (no\-op if not running). +.TP +restart +Stops and then starts knot server. +.TP +reload +Reload knot configuration and compiled zones. +.TP +running +check if server is running. +.TP +compile +Compile zone file. +.SH "SEE ALSO" +The full documentation for +.B Knot +is maintained as a Texinfo manual. If the +.B info +and +.B Knot +programs are properly installed at your site, the command +.IP +.B info Knot +.PP +should give you access to the complete manual. diff --git a/src/knotd.8 b/src/knotd.8 new file mode 100644 index 0000000..3275e9b --- /dev/null +++ b/src/knotd.8 @@ -0,0 +1,35 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4. +.TH KNOT "1" "November 2011" "Knot DNS, version 0.8" "User Commands" +.SH NAME +Knot \- manual page for Knot DNS, version 0.8 +.SH SYNOPSIS +.B knotd +[\fIparameters\fR] +.SH DESCRIPTION +.SS "Parameters:" +.HP +\fB\-c\fR, \fB\-\-config\fR [file] Select configuration file. +.TP +\fB\-d\fR, \fB\-\-daemonize\fR +Run server as a daemon. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Verbose mode \- additional runtime information. +.TP +\fB\-V\fR, \fB\-\-version\fR +Print version of the server. +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help and usage. +.SH "SEE ALSO" +The full documentation for +.B Knot +is maintained as a Texinfo manual. If the +.B info +and +.B Knot +programs are properly installed at your site, the command +.IP +.B info Knot +.PP +should give you access to the complete manual. diff --git a/src/libknot/common.h b/src/libknot/common.h new file mode 100644 index 0000000..9b2d8ae --- /dev/null +++ b/src/libknot/common.h @@ -0,0 +1,105 @@ +/*! + * \file common.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Common macros, includes and utilities. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#ifdef HAVE_LIBLDNS +#define TEST_WITH_LDNS +#endif + +#ifndef _KNOT_COMMON_H_ +#define _KNOT_COMMON_H_ + +#define KNOT_NAME "lib" PACKAGE_NAME // Project name +#define KNOT_VER PACKAGE_VERSION // 0xMMIIRR (MAJOR,MINOR,REVISION) + +#ifndef UINT_DEFINED +typedef unsigned int uint; /*!< \brief Unsigned. */ +#define UINT_DEFINED +#endif + +/*! \brief If defined, zone structures will use hash table for lookup. */ +#define USE_HASH_TABLE + +/*! \brief Eliminate compiler warning with unused parameters. */ +#define UNUSED(param) (void)(param) + +/*! \brief Type-safe minimum macro. */ +#define MIN(a, b) \ + ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; }) + +/*! \brief Type-safe maximum macro. */ +#define MAX(a, b) \ + ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) + +/* Optimisation macros. */ +#ifndef likely +/*! \brief Optimize for x to be true value. */ +#define likely(x) __builtin_expect((x),1) +#endif +#ifndef unlikely +/*! \brief Optimize for x to be false value. */ +#define unlikely(x) __builtin_expect((x),0) +#endif + +/* Optimisation macros. */ +#ifndef likely +/*! \brief Optimize for x to be true value. */ +#define likely(x) __builtin_expect((x),1) +#endif +#ifndef unlikely +/*! \brief Optimize for x to be false value. */ +#define unlikely(x) __builtin_expect((x),0) +#endif + +/*! \todo Refactor theese. We should have an allocator function handling this.*/ +#ifndef ERR_ALLOC_FAILED +#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d (%s ver.%s)\n", \ + __FILE__, __LINE__, KNOT_NAME, KNOT_VER) +#endif + +#ifndef CHECK_ALLOC_LOG +#define CHECK_ALLOC_LOG(var, ret) \ + do { \ + if ((var) == NULL) { \ + ERR_ALLOC_FAILED; \ + return (ret); \ + } \ + } while (0) +#endif + +#ifndef CHECK_ALLOC +#define CHECK_ALLOC(var, ret) \ + do { \ + if ((var) == NULL) { \ + return (ret); \ + } \ + } while (0) +#endif + +#endif /* _KNOT_COMMON_H_ */ + +/*! @} */ diff --git a/src/libknot/consts.h b/src/libknot/consts.h new file mode 100644 index 0000000..4249763 --- /dev/null +++ b/src/libknot/consts.h @@ -0,0 +1,108 @@ +/*! + * \file consts.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Contains some DNS-related constants. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_CONSTS_H_ +#define _KNOT_CONSTS_H_ + +#include <stdint.h> +#include "util/descriptor.h" + +/* + * OPCODEs + */ +typedef enum knot_opcode { + KNOT_OPCODE_QUERY = 0, /* a standard query (QUERY) */ + KNOT_OPCODE_IQUERY = 1, /* an inverse query (IQUERY) */ + KNOT_OPCODE_STATUS = 2, /* a server status request (STATUS) */ + KNOT_OPCODE_NOTIFY = 4, /* NOTIFY */ + KNOT_OPCODE_UPDATE = 5, /* Dynamic update */ + KNOT_OPCODE_OFFSET = 14 +} knot_opcode_t; + +/*! + * \brief Query types (internal use only). + * + * This type encompasses the different query types distinguished by both the + * OPCODE and the QTYPE. + */ +typedef enum knot_packet_type { + KNOT_QUERY_NORMAL, /*!< Normal query. */ + KNOT_QUERY_AXFR, /*!< Request for AXFR transfer. */ + KNOT_QUERY_IXFR, /*!< Request for IXFR transfer. */ + KNOT_QUERY_NOTIFY, /*!< NOTIFY query. */ + KNOT_QUERY_UPDATE, /*!< Dynamic update. */ + KNOT_RESPONSE_NORMAL, /*!< Normal response. */ + KNOT_RESPONSE_AXFR, /*!< AXFR transfer response. */ + KNOT_RESPONSE_IXFR, /*!< IXFR transfer response. */ + KNOT_RESPONSE_NOTIFY /*!< NOTIFY response. */ +} knot_packet_type_t; + +/* + * RCODEs + */ +typedef enum knot_rcode { + KNOT_RCODE_NOERROR = 0, /* No error condition */ + KNOT_RCODE_FORMERR = 1, /* Format error */ + KNOT_RCODE_SERVFAIL = 2, /* Server failure */ + KNOT_RCODE_NXDOMAIN = 3, /* Name Error */ + KNOT_RCODE_NOTIMPL = 4, /* Not implemented */ + KNOT_RCODE_REFUSED = 5, /* Refused */ + KNOT_RCODE_YXDOMAIN = 6, /* name should not exist */ + KNOT_RCODE_YXRRSET = 7, /* rrset should not exist */ + KNOT_RCODE_NXRRSET = 8, /* rrset does not exist */ + KNOT_RCODE_NOTAUTH = 9, /* server not authoritative */ + KNOT_RCODE_NOTZONE = 10, /* name not inside zone */ +} knot_rcode_t; + +typedef enum knot_tsig_rcode { + KNOT_TSIG_RCODE_BADSIG = 16, + KNOT_TSIG_RCODE_BADKEY = 17, + KNOT_TSIG_RCODE_BADTIME = 18 +} knot_tsig_rcode_t; + +/* + * CLASSes + */ +//typedef enum knot_class { +// KNOT_CLASS_IN = 1, /* Class IN */ +// KNOT_CLASS_CS = 2, /* Class CS */ +// KNOT_CLASS_CH = 3, /* Class CHAOS */ +// KNOT_CLASS_HS = 4, /* Class HS */ +// KNOT_CLASS_NONE = 254, /* Class NONE rfc2136 */ +// KNOT_CLASS_ANY = 255 /* Class ANY */ +//} knot_class_t; + +/* + * Other + */ +typedef enum knot_const { + KNOT_MAX_DNAME_LENGTH = 255, + KNOT_MAX_DNAME_LABELS = 127 // 1-char labels +} knot_const_t; + +#endif /* _KNOT_CONSTS_H_ */ + +/*! @} */ diff --git a/src/libknot/dname.c b/src/libknot/dname.c new file mode 100644 index 0000000..869b342 --- /dev/null +++ b/src/libknot/dname.c @@ -0,0 +1,1070 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdint.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> // tolower() + +#include "common.h" +#include "util/error.h" +#include "dname.h" +#include "consts.h" +#include "util/tolower.h" +#include "util/debug.h" +#include "util/utils.h" +#include "util/wire.h" + +/*! \todo dnames allocated from TLS cache will be discarded after thread + * termination. This shouldn't happpen. + */ +#if 0 +/* + * Memory cache. + */ +#include "common/slab/slab.h" +#include <stdio.h> +#include <pthread.h> + +/*! \brief TLS unique key for each thread cache. */ +static pthread_key_t dname_ckey; +static pthread_once_t dname_once = PTHREAD_ONCE_INIT; + +/*! \brief Destroy thread dname cache (automatically called). */ +static void knot_dname_cache_free(void *ptr) +{ + slab_cache_t* cache = (slab_cache_t*)ptr; + if (cache) { + slab_cache_destroy(cache); + free(cache); + } +} + +/*! \brief Cleanup for main() TLS. */ +static void knot_dname_cache_main_free() +{ + knot_dname_cache_free(pthread_getspecific(dname_ckey)); +} + +static void knot_dname_cache_init() +{ + (void) pthread_key_create(&dname_ckey, knot_dname_cache_free); + atexit(knot_dname_cache_main_free); // Main thread cleanup +} +#endif + +/*! + * \brief Allocate item from thread cache. + * \retval Allocated dname instance on success. + * \retval NULL on error. + */ +static knot_dname_t* knot_dname_alloc() +{ + return malloc(sizeof(knot_dname_t)); + + /*! \todo dnames allocated from TLS cache will be discarded after thread + * termination. This shouldn't happpen. + */ +#if 0 + /* Initialize dname cache TLS key. */ + (void)pthread_once(&dname_once, knot_dname_cache_init); + + /* Create cache if not exists. */ + slab_cache_t* cache = pthread_getspecific(dname_ckey); + if (unlikely(!cache)) { + cache = malloc(sizeof(slab_cache_t)); + if (!cache) { + return 0; + } + + /* Initialize cache. */ + slab_cache_init(cache, sizeof(knot_dname_t)); + (void)pthread_setspecific(dname_ckey, cache); + } + + return slab_cache_alloc(cache); +#endif +} + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ + +static int knot_dname_set(knot_dname_t *dname, uint8_t *wire, + short wire_size, const uint8_t *labels, + short label_count) +{ + dname->name = wire; + dname->size = wire_size; + dname->label_count = label_count; + + assert(label_count >= 0); + + dname->labels = (uint8_t *)malloc(dname->label_count * sizeof(uint8_t)); + CHECK_ALLOC_LOG(dname->labels, -1); + memcpy(dname->labels, labels, dname->label_count); + + return 0; +} + +/*! + * \brief Converts domain name from string representation to wire format. + * + * This function also allocates the space for the wire format. + * + * \param name Domain name in string representation (presentation format). + * \param size Size of the given domain name in characters (not counting the + * terminating 0 character. + * \param dname Domain name where to store the wire format. + * + * \return Size of the wire format of the domain name in octets. If 0, no + * space has been allocated. + * + * \todo handle \X and \DDD (RFC 1035 5.1) or it can be handled by the parser? + */ +static int knot_dname_str_to_wire(const char *name, uint size, + knot_dname_t *dname) +{ + if (size > KNOT_MAX_DNAME_LENGTH) { + return -1; + } + + uint wire_size; + int root = (*name == '.' && size == 1); + // root => different size + if (root) { + wire_size = 1; + } else { + wire_size = size + 1; + } + + uint8_t *wire; + uint8_t labels[KNOT_MAX_DNAME_LABELS]; + short label_count = 0; + + // signed / unsigned issues?? + wire = (uint8_t *)malloc(wire_size * sizeof(uint8_t)); + if (wire == NULL) { + return -1; + } + + dbg_dname("Allocated space for wire format of dname: %p\n", + wire); + + if (root) { + *wire = '\0'; + label_count = 0; + return knot_dname_set(dname, wire, wire_size, labels, + label_count); + } + + const uint8_t *ch = (const uint8_t *)name; + uint8_t *label_start = wire; + uint8_t *w = wire + 1; + uint8_t label_length = 0; + + while (ch - (const uint8_t *)name < size) { + assert(w - wire - 1 == ch - (const uint8_t *)name); + + if (*ch == '.') { + dbg_dname("Position %zd (%p): " + "label length: %u\n", + label_start - wire, + label_start, label_length); + *label_start = label_length; + labels[label_count++] = label_start - wire; + label_start = w; + label_length = 0; + } else { + assert(w - wire < wire_size); + dbg_dname("Position %zd (%p): character: %c\n", + w - wire, w, *ch); + *w = *ch; + ++label_length; + } + + ++w; + ++ch; + assert(ch >= (const uint8_t *)name); + } + + --ch; + if (*ch == '.') { // put 0 for root label if the name ended with . + --w; + dbg_dname("Position %zd (%p): character: (null)\n", + w - wire, w); + *w = 0; + } else { // otherwise we did not save the last label length + dbg_dname("Position %zd (%p): " + "label length: %u\n", + label_start - wire, + label_start, label_length); + *label_start = label_length; + labels[label_count++] = label_start - wire; + } + + return knot_dname_set(dname, wire, wire_size, labels, label_count); +} + +/*----------------------------------------------------------------------------*/ + +static inline int knot_dname_tolower(uint8_t c, int cs) +{ + return (cs) ? c : knot_tolower(c); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_dname_compare_labels(const uint8_t *label1, + const uint8_t *label2, int cs) +{ + const uint8_t *pos1 = label1; + const uint8_t *pos2 = label2; + + int label_length = (*pos1 < *pos2) ? *pos1 : *pos2; + int i = 0; + + while (i < label_length + && knot_dname_tolower(*(++pos1), cs) + == knot_dname_tolower(*(++pos2), cs)) { + ++i; + } + + if (i < label_length) { // difference in some octet + return (knot_dname_tolower(*pos1, cs) + - knot_dname_tolower(*pos2, cs)); + } + + return (label1[0] - label2[0]); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_dname_find_labels(knot_dname_t *dname, int alloc) +{ + const uint8_t *name = dname->name; + const uint8_t *pos = name; + const uint size = dname->size; + + uint8_t labels[KNOT_MAX_DNAME_LABELS]; + short label_count = 0; + + while (pos - name < size && *pos != '\0') { + labels[label_count++] = pos - name; + pos += *pos + 1; + } + + // TODO: how to check if the domain name has right format? + if (pos - name > size || *pos != '\0') { + dbg_dname("Wrong wire format of domain name!\n"); + dbg_dname("Position: %d, character: %d, expected" + " size: %d\n", pos - name, *pos, size); + return -1; + } + + if (alloc) { + dname->labels + = (uint8_t *)malloc(label_count * sizeof(uint8_t)); + CHECK_ALLOC_LOG(dname->labels, KNOT_ENOMEM); + } + + memcpy(dname->labels, labels, label_count); + dname->label_count = label_count; + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2, + int cs) +{ +dbg_dname_exec( + char *name1 = knot_dname_to_str(d1); + char *name2 = knot_dname_to_str(d2); + + dbg_dname("Comparing dnames %s and %s\n", + name1, name2); + + for (int i = 0; i < strlen(name1); ++i) { + name1[i] = knot_tolower(name1[i]); + } + for (int i = 0; i < strlen(name2); ++i) { + name2[i] = knot_tolower(name2[i]); + } + + dbg_dname("After to lower: %s and %s\n", + name1, name2); + + free(name1); + free(name2); +); + + if (!cs && d1 == d2) { + return 0; + } + + int l1 = d1->label_count; + int l2 = d2->label_count; + dbg_dname("Label counts: %d and %d\n", l1, l2); + assert(l1 >= 0); + assert(l2 >= 0); + + // compare labels from last to first + while (l1 > 0 && l2 > 0) { + dbg_dname("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname(" at offsets: %d and %d\n", + d1->labels[l1 - 1], d2->labels[l2 - 1]); + int res = knot_dname_compare_labels( + &d1->name[d1->labels[--l1]], + &d2->name[d2->labels[--l2]], + cs); + if (res != 0) { + return res; + } // otherwise the labels are identical, continue with previous + } + + // if all labels matched, the shorter name is first + if (l1 == 0 && l2 > 0) { + return -1; + } + + if (l1 > 0 && l2 == 0) { + return 1; + } + + return 0; +} + +/*! \brief Destructor for reference counter. */ +static void knot_dname_dtor(struct ref_t *p) +{ + knot_dname_t *dname = (knot_dname_t *)p; + knot_dname_free(&dname); +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_new() +{ + knot_dname_t *dname = knot_dname_alloc(); + dname->name = NULL; + dname->size = 0; + dname->node = NULL; + dname->labels = NULL; + dname->label_count = -1; + dname->id = 0; + + /* Initialize reference counting. */ + ref_init(&dname->ref, knot_dname_dtor); + + /* Set reference counter to 1, caller should release it after use. */ + knot_dname_retain(dname); + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_new_from_str(const char *name, uint size, + struct knot_node *node) +{ + if (name == NULL || size == 0) { + return NULL; + } + +// knot_dname_t *dname = knot_dname_alloc(); + knot_dname_t *dname = knot_dname_new(); + + if (dname == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + knot_dname_str_to_wire(name, size, dname); + dbg_dname("Created dname with size: %d\n", dname->size); + dbg_dname("Label offsets: "); + for (int i = 0; i < dname->label_count; ++i) { + dbg_dname("%d, ", dname->labels[i]); + } + dbg_dname("\n"); + + if (dname->size <= 0) { + fprintf(stderr, "Could not parse domain name " + "from string: '%.*s'\n", size, name); + } + assert(dname->name != NULL); + + dname->node = node; + dname->id = 0; + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +//int knot_dname_from_wire(knot_dname_t *dname, const uint8_t *name, +// uint size) +//{ +// int i = 0; +// uint8_t labels[KNOT_MAX_DNAME_LABELS]; +// int label_i = 0; + +// while (name[i] != 0) { +// labels[label_i++] = i; +// uint8_t label_length = name[i]; +// if (i + label_length >= size) { +// return -2; +// } +// for (int j = 1; j <= label_length; ++j) { +// } +// } +//} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size, + struct knot_node *node) +{ + if (name == NULL) { /* && size != 0) { !OS: Nerozumjaju */ + dbg_dname("No name given!\n"); + return NULL; + } + + knot_dname_t *dname = knot_dname_new(); + + if (dname == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + dname->name = (uint8_t *)malloc(size * sizeof(uint8_t)); + if (dname->name == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&dname); + return NULL; + } + + memcpy(dname->name, name, size); + dname->size = size; + + if (knot_dname_find_labels(dname, 1) != 0) { + knot_dname_free(&dname); + return NULL; + } + + dname->node = node; + dname->id = 0; + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, + size_t *pos, size_t size, + knot_node_t *node) +{ + uint8_t name[KNOT_MAX_DNAME_LENGTH]; + uint8_t labels[KNOT_MAX_DNAME_LABELS]; + + short l = 0; + size_t i = 0, p = *pos; + int pointer_used = 0; + + while (p < size && wire[p] != 0) { + labels[l] = i; + dbg_dname("Next label (%d.) position: %zu\n", l, i); + + if (knot_wire_is_pointer(wire + p)) { + // pointer. +// printf("Pointer.\n"); + p = knot_wire_get_pointer(wire + p); + if (!pointer_used) { + *pos += 2; + pointer_used = 1; + } + if (p >= size) { + return NULL; + } + } else { + // label; first byte is label length + uint8_t length = *(wire + p); +// printf("Label, length: %u.\n", length); + memcpy(name + i, wire + p, length + 1); + p += length + 1; + i += length + 1; + if (!pointer_used) { + *pos += length + 1; + } + ++l; + } + } + if (p >= size) { + return NULL; + } + + name[i] = 0; + if (!pointer_used) { + *pos += 1; + } + + knot_dname_t *dname = knot_dname_new(); + + if (dname == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + dname->name = (uint8_t *)malloc((i + 1) * sizeof(uint8_t)); + if (dname->name == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&dname); + return NULL; + } + + memcpy(dname->name, name, i + 1); + dname->size = i + 1; + + dname->labels = (uint8_t *)malloc((l + 1) * sizeof(uint8_t)); + if (dname->labels == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&dname); + return NULL; + } + memcpy(dname->labels, labels, l + 1); + + dname->label_count = l; + + dname->node = node; + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_from_wire(const uint8_t *name, uint size, + struct knot_node *node, knot_dname_t *target) +{ + if (name == NULL || target == NULL) { + return KNOT_EBADARG; + } + + memcpy(target->name, name, size); + target->size = size; + target->node = node; + target->id = 0; + + return knot_dname_find_labels(target, 0); +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname) +{ + return knot_dname_new_from_wire(dname->name, dname->size, + dname->node); +} + +/*----------------------------------------------------------------------------*/ + +char *knot_dname_to_str(const knot_dname_t *dname) +{ + if (!dname || dname->size == 0) { + return 0; + } + + char *name; + + // root => special treatment + if (dname->size == 1) { + assert(dname->name[0] == 0); + name = (char *)malloc(2 * sizeof(char)); + name[0] = '.'; + name[1] = '\0'; + return name; + } + + name = (char *)malloc(dname->size * sizeof(char)); + if (name == NULL) { + return NULL; + } + + uint8_t *w = dname->name; + char *ch = name; + int i = 0; + + do { + assert(*w != 0); + int label_size = *(w++); + // copy the label + memcpy(ch, w, label_size); + i += label_size; + ch += label_size; + w += label_size; + if (w - dname->name < dname->size) { // another label following + *(ch++) = '.'; + ++i; + } + } while (i < dname->size - 1); + + *ch = 0; + assert(ch - name == dname->size - 1); + + return name; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_to_lower(knot_dname_t *dname) +{ + if (dname == NULL) { + return KNOT_EBADARG; + } + + for (int i = 0; i < dname->size; ++i) { + dname->name[i] = knot_tolower(dname->name[i]); + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name, + size_t size) +{ + if (dname == NULL || name == NULL || size < dname->size) { + return KNOT_EBADARG; + } + + for (int i = 0; i < dname->size; ++i) { + name[i] = knot_tolower(dname->name[i]); + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +const uint8_t *knot_dname_name(const knot_dname_t *dname) +{ + return dname->name; +} + +/*----------------------------------------------------------------------------*/ + +uint knot_dname_size(const knot_dname_t *dname) +{ + return dname->size; +} + +/*----------------------------------------------------------------------------*/ + +unsigned int knot_dname_id(const knot_dname_t *dname) +{ + return dname->id; +} + +/*----------------------------------------------------------------------------*/ + +uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels) +{ + assert(labels < dname->label_count); + assert(dname->labels != NULL); + return (dname->labels[labels]); +} + +/*----------------------------------------------------------------------------*/ + +const struct knot_node *knot_dname_node(const knot_dname_t *dname, + int check_version) + +{ + if (check_version) { + return knot_node_current(dname->node); + } else { + return dname->node; + } +} + +/*----------------------------------------------------------------------------*/ + +struct knot_node *knot_dname_get_node(knot_dname_t *dname, + int check_version) +{ + if (check_version) { + return knot_node_get_current(dname->node); + } else { + return dname->node; + } +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_set_node(knot_dname_t *dname, knot_node_t *node) +{ + dname->node = node; +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_update_node(knot_dname_t *dname) +{ + knot_node_update_ref(&dname->node); +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_is_fqdn(const knot_dname_t *dname) +{ + return (dname->name[dname->size - 1] == '\0'); +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) +{ + knot_dname_t *parent = knot_dname_new(); + if (parent == NULL) { + return NULL; + } + + parent->size = dname->size - dname->name[0] - 1; + parent->name = (uint8_t *)malloc(parent->size); + if (parent->name == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&parent); + return NULL; + } + + parent->labels = (uint8_t *)malloc(dname->label_count - 1); + if (parent->labels == NULL) { + ERR_ALLOC_FAILED; + free(parent->name); + knot_dname_free(&parent); + return NULL; + } + + memcpy(parent->name, &dname->name[dname->name[0] + 1], parent->size); + + short first_label_length = dname->labels[1]; + + for (int i = 0; i < dname->label_count - 1; ++i) { + parent->labels[i] = dname->labels[i + 1] - first_label_length; + } + parent->label_count = dname->label_count - 1; + + return parent; +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_left_chop_no_copy(knot_dname_t *dname) +{ + // copy the name + short first_label_length = dname->labels[1]; + + if (dname->label_count > 1) { + memmove(dname->name, &dname->name[dname->labels[1]], + dname->size - first_label_length); + // adjust labels + for (int i = 0; i < dname->label_count - 1; ++i) { + dname->labels[i] = dname->labels[i + 1] + - first_label_length; + } + dname->label_count = dname->label_count - 1; + dname->size -= first_label_length; + } else { + dname->name[0] = '\0'; + dname->size = 1; + dname->label_count = 0; + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_is_subdomain(const knot_dname_t *sub, + const knot_dname_t *domain) +{ +dbg_dname_exec( + char *name1 = knot_dname_to_str(sub); + char *name2 = knot_dname_to_str(domain); + + dbg_dname("Checking if %s is subdomain of %s\n", + name1, name2); + free(name1); + free(name2); +); + + if (sub == domain) { + return 0; + } + + // if one of the names is fqdn and the other is not + if ((sub->name[sub->size - 1] == '\0' + && domain->name[domain->size - 1] != '\0') + || (sub->name[sub->size - 1] != '\0' + && domain->name[domain->size - 1] == '\0')) { + return 0; + } + + int l1 = sub->label_count; + int l2 = domain->label_count; + + dbg_dname("Label counts: %d and %d\n", l1, l2); + + if (l1 <= l2) { // if sub does not have more labes than domain + return 0; // it is not its subdomain + } + + // compare labels from last to first + while (l1 > 0 && l2 > 0) { + dbg_dname("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname(" at offsets: %d and %d\n", + sub->labels[l1 - 1], domain->labels[l2 - 1]); + // if some labels do not match + if (knot_dname_compare_labels(&sub->name[sub->labels[--l1]], + &domain->name[domain->labels[--l2]], 0) + != 0) { + return 0; // sub is not a subdomain of domain + } // otherwise the labels are identical, continue with previous + } + + // if all labels matched, it should be subdomain (more labels) + assert(l1 > l2); + + return 1; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_is_wildcard(const knot_dname_t *dname) +{ + return (dname->size >= 2 + && dname->name[0] == 1 + && dname->name[1] == '*'); +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_matched_labels(const knot_dname_t *dname1, + const knot_dname_t *dname2) +{ + int l1 = dname1->label_count; + int l2 = dname2->label_count; + + // compare labels from last to first + int matched = 0; + while (l1 > 0 && l2 > 0) { + int res = knot_dname_compare_labels( + &dname1->name[dname1->labels[--l1]], + &dname2->name[dname2->labels[--l2]], 0); + if (res == 0) { + ++matched; + } else { + break; + } + } + + return matched; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_label_count(const knot_dname_t *dname) +{ + return dname->label_count; +} + +/*----------------------------------------------------------------------------*/ + +uint8_t knot_dname_label_size(const knot_dname_t *dname, int i) +{ +// printf("Returning size of %d. label starting on %d\n", +// i, dname->labels[i]); +// printf("Label count: %d, size of %d. label: %d, size of %d.label: %d\n", +// dname->label_count, i, dname->labels[i], i + 1, +// dname->labels[i+1]); +// printf("Size from the name: %u\n", dname->name[dname->labels[i]]); +// printf("Size from label offsets: %u\n", +// dname->labels[i + 1] - dname->labels[i]); + + assert(i >= 0); + assert(dname->size == 1 || i + 1 == dname->label_count + || dname->labels[i + 1] - dname->labels[i] - 1 + == dname->name[dname->labels[i]]); + return dname->name[dname->labels[i]]; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, + int size, + const knot_dname_t *suffix) +{ +dbg_dname_exec( + char *name = knot_dname_to_str(dname); + dbg_dname("Replacing suffix of name %s, size %d with ", name, + size); + free(name); + name = knot_dname_to_str(suffix); + dbg_dname("%s (size %d)\n", name, suffix->size); + free(name); +); + knot_dname_t *res = knot_dname_new(); + CHECK_ALLOC(res, NULL); + + res->size = dname->size - size + suffix->size; + + dbg_dname("Allocating %d bytes...\n", res->size); + res->name = (uint8_t *)malloc(res->size); + if (res->name == NULL) { + knot_dname_free(&res); + return NULL; + } + + dbg_dname_hex((char *)res->name, res->size); + + dbg_dname("Copying %d bytes from the original name.\n", + dname->size - size); + memcpy(res->name, dname->name, dname->size - size); + dbg_dname_hex((char *)res->name, res->size); + + dbg_dname("Copying %d bytes from the suffix.\n", suffix->size); + memcpy(res->name + dname->size - size, suffix->name, suffix->size); + + dbg_dname_hex((char *)res->name, res->size); + + knot_dname_find_labels(res, 1); + + return res; +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_free(knot_dname_t **dname) +{ + if (dname == NULL || *dname == NULL) { + return; + } + +// char *name = knot_dname_to_str((*dname)); + +// printf("freeing in dname: %s %p\n", name, *dname); + +// free(name); + + + if ((*dname)->name != NULL) { + free((*dname)->name); + } + + if((*dname)->labels != NULL) { + free((*dname)->labels); + } + + +// slab_free(*dname); + free(*dname); + *dname = NULL; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2) +{ + return knot_dname_cmp(d1, d2, 0); +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2) +{ + return knot_dname_cmp(d1, d2, 1); +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) +{ + if (d2->size == 0) { + return d1; + } + + if (knot_dname_is_fqdn(d1)) { + return NULL; + } + + // allocate new space + uint8_t *new_dname = (uint8_t *)malloc(d1->size + d2->size); + CHECK_ALLOC_LOG(new_dname, NULL); + + uint8_t *new_labels = (uint8_t *)malloc(d1->label_count + + d2->label_count); + if (new_labels == NULL) { + ERR_ALLOC_FAILED; + free(new_dname); + return NULL; + } + + dbg_dname("1: copying %d bytes from adress %p to %p\n", + d1->size, d1->name, new_dname); + + memcpy(new_dname, d1->name, d1->size); + + dbg_dname("2: copying %d bytes from adress %p to %p\n", + d2->size, d2->name, new_dname + d1->size); + + memcpy(new_dname + d1->size, d2->name, d2->size); + + // update labels + memcpy(new_labels, d1->labels, d1->label_count); + for (int i = 0; i < d2->label_count; ++i) { + new_labels[d1->label_count + i] = d2->labels[i] + d1->size; + } + + uint8_t *old_labels = d1->labels; + d1->labels = new_labels; + free(old_labels); + d1->label_count += d2->label_count; + + uint8_t *old_name = d1->name; + d1->name = new_dname; + free(old_name); + + d1->size += d2->size; + + return d1; +} + +void knot_dname_set_id(knot_dname_t *dname, unsigned int id) +{ + dname->id = id; +} + +unsigned int knot_dname_get_id(const knot_dname_t *dname) +{ + if (dname != NULL) { + return dname->id; + } else { + return 0; /* 0 should never be used and is reserved for err. */ + } +} diff --git a/src/libknot/dname.h b/src/libknot/dname.h new file mode 100644 index 0000000..c0e3f35 --- /dev/null +++ b/src/libknot/dname.h @@ -0,0 +1,428 @@ +/*! + * \file dname.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Domain name structure and API for manipulating it. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_DNAME_H_ +#define _KNOT_DNAME_H_ + +#include <stdint.h> +#include <string.h> +#include "common/ref.h" + +struct knot_node; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure for representing a domain name. + * + * Stores the domain name in wire format. + * + * \todo Consider restricting to FQDN only (see knot_dname_new_from_str()). + */ +struct knot_dname { + ref_t ref; /*!< Reference counting. */ + uint8_t *name; /*!< Wire format of the domain name. */ + /*! + * \brief Size of the domain name in octets. + * \todo Is this needed? Every dname should end with \0 or pointer. + */ + unsigned int size; + uint8_t *labels; + unsigned short label_count; + struct knot_node *node; /*!< Zone node the domain name belongs to. */ + unsigned int id; /*!< ID of domain name used in zone dumping. */ +}; + +typedef struct knot_dname knot_dname_t; + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Creates empty dname structure (no name, no owner node). + * + * \note Newly created dname is referenced, caller is responsible for releasing + * it after use. + * + * \return Newly allocated and initialized dname structure. + * + * \todo Possibly useless. + */ +knot_dname_t *knot_dname_new(); + +/*! + * \brief Creates a dname structure from domain name given in presentation + * format. + * + * The resulting domain name is stored in wire format, but it may not end with + * root label (0). + * + * \note Newly created dname is referenced, caller is responsible for releasing + * it after use. + * + * \param name Domain name in presentation format (labels separated by dots). + * \param size Size of the domain name (count of characters with all dots). + * \param node Zone node the domain name belongs to. Set to NULL if not + * applicable. + * + * \return Newly allocated and initialized dname structure representing the + * given domain name. + */ +knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size, + struct knot_node *node); + +/*! + * \brief Creates a dname structure from domain name given in wire format. + * + * \note The name is copied into the structure. + * \note If the given name is not a FQDN, the result will be neither. + * \note Newly created dname is referenced, caller is responsible for releasing + * it after use. + * + * \param name Domain name in wire format. + * \param size Size of the domain name in octets. + * \param node Zone node the domain name belongs to. Set to NULL if not + * applicable. + * + * \return Newly allocated and initialized dname structure representing the + * given domain name. + * + * \todo This function does not check if the given data is in correct wire + * format at all. It thus creates a invalid domain name, which if passed + * e.g. to knot_dname_to_str() may result in crash. Decide whether it + * is OK to retain this and check the data in other functions before + * calling this one, or if it should verify the given data. + */ +knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, + unsigned int size, + struct knot_node *node); + +knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, + size_t *pos, size_t size, + struct knot_node *node); + +/*! + * \brief Initializes domain name by the name given in wire format. + * + * \note The name is copied into the structure. + * \note If there is any name in the structure, it will be replaced. + * \note If the given name is not a FQDN, the result will be neither. + * + * \param name Domain name in wire format. + * \param size Size of the domain name in octets. + * \param node Zone node the domain name belongs to. Set to NULL if not + * applicable. + * \param target Domain name structure to initialize. + * + * \retval KNOT_EOK on success. + * \retval KNOT_ENOMEM if allocation of labels info failed. + * \retval KNOT_EBADARG if name or target is null. + * + * \todo This function does not check if the given data is in correct wire + * format at all. It thus creates a invalid domain name, which if passed + * e.g. to knot_dname_to_str() may result in crash. Decide whether it + * is OK to retain this and check the data in other functions before + * calling this one, or if it should verify the given data. + */ +int knot_dname_from_wire(const uint8_t *name, unsigned int size, + struct knot_node *node, knot_dname_t *target); + +/*! + * \brief Duplicates the given domain name. + * + * \note Copied dname referense count is reset to 1, caller is responsible + * for releasing it after use. + * + * \param dname Domain name to be copied. + * + * \return New domain name which is an exact copy of \a dname. + */ +knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname); + +/*! + * \brief Converts the given domain name to string representation. + * + * \note Allocates new memory, remember to free it. + * + * \param dname Domain name to be converted. + * + * \return 0-terminated string representing the given domain name in + * presentation format. + */ +char *knot_dname_to_str(const knot_dname_t *dname); + +int knot_dname_to_lower(knot_dname_t *dname); + +int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name, + size_t size); + +/*! + * \brief Returns the domain name in wire format. + * + * \param dname Domain name. + * + * \return Wire format of the domain name. + */ +const uint8_t *knot_dname_name(const knot_dname_t *dname); + +/*! + * \brief Returns size of the given domain name. + * + * \param dname Domain name to get the size of. + * + * \return Size of the domain name in wire format in octets. + */ +unsigned int knot_dname_size(const knot_dname_t *dname); + +unsigned int knot_dname_id(const knot_dname_t *dname); + +/*! + * \brief Returns size of a part of domain name. + * + * \param dname Domain name. + * \param labels Count of labels to get the size of (counted from left). + * + * \return Size of first \a labels labels of \a dname, counted from left. + */ +uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels); + +/*! + * \brief Returns the zone node the domain name belongs to. + * + * \param dname Domain name to get the zone node of. + * + * \return Zone node the domain name belongs to or NULL if none. + */ +const struct knot_node *knot_dname_node(const knot_dname_t *dname, + int check_version); + +struct knot_node *knot_dname_get_node(knot_dname_t *dname, + int check_version); + +void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node); + +void knot_dname_update_node(knot_dname_t *dname); + +void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node); + +/*! + * \brief Checks if the given domain name is a fully-qualified domain name. + * + * \param dname Domain name to check. + * + * \retval <> 0 if \a dname is a FQDN. + * \retval 0 otherwise. + */ +int knot_dname_is_fqdn(const knot_dname_t *dname); + +/*! + * \brief Creates new domain name by removing leftmost label from \a dname. + * + * \note Newly created dname reference count is set to 1, caller is responsible + * for releasing it after use. + * + * \param dname Domain name to remove the first label from. + * + * \return New domain name with the same labels as \a dname, except for the + * leftmost label, which is removed. + */ +knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname); + +/*! + * \brief Removes leftmost label from \a dname. + * + * \param dname Domain name to remove the first label from. + */ +void knot_dname_left_chop_no_copy(knot_dname_t *dname); + +/*! + * \brief Checks if one domain name is a subdomain of other. + * + * \param sub Domain name to be the possible subdomain. + * \param domain Domain name to be the possible parent domain. + * + * \retval <> 0 if \a sub is a subdomain of \a domain. + * \retval 0 otherwise. + */ +int knot_dname_is_subdomain(const knot_dname_t *sub, + const knot_dname_t *domain); + +/*! + * \brief Checks if the domain name is a wildcard. + * + * \param dname Domain name to check. + * + * \retval <> 0 if \a dname is a wildcard domain name. + * \retval 0 otherwise. + */ +int knot_dname_is_wildcard(const knot_dname_t *dname); + +/*! + * \brief Returns the number of labels common for the two domain names (counted + * from the rightmost label. + * + * \param dname1 First domain name. + * \param dname2 Second domain name. + * + * \return Number of labels common for the two domain names. + */ +int knot_dname_matched_labels(const knot_dname_t *dname1, + const knot_dname_t *dname2); + +/*! + * \brief Returns the number of labels in the domain name. + * + * \param dname Domain name to get the label count of. + * + * \return Number of labels in \a dname. + * + * \todo Find out if this counts the root label also. + */ +int knot_dname_label_count(const knot_dname_t *dname); + +/*! + * \brief Returns the size of the requested label in the domain name. + * + * \param dname Domain name to get the label size from. + * \param i Index of the label (0 is the leftmost label). + * + * \return Size of \a i-th label in \a dname (counted from left). + */ +uint8_t knot_dname_label_size(const knot_dname_t *dname, int i); + +/*! + * \brief Replaces the suffix of given size in one domain name with other domain + * name. + * + * \param dname Domain name where to replace the suffix. + * \param size Size of the suffix to be replaced. + * \param suffix New suffix to be used as a replacement. + * + * \return New domain name created by replacing suffix of \a dname of size + * \a size with \a suffix. + */ +knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, + int size, + const knot_dname_t *suffix); + +/*! + * \brief Destroys the given domain name. + * + * Frees also the data within the struct. This is somewhat different behaviour + * than that of RDATA and RRSet structures which do not deallocate their + * contents. + * + * Sets the given pointer to NULL. + * + * \param dname Domain name to be destroyed. + */ +void knot_dname_free(knot_dname_t **dname); + +/*! + * \brief Compares two domain names (case insensitive). + * + * \param d1 First domain name. + * \param d2 Second domain name. + * + * \retval < 0 if \a d1 goes before \a d2 in canonical order. + * \retval > 0 if \a d1 goes after \a d2 in canonical order. + * \retval 0 if the domain names are identical. + */ +int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2); + +/*! + * \brief Compares two domain names (case sensitive). + * + * \param d1 First domain name. + * \param d2 Second domain name. + * + * \retval < 0 if \a d1 goes before \a d2 in canonical order. + * \retval > 0 if \a d1 goes after \a d2 in canonical order. + * \retval 0 if the domain names are identical. + */ +int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2); + +/*! + * \brief Concatenates two domain names. + * + * \note Member \a node is ignored, i.e. preserved. + * + * \param d1 First domain name (will be modified). + * \param d2 Second domain name (will not be modified). + * + * \return The concatenated domain name (i.e. modified \a d1) or NULL if + * the operation is not valid (e.g. \a d1 is a FQDN). + */ +knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2); + +void knot_dname_set_id(knot_dname_t *dname, unsigned int id); + +unsigned int knot_dname_get_id(const knot_dname_t *dname); + +/*! + * \brief Increment reference counter for dname. + * + * Function makes shallow copy (reference). + * + * \param dname Referenced dname. + */ +static inline void knot_dname_retain(knot_dname_t *dname) { + if (dname) { + ref_retain(&dname->ref); +// char *name = knot_dname_to_str(dname); +// printf("retain: %s %p %d\n", name, dname, dname->ref.count); +// free(name); + + } +} + +/*#define knot_dname_retain(d) \ + knot_dname_retain_((d));\ + if ((d))\ + printf("dname_retain: %s() at %s:%d, %p refcount=%zu\n",\ + __func__, __FILE__, __LINE__, d, (d)->ref.count) */ + +/*! + * \brief Decrement reference counter for dname. + * + * \param dname Referenced dname. + */ +static inline void knot_dname_release(knot_dname_t *dname) { + if (dname) { +// char *name = knot_dname_to_str(dname); +// printf("releasing: %p %s %d\n", dname, name, dname->ref.count - 1); +// free(name); + ref_release(&dname->ref); + } +} + +/*#define knot_dname_release(d) \ + if ((d))\ + printf("dname_release: %s() at %s:%d, %p refcount=%zu\n",\ + __func__, __FILE__, __LINE__, d, (d)->ref.count-1);\ + knot_dname_release_((d)) */ + +#endif /* _KNOT_DNAME_H_ */ + +/*! @} */ diff --git a/src/libknot/edns.c b/src/libknot/edns.c new file mode 100644 index 0000000..05ebd7b --- /dev/null +++ b/src/libknot/edns.c @@ -0,0 +1,416 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <assert.h> + +#include "edns.h" +#include "common.h" +#include "util/descriptor.h" +#include "util/debug.h" +#include "util/error.h" + +/*! \brief Various EDNS constatns. */ +enum knot_edns_consts { + /*! \brief Mask for the DO bit. */ + KNOT_EDNS_DO_MASK = (uint16_t)0x8000, + /*! \brief Step for allocation of space for option entries. */ + KNOT_EDNS_OPTION_STEP = 1 +}; + +/*! \brief Minimum size of EDNS OPT RR in wire format. */ +static const short KNOT_EDNS_MIN_SIZE = 11; + +/*----------------------------------------------------------------------------*/ + +knot_opt_rr_t *knot_edns_new() +{ + knot_opt_rr_t *opt_rr = (knot_opt_rr_t *)malloc( + sizeof(knot_opt_rr_t)); + CHECK_ALLOC_LOG(opt_rr, NULL); + opt_rr->size = KNOT_EDNS_MIN_SIZE; + opt_rr->option_count = 0; + opt_rr->options_max = 0; + + opt_rr->ext_rcode = 0; + opt_rr->flags = 0; + opt_rr->version = 0; + + return opt_rr; +} + +/*----------------------------------------------------------------------------*/ + +int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire, + size_t max_size) +{ + const uint8_t *pos = wire; + int parsed = 0; + + if (pos == NULL || max_size == 0 || opt_rr == NULL) { + return KNOT_EBADARG; + } + + if (max_size < KNOT_EDNS_MIN_SIZE) { + dbg_edns("Not enough data to parse OPT RR header.\n"); + return KNOT_EFEWDATA; + } + + // owner of EDNS OPT RR must be root (0) + if (*pos != 0) { + dbg_edns("EDNS packet malformed (expected root " + "domain as owner).\n"); + return KNOT_EMALF; + } + pos += 1; + + // check the type of the record (must be OPT) + if (knot_wire_read_u16(pos) != KNOT_RRTYPE_OPT) { + dbg_edns("EDNS packet malformed (expected OPT type" + ".\n"); + return KNOT_EMALF; + } + pos += 2; + + opt_rr->payload = knot_wire_read_u16(pos); + dbg_edns("Parsed payload: %u\n", opt_rr->payload); + + pos += 2; + opt_rr->ext_rcode = *(pos++); + opt_rr->version = *(pos++); + opt_rr->flags = knot_wire_read_u16(pos); + pos += 2; + + parsed = KNOT_EDNS_MIN_SIZE; + + // ignore RDATA, but move pos behind them + uint16_t rdlength = knot_wire_read_u16(pos); + pos += 2; + + if (max_size - parsed < rdlength) { + dbg_edns("Not enough data to parse OPT RR.\n"); + return KNOT_EFEWDATA; + } + + while (parsed < rdlength + KNOT_EDNS_MIN_SIZE) { + if (max_size - parsed < 4) { + dbg_edns("Not enough data to parse OPT RR" + " OPTION header.\n"); + return KNOT_EFEWDATA; + } + uint16_t code = knot_wire_read_u16(pos); + pos += 2; + uint16_t length = knot_wire_read_u16(pos); + pos += 2; + dbg_edns("EDNS OPTION: Code: %u, Length: %u\n", + code, length); + if (max_size - parsed - 4 < length) { + dbg_edns("Not enough data to parse OPT RR" + " OPTION data.\n"); + return KNOT_EFEWDATA; + } + int ret; + if ((ret = + knot_edns_add_option(opt_rr, code, length, pos)) != 0) { + dbg_edns("Error parsing OPT option field.\n"); + return ret; + } + pos += length; + parsed += length + 4; + } + + return parsed; +} + +/*----------------------------------------------------------------------------*/ + +int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, + const knot_rrset_t *rrset) +{ + if (opt_rr == NULL || rrset == NULL + || knot_rrset_type(rrset) != KNOT_RRTYPE_OPT) { + return KNOT_EBADARG; + } + + dbg_edns("Parsing payload.\n"); + opt_rr->payload = knot_rrset_class(rrset); + + // the TTL has switched bytes + uint32_t ttl; + dbg_edns("TTL: %u\n", knot_rrset_ttl(rrset)); + knot_wire_write_u32((uint8_t *)&ttl, knot_rrset_ttl(rrset)); + // first byte of TTL is extended RCODE + dbg_edns("TTL: %u\n", ttl); + memcpy(&opt_rr->ext_rcode, &ttl, 1); + dbg_edns("Parsed extended RCODE: %u.\n", opt_rr->ext_rcode); + // second is the version + memcpy(&opt_rr->version, (const uint8_t *)(&ttl) + 1, 1); + dbg_edns("Parsed version: %u.\n", opt_rr->version); + // third and fourth are flags + opt_rr->flags = knot_wire_read_u16((const uint8_t *)(&ttl) + 2); + dbg_edns("Parsed flags: %u.\n", opt_rr->flags); + // size of the header, options are counted elsewhere + opt_rr->size = 11; + + int rc = 0; + dbg_edns("Parsing options.\n"); + const knot_rdata_t *rdata = knot_rrset_rdata(rrset); + + // in OPT RR, all RDATA are in one RDATA item stored as BINARY data, + // i.e. preceded by their length + if (rdata != NULL) { + assert(knot_rdata_item_count(rdata) == 1); + const uint8_t *raw = (const uint8_t *) + knot_rdata_item(rdata, 0)->raw_data; + uint16_t size = knot_wire_read_u16(raw); + int pos = 2; + assert(size > 0); + while (pos - 2 < size) { + // ensure there is enough data to parse the OPTION CODE + // and OPTION LENGTH + if (size - pos + 2 < 4) { + return KNOT_EMALF; + } + uint16_t opt_code = knot_wire_read_u16(raw + pos); + uint16_t opt_size = knot_wire_read_u16(raw + pos + 2); + + // there should be enough data for parsing the OPTION + // data + if (size - pos - 2 < opt_size) { + return KNOT_EMALF; + } + rc = knot_edns_add_option(opt_rr, opt_code, opt_size, + raw + pos + 4); + if (rc != KNOT_EOK) { + return rc; + } + pos += 4 + opt_size; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_edns_get_payload(const knot_opt_rr_t *opt_rr) +{ + assert(opt_rr != NULL); + return opt_rr->payload; +} + +/*----------------------------------------------------------------------------*/ + +void knot_edns_set_payload(knot_opt_rr_t *opt_rr, + uint16_t payload) +{ + assert(opt_rr != NULL); + opt_rr->payload = payload; +} + +/*----------------------------------------------------------------------------*/ + +uint8_t knot_edns_get_ext_rcode(const knot_opt_rr_t *opt_rr) +{ + return opt_rr->ext_rcode; +} + +/*----------------------------------------------------------------------------*/ + +void knot_edns_set_ext_rcode(knot_opt_rr_t *opt_rr, + uint8_t ext_rcode) +{ + assert(opt_rr != NULL); + opt_rr->ext_rcode = ext_rcode; +} + +/*----------------------------------------------------------------------------*/ + +uint8_t knot_edns_get_version(const knot_opt_rr_t *opt_rr) +{ + assert(opt_rr != NULL); + return opt_rr->version; +} + +/*----------------------------------------------------------------------------*/ + +void knot_edns_set_version(knot_opt_rr_t *opt_rr, + uint8_t version) +{ + assert(opt_rr != NULL); + opt_rr->version = version; +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_edns_get_flags(const knot_opt_rr_t *opt_rr) +{ + assert(opt_rr != NULL); + return opt_rr->flags; +} + +/*----------------------------------------------------------------------------*/ + +int knot_edns_do(const knot_opt_rr_t *opt_rr) +{ + if (opt_rr == NULL) { + return KNOT_EBADARG; + } + + dbg_edns("Flags: %u\n", opt_rr->flags); + return (opt_rr->flags & KNOT_EDNS_DO_MASK); +} + +/*----------------------------------------------------------------------------*/ + +void knot_edns_set_do(knot_opt_rr_t *opt_rr) +{ + if (opt_rr == NULL) { + return; + } + + opt_rr->flags |= KNOT_EDNS_DO_MASK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_edns_add_option(knot_opt_rr_t *opt_rr, uint16_t code, + uint16_t length, const uint8_t *data) +{ + if (opt_rr == NULL) { + return KNOT_EBADARG; + } + + if (opt_rr->option_count == opt_rr->options_max) { + knot_opt_option_t *options_new = + (knot_opt_option_t *)calloc( + (opt_rr->options_max + KNOT_EDNS_OPTION_STEP), + sizeof(knot_opt_option_t)); + CHECK_ALLOC_LOG(options_new, KNOT_ENOMEM); + memcpy(options_new, opt_rr->options, opt_rr->option_count); + opt_rr->options = options_new; + opt_rr->options_max += KNOT_EDNS_OPTION_STEP; + } + + dbg_edns("Adding option.\n"); + dbg_edns("Code: %u.\n", code); + dbg_edns("Length: %u.\n", length); + dbg_edns("Data: %p.\n", data); + + opt_rr->options[opt_rr->option_count].data = (uint8_t *)malloc(length); + CHECK_ALLOC_LOG(opt_rr->options[opt_rr->option_count].data, KNOT_ENOMEM); + memcpy(opt_rr->options[opt_rr->option_count].data, data, length); + + opt_rr->options[opt_rr->option_count].code = code; + opt_rr->options[opt_rr->option_count].length = length; + + ++opt_rr->option_count; + opt_rr->size += 4 + length; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_edns_has_option(const knot_opt_rr_t *opt_rr, uint16_t code) +{ + if (opt_rr == NULL) { + return KNOT_EBADARG; + } + + int i = 0; + while (i < opt_rr->option_count && opt_rr->options[i].code != code) { + ++i; + } + + assert(i >= opt_rr->option_count || opt_rr->options[i].code == code); + + return (i < opt_rr->option_count); +} + +/*----------------------------------------------------------------------------*/ + +short knot_edns_to_wire(const knot_opt_rr_t *opt_rr, uint8_t *wire, + size_t max_size) +{ + if (opt_rr == NULL) { + return KNOT_EBADARG; + } + + assert(KNOT_EDNS_MIN_SIZE <= max_size); + + if (max_size < opt_rr->size) { + dbg_edns("Not enough place for OPT RR wire format.\n"); + return KNOT_ESPACE; + } + + uint8_t *pos = wire; + *(pos++) = 0; + knot_wire_write_u16(pos, KNOT_RRTYPE_OPT); + pos += 2; + knot_wire_write_u16(pos, opt_rr->payload); + pos += 2; + *(pos++) = opt_rr->ext_rcode; + *(pos++) = opt_rr->version; + knot_wire_write_u16(pos, opt_rr->flags); + pos += 2; + + uint8_t *rdlen = pos; + uint16_t len = 0; + pos += 2; + + // OPTIONs + for (int i = 0; i < opt_rr->option_count; ++i) { + knot_wire_write_u16(pos, opt_rr->options[i].code); + pos += 2; + knot_wire_write_u16(pos, opt_rr->options[i].length); + pos += 2; + memcpy(pos, opt_rr->options[i].data, opt_rr->options[i].length); + pos += opt_rr->options[i].length; + len += 4 + opt_rr->options[i].length; + } + + knot_wire_write_u16(rdlen, len); + + return opt_rr->size; +} + +/*----------------------------------------------------------------------------*/ + +short knot_edns_size(knot_opt_rr_t *opt_rr) +{ + if (opt_rr == NULL) { + return KNOT_EBADARG; + } + + return opt_rr->size; +} + +/*----------------------------------------------------------------------------*/ + +void knot_edns_free(knot_opt_rr_t **opt_rr) +{ + if (opt_rr == NULL || *opt_rr == NULL) { + return; + } + + if ((*opt_rr)->option_count > 0) { + free((*opt_rr)->options); + } + free(*opt_rr); + *opt_rr = NULL; +} diff --git a/src/libknot/edns.h b/src/libknot/edns.h new file mode 100644 index 0000000..010d155 --- /dev/null +++ b/src/libknot/edns.h @@ -0,0 +1,273 @@ +/*! + * \file edns.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Functions for manipulating and parsing EDNS OPT pseudo-RR. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_EDNS_H_ +#define _KNOT_EDNS_H_ + +#include <stdint.h> + +#include "util/utils.h" +#include "rrset.h" + +/*----------------------------------------------------------------------------*/ +/*! \brief Structure representing one OPT RR Option. */ +struct knot_opt_option { + uint16_t code; + uint16_t length; + uint8_t *data; +}; + +/*! \brief Structure representing one OPT RR Option. */ +typedef struct knot_opt_option knot_opt_option_t; + +/*! + * \brief Structure for holding EDNS parameters. + * + * \todo NSID + */ +struct knot_opt_rr { + uint16_t payload; /*!< UDP payload. */ + uint8_t ext_rcode; /*!< Extended RCODE. */ + + /*! + * \brief Supported version of EDNS. + * + * Set to EDNS_NOT_SUPPORTED if not supported. + */ + uint8_t version; + + uint16_t flags; /*!< EDNS flags. */ + knot_opt_option_t *options; /*!< EDNS options. */ + short option_count; /*!< Count of EDNS options in this OPT RR.*/ + short options_max; /*!< Maximum count of options. */ + short size; /*!< Total size of the OPT RR in wire format. */ +}; + +/*! \brief Structure for holding EDNS parameters. */ +typedef struct knot_opt_rr knot_opt_rr_t; + +/*----------------------------------------------------------------------------*/ +/*! \brief Constants for supported versions of EDNS. */ +enum knot_edns_versions { + EDNS_VERSION_0 = (uint8_t)0, /*!< EDNS version 0. */ + EDNS_NOT_SUPPORTED = (uint8_t)255 /*!< EDNS not supported. */ +}; + +/*! \brief Constants for EDNS option codes. */ +enum knot_edns_option_codes { + EDNS_OPTION_NSID = (uint16_t)3 /*!< NSID option code. */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates new empty OPT RR structure for holding EDNS parameters. + * + * \return New empty knot_opt_rr_t structure, or NULL if not successful. + */ +knot_opt_rr_t *knot_edns_new(); + +/*! + * \brief Initializes OPT RR structure from given OPT RR in wire format. + * + * \param opt_rr OPT RR structure to initialize. + * \param wire Wire format of the OPT RR to parse. + * \param max_size Maximum size of the wire format in bytes (may be more + * than acutal size of the OPT RR). + * + * \return Size of the parserd OPT RR in bytes if successful (always > 0). + * \retval KNOT_EBADARG + * \retval KNOT_EFEWDATA + * \retval KNOT_EMALF + * \retval KNOT_ENOMEM + */ +int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire, + size_t max_size); + +int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, + const knot_rrset_t *rrset); + +/*! + * \brief Returns the UDP payload stored in the OPT RR. + * + * \warning This function does not check the parameter, so ensure to check it + * before calling the function. It must not be NULL. + * \note There is an assert() for debug checking of the parameter. + * + * \param opt_rr OPT RR structure to get the payload from. + * + * \return UDP payload in bytes. + */ +uint16_t knot_edns_get_payload(const knot_opt_rr_t *opt_rr); + +/*! + * \brief Sets the UDP payload field in the OPT RR. + * + * \warning This function does not check the parameter, so ensure to check it + * before calling the function. It must not be NULL. + * \note There is an assert() for debug checking of the parameter. + * + * \param opt_rr OPT RR structure to set the payload to. + * \param payload UDP payload in bytes. + */ +void knot_edns_set_payload(knot_opt_rr_t *opt_rr, uint16_t payload); + +/*! + * \brief Returns the Extended RCODE stored in the OPT RR. + * + * \warning This function does not check the parameter, so ensure to check it + * before calling the function. It must not be NULL. + * \note There is an assert() for debug checking of the parameter. + * + * \param opt_rr OPT RR structure to get the Extended RCODE from. + * + * \return Extended RCODE. + */ +uint8_t knot_edns_get_ext_rcode(const knot_opt_rr_t *opt_rr); + +/*! + * \brief Sets the Extended RCODE field in the OPT RR. + * + * \warning This function does not check the parameter, so ensure to check it + * before calling the function. It must not be NULL. + * \note There is an assert() for debug checking of the parameter. + * + * \param opt_rr OPT RR structure to set the Extended RCODE to. + * \param ext_rcode Extended RCODE to set. + */ +void knot_edns_set_ext_rcode(knot_opt_rr_t *opt_rr, uint8_t ext_rcode); + +/*! + * \brief Returns the EDNS version stored in the OPT RR. + * + * \warning This function does not check the parameter, so ensure to check it + * before calling the function. It must not be NULL. + * \note There is an assert() for debug checking of the parameter. + * + * \param opt_rr OPT RR structure to get the EDNS version from. + * + * \return EDNS version. + */ +uint8_t knot_edns_get_version(const knot_opt_rr_t *opt_rr); + +/*! + * \brief Sets the EDNS version field in the OPT RR. + * + * \warning This function does not check the parameter, so ensure to check it + * before calling the function. It must not be NULL. + * \note There is an assert() for debug checking of the parameter. + * + * \param opt_rr OPT RR structure to set the EDNS version to. + * \param version EDNS version to set. + */ +void knot_edns_set_version(knot_opt_rr_t *opt_rr, uint8_t version); + +/*! + * \brief Returns the flags stored in the OPT RR. + * + * \warning This function does not check the parameter, so ensure to check it + * before calling the function. It must not be NULL. + * \note There is an assert() for debug checking of the parameter. + * + * \param opt_rr OPT RR structure to get the flags from. + * + * \return EDNS flags. + */ +uint16_t knot_edns_get_flags(const knot_opt_rr_t *opt_rr); + +/*! + * \brief Returns the state of the DO bit in the OPT RR flags. + * + * \param opt_rr OPT RR structure to get the DO bit from. + * + * \return <> 0 if the DO bit is set. + * \return 0 if the DO bit is not set. + */ +int knot_edns_do(const knot_opt_rr_t *opt_rr); + +/*! + * \brief Sets the DO bit in the OPT RR. + * + * \param opt_rr OPT RR structure to set the DO bit in. + */ +void knot_edns_set_do(knot_opt_rr_t *opt_rr); + +/*! + * \brief Adds EDNS Option to the OPT RR. + * + * \param opt_rr OPT RR structure to add the Option to. + * \param code Option code. + * \param length Option data length in bytes. + * \param data Option data. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +int knot_edns_add_option(knot_opt_rr_t *opt_rr, uint16_t code, + uint16_t length, const uint8_t *data); + +/*! + * \brief Checks if the OPT RR contains Option with the specified code. + * + * \param opt_rr OPT RR structure to check for the Option in. + * \param code Option code to check for. + * + * \retval <> 0 if the OPT RR contains Option with Option code \a code. + * \retval 0 otherwise. + */ +int knot_edns_has_option(const knot_opt_rr_t *opt_rr, uint16_t code); + +/*! + * \brief Converts the given OPT RR into wire format. + * + * \param opt_rr OPT RR structure to convert into wire format. + * \param wire Place to put the wire format to. + * \param max_size Maximum space available for the wire format in bytes. + * + * \return Size of the wire format in bytes if successful. + * \retval KNOT_ESPACE + */ +short knot_edns_to_wire(const knot_opt_rr_t *opt_rr, uint8_t *wire, + size_t max_size); + +/*! + * \brief Returns size of the OPT RR in wire format. + * + * \param opt_rr OPT RR to get the size of. + * + * \return Size of the OPT RR in bytes. + */ +short knot_edns_size(knot_opt_rr_t *opt_rr); + +/*! + * \brief Properly destroys the OPT RR structure. + * + * \note Also sets the given pointer to NULL. + */ +void knot_edns_free(knot_opt_rr_t **opt_rr); + +#endif /* _KNOT_EDNS_H_ */ + +/*! @} */ diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c new file mode 100644 index 0000000..c5d1c4f --- /dev/null +++ b/src/libknot/hash/cuckoo-hash-table.c @@ -0,0 +1,1688 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> /* defines uint32_t etc */ +#include <assert.h> +#include <pthread.h> +#include <math.h> + +#include <urcu.h> + +#include "util/utils.h" +#include "common.h" +#include "util/debug.h" +#include "hash/cuckoo-hash-table.h" +#include "hash/hash-functions.h" +#include "common/dynamic-array.h" + +/*----------------------------------------------------------------------------*/ +/* Macros and inline functions */ +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Default size table holding information about used hash table cells + * when hashing. + */ +#define RELOCATIONS_DEFAULT 200 + +/*! + * \brief Maximum size table holding information about used hash table cells + * when hashing (just for debug issues). + */ +#define RELOCATIONS_MAX 1000 + +/*! + * \brief Macro for hashing the given key using the universal system. + * + * \param system Universal system to use for the hashing. + * \param key Key to hash. + * \param length Size of the key in bytes. + * \param exp Exponent of the hash table size (the size is a power of 2). + * \param table Hash table index. + * \param gen Universal system generation. + * + * \return Hashed key. + */ +#define HASH(system, key, length, exp, gen, table) \ + us_hash(system, fnv_32_buf(key, length, FNV1_32_INIT), exp, table, gen) + +/*! + * \brief Approximate ratio of hash table size to number of hashed items when 2 + * tables are used. + */ +static const float SIZE_RATIO_2 = 2; + +/*! + * \brief Approximate ratio of hash table size to number of hashed items when 3 + * tables are used. + */ +static const float SIZE_RATIO_3 = 1.15; + +/*! + * \brief Approximate ratio of hash table size to number of hashed items when 4 + * tables are used. + */ +static const float SIZE_RATIO_4 = 1.08; + +/*----------------------------------------------------------------------------*/ + +/*! \brief Flag marking the generation of hash table or its item to be 1. */ +static const uint8_t FLAG_GENERATION1 = 0x1; // 00000001 +/*! \brief Flag marking the generation of hash table or its item to be 2. */ +static const uint8_t FLAG_GENERATION2 = 0x2; // 00000010 +/*! \brief Flag marking both generations. */ +static const uint8_t FLAG_GENERATION_BOTH = 0x3; // 00000011 + +/*! \brief Flag used to mark the table when it's being rehashed. */ +static const uint8_t FLAG_REHASH = 0x4; // 00000100 + +/*----------------------------------------------------------------------------*/ +/*! \brief Clears the table / item flags. */ +static inline void CLEAR_FLAGS(uint8_t *flags) +{ + *flags = (uint8_t)0x0; +} + +/*! \brief Returns the generation stored in the flags. */ +static inline uint8_t GET_GENERATION(uint8_t flags) +{ + return (flags & FLAG_GENERATION_BOTH); +} + +/*! \brief Checks if the generation stored in both flags are the same. */ +static inline int EQUAL_GENERATIONS(uint8_t flags1, uint8_t flags2) +{ + return (GET_GENERATION(flags1) == GET_GENERATION(flags2)); +} + +/*! \brief Checks if the generation stored in the flags is 1. */ +static inline int IS_GENERATION1(uint8_t flags) +{ + return ((flags & FLAG_GENERATION1) != 0); +} + +/*! \brief Sets the generation stored in the flags to 1. */ +static inline void SET_GENERATION1(uint8_t *flags) +{ + *flags = ((*flags) & ~FLAG_GENERATION2) | FLAG_GENERATION1; +} + +/*! \brief Checks if the generation stored in the flags is 2. */ +static inline int IS_GENERATION2(uint8_t flags) +{ + return ((flags & FLAG_GENERATION2) != 0); +} + +/*! \brief Sets the generation stored in the flags to 2. */ +static inline void SET_GENERATION2(uint8_t *flags) +{ + *flags = ((*flags) & ~FLAG_GENERATION1) | FLAG_GENERATION2; +} + +/*! \brief Sets the generation stored in the flags to the given generation. */ +static inline void SET_GENERATION(uint8_t *flags, uint8_t generation) +{ + *flags = ((*flags) & ~FLAG_GENERATION_BOTH) | generation; +} + +/*! \brief Sets the generation stored in the flags to the next one (cyclic). */ +static inline uint8_t SET_NEXT_GENERATION(uint8_t *flags) +{ + return ((*flags) ^= FLAG_GENERATION_BOTH); +} + +/*! \brief Returns the next generation to the one stored in flags (cyclic). */ +static inline uint8_t NEXT_GENERATION(uint8_t flags) +{ + return ((flags & FLAG_GENERATION_BOTH) ^ FLAG_GENERATION_BOTH); +} + +/*! \brief Sets the rehashing flag to the flags. */ +static inline void SET_REHASHING_ON(uint8_t *flags) +{ + *flags = (*flags | FLAG_REHASH); +} + +/*! \brief Removes the rehashing flag from the flags. */ +static inline void SET_REHASHING_OFF(uint8_t *flags) +{ + *flags = (*flags & ~FLAG_REHASH); +} + +/*! \brief Checks if the rehashing flag is set in the flags. */ +static inline int IS_REHASHING(uint8_t flags) +{ + return ((flags & FLAG_REHASH) != 0); +} + +/*----------------------------------------------------------------------------*/ +/* Private functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns the exponent of the nearest larger power of two. + */ +static uint get_larger_exp(uint n) +{ + uint res = 0; + while (hashsize(++res) < n) {} + + return res; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Counts the ideal table count and the exponent of those tables' sizes. + * + * Only 3 or 4 hash tables are considered. The setup in which less items are + * wasted is recommended. + * + * \param items Number of items to hash. + * \param table_count Recommended number of tables will be saved here. + * + * \return Exponent of the tables' sizes. + */ +static uint get_table_exp_and_count(uint items, uint *table_count) +{ + // considering only 3 or 4 tables + int exp3 = get_larger_exp((items * SIZE_RATIO_3) / 3); + int exp4 = get_larger_exp(items * SIZE_RATIO_4) - 2; + + if (exp4 < 0) { + exp4 = 1; + } + + dbg_ck("Determining ideal table size...\n"); + dbg_ck("\tNumber of items: %u\n", items); + dbg_ck("\tThree tables: size of one table: %u, total size: %u\n", + hashsize(exp3), 3 * hashsize(exp3)); + dbg_ck("\tFour tables: size of one table: %u, total size: %u\n", + hashsize(exp4), 4 * hashsize(exp4)); + + // we need exponent at least 1 (this is quite ugly..) + if (exp3 == 0) { + exp3 = 1; + } + if (exp4 == 0) { + exp4 = 1; + } + + if (exp3 >= 32 || exp4 >= 32) { + return 0; + } + + if (((hashsize(exp3) * 3) - (items)) < ((hashsize(exp4) * 4) - items)) { + *table_count = 3; + return exp3; + } else { + *table_count = 4; + return exp4; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Counts the maximum effective item count based on size of the tables. + * + * For 3 tables, the effective utilization should be around 91%. + * For 4 tables it is 97%. + * + * See Fotakis, Dimitris, et al. - Space Efficient Hash Tables with Worst Case + * Constant Access Time. CiteSeerX. 2003 + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.5337 + */ +static uint get_max_table_items(uint table_count, int table_exponent) +{ + assert(table_count == 3 || table_count == 4); + + float coef; + + if (table_count == 3) { + coef = 0.91; + } else { + coef = 0.97; + } + + return (uint)floor((table_count * hashsize(table_exponent)) * coef); +} + +/*----------------------------------------------------------------------------*/ + +static int ck_is_full(const ck_hash_table_t *table) +{ + return (table->items >= get_max_table_items(table->table_count, + table->table_size_exp)); +} + +/*----------------------------------------------------------------------------*/ + +static int ck_stash_is_full(const ck_hash_table_t *table) +{ + return (table->items_in_stash >= STASH_SIZE_MAX); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Clears the given item by assigning a NULL pointer to it. + */ +static inline void ck_clear_item(ck_hash_table_item_t **item) +{ + *item = NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Insert given contents to the hash table item. + */ +static void ck_fill_item(const char *key, size_t key_length, void *value, + uint generation, ck_hash_table_item_t *item) +{ + // must allocate new space for key and value, otherwise it will be lost! + item->key = key; + item->key_length = key_length; + item->value = value; + CLEAR_FLAGS(&item->timestamp); + item->timestamp = generation; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Swaps two hash table items. + */ +static inline void ck_swap_items(ck_hash_table_item_t **item1, + ck_hash_table_item_t **item2) +{ + ck_hash_table_item_t *tmp = *item1; + *item1 = *item2; + *item2 = tmp; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets the \a item pointer to the \a to pointer. + */ +static inline void ck_put_item(ck_hash_table_item_t **to, + ck_hash_table_item_t *item) +{ + *to = item; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks if the hash was already used twice. + * + * If yes, it means we entered a loop in the hashing process, so we must stop. + * Otherwise it remembers that we used the hash. + * + * \note According to Kirsch, et al. a check that at most one hash was used + * twice should be sufficient. We will retain our version for now. + * + * \param used Array of used table indices (hashes). + * \param hash Hash to check. + * + * \retval -1 if the hash was already used twice. + * \retval -2 if an error occured. + * \retval 0 if the hash was not used twice yet. + */ +static uint ck_check_used_twice(da_array_t *used, uint32_t hash) +{ + uint i = 0, found = 0; + while (i <= da_get_count(used) && found < 2) { + ++i; + if (((uint *)(da_get_items(used)))[i] == hash) { + ++found; + } + } + + if (i <= da_get_count(used) && found == 2) { + dbg_ck_hash("Hashing entered infinite loop.\n"); + return -1; + } else { + if (da_reserve(used, 1) < 0) { + ERR_ALLOC_FAILED; + return -2; + } + ((uint *)da_get_items(used))[da_get_count(used)] = hash; + da_occupy(used, 1); + assert(da_get_count(used) < RELOCATIONS_MAX); + return 0; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Compares the key of item with the given key. + * + * \param item Item to compare with. + * \param key Key to compare. + * \param length Size of the key in bytes. + * + * \return <> 0 if the keys match. + * \return 0 if they don't. + */ +static inline uint ck_items_match(const ck_hash_table_item_t *item, + const char *key, size_t length) +{ + return (length == item->key_length + && (strncmp(item->key, key, length) == 0)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Switches the given table number to a randomly chosen other table + * number. + */ +static inline void ck_next_table(uint *table, uint table_count) +{ + uint next; + while ((*table) == (next = knot_quick_rand() % table_count)) {} + *table = next; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tries to find the given key in the hash table's stash. + * + * \param table Hash table to search in. + * \param key Key to find. + * \param length Size of the key in bytes. + * + * \return Hash table item matching the key or NULL if not found in the stash. + */ +static ck_hash_table_item_t **ck_find_in_stash(const ck_hash_table_t *table, + const char *key, uint length) +{ + ck_stash_item_t *item = table->stash; + while (item != NULL) { + dbg_ck("Comparing item in stash (key: %.*s (size %zu))" + "with searched item (key %.*s (size %u)).\n", + (int)item->item->key_length, item->item->key, + item->item->key_length, (int)length, key, length); + if (ck_items_match(item->item, key, length)) { + return &item->item; + } + item = item->next; + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tries to find item with given key using hash functions from the given + * generation. + * + * \param table Hash table to search in. + * \param key Key to find. + * \param length Size of the key in bytes. + * \param generation Generation of items (table) to use. Items having other + * generation are ignored. + */ +static ck_hash_table_item_t **ck_find_gen(const ck_hash_table_t *table, + const char *key, + size_t length, uint8_t generation) +{ + uint32_t hash; + dbg_ck("Finding item in generation: %u\n", generation); + + // check hash tables + for (uint t = 0; t < table->table_count; ++t) { + hash = HASH(&table->hash_system, key, length, + table->table_size_exp, generation, t); + + dbg_ck("Hash: %u, key: %.*s\n", hash, (int)length, key); + dbg_ck("Table %d, hash: %u, item: %p\n", t + 1, hash, + table->tables[t][hash]); + if (table->tables[t][hash] != NULL) { + dbg_ck("Table %u, key: %.*s, value: %p, key " + "length: %zu\n", + t + 1, (int)table->tables[t][hash]->key_length, + table->tables[t][hash]->key, + table->tables[t][hash]->value, + table->tables[t][hash]->key_length); + } + + if (table->tables[t][hash] && + ck_items_match(table->tables[t][hash], key, length)) { + // found + return &table->tables[t][hash]; + } + } + + // try to find in stash + dbg_ck("Searching in stash...\n"); + + ck_hash_table_item_t **found = + ck_find_in_stash(table, key, length); + + dbg_ck("Found pointer: %p\n", found); + if (found != NULL) { + dbg_ck("Stash, key: %.*s, value: %p, key length: %zu\n", + (int)(*found)->key_length, (*found)->key, + (*found)->value, (*found)->key_length); + } + + // ck_find_in_buffer returns NULL if not found, otherwise pointer to + // item + return found; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Finds item with given key and returns non-constant pointer to pointer + * to the appropriate hash table item. + * + * \param table Hash table to search in. + * \param key Key to find. + * \param length Size of the key in bytes. + */ +static ck_hash_table_item_t **ck_find_item_nc(const ck_hash_table_t *table, + const char *key, size_t length) +{ + // get the generation of the table so that we use the same value + uint8_t generation = table->generation; + + // find item using the table generation's hash functions + ck_hash_table_item_t **found = ck_find_gen(table, key, length, + GET_GENERATION(generation)); + // if rehashing is in progress, try the next generation's functions + if (!found && IS_REHASHING(generation)) { + found = ck_find_gen(table, key, length, + NEXT_GENERATION(generation)); + } + + return found; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hashes the given item using the given generation. + * + * \param table Hash table where to put the item. + * \param to_hash In: Item to hash. Out: NULL if successful, item that failed + * to hash if not. + * \param free Free place where to put the last moved item when the hasing + * is unsuccessful. + * \param generation Generation of items (table) to be used for hashing. + * + * \retval 0 if successful and no loop occured. + * \retval 1 if a loop occured and the item was inserted to the \a free place. + */ +static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, + ck_hash_table_item_t **free, uint8_t generation) +{ + da_array_t used[table->table_count]; + for (uint i = 0; i < table->table_count; ++i) { + da_initialize(&used[i], RELOCATIONS_DEFAULT, sizeof(uint)); + } + + // hash until empty cell is encountered or until loop appears + + dbg_ck_hash("Hashing key: %.*s of size %zu.\n", + (int)(*to_hash)->key_length, (*to_hash)->key, + (*to_hash)->key_length); + + uint next_table = 0; + + uint32_t hash = HASH(&table->hash_system, (*to_hash)->key, + (*to_hash)->key_length, table->table_size_exp, + generation, next_table); + + dbg_ck_hash("New hash: %u.\n", hash); + assert(hash < hashsize(table->table_size_exp)); + + ((uint *)da_get_items(&used[next_table])) + [da_get_count(&used[next_table])] = hash; + ck_hash_table_item_t **next = &table->tables[next_table][hash]; + dbg_ck_hash("Item to be moved: %p, place in table: %p\n", + *next, next); + ck_hash_table_item_t **moving = to_hash; + + int loop = 0; + + while (*next != NULL) { + dbg_ck_hash("Swapping items to hash: %p and Moving: %p\n", + to_hash, moving); + ck_swap_items(to_hash, moving); // first time it's unnecessary + + // set the generation of the inserted item to the next + SET_GENERATION(&(*moving)->timestamp, generation); + + moving = next; + + dbg_ck_hash("Moving item from table %u, key: %.*s, hash %u ", + next_table + 1, (int)(*moving)->key_length, + (*moving)->key, hash); + + // if rehashing and the 'next' item is from the old generation, + // start from table 1 + if (generation != table->generation && + EQUAL_GENERATIONS((*next)->timestamp, table->generation)) { + next_table = 0; + } else { + ck_next_table(&next_table, table->table_count); + } + + hash = HASH(&table->hash_system, (*next)->key, + (*next)->key_length, table->table_size_exp, + generation, next_table); + + next = &table->tables[next_table][hash]; + + dbg_ck_hash("to table %u, hash %u, item: %p, place: %p\n", + next_table + 1, hash, *next, next); + + if ((*next) != NULL) { + dbg_ck_hash("Table %u, hash: %u, key: %.*s\n", + next_table + 1, hash, + (int)(*next)->key_length, (*next)->key); + } + + // check if this cell wasn't already used in this item's hashing + if (ck_check_used_twice(&used[next_table], hash) != 0) { + next = free; + loop = -1; + break; + } + } + + dbg_ck_hash("Putting pointer %p (*moving) to item %p (next).\n", + *moving, next); + + ck_put_item(next, *moving); + // set the new generation for the inserted item + SET_GENERATION(&(*next)->timestamp, generation); + dbg_ck_hash("Putting pointer %p (*old) to item %p (moving).\n", + *to_hash, moving); + + ck_put_item(moving, *to_hash); + + // set the new generation for the inserted item + SET_GENERATION(&(*moving)->timestamp, generation); + *to_hash = NULL; + + for (uint i = 0; i < table->table_count; ++i) { + da_destroy(&used[i]); + } + + return loop; +} + +/*----------------------------------------------------------------------------*/ + +static void ck_rollback_rehash(ck_hash_table_t *table) +{ + // set old generation in tables + for (int i = 0; i < hashsize(table->table_size_exp); ++i) { + // no need for locking - timestamp is not used in lookup + // and two paralel insertions (and thus rehashings) are + // impossible + for (uint t = 0; t < table->table_count; ++t) { + if (table->tables[t][i] != NULL) { + SET_GENERATION(&table->tables[t][i]->timestamp, + table->generation); + } + } + } + + // set old generation in stash + ck_stash_item_t *item = table->stash; + while (item != NULL) { + assert(item->item != NULL); + SET_GENERATION(&item->item->timestamp, table->generation); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adds the given item to the hash table's stash. + * + * \param table Hash table to add the item to. + * \param item Item to add. + * + * \retval 0 if successful. + * \retval -1 if an error occured. + */ +int ck_add_to_stash(ck_hash_table_t *table, ck_hash_table_item_t *item) +{ + ck_stash_item_t *new_item + = (ck_stash_item_t *)malloc(sizeof(ck_stash_item_t)); + if (new_item == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + new_item->item = item; + new_item->next = table->stash; + table->stash = new_item; + + dbg_ck_hash("First item in stash (now inserted): key: %.*s (size %zu)" + ", value: %p\n", (int)table->stash->item->key_length, + table->stash->item->key, table->stash->item->key_length, + table->stash->item->value); + + // increase count of items in stash + ++table->items_in_stash; + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static int ck_new_table(ck_hash_table_item_t ***table, int exp) +{ + *table = (ck_hash_table_item_t **) + malloc(hashsize(exp) * sizeof(ck_hash_table_item_t *)); + if (*table == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + // set to 0 + memset(*table, 0, hashsize(exp) * sizeof(ck_hash_table_item_t *)); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Public functions */ +/*----------------------------------------------------------------------------*/ + +ck_hash_table_t *ck_create_table(uint items) +{ + ck_hash_table_t *table = + (ck_hash_table_t *)malloc(sizeof(ck_hash_table_t)); + + if (table == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + memset(table, 0, sizeof(ck_hash_table_t)); + + // determine ideal size of one table in powers of 2 and save the + // exponent + table->table_size_exp = get_table_exp_and_count(items, + &table->table_count); + assert(table->table_size_exp <= 32); + + if (table->table_size_exp == 0) { + dbg_ck("Failed to count exponent of the hash table.\n"); + return NULL; + } + + dbg_ck("Creating hash table for %u items.\n", items); + dbg_ck("Exponent: %u, number of tables: %u\n ", + table->table_size_exp, table->table_count); + dbg_ck("Table size: %u items, each %zu bytes, total %zu bytes\n", + hashsize(table->table_size_exp), + sizeof(ck_hash_table_item_t *), + hashsize(table->table_size_exp) + * sizeof(ck_hash_table_item_t *)); + + // create tables + for (uint t = 0; t < table->table_count; ++t) { + dbg_ck("Creating table %u...\n", t); + if (ck_new_table(&table->tables[t], table->table_size_exp) + != 0) { + for (uint i = 0; i < t; ++i) { + free(table->tables[i]); + } + free(table); + return NULL; + } + } + + assert(table->stash == NULL); + assert(table->hashed == NULL); + assert(table->items == 0); + assert(table->items_in_stash == 0); + assert(table->table_count == MAX_TABLES + || table->tables[table->table_count] == NULL); + + // initialize rehash/insert mutex + pthread_mutex_init(&table->mtx_table, NULL); + + // set the generation to 1 and initialize the universal system + CLEAR_FLAGS(&table->generation); + SET_GENERATION1(&table->generation); + + us_initialize(&table->hash_system); + + return table; +} + +/*----------------------------------------------------------------------------*/ + +void ck_destroy_table(ck_hash_table_t **table, void (*dtor_value)(void *value), + int delete_key) +{ + assert(table); + assert(*table); + pthread_mutex_lock(&(*table)->mtx_table); + + // destroy items in tables + for (uint i = 0; i < hashsize((*table)->table_size_exp); ++i) { + for (uint t = 0; t < (*table)->table_count; ++t) { + if ((*table)->tables[t][i] != NULL) { + if (dtor_value) { + dtor_value( + (*table)->tables[t][i]->value); + } + if (delete_key != 0) { + free( + (void *)(*table)->tables[t][i]->key); + } + free((void *)(*table)->tables[t][i]); + } + } + } + + // destroy items in stash +// ck_hash_table_item_t **stash = +// ((ck_hash_table_item_t **)(da_get_items(&(*table)->stash))); +// for (uint i = 0; i < da_get_count(&(*table)->stash); ++i) { +// assert(stash[i] != NULL); +// if (dtor_value) { +// dtor_value(stash[i]->value); +// } +// if (delete_key != 0) { +// free((void *)stash[i]->key); +// } +// free((void *)stash[i]); +// } + ck_stash_item_t *item = (*table)->stash; + while (item != NULL) { + // disconnect the item + (*table)->stash = item->next; + /*! \todo Investigate this. */ + assert(item->item != NULL); + + if (dtor_value) { + dtor_value(item->item->value); + } + if (delete_key) { + free((void *)item->item->key); + } + + free((void *)item->item); + free(item); + item = (*table)->stash; + } + + // deallocate tables + for (uint t = 0; t < (*table)->table_count; ++t) { + free((*table)->tables[t]); + } + // destroy stash +// da_destroy(&(*table)->stash); + + pthread_mutex_unlock(&(*table)->mtx_table); + // destroy mutex, assuming that here noone will lock the mutex again + pthread_mutex_destroy(&(*table)->mtx_table); + + free(*table); + (*table) = NULL; +} + +void ck_table_free(ck_hash_table_t **table) +{ + if (table == NULL || *table == NULL) { + return; + } + + pthread_mutex_lock(&(*table)->mtx_table); + + ck_stash_item_t *item = (*table)->stash; + while (item != NULL) { + // disconnect the item + (*table)->stash = item->next; + free(item); + item = (*table)->stash; + } + + // deallocate tables + for (uint t = 0; t < (*table)->table_count; ++t) { + free((*table)->tables[t]); + } + + pthread_mutex_unlock(&(*table)->mtx_table); + pthread_mutex_destroy(&(*table)->mtx_table); + + free(*table); + (*table) = NULL; +} + +int ck_resize_table(ck_hash_table_t *table) +{ + dbg_ck("Resizing hash table.\n"); + + /* + * Easiest is just to increment the exponent, resulting in doubling + * the table sizes. This is not very memory-effective, but should do + * the job. + */ + + if (table->table_size_exp == 31) { + dbg_ck("Hash tables achieved max size (exponent 31).\n"); + return -1; + } + + ck_hash_table_item_t **tables_new[MAX_TABLES]; + ck_hash_table_item_t **tables_old[MAX_TABLES]; + int exp_new = table->table_size_exp + 1; + + dbg_ck("New tables exponent: %d\n", exp_new); + + for (int t = 0; t < table->table_count; ++t) { + if (ck_new_table(&tables_new[t], exp_new) != 0) { + dbg_ck("Failed to create new table.\n"); + for (int i = 0; i < t; ++i) { + free(tables_new[i]); + } + return -1; + } + } + + dbg_ck("Created new tables, copying data to them.\n"); + + for (int t = 0; t < table->table_count; ++t) { + size_t old_size = hashsize(table->table_size_exp) + * sizeof(ck_hash_table_item_t *); + + // copy the old table items + dbg_ck("Copying to: %p, from %p, size: %zu\n", + tables_new[t], table->tables[t], old_size); + memcpy(tables_new[t], table->tables[t], old_size); + // set the rest to 0 + dbg_ck("Setting to 0 from %p, size %zu\n", + tables_new[t] + hashsize(table->table_size_exp), + (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) + - old_size); + memset(tables_new[t] + hashsize(table->table_size_exp), 0, + (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) + - old_size); + } + + dbg_ck("Done, switching the tables and running rehash.\n"); + + + memcpy(tables_old, table->tables, + MAX_TABLES * sizeof(ck_hash_table_item_t **)); + memcpy(table->tables, tables_new, + MAX_TABLES * sizeof(ck_hash_table_item_t **)); + + table->table_size_exp = exp_new; + + // delete the old tables + for (int t = 0; t < table->table_count; ++t) { + free(tables_old[t]); + } + + return ck_rehash(table); + //return 0; +} + +int ck_insert_item(ck_hash_table_t *table, const char *key, + size_t length, void *value) +{ + // lock mutex to avoid write conflicts + pthread_mutex_lock(&table->mtx_table); + + assert(value != NULL); + + dbg_ck_hash("Inserting item with key: %.*s.\n", (int)length, key); + dbg_ck_hash_hex(key, length); + dbg_ck_hash("\n"); + + // create item structure and fill in the given data, key won't be copied + ck_hash_table_item_t *new_item = + (ck_hash_table_item_t *)malloc((sizeof(ck_hash_table_item_t))); + ck_fill_item(key, length, value, GET_GENERATION(table->generation), + new_item); + + // check if the table is not full; if yes, resize and rehash! + if (ck_is_full(table)) { + dbg_ck("Table is full, resize needed.\n"); + if (ck_resize_table(table) != 0) { + dbg_ck("Failed to resize hash table!\n"); + return -1; + } + } + + // there should be at least 2 free places + //assert(da_try_reserve(&table->stash, 2) == 0); + //da_reserve(&table->stash, 1); + ck_hash_table_item_t *free_place = NULL; + if (ck_hash_item(table, &new_item, &free_place, + table->generation) != 0) { + + dbg_ck("Adding item with key %.*s to stash.\n", + (int)free_place->key_length, free_place->key); + + // maybe some limit on the stash and rehash if full + if (ck_add_to_stash(table, free_place) != 0) { + dbg_ck_hash("Could not add item to stash!!\n"); + assert(0); + } + + if (ck_stash_is_full(table)) { + dbg_ck("Stash is full, resize needed.\n"); + if (ck_resize_table(table) != 0) { + dbg_ck("Failed to resize hash table!\n"); + return -1; + } + } + } + + ++table->items; + pthread_mutex_unlock(&table->mtx_table); + return 0; +} + +/*----------------------------------------------------------------------------*/ + +const ck_hash_table_item_t *ck_find_item(const ck_hash_table_t *table, + const char *key, size_t length) +{ + dbg_ck("ck_find_item(), key: %.*s, size: %zu\n", + (int)length, key, length); + + ck_hash_table_item_t **found = ck_find_item_nc(table, key, length); + + return (found == NULL) ? NULL : rcu_dereference(*found); +} + +/*----------------------------------------------------------------------------*/ + +int ck_update_item(const ck_hash_table_t *table, const char *key, size_t length, + void *new_value, void (*dtor_value)(void *value)) +{ + rcu_read_lock(); // is needed? + + assert(new_value != NULL); + + ck_hash_table_item_t **item = ck_find_item_nc(table, key, length); + + if (item == NULL || (*item) == NULL) { + return -1; + } + + void *old = rcu_xchg_pointer(&(*item)->value, new_value); + rcu_read_unlock(); + + synchronize_rcu(); + if (dtor_value) { + dtor_value(old); + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +int ck_delete_item(const ck_hash_table_t *table, const char *key, size_t length, + void (*dtor_value)(void *value), int delete_key) +{ + rcu_read_lock(); // is needed? + ck_hash_table_item_t **place = ck_find_item_nc(table, key, length); + + if (place == NULL) { + return -1; + } + + ck_hash_table_item_t *item = *place; + + assert(item != NULL); + + ck_put_item(place, NULL); + rcu_read_unlock(); + + synchronize_rcu(); + if (dtor_value) { + dtor_value(item->value); + } + item->value = NULL; + if (delete_key != 0) { + free((void *)item->key); + } + free(item); + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +ck_hash_table_item_t *ck_remove_item(ck_hash_table_t *table, const char *key, + size_t length) +{ + ck_hash_table_item_t **place = ck_find_item_nc(table, key, length); + if (place == NULL) { + return NULL; + } + + ck_hash_table_item_t *item = *place; + *place = NULL; + return item; +} + +/*----------------------------------------------------------------------------*/ + +int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to) +{ + if (from == NULL || to == NULL) { + return -1; + } + + *to = (ck_hash_table_t *)malloc(sizeof(ck_hash_table_t)); + + if (*to == NULL) { + ERR_ALLOC_FAILED; + return -2; + } + memset(*to, 0, sizeof(ck_hash_table_t)); + + // copy table count and table size exponent + (*to)->table_size_exp = from->table_size_exp; + (*to)->table_count = from->table_count; + assert((*to)->table_size_exp <= 32); + + dbg_ck("Creating hash table for %u items.\n", from->table_count); + dbg_ck("Exponent: %u, number of tables: %u\n ", + (*to)->table_size_exp, (*to)->table_count); + dbg_ck("Table size: %u items, each %zu bytes, total %zu bytes\n", + hashsize((*to)->table_size_exp), + sizeof(ck_hash_table_item_t *), + hashsize((*to)->table_size_exp) + * sizeof(ck_hash_table_item_t *)); + + // create tables + for (uint t = 0; t < (*to)->table_count; ++t) { + dbg_ck("Creating table %u...\n", t); + (*to)->tables[t] = (ck_hash_table_item_t **)malloc( + hashsize((*to)->table_size_exp) + * sizeof(ck_hash_table_item_t *)); + if ((*to)->tables[t] == NULL) { + ERR_ALLOC_FAILED; + for (uint i = 0; i < t; ++i) { + free((*to)->tables[i]); + } + free(*to); + return -2; + } + + // copy the table + memcpy((*to)->tables[t], from->tables[t], + hashsize((*to)->table_size_exp) + * sizeof(ck_hash_table_item_t *)); + } + + // copy the stash - we must explicitly copy each stash item, but do not + // copy the ck_hash_table_item_t within them. + ck_stash_item_t *si = from->stash; + ck_stash_item_t **pos = &(*to)->stash; + dbg_ck_verb(stderr, "Copying hash table stash.\n"); + while (si != NULL) { + ck_stash_item_t *si_new = (ck_stash_item_t *) + malloc(sizeof(ck_stash_item_t)); + if (si_new == NULL) { + ERR_ALLOC_FAILED; + // delete tables + for (uint i = 0; i < (*to)->table_count; ++i) { + free((*to)->tables[i]); + } + // delete created stash items + si_new = (*to)->stash; + while (si_new != NULL) { + ck_stash_item_t *prev = si_new; + si_new = si_new->next; + free(prev); + } + free(*to); + return -2; + } + + dbg_ck("Copying stash item: %p with item %p, ", si, si->item); + dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); + + si_new->item = si->item; + *pos = si_new; + pos = &si_new->next; + si = si->next; + + + dbg_ck("Old stash item: %p with item %p, ", si, + ((si == NULL) ? NULL : si->item)); + if (si != NULL) { + dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); + } else { + dbg_ck("\n"); + } + dbg_ck("New stash item: %p with item %p, ", si_new, + si_new->item); + dbg_ck("key: %.*s\n", (int)si_new->item->key_length, + si_new->item->key); + } + + *pos = NULL; + + // there should be no item being hashed right now + /*! \todo This operation should not be done while inserting / rehashing. + */ + assert(from->hashed == NULL); + (*to)->hashed = NULL; + + // initialize rehash/insert mutex + pthread_mutex_init(&(*to)->mtx_table, NULL); + + // copy the generation + (*to)->generation = from->generation; + + // copy the hash functions + memcpy(&(*to)->hash_system, &from->hash_system, sizeof(us_system_t)); + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +int ck_apply(ck_hash_table_t *table, + void (*function)(ck_hash_table_item_t *item, void *data), + void *data) +{ + if (table == NULL || function == NULL) { + return -1; + } + + /*! \todo Ensure that no insertion nor rehash is made during applying.*/ + + // apply the function to all items in all tables + for (int t = 0; t < table->table_count; ++t) { + for (int i = 0; i < hashsize(table->table_size_exp); ++i) { + function(table->tables[t][i], data); + } + } + + // apply the function to the stash items + ck_stash_item_t *si = table->stash; + while (si != NULL) { + function(si->item, data); + si = si->next; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +int ck_rehash(ck_hash_table_t *table) +{ + dbg_ck_hash("Rehashing items in table.\n"); + SET_REHASHING_ON(&table->generation); + + ck_stash_item_t *free_stash_items = NULL; + + do { + // 1) Rehash items from stash + dbg_ck_rehash("Rehashing items from stash.\n"); + ck_stash_item_t *item = table->stash; + ck_stash_item_t **item_place = &table->stash; + // terminate when at the end; this way the newly added items + // (added to the beginning) will be properly ignored + while (item != NULL) { + dbg_ck_rehash("Rehashing item with " + "key (length %zu): %.*s, generation: %hu, " + "table generation: %hu.\n", item->item->key_length, + (int)item->item->key_length, item->item->key, + GET_GENERATION( + item->item->timestamp), + GET_GENERATION(table->generation)); + + // put the hashed item to the prepared space + table->hashed = item->item; + item->item = NULL; + // we may use the place in the stash item as the free + // place for rehashing + if (ck_hash_item(table, &table->hashed, &item->item, + NEXT_GENERATION(table->generation)) != 0) { + // the free place was used + assert(item->item != NULL); + // we may leave the item there (in the stash) + assert(EQUAL_GENERATIONS(item->item->timestamp, + NEXT_GENERATION(table->generation))); + //assert(item->item == table->hashed); + + item_place = &item->next; + item = item->next; + } else { + // the free place should be free + assert(item->item == NULL); + // and the item should be hashed too +// assert(table->hashed == NULL); + + // fix the pointer from the previous hash item + *item_place = item->next; + // and do not change the item place pointer + + // put the stash item into list of free stash + // items + item->next = free_stash_items; + free_stash_items = item; + + item = *item_place; + } + } + + // 2) Rehash items from tables + + // in case of failure, save the item in a temp variable + // which will be put to the stash + ck_hash_table_item_t *free = NULL; + assert(table->hashed == NULL); +// ck_hash_table_item_t *old = table->hashed; + + for (uint t = 0; t < table->table_count; ++t) { + uint rehashed = 0; + + dbg_ck_rehash("Rehashing table %d.\n", t); + + while (rehashed < hashsize(table->table_size_exp)) { + + // if item's generation is the new generation, + // skip + if (table->tables[t][rehashed] == NULL + || !(EQUAL_GENERATIONS( + table->tables[t][rehashed]->timestamp, + table->generation))) { + dbg_ck_rehash("Skipping item.\n"); + ++rehashed; + continue; + } + + dbg_ck_rehash("Rehashing item with hash %u, " + "key (length %zu): %.*s, generation: %hu, " + "table generation: %hu.\n", rehashed, + table->tables[t][rehashed]->key_length, + (int)(table->tables[t][rehashed]->key_length), + table->tables[t][rehashed]->key, + GET_GENERATION( + table->tables[t][rehashed]->timestamp), + GET_GENERATION(table->generation)); + + // otherwise copy the item for rehashing + ck_put_item(&table->hashed, table->tables[t][rehashed]); + // clear the place so that this item will not + // get rehashed again + ck_clear_item(&table->tables[t][rehashed]); + + dbg_ck_rehash("Table generation: %hu, next " + "generation: %hu.\n", + GET_GENERATION(table->generation), + NEXT_GENERATION(table->generation)); + + if (ck_hash_item(table, &table->hashed, &free, + NEXT_GENERATION(table->generation)) != 0) { + // loop occured + dbg_ck_hash("Hashing entered a loop." + "\n"); + dbg_ck_rehash("Item with key %.*s " + "inserted into the free slot.\n", + free->key_length, free->key); + + //assert(old == free); + + // put the item into the stash, but + // try the free stash items first + if (free_stash_items != NULL) { + // take first + ck_stash_item_t *item = + free_stash_items; + free_stash_items = item->next; + + item->item = free; + item->next = table->stash; + table->stash = item; + } else { + if (ck_add_to_stash(table, free) + != 0) { + ck_rollback_rehash( + table); + } + } + + free = NULL; + table->hashed = NULL; + } + ++rehashed; + } + } + + dbg_ck_rehash("Old table generation: %u\n", + GET_GENERATION(table->generation)); + // rehashing completed, switch generation of the table + SET_NEXT_GENERATION(&table->generation); + dbg_ck_rehash("New table generation: %u\n", + GET_GENERATION(table->generation)); + // generate new hash functions for the old generation + dbg_ck_rehash("Generating coeficients for generation: %u\n", + NEXT_GENERATION(table->generation)); + us_next(&table->hash_system, + NEXT_GENERATION(table->generation)); + + } while (false /*! \todo Add proper condition!! */); + + SET_REHASHING_OFF(&table->generation); + + assert(table->hashed == NULL); + + + while (free_stash_items != NULL) { + ck_stash_item_t *item = free_stash_items; + free_stash_items = item->next; + assert(item->item == NULL); + free(item); + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Rehashes the whole table. + * + * \param table Hash table to be rehashed. + * + * \note While rehashing no item should be inserted as it will result in a + * deadlock. + * + * \retval 0 No error. + * \retval -1 Rehashing failed. Some items may have been already moved and the + * rehashing flag remains set. + * + * \todo What if the stash is reallocated during ck_hash_item()? We'd be using + * the old stash for saving items! The old stash would not get deallocated + * (due to RCU - maybe put some rcu_read_lock() here), but the item + * would not be saved into the new stash! + * Maybe add a function for getting a pointer to particular item from + * the dynamic array and protect it using rcu_read_lock(). + * Other option: Do not use pointer to an item in stash in the call to + * ck_hash_item(). Use some new place & put the item to the stash + * afterwards, protecting it using rcu_read_lock() and rcu_assign_pointer. + */ +//int ck_rehash(ck_hash_table_t *table) +//{ +// dbg_ck_rehash("Rehashing items in table.\n"); +// SET_REHASHING_ON(&table->generation); + +// // we already have functions for the next generation, begin rehashing +// // we wil use the last item in the buffer as free cell for hashing +// assert(da_try_reserve(&table->stash, 1) == 0); +// ck_hash_table_item_t *old = (ck_hash_table_item_t *) +// (malloc(sizeof(ck_hash_table_item_t))); + +// do { +// dbg_ck_hash("Rehash!\n"); + +// if (da_get_count(&table->stash) > STASH_SIZE) { +// dbg_ck_hash("STASH RESIZED!!! (new stash size: %d)\n", +// da_get_count(&table->stash)); +// } + +// // rehash items from stash, starting from the last old item +// int stash_i = da_get_count(&table->stash) - 1; +// while (stash_i >= 0) { +// // if item's generation is the new generation, skip +// if (STASH_ITEMS(&table->stash)[stash_i] == NULL +// || !(EQUAL_GENERATIONS(STASH_ITEMS(&table->stash) +// [stash_i]->timestamp, +// table->generation))) { +// dbg_ck_rehash("Skipping item.\n"); +// --stash_i; +// continue; +// } + +// dbg_ck_rehash("Rehashing item from buffer position %u" +// ", key (length %u): %.*s, generation: " +// "%hu, table generation: %hu.\n", +// stash_i, +// STASH_ITEMS(&table->stash)[stash_i]->key_length, +// (int)STASH_ITEMS(&table->stash)[stash_i]->key_length, +// STASH_ITEMS(&table->stash)[stash_i]->key, +// GET_GENERATION( +// STASH_ITEMS(&table->stash)[stash_i]->timestamp), +// GET_GENERATION(table->generation)); + +// // otherwise copy the item for rehashing +// ck_put_item(&old, STASH_ITEMS(&table->stash)[stash_i]); +// // clear the place so that this item will not get +// // rehashed again +// ck_clear_item(&STASH_ITEMS(&table->stash)[stash_i]); +// da_release(&table->stash, 1); + +// // there should be at least one place in the stash +// assert(da_try_reserve(&table->stash, 1) == 0); +// da_reserve(&table->stash, 1); + +// assert(STASH_ITEMS(&table->stash)[stash_i] == NULL); + +// // and start rehashing +// if (ck_hash_item(table, &old, +// &STASH_ITEMS(&table->stash)[stash_i], +// NEXT_GENERATION(table->generation)) != 0) { +// // loop occured +// dbg_ck_hash("Hashing entered a loop.\n"); + +// dbg_ck_rehash("Item with key %.*s inserted " +// "into the stash on position %d.\n", +// STASH_ITEMS(&table->stash) +// [stash_i]->key_length, +// STASH_ITEMS(&table->stash) +// [stash_i]->key, +// da_get_count(&table->stash)); + +// // hashing unsuccessful, the item was inserted +// // into the stash +// da_occupy(&table->stash, 1); +// assert(STASH_ITEMS(&table->stash)[stash_i] +// != NULL); + +// // if only one place left, resize the stash +// // TODO: Why??? +// if (da_reserve(&table->stash, 2) < 0) { +// // stash could not be resized => !!! +// dbg_ck_hash("Failed to rehash items " +// "from " +// "table, no other rehash possible!\n"); +// // so rollback +// ck_rollback_rehash(table); +// // clear the 'old' item +// ck_clear_item(&old); +// return -1; +// } +// } + +// // clear the 'old' item +// ck_clear_item(&old); +// // decrement the index +// --stash_i; +// } + +// uint i = 0; +// while (i < da_get_count(&table->stash)) { +// assert(STASH_ITEMS(&table->stash)[i] != NULL); +// ++i; +// } +// dbg_ck_hash("OK\n"); +// assert(da_try_reserve(&table->stash, 1) == 0); +// assert(STASH_ITEMS(&table->stash)[da_get_count(&table->stash)] +// == NULL); + +// // rehash items from hash tables +// for (uint t = TABLE_FIRST; +// t <= TABLE_LAST(table->table_count); ++t) { +// dbg_ck_rehash("Rehashing items from table %d.\n", +// t + 1); +// uint rehashed = 0; + +// while (rehashed < hashsize(table->table_size_exp)) { + +// // if item's generation is the new generation, +// // skip +// if (table->tables[t][rehashed] == NULL +// || !(EQUAL_GENERATIONS( +// table->tables[t][rehashed]->timestamp, +// table->generation))) { +// dbg_ck_rehash("Skipping item.\n"); +// ++rehashed; +// continue; +// } + +// dbg_ck_rehash("Rehashing item with hash %u, " +// "key (length %u): %.*s, generation: %hu, " +// "table generation: %hu.\n", rehashed, +// table->tables[t][rehashed]->key_length, +// (int)(table->tables[t][rehashed]->key_length), +// table->tables[t][rehashed]->key, +// GET_GENERATION( +// table->tables[t][rehashed]->timestamp), +// GET_GENERATION(table->generation)); + +// // otherwise copy the item for rehashing +// ck_put_item(&old, table->tables[t][rehashed]); +// // clear the place so that this item will not +// // get rehashed again +// ck_clear_item(&table->tables[t][rehashed]); + +// dbg_ck_rehash("Table generation: %hu, next " +// "generation: %hu.\n", +// GET_GENERATION(table->generation), +// NEXT_GENERATION(table->generation)); + +// // and start rehashing +// assert(&old != &STASH_ITEMS(&table->stash)[ +// da_get_count(&table->stash)]); +// assert(da_try_reserve(&table->stash, 1) == 0); +// da_reserve(&table->stash, 1); + +// if (ck_hash_item(table, &old, +// &STASH_ITEMS(&table->stash)[ +// da_get_count(&table->stash)], +// NEXT_GENERATION(table->generation)) != 0) { +// // loop occured +// dbg_ck_hash("Hashing entered a loop." +// "\n"); +// dbg_ck_rehash("Item with key %.*s " +// "inserted into the stash on position " +// "%d.\n", STASH_ITEMS(&table->stash)[ +// da_get_count(&table->stash)] +// ->key_length, +// STASH_ITEMS(&table->stash)[ +// da_get_count(&table->stash)]->key, +// da_get_count(&table->stash)); + +// assert(STASH_ITEMS(&table->stash)[ +// da_get_count(&table->stash)] != NULL); +// // loop occured, the item is already at +// // its new place in the buffer, so just +// // increment the index +// da_occupy(&table->stash, 1); + +// // if only one place left, resize the +// // stash TODO: Why? +// if (da_reserve(&table->stash, 2) < 0) { +// // stash could not be resized +// dbg_ck_hash("Failed to rehash" +// " items from table, no other " +// "rehash possible!\n"); +// // so rollback +// ck_rollback_rehash(table); +// // clear the 'old' item +// ck_clear_item(&old); +// return -1; +// } +// } +// ++rehashed; +// } +// } + +// dbg_ck_rehash("Old table generation: %u\n", +// GET_GENERATION(table->generation)); +// // rehashing completed, switch generation of the table +// SET_NEXT_GENERATION(&table->generation); +// dbg_ck_rehash("New table generation: %u\n", +// GET_GENERATION(table->generation)); +// // generate new hash functions for the old generation +// dbg_ck_rehash("Generating coeficients for generation: %u\n", +// NEXT_GENERATION(table->generation)); +// us_next(NEXT_GENERATION(table->generation)); + +// // repeat rehashing while there are more items in the stash than +// // its initial size +// if (da_get_count(&table->stash) > STASH_SIZE) { +// dbg_ck_rehash("Rehashing again!\n"); +// } +// } while (da_get_count(&table->stash) > STASH_SIZE); + +// SET_REHASHING_OFF(&table->generation); + +// return 0; +//} + +/*----------------------------------------------------------------------------*/ + +void ck_dump_table(const ck_hash_table_t *table) +{ +#ifdef CUCKOO_DEBUG + uint i = 0; + dbg_ck("----------------------------------------------\n"); + dbg_ck("Hash table dump:\n\n"); + dbg_ck("Size of each table: %u\n\n", hashsize(table->table_size_exp)); + + for (uint t = 0; t < table->table_count; ++t) { + dbg_ck("Table %d:\n", t + 1); + + for (i = 0; i < hashsize(table->table_size_exp); i++) { + dbg_ck("Hash: %u, Key: %.*s, Value: %p.\n", i, + (int)(table->tables[t])[i]->key_length, + (table->tables[t])[i]->key, + (table->tables[t])[i]->value); + } + } + + dbg_ck("Stash:\n"); +// for (i = 0; i < da_get_count(&table->stash); ++i) { +// dbg_ck("Index: %u, Key: %.*s Value: %p.\n", i, +// ((ck_hash_table_item_t **) +// da_get_items(&table->stash))[i]->key_length, +// ((ck_hash_table_item_t **) +// da_get_items(&table->stash))[i]->key, +// ((ck_hash_table_item_t **) +// da_get_items(&table->stash))[i]->value); +// } + ck_stash_item_t *item = table->stash; + while (item != NULL) { + dbg_ck("Hash: %u, Key: %.*s, Value: %p.\n", i, + (int)item->item->key_length, item->item->key, + item->item->value); + item = item->next; + } + + dbg_ck("\n"); +#endif +} diff --git a/src/libknot/hash/cuckoo-hash-table.h b/src/libknot/hash/cuckoo-hash-table.h new file mode 100644 index 0000000..dd78294 --- /dev/null +++ b/src/libknot/hash/cuckoo-hash-table.h @@ -0,0 +1,333 @@ +/*! + * \file cuckoo-hash-table.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Implementation of Cuckoo hashing scheme. + * + * Uses d-ary Cuckoo hashing with stash. + * + * \todo Maybe provide some way to resize the whole table if the number of items + * grows too much. + * \todo Check size of integers, the table size may be larger than unsigned int. + * \todo Maybe do not return ck_hash_table_item from ck_find_item(), but only + * its value. + * \todo When hashing an item, only the first table is tried for this item. + * We may try all tables. (But it is not neccessary.) + * + * \addtogroup hashing + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_CUCKOO_HASH_TABLE_H_ +#define _KNOT_CUCKOO_HASH_TABLE_H_ + +#include <stdint.h> /* uint32_t */ +#include <stdlib.h> /* size_t */ +#include <pthread.h> + +#include "hash/universal-system.h" +#include "common/dynamic-array.h" + +/*----------------------------------------------------------------------------*/ + +/*! \brief Macro for getting one hash table size. */ +#define hashsize(n) ((uint32_t)1 << (n)) + +/*! + * \brief Max number of hash tables - must be the same as number of the hash + * functions in each generation of the universal system. + */ +#define MAX_TABLES US_FNC_COUNT + +/*! \brief Default stash size. */ +static const uint STASH_SIZE = 10; + +/*! \brief Maximum stash size. When achieved, rehashing is needed. */ +static const uint STASH_SIZE_MAX = 30; + +/*----------------------------------------------------------------------------*/ +/* Public structures */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure for storing the hashed data. + */ +struct ck_hash_table_item { + const char *key; /*!< Key of the item, used for hashing. */ + + size_t key_length; /*!< Length of the key in octets. */ + + void *value; /*!< The actual item stored in the table. */ + + /*! + * \brief Flags. Currently used for keeping the generation of the item, + * i.e. the generation of the functions used for hashing this + * item. + * + * Form: 000000xy; + * xy - generation; may be 01 (1) or 10 (2). + */ + uint8_t timestamp; +}; + +typedef struct ck_hash_table_item ck_hash_table_item_t; + +struct ck_stash_item { + ck_hash_table_item_t *item; + struct ck_stash_item *next; +}; + +typedef struct ck_stash_item ck_stash_item_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hash table structure which uses cuckoo hashing. + * + * Keys are expected to be strings of characters (char *), not necesarily + * null-terminated. It uses the Fowler/Noll/Vo (FNV) hash function to + * obtain a 32bit unsigned integer from the character data and a function + * randomly chosen from an universal system (see universal-system.h) to obtain + * the final hash. The FNV hash was taken from + * http://home.comcast.net/~bretm/hash/6.html and the universal system is + * constructed according to Katajainen J., Lykke M., Experiments with universal + * hashing (obtained from + * http://www.diku.dk/OLD/publikationer/tekniske.rapporter/rapporter/96-08.pdf). + * + * The table uses either 3-ary or 4-ary cuckoo hashing (and thus 3 or 4 tables) + * with stash, according to the number of items provided to ck_create_table() + * function. The number of table pointers is however set to be the larger value + * (4) always, so the \a tables array may be statically allocated. Size of one + * table is always a power of 2 (due to the character of the hash function). + * The stash has a default size STASH_SIZE, but can be resized if needed. + * However, the resizing is only done in rehashing process, if the items do not + * fit into the table and the original stash. + * + * Rehashing is done when the stash gets full (actually, last item is always + * free and is used in the rehashing process as a temporary variable). + */ +struct ck_hash_table { + uint table_count; /*!< Actual number of hash tables used. */ + + /*! + * \brief Exponent of one table's size (2^table_size_exp is table size). + */ + int table_size_exp; + + ck_hash_table_item_t **tables[MAX_TABLES]; /*!< Array of hash tables. */ + + //da_array_t stash; /*!< Stash implemented as a dynamic array. */ + ck_stash_item_t *stash; + + /*! \brief Temporary storage for item being hashed. */ + ck_hash_table_item_t *hashed; + + /*! \brief Mutex for avoiding multiple insertions / rehashes at once. */ + pthread_mutex_t mtx_table; + + /*! + * \brief Flags used for determining which hash functions are currently + * used + * + * Form: 00000xyz. + * x - rehash flag (1 if rehashing is in progress) + * yz - generation (may be 10 = 2, or 01 = 1) + * + * There are always two sets of hash functions available via the + * us_hash() function (see universal-hashing.h). Normally all items in + * the table are hashed using one set of functions. However, during + * rehash, the other set is used for rehashing. In this case the rehash + * flag (x) is set, so the lookup function (ck_find_item()) tries to use + * both sets of functions when searching for item. + */ + uint8_t generation; + + us_system_t hash_system; /*!< Universal system of hash functions. */ + + size_t items; + size_t items_in_stash; +}; + +typedef struct ck_hash_table ck_hash_table_t; + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates and initializes the hash table structure. + * + * All hash tables are allocated and their items initialized to 0 (NULL). + * A stash of default size is also created. The \a generation flags are set to + * 0. + * + * \param items Number of items to be hashed to the table. This number + * determines the size of the hash table that will be created. + * + * + * \return Pointer to the initialized hash table. + */ +ck_hash_table_t *ck_create_table(uint items); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Destroys the whole hash table together with the saved values. + * + * \param table Pointer to pointer to the hash table. + * \param dtor_value Destructor function for the values that are be stored in + * the hash table. Set to NULL if you do not want the values + * to be deleted. + * \param delete_key Set to 0 if you do not want the function to delete the + * key of the item (e.g. when used elsewhere). Set to any + * other value otherwise. + * + * \note Make sure the table and its items are not used anymore when calling + * this function. + */ +void ck_destroy_table(ck_hash_table_t **table, + void (*dtor_value)(void *value), int delete_key); + +/*! + * \brief Destroys the table structures, but does not remove the individual + * hash table items. + */ +void ck_table_free(ck_hash_table_t **table); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Inserts item into the hash table. + * + * Insertion starts always by trying to hash the item into the first table. The + * possible displaced item is then hashed into randomly chosen other table, + * etc., until a free place is found or a loop occured. A loop occurs when one + * position in one table is tried more than twice. + * + * \param table Hash table the item should be inserted into. + * \param key Item's key. It can be any string of octets. The key is not copied + * by the function. + * \param length Length of the key in bytes (octets). + * \param value Pointer to the actual item to be inserted into the hash table. + * + * \note This function does not copy the key. + * \note This function may trigger rehash of the whole table in case the stash + * gets full. + * + * \retval 0 No error. + * \retval -1 Insertion failed. This may occur only when the rehashing fails. + * In this case it is necessary to somehow manually force another + * rehash as no other rehash would be possible. + */ +int ck_insert_item(ck_hash_table_t *table, const char *key, size_t length, + void *value); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Finds item in table. + * + * \param table Hash table to search in. + * \param key Key of the item. It can be an arbitrary string of octets. + * \param length Length of the key in bytes (octets). + * + * \return Pointer to the item if found. NULL otherwise. + */ +const ck_hash_table_item_t *ck_find_item(const ck_hash_table_t *table, + const char *key, size_t length); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Updates item with the given key by replacing its value. + * + * The update process is synchronized using RCU mechanism, so the old item's + * value will not be deleted while some thread is using it. + * + * \param table Hash table where to search for the item. + * \param key Key of the item to be updated. It can be an arbitrary string of + * octets. + * \param length Length of the key in bytes (octets). + * \param new_value New value for the item with key \a key. + * \param dtor_value Destructor function for the values that are be stored in + * the hash table. Set to NULL if you do not want the values + * to be deleted. + * + * \retval 0 If successful. + * \retval -1 If the item was not found in the table. No changes are made. + */ +int ck_update_item(const ck_hash_table_t *table, const char *key, size_t length, + void *new_value, void (*dtor_value)(void *value)); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Removes item with the given key from table. + * + * The deletion process is synchronized using RCU mechanism, so the old item + * will not be deleted while some thread is using it. + * + * \param table Hash table where to search for the item. + * \param key Key of the item to be removed. It can be an arbitrary string of + * octets. + * \param length Length of the key in bytes (octets). + * \param dtor_value Destructor function for the values that are be stored in + * the hash table. Set to NULL if you do not want the values + * to be deleted. + * \param delete_key Set to 0 if you do not want the function to delete the + * key of the item (e.g. when used elsewhere). Set to any + * other value otherwise. + * + * \retval 0 If successful. + * \retval -1 If the item was not found in the table. + */ +int ck_delete_item(const ck_hash_table_t *table, const char *key, size_t length, + void (*dtor_value)(void *value), int delete_key); + +ck_hash_table_item_t *ck_remove_item(ck_hash_table_t *table, const char *key, + size_t length); + +/*! + * \brief Creates a shallow copy of the cuckoo hash table. + * + * This function creates just the ck_hash_table_t structure and its tables and + * stash. It does not copy individual ck_hash_table_item_t structures. + * + * \param from Table to copy. + * \param to The new copy will be stored here. + * + * \retval 0 if successful. + * \retval + */ +int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to); + +int ck_apply(ck_hash_table_t *table, + void (*function)(ck_hash_table_item_t *item, void *data), + void *data); + +/*----------------------------------------------------------------------------*/ + +int ck_rehash(ck_hash_table_t *table); + +// for testing purposes only +int ck_resize_table(ck_hash_table_t *table); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dumps the whole hash table to the standard output. + */ +void ck_dump_table(const ck_hash_table_t *table); + +/*----------------------------------------------------------------------------*/ + +#endif /* _KNOT_CUCKOO_HASH_TABLE_H_ */ + +/*! @} */ diff --git a/src/libknot/hash/hash-functions.c b/src/libknot/hash/hash-functions.c new file mode 100644 index 0000000..a33dd6b --- /dev/null +++ b/src/libknot/hash/hash-functions.c @@ -0,0 +1,241 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include "hash-functions.h" + +/*--------------------------------- FNV HASH ---------------------------------*/ + +unsigned long int fnv_hash(const char *data, int size, int bits) +{ + int shift, i; + unsigned long int mask; + unsigned long int hash = 2166136261; + + if (bits == -1) { + shift = 0; + mask = 0xFFFFFFFF; + } else { + shift = 32 - bits; + mask = (1U << shift) - 1U; + } + + for (i = 0; i < size; i++) { + hash = (hash * 16777619) ^ data[i]; + } + + if (shift == 0) { + return hash; + } + + return (hash ^(hash >> shift)) & mask; +} + +/*------------------------------- JENKINS HASH -------------------------------*/ + +/* The mixing step */ +/* +#define mix(a,b,c) \ + { \ + a=a-b; a=a-c; a=a^(c>>13); \ + b=b-c; b=b-a; b=b^(a<<8); \ + c=c-a; c=c-b; c=c^(b>>13); \ + a=a-b; a=a-c; a=a^(c>>12); \ + b=b-c; b=b-a; b=b^(a<<16); \ + c=c-a; c=c-b; c=c^(b>>5); \ + a=a-b; a=a-c; a=a^(c>>3); \ + b=b-c; b=b-a; b=b^(a<<10); \ + c=c-a; c=c-b; c=c^(b>>15); \ + } +*/ + +///* The whole new hash function */ +//u4 jhash(register u1 *k, u4 length, u4 initval) +//{ +// register u4 a, b, c; /* the internal state */ +// u4 len; /* how many key bytes still need mixing */ + +// /* Set up the internal state */ +// len = length; +// a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ +// c = initval; /* variable initialization of internal state */ + +// /*---------------------------------------- handle most of the key */ +// while (len >= 12) { +// a = a + (k[0] + ((u4)k[1] << 8) +// + ((u4)k[2] << 16) + ((u4)k[3] << 24)); +// b = b + (k[4] + ((u4)k[5] << 8) +// + ((u4)k[6] << 16) + ((u4)k[7] << 24)); +// c = c + (k[8] + ((u4)k[9] << 8) +// + ((u4)k[10] << 16) + ((u4)k[11] << 24)); +// mix(a, b, c); +// k = k + 12; +// len = len - 12; +// } + +// /*------------------------------------- handle the last 11 bytes */ +// c = c + length; +// switch (len) { /* all the case statements fall through */ +// case 11: +// c = c + ((u4)k[10] << 24); +// case 10: +// c = c + ((u4)k[9] << 16); +// case 9 : +// c = c + ((u4)k[8] << 8); +// /* the first byte of c is reserved for the length */ +// case 8 : +// b = b + ((u4)k[7] << 24); +// case 7 : +// b = b + ((u4)k[6] << 16); +// case 6 : +// b = b + ((u4)k[5] << 8); +// case 5 : +// b = b + k[4]; +// case 4 : +// a = a + ((u4)k[3] << 24); +// case 3 : +// a = a + ((u4)k[2] << 16); +// case 2 : +// a = a + ((u4)k[1] << 8); +// case 1 : +// a = a + k[0]; +// /* case 0: nothing left to add */ +// } +// mix(a, b, c); +// /*-------------------------------------------- report the result */ +// return c; +//} + + + +#define hashsize(n) ((ub4)1<<(n)) +#define hashmask(n) (hashsize(n)-1) + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bits set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 6*len+35 instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); + +By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. It's free. + +See http://burtleburtle.net/bob/hash/evahash.html +Use for hash table lookup, or anything where one collision in 2^^32 is +acceptable. Do NOT use for cryptographic purposes. +-------------------------------------------------------------------- +*/ + +ub4 jhash(k, length, initval) +register ub1 *k; /* the key */ +register ub4 length; /* the length of the key */ +register ub4 initval; /* the previous hash, or an arbitrary value */ +{ + register ub4 a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + while (len >= 12) + { + a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); + b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); + c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((ub4)k[10]<<24); + case 10: c+=((ub4)k[9]<<16); + case 9 : c+=((ub4)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((ub4)k[7]<<24); + case 7 : b+=((ub4)k[6]<<16); + case 6 : b+=((ub4)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((ub4)k[3]<<24); + case 3 : a+=((ub4)k[2]<<16); + case 2 : a+=((ub4)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + +#undef hashsize +#undef hashmask + diff --git a/src/libknot/hash/hash-functions.h b/src/libknot/hash/hash-functions.h new file mode 100644 index 0000000..f23730b --- /dev/null +++ b/src/libknot/hash/hash-functions.h @@ -0,0 +1,85 @@ +/*! + * \file hash-functions.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Various hash functions. + * + * All of the hash functions are downloaded from various sources. + * + * \todo Add references to sources. + * + * \addtogroup hashing + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_HASH_FUNCTIONS_H_ +#define _KNOT_HASH_FUNCTIONS_H_ + +#include <stdint.h> +#include <string.h> + +/* + * Fowler / Noll / Vo Hash (FNV Hash) + * http://www.isthe.com/chongo/tech/comp/fnv/ + * + * This is an implementation of the algorithms posted above. + * This file is placed in the public domain by Peter Wemm. + * + * $FreeBSD: src/sys/sys/fnv_hash.h,v 1.2.2.1 2001/03/21 10:50:59 peter Exp $ + */ + +typedef uint32_t Fnv32_t; + +#define FNV1_32_INIT ((Fnv32_t) 33554467UL) + +#define FNV_32_PRIME ((Fnv32_t) 0x01000193UL) + +static __inline Fnv32_t +fnv_32_buf(const void *buf, size_t len, Fnv32_t hval) +{ + const uint8_t *s = (const uint8_t *)buf; + + while (len-- != 0) { + hval *= FNV_32_PRIME; + hval ^= *s++; + } + return hval; +} + +/*! + * \brief Jenkins hash function. + * + * Downloaded from http://burtleburtle.net/bob/hash/evahash.html + * + * \param k Data to hash + * \param length Size of the data in bytes. + * \param initval The previous hash or an arbitrary value. + * + * \return Hash of the data. + * + * \todo Add source. + */ +typedef unsigned long int ub4; /* unsigned 4-byte quantities */ +typedef unsigned char ub1; /* unsigned 1-byte quantities */ + +ub4 jhash(register ub1 *k, register ub4 length, register ub4 initval); + +#endif /* _KNOT_HASH_FUNCTIONS_H_ */ + +/*! @} */ diff --git a/src/libknot/hash/universal-system.c b/src/libknot/hash/universal-system.c new file mode 100644 index 0000000..096974c --- /dev/null +++ b/src/libknot/hash/universal-system.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <limits.h> +#include <stdint.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "universal-system.h" +#include "common.h" +#include "util/utils.h" + +/*----------------------------------------------------------------------------*/ + +const uint MAX_UINT_EXP = 32; +const unsigned long MAX_UINT_MY = UINT32_MAX; /* 4294967295 */ + +/*----------------------------------------------------------------------------*/ +/* Private functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Generates new set of coeficients. + * + * \param system Universal system to generate the coeficients for. + * \param from First coeficient to be replaced. + * \param to Up to this the coeficients will be replaced. + */ +static void us_generate_coefs(us_system_t *system, uint from, uint to) +{ + assert(system != NULL); + + for (uint i = from; i < to; ++i) { + int used = 0; + + do { + // generate random odd number + system->coefs[i] = knot_quick_rand() % MAX_UINT_MY; + if (system->coefs[i] % 2 == 0) { + system->coefs[i] = (system->coefs[i] == 0) + ? 1 + : system->coefs[i] - 1; + } + // check if this coeficient is already used + uint j = from; + while (used == 0 && j < i) { + if (system->coefs[j++] == system->coefs[i]) { + used = 1; + } + } + // if already used, generate again + } while (used != 0); + } +} + +/*----------------------------------------------------------------------------*/ +/* Public functions */ +/*----------------------------------------------------------------------------*/ + +void us_initialize(us_system_t *system) +{ + assert(system != NULL); + assert(UINT_MAX == MAX_UINT_MY); + + // Initialize both generations of functions by generating random odd + // numbers + us_generate_coefs(system, 0, US_FNC_COUNT * GEN_COUNT); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \note \a generation starts from 1 + */ +int us_next(us_system_t *system, uint generation) +{ + assert(system != NULL); + // generate new coeficients for the new generation + us_generate_coefs(system, (generation - 1) * US_FNC_COUNT, + generation * US_FNC_COUNT); + return 0; +} + +/*----------------------------------------------------------------------------*/ + +uint32_t us_hash(const us_system_t *system, uint32_t value, uint table_exp, + uint fnc, uint generation) +{ + /* + * multiplication should overflow if larger than MAX_UINT + * this is the same as (coef * value) mod MAX_UINT + * + * TODO: maybe we should not rely on this + */ + assert(system != NULL); + assert(table_exp <= 32); + assert(fnc < US_FNC_COUNT); + assert(generation <= GEN_COUNT); + + return ((system->coefs[((generation - 1) * US_FNC_COUNT) + fnc] * value) + >> (MAX_UINT_EXP - table_exp)); +} diff --git a/src/libknot/hash/universal-system.h b/src/libknot/hash/universal-system.h new file mode 100644 index 0000000..25330de --- /dev/null +++ b/src/libknot/hash/universal-system.h @@ -0,0 +1,109 @@ +/*! + * \file universal-system.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * This file provides interface to a 2-universal system of hash functions that + * hash from 32-bit unsigned integer to a 32-bit unsigned integer within a given + * range. The range is always a power of two and is given by the exponent (see + * function us_hash(). + * + * Before using the system, it must be initialized by calling us_initialize(). + * The system stores 2 sets (generations), each of US_FNC_COUNT functions. + * For generating a new set of coeficients (i.e. hash functions) use the + * us_next() function. + * + * For hashing use the us_hash() function. + * + * \todo What if all numbers are tried and still need rehash? + * (that means 2mld rehashes - we can probably live with that ;) + * \todo Consider counting generations from 0, will be easier! + * \todo Check out some better random number generator. + * + * \addtogroup hashing + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_UNIVERSAL_SYSTEM_H_ +#define _KNOT_UNIVERSAL_SYSTEM_H_ + +#include <stdint.h> +#include "common.h" + + +enum { US_FNC_COUNT = 4 /*!< Number of functions for one generation. */ }; + +enum { GEN_COUNT = 2 /*!< Number of generations. */ }; + +/*----------------------------------------------------------------------------*/ +/*! \brief Analytically defined universal system of hashing functions. */ +struct us_system { + /*! \brief Coeficients for the functions */ + uint coefs[US_FNC_COUNT * GEN_COUNT]; +}; + +typedef struct us_system us_system_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Initializes the universal system by generating coeficients for all + * hash functions and all generations. + * + * \param system Universal system to be used. + */ +void us_initialize(us_system_t *system); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Generates new hash functions' coeficients for the given \a generation. + * + * \param system Universal system to be used. + * \param generation Generation for which to generate the new coeficients. + * + * \return 0 + */ +int us_next(us_system_t *system, uint generation); + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Hashes the \a value using the given \a exponent and function. + * + * The actual formula of the hash is: + * h = ((coef * value) mod 2^32) / 2^(32 - table_exp) + * where \a coef is the proper coeficient. + * + * \param system Universal system to be used. + * \param value Value to be hashed. + * \param table_exp Determines the upper bound for the result - the hash will + * be between 0 and 2^(32 - table_exp). + * \param fnc Which function from the set should be used. + * \param generation Which set (generation) of functions should be used. + * + * \todo Make inline? + * + * \return Hash value (32bit unsigned). + */ +uint32_t us_hash(const us_system_t *system, uint32_t value, uint table_exp, + uint fnc, uint generation); + +/*----------------------------------------------------------------------------*/ + +#endif /* _KNOT_UNIVERSAL_SYSTEM_H_ */ + +/*! @} */ diff --git a/src/libknot/libknot.h b/src/libknot/libknot.h new file mode 100644 index 0000000..a401be7 --- /dev/null +++ b/src/libknot/libknot.h @@ -0,0 +1,48 @@ +/*! + * \file libknot.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief Convenience header for including whole library. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_LIBKNOT_H_ +#define _KNOT_LIBKNOT_H_ + +#include "consts.h" +#include "util/descriptor.h" +#include "dname.h" +#include "edns.h" +#include "zone/node.h" +#include "nsec3.h" +#include "util/wire.h" +#include "rdata.h" +#include "packet/response.h" +#include "rrset.h" +#include "util/tolower.h" +#include "util/utils.h" +#include "zone/zone.h" +#include "zone/zonedb.h" +#include "util/error.h" + +#endif + +/*! @} */ diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c new file mode 100644 index 0000000..f88f802 --- /dev/null +++ b/src/libknot/nameserver/name-server.c @@ -0,0 +1,3663 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <assert.h> +#include <sys/time.h> + +#include <urcu.h> + +#include "nameserver/name-server.h" +#include "updates/xfr-in.h" + +#include "util/error.h" +#include "libknot.h" +#include "util/debug.h" +#include "packet/packet.h" +#include "packet/response.h" +#include "packet/query.h" +#include "consts.h" +#include "updates/changesets.h" +#include "updates/ddns.h" +#include "tsig-op.h" + +/*----------------------------------------------------------------------------*/ + +/*! \brief Maximum UDP payload with EDNS enabled. */ +static const uint16_t MAX_UDP_PAYLOAD_EDNS = 4096; +/*! \brief Maximum UDP payload with EDNS disabled. */ +static const uint16_t MAX_UDP_PAYLOAD = 504; // 512 - 8B header +/*! \brief Maximum size of one AXFR response packet. */ +static const uint16_t MAX_AXFR_PAYLOAD = 65535; +/*! \brief Supported EDNS version. */ +static const uint8_t EDNS_VERSION = 0; +/*! \brief Determines whether EDNS is enabled. */ +static const int EDNS_ENABLED = 1; + +/*! \brief TTL of a CNAME synthetized from a DNAME. */ +static const uint32_t SYNTH_CNAME_TTL = 0; + +/*! \brief Determines whether DNSSEC is enabled. */ +static const int DNSSEC_ENABLED = 1; + +/*! \brief Determines whether NSID is enabled. */ +static const int NSID_ENABLED = 1; + +/*! \brief Length of NSID option data. */ +static const uint16_t NSID_LENGTH = 6; +/*! \brief NSID option data. */ +static const uint8_t NSID_DATA[6] = {0x46, 0x6f, 0x6f, 0x42, 0x61, 0x72}; + +/*! \brief Internal error code to propagate need for SERVFAIL response. */ +static const int NS_ERR_SERVFAIL = -999; + +/*----------------------------------------------------------------------------*/ +/* Private functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Finds zone where to search for the QNAME. + * + * \note As QTYPE DS requires special handling, this function finds a zone for + * a direct predecessor of QNAME in such case. + * + * \param zdb Zone database where to search for the proper zone. + * \param qname QNAME. + * \param qtype QTYPE. + * + * \return Zone to which QNAME belongs (according to QTYPE), or NULL if no such + * zone was found. + */ +static const knot_zone_t *ns_get_zone_for_qname(knot_zonedb_t *zdb, + const knot_dname_t *qname, + uint16_t qtype) +{ + const knot_zone_t *zone; + /* + * Find a zone in which to search. + * + * In case of DS query, we strip the leftmost label when searching for + * the zone (but use whole qname in search for the record), as the DS + * records are only present in a parent zone. + */ + if (qtype == KNOT_RRTYPE_DS) { + /*! \todo Optimize, do not deep copy dname. */ + knot_dname_t *name = knot_dname_left_chop(qname); + zone = knot_zonedb_find_zone_for_name(zdb, name); + /* Directly discard. */ + knot_dname_free(&name); + } else { + zone = knot_zonedb_find_zone_for_name(zdb, qname); + } + + return zone; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Synthetizes RRSet from a wildcard RRSet using the given QNAME. + * + * The synthetized RRSet is identical to the wildcard RRSets, except that the + * owner name is replaced by \a qname. + * + * \param wildcard_rrset Wildcard RRSet to synthetize from. + * \param qname Domain name to be used as the owner of the synthetized RRset. + * + * \return The synthetized RRSet (this is a newly created RRSet, remember to + * free it). + */ +static knot_rrset_t *ns_synth_from_wildcard( + const knot_rrset_t *wildcard_rrset, const knot_dname_t *qname) +{ + dbg_ns("Synthetizing RRSet from wildcard...\n"); + + knot_dname_t *owner = knot_dname_deep_copy(qname); +// printf("Copied owner ptr: %p\n", owner); + + knot_rrset_t *synth_rrset = knot_rrset_new( + owner, knot_rrset_type(wildcard_rrset), + knot_rrset_class(wildcard_rrset), + knot_rrset_ttl(wildcard_rrset)); + + /* Release owner, as it's retained in rrset. */ + knot_dname_release(owner); + + if (synth_rrset == NULL) { + return NULL; + } + + dbg_ns("Created RRSet header:\n"); + knot_rrset_dump(synth_rrset, 1); + + // copy all RDATA + const knot_rdata_t *rdata = knot_rrset_rdata(wildcard_rrset); + while (rdata != NULL) { + // we could use the RDATA from the wildcard rrset + // but there is no way to distinguish it when deleting + // temporary RRSets + knot_rdata_t *rdata_copy = knot_rdata_deep_copy(rdata, + knot_rrset_type(synth_rrset)); + if (rdata_copy == NULL) { + knot_rrset_deep_free(&synth_rrset, 1, 1, 0); + return NULL; + } + + dbg_ns("Copied RDATA:\n"); + knot_rdata_dump(rdata_copy, + knot_rrset_type(synth_rrset), 1); + + knot_rrset_add_rdata(synth_rrset, rdata_copy); + rdata = knot_rrset_rdata_next(wildcard_rrset, rdata); + } + +// printf("Synthetized RRSet pointer: %p\n", synth_rrset); + return synth_rrset; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks if the given RRSet is a wildcard RRSet and replaces it with + * a synthetized RRSet if required. + * + * \param name Domain name to be used as the owner of the possibly synthetized + * RRSet + * \param resp Response to which the synthetized RRSet should be stored (as a + * temporary RRSet). + * \param rrset RRSet to check (and possibly replace). + */ +static void ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp, + const knot_rrset_t **rrset) +{ + assert(name != NULL); + assert(resp != NULL); + assert(rrset != NULL); + assert(*rrset != NULL); + + if (knot_dname_is_wildcard((*rrset)->owner)) { + knot_rrset_t *synth_rrset = + ns_synth_from_wildcard(*rrset, name); + dbg_ns("Synthetized RRSet:\n"); + knot_rrset_dump(synth_rrset, 1); + knot_packet_add_tmp_rrset(resp, synth_rrset); + *rrset = synth_rrset; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adds signatures (RRSIGs) for the given RRSet to the response. + * + * This function first checks if DNSSEC is enabled and if it was requested in + * the response (DO bit set). If not, it does nothing and returns 0. If yes, + * it retrieves RRSIGs stored in the RRSet, deals with possible wildcard owner + * and adds the RRSIGs to response using the given function (that determines + * to which section of the response they will be added). + * + * \param rrset RRSet to get the RRSIGs from. + * \param resp Response where to add the RRSIGs. + * \param name Actual name to be used as owner in case of wildcard RRSet. + * \param add_rrset_to_resp Function for adding the RRSIG RRset to the response. + * \param tc Set to 1 if omitting the RRSIG RRSet should result in setting the + * TC bit in the response. + * + * \return KNOT_EOK + * \return KNOT_ENOMEM + * \return KNOT_ESPACE + */ +static int ns_add_rrsigs(const knot_rrset_t *rrset, knot_packet_t *resp, + const knot_dname_t *name, + int (*add_rrset_to_resp)(knot_packet_t *, + const knot_rrset_t *, + int, int, int), + int tc) +{ + const knot_rrset_t *rrsigs; + + dbg_ns("Adding RRSIGs for RRSet, type: %s.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + + assert(resp != NULL); + assert(add_rrset_to_resp != NULL); + + dbg_ns("DNSSEC requested: %d\n", + knot_query_dnssec_requested(knot_packet_query(resp))); + dbg_ns("RRSIGS: %p\n", knot_rrset_rrsigs(rrset)); + + if (DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp)) + && (rrsigs = knot_rrset_rrsigs(rrset)) != NULL) { + if (name != NULL) { + ns_check_wildcard(name, resp, &rrsigs); + } + return add_rrset_to_resp(resp, rrsigs, tc, 0, 0); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Resolves CNAME chain starting in \a node, stores all the CNAMEs in the + * response and updates \a node and \a qname to the last node in the + * chain. + * + * \param node Node (possibly) containing a CNAME RR. + * \param qname Searched name. Will be updated to the canonical name. + * \param resp Response where to add the CNAME RRs. + * \param add_rrset_to_resp Function for adding the CNAME RRs to the response. + * \param tc Set to 1 if omitting the RRSIG RRSet should result in setting the + * TC bit in the response. + */ +static void ns_follow_cname(const knot_node_t **node, + const knot_dname_t **qname, + knot_packet_t *resp, + int (*add_rrset_to_resp)(knot_packet_t *, + const knot_rrset_t *, + int, int, int), + int tc) +{ + dbg_ns("Resolving CNAME chain...\n"); + const knot_rrset_t *cname_rrset; + + while (*node != NULL + && (cname_rrset = knot_node_rrset(*node, KNOT_RRTYPE_CNAME)) + != NULL) { + /* put the CNAME record to answer, but replace the possible + wildcard name with qname */ + + assert(cname_rrset != NULL); + + dbg_ns("CNAME RRSet: %p, owner: %p\n", cname_rrset, + cname_rrset->owner); + + const knot_rrset_t *rrset = cname_rrset; + + // ignoring other than the first record + if (knot_dname_is_wildcard(knot_node_owner(*node))) { + /* if wildcard node, we must copy the RRSet and + replace its owner */ + rrset = ns_synth_from_wildcard(cname_rrset, *qname); + knot_packet_add_tmp_rrset(resp, (knot_rrset_t *)rrset); + add_rrset_to_resp(resp, rrset, tc, 0, 0); + ns_add_rrsigs(cname_rrset, resp, *qname, + add_rrset_to_resp, tc); + } else { + add_rrset_to_resp(resp, rrset, tc, 0, 0); + ns_add_rrsigs(rrset, resp, *qname, add_rrset_to_resp, + tc); + } + + dbg_ns("Using RRSet: %p, owner: %p\n", rrset, rrset->owner); + +dbg_ns_exec( + char *name = knot_dname_to_str(knot_rrset_owner(rrset)); + dbg_ns("CNAME record for owner %s put to response.\n", name); + free(name); +); + + // get the name from the CNAME RDATA + const knot_dname_t *cname = knot_rdata_cname_name( + knot_rrset_rdata(cname_rrset)); + dbg_ns("CNAME name from RDATA: %p\n", cname); + // change the node to the node of that name + *node = knot_dname_node(cname, 1); + dbg_ns("This name's node: %p\n", *node); +// // it is not an old node and if yes, skip it +// if (knot_node_is_old(*node)) { +// *node = knot_node_new_node(*node); +// } + + // save the new name which should be used for replacing wildcard + *qname = cname; + }; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Retrieves RRSet(s) of given type from the given node and adds them to + * the response's Answer section. + * + * \param node Node where to take the RRSet from. + * \param name Actual searched name (used in case of wildcard RRSet(s)). + * \param type Type of the RRSet(s). If set to KNOT_RRTYPE_ANY, all RRSets + * from the node will be added to the answer. + * \param resp Response where to add the RRSets. + * + * \return Number of RRSets added. + */ +static int ns_put_answer(const knot_node_t *node, const knot_dname_t *name, + uint16_t type, knot_packet_t *resp) +{ + int added = 0; +dbg_ns_exec( + char *name_str = knot_dname_to_str(node->owner); + dbg_ns("Putting answers from node %s.\n", name_str); + free(name_str); +); + + switch (type) { + case KNOT_RRTYPE_ANY: { + dbg_ns("Returning all RRTYPES.\n"); + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + break; + } + int i = 0; + int ret = 0; + const knot_rrset_t *rrset; + while (i < knot_node_rrset_count(node)) { + assert(rrsets[i] != NULL); + rrset = rrsets[i]; + + dbg_ns(" Type: %s\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + + ns_check_wildcard(name, resp, &rrset); + ret = knot_response_add_rrset_answer(resp, rrset, 1, + 0, 0); + if (ret >= 0 && (added += 1) + && (ret = ns_add_rrsigs(rrset, resp, name, + knot_response_add_rrset_answer, 1)) + >=0 ) { + added += 1; + } else { + free(rrsets); + rrsets = NULL; + break; + } + + ++i; + } + if (rrsets != NULL) { + free(rrsets); + } + break; + } + case KNOT_RRTYPE_RRSIG: { + dbg_ns("Returning all RRSIGs.\n"); + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + break; + } + int i = 0; + int ret = 0; + const knot_rrset_t *rrset; + while (i < knot_node_rrset_count(node)) { + assert(rrsets[i] != NULL); + rrset = knot_rrset_rrsigs(rrsets[i]); + + if (rrset == NULL) { + ++i; + continue; + } + + ns_check_wildcard(name, resp, &rrset); + ret = knot_response_add_rrset_answer(resp, rrset, 1, + 0, 0); + + if (ret < 0) { + break; + } + + added += 1; + ++i; + } + free(rrsets); + break; + } + default: { + int ret = 0; + const knot_rrset_t *rrset = knot_node_rrset(node, type); + const knot_rrset_t *rrset2 = rrset; + if (rrset != NULL) { + dbg_ns("Found RRSet of type %s\n", + knot_rrtype_to_string(type)); + ns_check_wildcard(name, resp, &rrset2); + ret = knot_response_add_rrset_answer(resp, rrset2, 1, + 0, 0); + if (ret >= 0 && (added += 1) + && (ret = ns_add_rrsigs(rrset, resp, name, + knot_response_add_rrset_answer, 1)) > 0) { + added += 1; + } + } + } + } + + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + return added; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adds RRSets to Additional section of the response. + * + * This function uses knot_rdata_get_name() to get the domain name from the + * RDATA of the RRSet according to its type. It also does not search for the + * retrieved domain name, but just uses its node field. Thus to work correctly, + * the zone where the RRSet is from should be adjusted using + * knot_zone_adjust_dnames(). + * + * A and AAAA RRSets (and possible CNAMEs) for the found domain names are added. + * + * \warning Use this function only with types containing some domain name, + * otherwise it will crash (or behave strangely). + * + * \param resp Response where to add the Additional data. + * \param rrset RRSet to get the Additional data for. + */ +static void ns_put_additional_for_rrset(knot_packet_t *resp, + const knot_rrset_t *rrset) +{ + const knot_node_t *node = NULL; + const knot_rdata_t *rdata = NULL; + const knot_dname_t *dname = NULL; + + // for all RRs in the RRset + rdata = knot_rrset_rdata(rrset); + while (rdata != NULL) { + dbg_ns("Getting name from RDATA, type %s..\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + dname = knot_rdata_get_name(rdata, + knot_rrset_type(rrset)); + assert(dname != NULL); + node = knot_dname_node(dname, 1); +// // check if the node is not old and if yes, take the new one +// if (knot_node_is_old(node)) { +// node = knot_node_new_node(node); +// } + + dbg_ns_detail("Node saved in RDATA dname: %p\n", node); + + if (node != NULL && node->owner != dname) { + // the stored node should be the closest encloser + assert(knot_dname_is_subdomain(dname, node->owner)); + // try the wildcard child, if any + node = knot_node_wildcard_child(node, 1); +// // this should not be old node!! +// assert(!knot_node_is_old(node)); + } + + const knot_rrset_t *rrset_add; + + if (node != NULL) { +dbg_ns_exec( + char *name = knot_dname_to_str(node->owner); + dbg_ns("Putting additional from node %s\n", name); + free(name); +); + dbg_ns("Checking CNAMEs...\n"); + if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) + != NULL) { + dbg_ns("Found CNAME in node, following...\n"); + const knot_dname_t *dname + = knot_node_owner(node); + ns_follow_cname(&node, &dname, resp, + knot_response_add_rrset_additional, 0); + } + + // A RRSet + dbg_ns("A RRSets...\n"); + rrset_add = knot_node_rrset(node, KNOT_RRTYPE_A); + if (rrset_add != NULL) { + dbg_ns("Found A RRsets.\n"); + const knot_rrset_t *rrset_add2 = rrset_add; + ns_check_wildcard(dname, resp, &rrset_add2); + knot_response_add_rrset_additional( + resp, rrset_add2, 0, 1, 0); + ns_add_rrsigs(rrset_add, resp, dname, + knot_response_add_rrset_additional, 0); + } + + // AAAA RRSet + dbg_ns("AAAA RRSets...\n"); + rrset_add = knot_node_rrset(node, KNOT_RRTYPE_AAAA); + if (rrset_add != NULL) { + dbg_ns("Found AAAA RRsets.\n"); + const knot_rrset_t *rrset_add2 = rrset_add; + ns_check_wildcard(dname, resp, &rrset_add2); + knot_response_add_rrset_additional( + resp, rrset_add2, 0, 1, 0); + ns_add_rrsigs(rrset_add, resp, dname, + knot_response_add_rrset_additional, 0); + } + } + + assert(rrset != NULL); + assert(rdata != NULL); + rdata = knot_rrset_rdata_next(rrset, rdata); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks whether the given type requires additional processing. + * + * Only MX, NS and SRV types require additional processing. + * + * \param qtype Type to check. + * + * \retval <> 0 if additional processing is needed for \a qtype. + * \retval 0 otherwise. + */ +static int ns_additional_needed(uint16_t qtype) +{ + return (qtype == KNOT_RRTYPE_MX || + qtype == KNOT_RRTYPE_NS || + qtype == KNOT_RRTYPE_SRV); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adds whatever Additional RRSets are required for the response. + * + * For each RRSet in Answer and Authority sections this function checks if + * additional processing is needed and if yes, it puts any Additional RRSets + * available to the Additional section of the response. + * + * \param resp Response to process. + */ +static void ns_put_additional(knot_packet_t *resp) +{ + dbg_ns("ADDITIONAL SECTION PROCESSING\n"); + + const knot_rrset_t *rrset = NULL; + + for (int i = 0; i < knot_packet_answer_rrset_count(resp); ++i) { + rrset = knot_packet_answer_rrset(resp, i); + assert(rrset != NULL); + if (ns_additional_needed(knot_rrset_type(rrset))) { + ns_put_additional_for_rrset(resp, rrset); + } + } + + for (int i = 0; i < knot_packet_authority_rrset_count(resp); ++i) { + rrset = knot_packet_authority_rrset(resp, i); + if (ns_additional_needed(knot_rrset_type(rrset))) { + ns_put_additional_for_rrset(resp, rrset); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts authority NS RRSet to the Auhority section of the response. + * + * \param zone Zone to take the authority NS RRSet from. + * \param resp Response where to add the RRSet. + */ +static void ns_put_authority_ns(const knot_zone_contents_t *zone, + knot_packet_t *resp) +{ + const knot_rrset_t *ns_rrset = knot_node_rrset( + knot_zone_contents_apex(zone), KNOT_RRTYPE_NS); + + if (ns_rrset != NULL) { + knot_response_add_rrset_authority(resp, ns_rrset, 0, 1, 0); + ns_add_rrsigs(ns_rrset, resp, knot_node_owner( + knot_zone_contents_apex(zone)), + knot_response_add_rrset_authority, 1); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts SOA RRSet to the Auhority section of the response. + * + * \param zone Zone to take the SOA RRSet from. + * \param resp Response where to add the RRSet. + */ +static void ns_put_authority_soa(const knot_zone_contents_t *zone, + knot_packet_t *resp) +{ + const knot_rrset_t *soa_rrset = knot_node_rrset( + knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); + assert(soa_rrset != NULL); + + knot_response_add_rrset_authority(resp, soa_rrset, 0, 0, 0); + ns_add_rrsigs(soa_rrset, resp, + knot_node_owner(knot_zone_contents_apex(zone)), + knot_response_add_rrset_authority, 1); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a 'next closer name' to the given domain name. + * + * For definition of 'next closer name', see RFC5155, Page 6. + * + * \param closest_encloser Closest encloser of \a name. + * \param name Domain name to create the 'next closer' name to. + * + * \return 'Next closer name' to the given domain name or NULL if an error + * occured. + */ +static knot_dname_t *ns_next_closer(const knot_dname_t *closest_encloser, + const knot_dname_t *name) +{ + int ce_labels = knot_dname_label_count(closest_encloser); + int qname_labels = knot_dname_label_count(name); + + assert(ce_labels < qname_labels); + + // the common labels should match + assert(knot_dname_matched_labels(closest_encloser, name) + == ce_labels); + + // chop some labels from the qname + knot_dname_t *next_closer = knot_dname_deep_copy(name); + if (next_closer == NULL) { + return NULL; + } + + for (int i = 0; i < (qname_labels - ce_labels - 1); ++i) { + knot_dname_left_chop_no_copy(next_closer); + } + + return next_closer; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adds NSEC3 RRSet (together with corresponding RRSIGs) from the given + * node into the response. + * + * \param node Node to get the NSEC3 RRSet from. + * \param resp Response where to add the RRSets. + */ +static void ns_put_nsec3_from_node(const knot_node_t *node, + knot_packet_t *resp) +{ + assert(DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp))); + + const knot_rrset_t *rrset = knot_node_rrset(node, + KNOT_RRTYPE_NSEC3); + assert(rrset != NULL); + + int res = knot_response_add_rrset_authority(resp, rrset, 1, 1, 0); + // add RRSIG for the RRSet + if (res == 0 && (rrset = knot_rrset_rrsigs(rrset)) != NULL) { + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Finds and adds NSEC3 covering the given domain name (and their + * associated RRSIGs) to the response. + * + * \param zone Zone used for answering. + * \param name Domain name to cover. + * \param resp Response where to add the RRSets. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL if a runtime collision occured. The server should + * respond with SERVFAIL in such case. + */ +static int ns_put_covering_nsec3(const knot_zone_contents_t *zone, + const knot_dname_t *name, + knot_packet_t *resp) +{ + const knot_node_t *prev, *node; + /*! \todo Check version. */ + int match = knot_zone_contents_find_nsec3_for_name(zone, name, + &node, &prev, 1); + assert(match >= 0); + node = knot_node_current(node); + prev = knot_node_current(prev); + + if (match == KNOT_ZONE_NAME_FOUND){ + // run-time collision => SERVFAIL + return KNOT_EOK; + } + +// // check if the prev node is not old and if yes, take the new one +// if (knot_node_is_old(prev)) { +// prev = knot_node_new_node(prev); +// assert(prev != NULL); +// } + +dbg_ns_exec( + char *name = knot_dname_to_str(prev->owner); + dbg_ns("Covering NSEC3 node: %s\n", name); + free(name); +); + + ns_put_nsec3_from_node(prev, resp); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adds NSEC3s comprising the 'closest encloser proof' for the given + * (non-existent) domain name (and their associated RRSIGs) to the + * response. + * + * For definition of 'closest encloser proof', see RFC5155, section 7.2.1, + * Page 18. + * + * \note This function does not check if DNSSEC is enabled, nor if it is + * requested by the query. + * + * \param zone Zone used for answering. + * \param closest_encloser Closest encloser of \a qname in the zone. + * \param qname Searched (non-existent) name. + * \param resp Response where to add the NSEC3s. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec3_closest_encloser_proof( + const knot_zone_contents_t *zone, + const knot_node_t **closest_encloser, + const knot_dname_t *qname, + knot_packet_t *resp) +{ + assert(zone != NULL); + assert(closest_encloser != NULL); + assert(*closest_encloser != NULL); + assert(qname != NULL); + assert(resp != NULL); + + if (knot_zone_contents_nsec3params(zone) == NULL) { +dbg_ns_exec( + char *name = knot_dname_to_str(knot_node_owner( + knot_zone_contents_apex(zone))); + dbg_ns("No NSEC3PARAM found in zone %s.\n", name); + free(name); +); + return KNOT_EOK; + } + +dbg_ns_exec( + char *name = knot_dname_to_str(knot_node_owner(*closest_encloser)); + dbg_ns("Closest encloser: %s\n", name); + free(name); +); + + /* + * 1) NSEC3 that matches closest provable encloser. + */ + const knot_node_t *nsec3_node = NULL; + const knot_dname_t *next_closer = NULL; + while ((nsec3_node = knot_node_nsec3_node((*closest_encloser), 1)) + == NULL) { + next_closer = knot_node_owner((*closest_encloser)); + *closest_encloser = knot_node_parent(*closest_encloser, 1); + if (*closest_encloser == NULL) { + // there are no NSEC3s to add + return KNOT_EOK; + } + } + + assert(nsec3_node != NULL); + +dbg_ns_exec( + char *name = knot_dname_to_str(nsec3_node->owner); + dbg_ns("NSEC3 node: %s\n", name); + free(name); + name = knot_dname_to_str((*closest_encloser)->owner); + dbg_ns("Closest provable encloser: %s\n", name); + free(name); + if (next_closer != NULL) { + name = knot_dname_to_str(next_closer); + dbg_ns("Next closer name: %s\n", name); + free(name); + } else { + dbg_ns("Next closer name: none\n"); + } +); + + ns_put_nsec3_from_node(nsec3_node, resp); + + /* + * 2) NSEC3 that covers the "next closer" name. + */ + int ret = 0; + if (next_closer == NULL) { + // create the "next closer" name by appending from qname + next_closer = ns_next_closer( + knot_node_owner(*closest_encloser), qname); + + if (next_closer == NULL) { + return NS_ERR_SERVFAIL; + } +dbg_ns_exec( + char *name = knot_dname_to_str(next_closer); + dbg_ns("Next closer name: %s\n", name); + free(name); +); + ret = ns_put_covering_nsec3(zone, next_closer, resp); + + // the cast is ugly, but no better way around it + knot_dname_release((knot_dname_t *)next_closer); + } else { + ret = ns_put_covering_nsec3(zone, next_closer, resp); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a name of a wildcard child of \a name. + * + * \param name Domain name to get the wildcard child name of. + * + * \return Wildcard child name or NULL if an error occured. + */ +static knot_dname_t *ns_wildcard_child_name(const knot_dname_t *name) +{ + assert(name != NULL); + + knot_dname_t *wildcard = knot_dname_new_from_str("*", 1, NULL); + if (wildcard == NULL) { + return NULL; + } + + if (knot_dname_cat(wildcard, name) == NULL) { + /* Directly discard dname. */ + knot_dname_free(&wildcard); + return NULL; + } + +dbg_ns_exec( + char *name = knot_dname_to_str(wildcard); + dbg_ns("Wildcard: %s\n", name); + free(name); +); + return wildcard; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSEC3s covering the non-existent wildcard child of a node + * (and their associated RRSIGs) into the response. + * + * \note This function does not check if DNSSEC is enabled, nor if it is + * requested by the query. + * + * \param zone Zone used for answering. + * \param node Node whose non-existent wildcard child should be covered. + * \param resp Response where to add the NSEC3s. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec3_no_wildcard_child(const knot_zone_contents_t *zone, + const knot_node_t *node, + knot_packet_t *resp) +{ + assert(node != NULL); + assert(resp != NULL); + assert(node->owner != NULL); + + int ret = 0; + knot_dname_t *wildcard = ns_wildcard_child_name(node->owner); + if (wildcard == NULL) { + ret = NS_ERR_SERVFAIL; + } else { + ret = ns_put_covering_nsec3(zone, wildcard, resp); + + /* Directly discard wildcard. */ + knot_dname_free(&wildcard); + } + + return ret; +} +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSECs or NSEC3s for NODATA error (and their associated RRSIGs) + * to the response. + * + * \note This function first checks if DNSSEC is enabled and requested by the + * query. + * \note Note that for each zone there are either NSEC or NSEC3 records used. + * + * \param node Node which generated the NODATA response (i.e. not containing + * RRSets of the requested type). + * \param resp Response where to add the NSECs or NSEC3s. + */ +static void ns_put_nsec_nsec3_nodata(const knot_node_t *node, + knot_packet_t *resp) +{ + if (!DNSSEC_ENABLED || + !knot_query_dnssec_requested(knot_packet_query(resp))) { + return; + } + + const knot_node_t *nsec3_node = knot_node_nsec3_node(node, 1); + const knot_rrset_t *rrset = NULL; + if ((rrset = knot_node_rrset(node, KNOT_RRTYPE_NSEC)) != NULL + || (nsec3_node != NULL && (rrset = + knot_node_rrset(nsec3_node, KNOT_RRTYPE_NSEC3)) != NULL)) { + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + // add RRSIG for the RRSet + if ((rrset = knot_rrset_rrsigs(rrset)) != NULL) { + knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSECs for NXDOMAIN error to the response. + * + * \note This function does not check if DNSSEC is enabled, nor if it is + * requested by the query. + * + * \param qname QNAME which generated the NXDOMAIN error (i.e. not found in the + * zone). + * \param zone Zone used for answering. + * \param previous Previous node to \a qname in the zone. May also be NULL. In + * such case the function finds the previous node in the zone. + * \param closest_encloser Closest encloser of \a qname. Must not be NULL. + * \param resp Response where to put the NSECs. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec_nxdomain(const knot_dname_t *qname, + const knot_zone_contents_t *zone, + const knot_node_t *previous, + const knot_node_t *closest_encloser, + knot_packet_t *resp) +{ + const knot_rrset_t *rrset = NULL; + + // check if we have previous; if not, find one using the tree + if (previous == NULL) { + /*! \todo Check version. */ + previous = knot_zone_contents_find_previous(zone, qname); + + while (!knot_node_is_auth(previous)) { + previous = knot_node_previous(previous, 1); + } + + previous = knot_node_current(previous); + assert(previous != NULL); + } + + char *name = knot_dname_to_str(previous->owner); + dbg_ns("Previous node: %s\n", name); + free(name); + + // 1) NSEC proving that there is no node with the searched name + rrset = knot_node_rrset(previous, KNOT_RRTYPE_NSEC); + if (rrset == NULL) { + // no NSEC records + //return NS_ERR_SERVFAIL; + return KNOT_EOK; + + } + + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + rrset = knot_rrset_rrsigs(rrset); + assert(rrset != NULL); + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + + // 2) NSEC proving that there is no wildcard covering the name + // this is only different from 1) if the wildcard would be + // before 'previous' in canonical order, i.e. we can + // search for previous until we find name lesser than wildcard + assert(closest_encloser != NULL); + + knot_dname_t *wildcard = + ns_wildcard_child_name(closest_encloser->owner); + if (wildcard == NULL) { + return NS_ERR_SERVFAIL; + } + + const knot_node_t *prev_new = previous; + + while (knot_dname_compare(knot_node_owner(prev_new), + wildcard) > 0) { + dbg_ns("Previous node: %s\n", + knot_dname_to_str(knot_node_owner(prev_new))); + assert(prev_new != knot_zone_contents_apex(zone)); + prev_new = knot_node_previous(prev_new, 1); + } + assert(knot_dname_compare(knot_node_owner(prev_new), + wildcard) < 0); + + dbg_ns("Previous node: %s\n", + knot_dname_to_str(knot_node_owner(prev_new))); + + /* Directly discard dname. */ + knot_dname_free(&wildcard); + + if (prev_new != previous) { + rrset = knot_node_rrset(prev_new, KNOT_RRTYPE_NSEC); + assert(rrset != NULL); + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + rrset = knot_rrset_rrsigs(rrset); + assert(rrset != NULL); + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSEC3s for NXDOMAIN error to the response. + * + * \note This function does not check if DNSSEC is enabled, nor if it is + * requested by the query. + * + * \param zone Zone used for answering. + * \param closest_encloser Closest encloser of \a qname. + * \param qname Domain name which generated the NXDOMAIN error (i.e. not found + * in the zone. + * \param resp Response where to put the NSEC3s. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec3_nxdomain(const knot_zone_contents_t *zone, + const knot_node_t *closest_encloser, + const knot_dname_t *qname, + knot_packet_t *resp) +{ + // 1) Closest encloser proof + dbg_ns("Putting closest encloser proof.\n"); + int ret = ns_put_nsec3_closest_encloser_proof(zone, &closest_encloser, + qname, resp); + // 2) NSEC3 covering non-existent wildcard + if (ret == KNOT_EOK && closest_encloser != NULL) { + dbg_ns("Putting NSEC3 for no wildcard child of closest " + "encloser.\n"); + ret = ns_put_nsec3_no_wildcard_child(zone, closest_encloser, + resp); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSECs or NSEC3s for the NXDOMAIN error to the response. + * + * \note This function first checks if DNSSEC is enabled and requested by the + * query. + * \note Note that for each zone there are either NSEC or NSEC3 records used. + * + * \param zone Zone used for answering. + * \param previous Previous node to \a qname in the zone. May also be NULL. In + * such case the function finds the previous node in the zone. + * \param closest_encloser Closest encloser of \a qname. Must not be NULL. + * \param qname QNAME which generated the NXDOMAIN error (i.e. not found in the + * zone). + * \param resp Response where to put the NSECs. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec_nsec3_nxdomain(const knot_zone_contents_t *zone, + const knot_node_t *previous, + const knot_node_t *closest_encloser, + const knot_dname_t *qname, + knot_packet_t *resp) +{ + int ret = 0; + if (DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp))) { + if (knot_zone_contents_nsec3_enabled(zone)) { + ret = ns_put_nsec3_nxdomain(zone, closest_encloser, + qname, resp); + } else { + ret = ns_put_nsec_nxdomain(qname, zone, previous, + closest_encloser, resp); + } + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSEC3s for wildcard answer into the response. + * + * \note This function does not check if DNSSEC is enabled, nor if it is + * requested by the query. + * + * \param zone Zone used for answering. + * \param closest_encloser Closest encloser of \a qname in the zone. In this + * case it is the parent of the source of synthesis. + * \param qname Domain name covered by the wildcard used for answering the + * query. + * \param resp Response to put the NSEC3s into. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec3_wildcard(const knot_zone_contents_t *zone, + const knot_node_t *closest_encloser, + const knot_dname_t *qname, + knot_packet_t *resp) +{ + assert(closest_encloser != NULL); + assert(qname != NULL); + assert(resp != NULL); + assert(DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp))); + + if (!knot_zone_contents_nsec3_enabled(zone)) { + return KNOT_EOK; + } + + /* + * NSEC3 that covers the "next closer" name. + */ + // create the "next closer" name by appending from qname + dbg_ns("Finding next closer name for wildcard NSEC3.\n"); + knot_dname_t *next_closer = + ns_next_closer(closest_encloser->owner, qname); + + if (next_closer == NULL) { + return NS_ERR_SERVFAIL; + } +dbg_ns_exec( + char *name = knot_dname_to_str(next_closer); + dbg_ns("Next closer name: %s\n", name); + free(name); +); + int ret = ns_put_covering_nsec3(zone, next_closer, resp); + + + /* Duplicate from ns_next_close(), safe to discard. */ + knot_dname_release(next_closer); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSECs for wildcard answer into the response. + * + * \note This function does not check if DNSSEC is enabled, nor if it is + * requested by the query. + * + * \param zone Zone used for answering. + * \param qname Domain name covered by the wildcard used for answering the + * query. + * \param previous Previous node of \a qname in canonical order. + * \param resp Response to put the NSEC3s into. + */ +static void ns_put_nsec_wildcard(const knot_zone_contents_t *zone, + const knot_dname_t *qname, + const knot_node_t *previous, + knot_packet_t *resp) +{ + assert(DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp))); + + // check if we have previous; if not, find one using the tree + if (previous == NULL) { + previous = knot_zone_contents_find_previous(zone, qname); + + while (!knot_node_is_auth(previous)) { + previous = knot_node_previous(previous, 1); + } + + previous = knot_node_current(previous); + assert(previous != NULL); + } + + const knot_rrset_t *rrset = + knot_node_rrset(previous, KNOT_RRTYPE_NSEC); + if (rrset != NULL) { + // NSEC proving that there is no node with the searched name + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + rrset = knot_rrset_rrsigs(rrset); + assert(rrset != NULL); + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSECs or NSEC3s for wildcard NODATA answer into the response. + * + * \note This function first checks if DNSSEC is enabled and requested by the + * query. + * + * \param node Node used for answering. + * \param closest_encloser Closest encloser of \a qname in the zone. + * \param previous Previous node of \a qname in canonical order. + * \param zone Zone used for answering. + * \param qname Actual searched domain name. + * \param resp Response where to put the NSECs and NSEC3s. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec_nsec3_wildcard_nodata(const knot_node_t *node, + const knot_node_t *closest_encloser, + const knot_node_t *previous, + const knot_zone_contents_t *zone, + const knot_dname_t *qname, + knot_packet_t *resp) +{ + int ret = KNOT_EOK; + if (DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp))) { + if (knot_zone_contents_nsec3_enabled(zone)) { + ret = ns_put_nsec3_closest_encloser_proof(zone, + &closest_encloser, + qname, resp); + + const knot_node_t *nsec3_node; + if (ret == KNOT_EOK + && (nsec3_node = knot_node_nsec3_node(node, 1)) + != NULL) { + ns_put_nsec3_from_node(nsec3_node, resp); + } + } else { + ns_put_nsec_wildcard(zone, qname, previous, resp); + } + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Puts NSECs or NSEC3s for wildcard answer into the response. + * + * \note This function first checks if DNSSEC is enabled and requested by the + * query and if the node's owner is a wildcard. + * + * \param node Node used for answering. + * \param closest_encloser Closest encloser of \a qname in the zone. + * \param previous Previous node of \a qname in canonical order. + * \param zone Zone used for answering. + * \param qname Actual searched domain name. + * \param resp Response where to put the NSECs and NSEC3s. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node, + const knot_node_t *closest_encloser, + const knot_node_t *previous, + const knot_zone_contents_t *zone, + const knot_dname_t *qname, + knot_packet_t *resp) +{ + int r = KNOT_EOK; + if (DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp)) + && knot_dname_is_wildcard(knot_node_owner(node))) { + if (knot_zone_contents_nsec3_enabled(zone)) { + r = ns_put_nsec3_wildcard(zone, closest_encloser, qname, + resp); + } else { + ns_put_nsec_wildcard(zone, qname, previous, resp); + } + } + return r; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a referral response. + * + * This function puts the delegation NS RRSet to the Authority section of the + * response, possibly adds DS and their associated RRSIGs (if DNSSEC is enabled + * and requested by the query) and adds any available additional data (A and + * AAAA RRSets for the names in the NS RRs) with their associated RRSIGs + * to the Additional section. + * + * \param node Delegation point node. + * \param zone Parent zone (the one from which the response is generated). + * \param qname Searched name (which caused the referral). + * \param resp Response. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static inline int ns_referral(const knot_node_t *node, + const knot_zone_contents_t *zone, + const knot_dname_t *qname, + knot_packet_t *resp) +{ + dbg_ns("Referral response.\n"); + + while (!knot_node_is_deleg_point(node)) { + assert(knot_node_parent(node, 1) != NULL); + node = knot_node_parent(node, 1); + } + + const knot_rrset_t *rrset = knot_node_rrset(node, KNOT_RRTYPE_NS); + assert(rrset != NULL); + + // TODO: wildcards?? + //ns_check_wildcard(name, resp, &rrset); + + knot_response_add_rrset_authority(resp, rrset, 1, 0, 0); + ns_add_rrsigs(rrset, resp, node->owner, + knot_response_add_rrset_authority, 1); + + int ret = KNOT_EOK; + // add DS records + dbg_ns("DNSSEC requested: %d\n", + knot_query_dnssec_requested(knot_packet_query(resp))); + dbg_ns("DS records: %p\n", knot_node_rrset(node, KNOT_RRTYPE_DS)); + if (DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp))) { + rrset = knot_node_rrset(node, KNOT_RRTYPE_DS); + if (rrset != NULL) { + knot_response_add_rrset_authority(resp, rrset, 1, 0, + 0); + ns_add_rrsigs(rrset, resp, node->owner, + knot_response_add_rrset_authority, 1); + } else { + // no DS, add NSEC3 or NSEC + // if NSEC3 enabled, search for NSEC3 + if (knot_zone_contents_nsec3_enabled(zone)) { + const knot_node_t *nsec3_node = + knot_node_nsec3_node(node, 1); + dbg_ns("There is no DS, putting NSEC3s...\n"); + if (nsec3_node != NULL) { + dbg_ns("Putting NSEC3s from the node.\n"); + ns_put_nsec3_from_node(nsec3_node, resp); + } else { + dbg_ns("Putting Opt-Out NSEC3s.\n"); + // no NSEC3 (probably Opt-Out) + // TODO: check if the zone is Opt-Out + ret = ns_put_nsec3_closest_encloser_proof(zone, + &node, qname, resp); + } + } else { + const knot_rrset_t *nsec = knot_node_rrset( + node, KNOT_RRTYPE_NSEC); + if (nsec) { + /*! \todo Check return value? */ + knot_response_add_rrset_authority( + resp, nsec, 1, 1, 0); + if ((nsec = knot_rrset_rrsigs(nsec)) != NULL) { + knot_response_add_rrset_authority(resp, nsec, 1, + 1, 0); + } + } + } + } + } + + if (ret == KNOT_EOK) { + ns_put_additional(resp); + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + } + return ret; +} + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Tries to answer the query from the given node. + * + * Tries to put RRSets of requested type (\a qtype) to the Answer section of the + * response. If successful, it also adds authority NS RRSet to the Authority + * section and it may add NSEC or NSEC3s in case of a wildcard answer (\a node + * is a wildcard node). If not successful (there are no such RRSets), it adds + * the SOA record to the Authority section and may add NSEC or NSEC3s according + * to the type of the response (NXDOMAIN if \a node is an empty non-terminal, + * NODATA if it is a regular node). It also adds any additional data that may + * be required. + * + * \param node Node to answer from. + * \param closest_encloser Closest encloser of \a qname in the zone. + * \param previous Previous domain name of \a qname in canonical order. + * \param zone Zone used for answering. + * \param qname Searched domain name. + * \param qtype Searched RR type. + * \param resp Response. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_answer_from_node(const knot_node_t *node, + const knot_node_t *closest_encloser, + const knot_node_t *previous, + const knot_zone_contents_t *zone, + const knot_dname_t *qname, uint16_t qtype, + knot_packet_t *resp) +{ + dbg_ns("Putting answers from found node to the response...\n"); + int answers = ns_put_answer(node, qname, qtype, resp); + + int ret = KNOT_EOK; + if (answers == 0) { // if NODATA response, put SOA + if (knot_node_rrset_count(node) == 0 + && !knot_zone_contents_nsec3_enabled(zone)) { + // node is an empty non-terminal => NSEC for NXDOMAIN + //assert(knot_node_rrset_count(closest_encloser) > 0); + dbg_ns("Adding NSEC/NSEC3 for NXDOMAIN.\n"); + ret = ns_put_nsec_nsec3_nxdomain(zone, + knot_node_previous(node, 1), closest_encloser, + qname, resp); + } else { + dbg_ns("Adding NSEC/NSEC3 for NODATA.\n"); + ns_put_nsec_nsec3_nodata(node, resp); + if (knot_dname_is_wildcard(node->owner)) { + dbg_ns("Putting NSEC/NSEC3 for wildcard" + " NODATA\n"); + ret = ns_put_nsec_nsec3_wildcard_nodata(node, + closest_encloser, previous, zone, qname, + resp); + } + } + ns_put_authority_soa(zone, resp); + } else { // else put authority NS + // if wildcard answer, add NSEC / NSEC3 + dbg_ns("Adding NSEC/NSEC3 for wildcard answer.\n"); + ret = ns_put_nsec_nsec3_wildcard_answer(node, closest_encloser, + previous, zone, qname, resp); + ns_put_authority_ns(zone, resp); + } + + if (ret == KNOT_EOK) { + ns_put_additional(resp); + } + return ret; +} + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Synthetizes a CNAME RR from a DNAME. + * + * \param dname_rrset DNAME RRSet to synthetize from (only the first RR is + * used). + * \param qname Name to be used as the owner name of the synthetized CNAME. + * + * \return Synthetized CNAME RRset (this is a newly created RRSet, remember to + * free it). + */ +static knot_rrset_t *ns_cname_from_dname(const knot_rrset_t *dname_rrset, + const knot_dname_t *qname) +{ + dbg_ns("Synthetizing CNAME from DNAME...\n"); + + // create new CNAME RRSet + + knot_dname_t *owner = knot_dname_deep_copy(qname); + if (owner == NULL) { + return NULL; + } + + knot_rrset_t *cname_rrset = knot_rrset_new( + owner, KNOT_RRTYPE_CNAME, KNOT_CLASS_IN, SYNTH_CNAME_TTL); + + /* Release owner, as it's retained in rrset. */ + knot_dname_release(owner); + + if (cname_rrset == NULL) { + return NULL; + } + + // replace last labels of qname with DNAME + knot_dname_t *cname = knot_dname_replace_suffix(qname, + knot_dname_size(knot_rrset_owner(dname_rrset)), + knot_rdata_get_item(knot_rrset_rdata(dname_rrset), 0)->dname); +dbg_ns_exec( + char *name = knot_dname_to_str(cname); + dbg_ns("CNAME canonical name: %s.\n", name); + free(name); +); + knot_rdata_t *cname_rdata = knot_rdata_new(); + knot_rdata_item_t cname_rdata_item; + cname_rdata_item.dname = cname; + knot_rdata_set_items(cname_rdata, &cname_rdata_item, 1); + + knot_rrset_add_rdata(cname_rrset, cname_rdata); + + return cname_rrset; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks if the name created by replacing the owner of \a dname_rrset + * in the \a qname by the DNAME's target would be longer than allowed. + * + * \param dname_rrset DNAME RRSet to be used for the check. + * \param qname Name whose part is to be replaced. + * + * \retval <>0 if the created domain name would be too long. + * \retval 0 otherwise. + */ +static int ns_dname_is_too_long(const knot_rrset_t *dname_rrset, + const knot_dname_t *qname) +{ + // TODO: add function for getting DNAME target + if (knot_dname_label_count(qname) + - knot_dname_label_count(knot_rrset_owner(dname_rrset)) + + knot_dname_label_count(knot_rdata_get_item( + knot_rrset_rdata(dname_rrset), 0)->dname) + > KNOT_MAX_DNAME_LENGTH) { + return 1; + } else { + return 0; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief DNAME processing. + * + * This function adds the DNAME RRSet (and possibly its associated RRSIGs to the + * Answer section of the response, synthetizes CNAME record from the DNAME and + * adds it there too. It also stores the synthetized CNAME in the temporary + * RRSets of the response. + * + * \param dname_rrset DNAME RRSet to use. + * \param qname Searched name. + * \param resp Response. + */ +static void ns_process_dname(const knot_rrset_t *dname_rrset, + const knot_dname_t *qname, + knot_packet_t *resp) +{ +dbg_ns_exec( + char *name = knot_dname_to_str(knot_rrset_owner(dname_rrset)); + dbg_ns("Processing DNAME for owner %s...\n", name); + free(name); +); + // TODO: check the number of RRs in the RRSet?? + + // put the DNAME RRSet into the answer + knot_response_add_rrset_answer(resp, dname_rrset, 1, 0, 0); + ns_add_rrsigs(dname_rrset, resp, qname, + knot_response_add_rrset_answer, 1); + + if (ns_dname_is_too_long(dname_rrset, qname)) { + knot_response_set_rcode(resp, KNOT_RCODE_YXDOMAIN); + return; + } + + // synthetize CNAME (no way to tell that client supports DNAME) + knot_rrset_t *synth_cname = ns_cname_from_dname(dname_rrset, qname); + // add the synthetized RRSet to the Answer + knot_response_add_rrset_answer(resp, synth_cname, 1, 0, 0); + + // no RRSIGs for this RRSet + + // add the synthetized RRSet into list of temporary RRSets of response + knot_packet_add_tmp_rrset(resp, synth_cname); + + // do not search for the name in new zone (out-of-bailiwick) +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adds DNSKEY RRSet from the apex of a zone to the response. + * + * \param apex Zone apex node. + * \param resp Response. + */ +static void ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp) +{ + const knot_rrset_t *rrset = + knot_node_rrset(apex, KNOT_RRTYPE_DNSKEY); + if (rrset != NULL) { + knot_response_add_rrset_additional(resp, rrset, 0, 0, 0); + ns_add_rrsigs(rrset, resp, apex->owner, + knot_response_add_rrset_additional, 0); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Answers the query from the given zone. + * + * This function performs the actual answering logic. + * + * \param zone Zone to use for answering. + * \param qname QNAME from the query. + * \param qtype QTYPE from the query. + * \param resp Response to fill in. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + * + * \todo Describe the answering logic in detail. + */ +static int ns_answer_from_zone(const knot_zone_contents_t *zone, + const knot_dname_t *qname, uint16_t qtype, + knot_packet_t *resp) +{ + const knot_node_t *node = NULL, *closest_encloser = NULL, + *previous = NULL; + int cname = 0, auth_soa = 0, ret = 0, find_ret = 0; + +search: +#ifdef USE_HASH_TABLE + /*! \todo Check version. */ + find_ret = knot_zone_contents_find_dname_hash(zone, qname, &node, + &closest_encloser); +// node = knot_node_current(node); +// closest_encloser = knot_node_current(closest_encloser); +#else + /*! \todo Check version. */ + find_ret = knot_zone_contents_find_dname(zone, qname, &node, + &closest_encloser, &previous); + node = knot_node_current(node); + closest_encloser = knot_node_current(closest_encloser); + previous = knot_node_current(previous); +#endif + if (find_ret == KNOT_EBADARG) { + return NS_ERR_SERVFAIL; + } + +dbg_ns_exec( + char *name; + if (node) { + name = knot_dname_to_str(node->owner); + dbg_ns("zone_find_dname() returned node %s ", name); + free(name); + } else { + dbg_ns("zone_find_dname() returned no node,"); + } + + if (closest_encloser != NULL) { + name = knot_dname_to_str(closest_encloser->owner); + dbg_ns(" closest encloser %s.\n", name); + free(name); + } else { + dbg_ns(" closest encloser (nil).\n"); + } + if (previous != NULL) { + name = knot_dname_to_str(previous->owner); + dbg_ns(" and previous node: %s.\n", name); + free(name); + } else { + dbg_ns(" and previous node: (nil).\n"); + } +); + if (find_ret == KNOT_EBADZONE) { + // possible only if we followed cname + assert(cname != 0); + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + auth_soa = 1; + knot_response_set_aa(resp); + goto finalize; + } + +have_node: + dbg_ns("Closest encloser is deleg. point? %s\n", + (knot_node_is_deleg_point(closest_encloser)) ? "yes" : "no"); + + dbg_ns("Closest encloser is non authoritative? %s\n", + (knot_node_is_non_auth(closest_encloser)) ? "yes" : "no"); + + if (knot_node_is_deleg_point(closest_encloser) + || knot_node_is_non_auth(closest_encloser)) { + ret = ns_referral(closest_encloser, zone, qname, resp); + goto finalize; + } + + if (find_ret == KNOT_ZONE_NAME_NOT_FOUND) { + // DNAME? + const knot_rrset_t *dname_rrset = knot_node_rrset( + closest_encloser, KNOT_RRTYPE_DNAME); + if (dname_rrset != NULL) { + ns_process_dname(dname_rrset, qname, resp); + auth_soa = 1; + knot_response_set_aa(resp); + goto finalize; + } + // else check for a wildcard child + const knot_node_t *wildcard_node = + knot_node_wildcard_child(closest_encloser, 1); + + if (wildcard_node == NULL) { + dbg_ns("No wildcard node. (cname: %d)\n", + cname); + auth_soa = 1; + if (cname == 0) { + dbg_ns("Setting NXDOMAIN RCODE.\n"); + // return NXDOMAIN + knot_response_set_rcode(resp, + KNOT_RCODE_NXDOMAIN); + if (ns_put_nsec_nsec3_nxdomain(zone, previous, + closest_encloser, qname, resp) != 0) { + return NS_ERR_SERVFAIL; + } + } else { + knot_response_set_rcode(resp, + KNOT_RCODE_NOERROR); + } + knot_response_set_aa(resp); + goto finalize; + } + // else set the node from which to take the answers to wild.node + node = wildcard_node; + } + + // now we have the node for answering + if (knot_node_is_deleg_point(node) || knot_node_is_non_auth(node)) { + ret = ns_referral(node, zone, qname, resp); + goto finalize; + } + + if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL) { +dbg_ns_exec( + char *name = knot_dname_to_str(node->owner); + dbg_ns("Node %s has CNAME record, resolving...\n", + name); + free(name); +); + const knot_dname_t *act_name = qname; + ns_follow_cname(&node, &act_name, resp, + knot_response_add_rrset_answer, 1); +dbg_ns_exec( + char *name = (node != NULL) ? knot_dname_to_str(node->owner) + : "(nil)"; + char *name2 = knot_dname_to_str(act_name); + dbg_ns("Canonical name: %s (%p), node found: %p\n", + name2, act_name, node); + dbg_ns("The node's owner: %s (%p)\n", name, (node != NULL) + ? node->owner : NULL); + if (node != NULL) { + free(name); + } + free(name2); +); + qname = act_name; + cname = 1; + + // otherwise search for the new name + if (node == NULL) { + goto search; + } else if (node->owner != act_name) { + // the stored node is closest encloser + find_ret = KNOT_ZONE_NAME_NOT_FOUND; + closest_encloser = node; + node = NULL; + goto have_node; + } // else do nothing, just continue + } + + ret = ns_answer_from_node(node, closest_encloser, previous, zone, qname, + qtype, resp); + if (ret == NS_ERR_SERVFAIL) { + // in this case we should drop the response and send an error + // for now, just send the error code with a non-complete answer +// knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL); +// goto finalize; + return ret; + } else if (ret != KNOT_EOK) { + /*! \todo Handle RCODE return values!!! */ + goto finalize; + } + knot_response_set_aa(resp); + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + + // this is the only case when the servers answers from + // particular node, i.e. the only case when it may return SOA + // or NS records in Answer section + if (DNSSEC_ENABLED + && knot_query_dnssec_requested(knot_packet_query(resp)) + && node == knot_zone_contents_apex(zone) + && (qtype == KNOT_RRTYPE_SOA || qtype == KNOT_RRTYPE_NS)) { + ns_add_dnskey(node, resp); + } + +finalize: + if (ret == KNOT_EOK && auth_soa) { + ns_put_authority_soa(zone, resp); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Answers the query from the given zone database. + * + * First it searches for a zone to answer from. If there is none, it sets + * RCODE REFUSED to the response and ends. Otherwise it tries to answer the + * query using the found zone (see ns_answer_from_zone()). + * + * \param db Zone database to use for answering. + * \param resp Response that holds the parsed query. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_answer(knot_zonedb_t *db, knot_packet_t *resp) +{ + const knot_dname_t *qname = knot_packet_qname(resp); + assert(qname != NULL); + + uint16_t qtype = knot_packet_qtype(resp); +dbg_ns_exec( + char *name_str = knot_dname_to_str(qname); + dbg_ns("Trying to find zone for QNAME %s\n", name_str); + free(name_str); +); + // find zone in which to search for the name + const knot_zone_t *zone = + ns_get_zone_for_qname(db, qname, qtype); + const knot_zone_contents_t *contents = knot_zone_contents(zone); + + // if no zone found, return REFUSED + if (zone == NULL) { + dbg_ns("No zone found.\n"); + knot_response_set_rcode(resp, KNOT_RCODE_REFUSED); + //knot_dname_free(&qname); + return KNOT_EOK; + } else if (contents == NULL) { + dbg_ns("Zone expired or not bootstrapped. Reply SERVFAIL.\n"); + knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL); + return KNOT_EOK; + } + +dbg_ns_exec( + char *name_str2 = knot_dname_to_str(zone->contents->apex->owner); + dbg_ns("Found zone for QNAME %s\n", name_str2); + free(name_str2); +); + + // take the zone contents and use only them for answering + + return ns_answer_from_zone(contents, qname, qtype, resp); + + //knot_dname_free(&qname); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Converts the response to wire format. + * + * \param resp Response to convert. + * \param wire Place for the wire format of the response. + * \param wire_size In: space available for the wire format in bytes. + * Out: actual size of the wire format in bytes. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_response_to_wire(knot_packet_t *resp, uint8_t *wire, + size_t *wire_size) +{ + uint8_t *rwire = NULL; + size_t rsize = 0; + int ret = 0; + + if ((ret = knot_packet_to_wire(resp, &rwire, &rsize)) + != KNOT_EOK) { + dbg_ns("Error converting response packet " + "to wire format (error %d).\n", ret); + return NS_ERR_SERVFAIL; + } + + if (rsize > *wire_size) { + dbg_ns("Reponse size (%zu) larger than allowed wire size " + "(%zu).\n", rsize, *wire_size); + return NS_ERR_SERVFAIL; + } + + if (rwire != wire) { + dbg_ns("Wire format reallocated, copying to place for " + "wire.\n"); + memcpy(wire, rwire, rsize); + } else { + dbg_ns("Using the same space or wire format.\n"); + } + + *wire_size = rsize; + //free(rwire); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a wire format of an error response from partially created + * response. + * + * \param resp Response to use. + * \param wire Place for the wire format of the response. + * \param wire_size In: space available for the wire format in bytes. + * Out: actual size of the wire format in bytes. + * + * \retval KNOT_EOK + * \retval NS_ERR_SERVFAIL + */ +static int ns_error_response_to_wire(knot_packet_t *resp, uint8_t *wire, + size_t *wire_size) +{ + /* Do not call the packet conversion function + * wire format is assembled, but COUNTs in header are not set. + * This is ideal, we just truncate the packet after the question. + */ + dbg_ns("Creating error response.\n"); + + size_t rsize = knot_packet_question_size(knot_packet_query(resp)); + dbg_ns("Error response (~ query) size: %zu\n", rsize); + + // take 'qsize' from the current wireformat of the response + // it is already assembled - Header and Question section are copied + const uint8_t *rwire = knot_packet_wireformat(resp); + if (rsize > *wire_size) { + dbg_ns("Reponse size (%zu) larger than allowed wire size" + " (%zu).\n", rsize, *wire_size); + return NS_ERR_SERVFAIL; + } + + assert(rwire != wire); + + /*! \todo Why is this copied?? Why we cannot use resp->wireformat?? */ + memcpy(wire, rwire, rsize); + + *wire_size = rsize; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +typedef struct ns_axfr_params { + knot_ns_xfr_t *xfr; + int ret; +} ns_axfr_params_t; + +/*----------------------------------------------------------------------------*/ + +int knot_ns_tsig_required(int packet_nr) +{ + dbg_ns_detail("ns_tsig_required(%d): %d\n", packet_nr, + (packet_nr % KNOT_NS_TSIG_FREQ == 0)); + return (packet_nr % KNOT_NS_TSIG_FREQ == 0); +} + +/*----------------------------------------------------------------------------*/ + +static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) +{ + assert(xfr != NULL); + assert(xfr->query != NULL); + assert(xfr->response != NULL); + assert(xfr->wire != NULL); + assert(xfr->send != NULL); + + // Transform the packet into wire format + dbg_ns("Converting response to wire format..\n"); + size_t real_size = xfr->wire_size; + if (ns_response_to_wire(xfr->response, xfr->wire, &real_size) != 0) { + return NS_ERR_SERVFAIL; +// // send back SERVFAIL (as this is our problem) +// ns_error_response(nameserver, +// knot_wire_get_id(query_wire), +// KNOT_RCODE_SERVFAIL, response_wire, +// rsize); + } + + int res = 0; + + size_t digest_real_size = xfr->digest_max_size; + + dbg_ns_detail("xfr->tsig_key=%p\n", xfr->tsig_key); + /*! \note [TSIG] Generate TSIG if required (during XFR/IN). */ + if (xfr->tsig_key && add_tsig) { + if (xfr->packet_nr == 0) { + /* Add key, digest and digest length. */ + dbg_ns_detail("Calling tsig_sign(): %p, %zu, %zu, " + "%p, %zu, %p, %zu, %p\n", + xfr->wire, real_size, xfr->wire_size, + xfr->digest, xfr->digest_size, xfr->digest, + digest_real_size, xfr->tsig_key); + res = knot_tsig_sign(xfr->wire, &real_size, + xfr->wire_size, xfr->digest, + xfr->digest_size, xfr->digest, + &digest_real_size, + xfr->tsig_key); + } else { + /* Add key, digest and digest length. */ + dbg_ns_detail("Calling tsig_sign_next()\n"); + res = knot_tsig_sign_next(xfr->wire, &real_size, + xfr->wire_size, + xfr->digest, + xfr->digest_size, + xfr->digest, + &digest_real_size, + xfr->tsig_key); + } + + dbg_ns_detail("Sign function returned: %s\n", + knot_strerror(res)); + dbg_ns_detail("Real size of digest: %zu\n", digest_real_size); + + if (res != KNOT_EOK) { + return res; + } + + assert(digest_real_size > 0); + // save the new previous digest size + xfr->digest_size = digest_real_size; + } + + // Send the response + dbg_ns("Sending response (size %zu)..\n", real_size); + //dbg_ns_hex((const char *)xfr->wire, real_size); + res = xfr->send(xfr->session, &xfr->addr, xfr->wire, real_size); + if (res < 0) { + dbg_ns("Send returned %d\n", res); + return res; + } else if (res != real_size) { + dbg_ns("AXFR did not send right amount of bytes." + " Transfer size: %zu, sent: %d\n", + real_size, res); + } + + // Clean the response structure + dbg_ns("Clearing response structure..\n"); + knot_response_clear(xfr->response, 0); + + // increment the packet number + ++xfr->packet_nr; + if (xfr->tsig_key && add_tsig) { + knot_packet_set_tsig_size(xfr->response, xfr->tsig_size); + } else { + knot_packet_set_tsig_size(xfr->response, 0); + } + + dbg_ns("Response structure after clearing:\n"); + knot_packet_dump(xfr->response); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static void ns_axfr_from_node(knot_node_t *node, void *data) +{ + assert(node != NULL); + assert(data != NULL); + + ns_axfr_params_t *params = (ns_axfr_params_t *)data; + + if (params->ret != KNOT_EOK) { + // just skip (will be called on next node with the same params + dbg_ns("Params contain error: %s, skipping node...\n", + knot_strerror(params->ret)); + return; + } + + dbg_ns("Params OK, answering AXFR from node %p.\n", node); +dbg_ns_exec( + char *name = knot_dname_to_str(knot_node_owner(node)); + dbg_ns("Node ownerr: %s\n", name); + free(name); +); + + if (knot_node_rrset_count(node) == 0) { + return; + } + + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + params->ret = KNOT_ENOMEM; + return; + } + + int i = 0; + int ret = 0; + const knot_rrset_t *rrset = NULL; + while (i < knot_node_rrset_count(node)) { + assert(rrsets[i] != NULL); + rrset = rrsets[i]; +rrset: + dbg_ns(" Type: %s\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + + // do not add SOA + if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + ++i; + continue; + } + + ret = knot_response_add_rrset_answer(params->xfr->response, + rrset, 0, 0, 1); + + if (ret == KNOT_ESPACE) { + // TODO: send the packet and clean the structure + dbg_ns("Packet full, sending..\n"); + ret = ns_xfr_send_and_clear(params->xfr, + knot_ns_tsig_required(params->xfr->packet_nr)); + if (ret != KNOT_EOK) { + // some wierd problem, we should end + params->ret = KNOT_ERROR; + break; + } + // otherwise try once more with the same RRSet + goto rrset; + } else if (ret != KNOT_EOK) { + // some wierd problem, we should end + params->ret = KNOT_ERROR; + break; + } + + // we can send the RRSets in any order, so add the RRSIGs now + rrset = knot_rrset_rrsigs(rrset); +rrsigs: + if (rrset == NULL) { + ++i; + continue; + } + + ret = knot_response_add_rrset_answer(params->xfr->response, + rrset, 0, 0, 1); + + if (ret == KNOT_ESPACE) { + // TODO: send the packet and clean the structure + dbg_ns("Packet full, sending..\n"); + ret = ns_xfr_send_and_clear(params->xfr, + knot_ns_tsig_required(params->xfr->packet_nr)); + if (ret != KNOT_EOK) { + // some wierd problem, we should end + params->ret = KNOT_ERROR; + break; + } + // otherwise try once more with the same RRSet + goto rrsigs; + } else if (ret != KNOT_EOK) { + // some wierd problem, we should end + params->ret = KNOT_ERROR; + break; + } + + // this way only whole RRSets are always sent + // we guess it will not create too much overhead + + ++i; + } + if (rrsets != NULL) { + free(rrsets); + } + + /*! \todo maybe distinguish some error codes. */ + //params->ret = (ret == 0) ? KNOT_EOK : KNOT_ERROR; +} + +/*----------------------------------------------------------------------------*/ + +static int ns_axfr_from_zone(knot_zone_contents_t *zone, knot_ns_xfr_t *xfr) +{ + assert(xfr != NULL); + assert(xfr->query != NULL); + assert(xfr->response != NULL); + assert(xfr->wire != NULL); + assert(xfr->send != NULL); + + ns_axfr_params_t params; + memset(¶ms, 0, sizeof(ns_axfr_params_t)); + params.xfr = xfr; + params.ret = KNOT_EOK; + + xfr->packet_nr = 0; + + /* + * First SOA + */ + + // retrieve SOA - must be send as first and last RR + const knot_rrset_t *soa_rrset = knot_node_rrset( + knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); + if (soa_rrset == NULL) { + // some really serious error + return KNOT_ERROR; + } + + int ret; + + // add SOA RR to the response + ret = knot_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0, 1); + if (ret != KNOT_EOK) { + // something is really wrong + return KNOT_ERROR; + } + + // add the SOA's RRSIG + const knot_rrset_t *rrset = knot_rrset_rrsigs(soa_rrset); + if (rrset != NULL + && (ret = knot_response_add_rrset_answer(xfr->response, rrset, + 0, 0, 1)) != KNOT_EOK) { + // something is really wrong, these should definitely fit in + return KNOT_ERROR; + } + + knot_zone_contents_tree_apply_inorder(zone, ns_axfr_from_node, + ¶ms); + + if (params.ret != KNOT_EOK) { + return KNOT_ERROR; // maybe do something with the code + } + + knot_zone_contents_nsec3_apply_inorder(zone, ns_axfr_from_node, + ¶ms); + + if (params.ret != KNOT_EOK) { + return KNOT_ERROR; // maybe do something with the code + } + + /* + * Last SOA + */ + + // try to add the SOA to the response again (last RR) + ret = knot_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0, 1); + if (ret == KNOT_ESPACE) { + + // if there is not enough space, send the response and + // add the SOA record to a new packet + dbg_ns("Packet full, sending..\n"); + ret = ns_xfr_send_and_clear(xfr, + knot_ns_tsig_required(xfr->packet_nr)); + if (ret != KNOT_EOK) { + return ret; + } + + ret = knot_response_add_rrset_answer(xfr->response, + soa_rrset, 0, 0, 1); + if (ret != KNOT_EOK) { + return KNOT_ERROR; + } + + } else if (ret != KNOT_EOK) { + // something is really wrong + return KNOT_ERROR; + } + + dbg_ns("Sending packet...\n"); + return ns_xfr_send_and_clear(xfr, 1); +} + +/*----------------------------------------------------------------------------*/ + +static int ns_ixfr_put_rrset(knot_ns_xfr_t *xfr, const knot_rrset_t *rrset) +{ + int res = knot_response_add_rrset_answer(xfr->response, rrset, + 0, 0, 0); + if (res == KNOT_ESPACE) { + knot_response_set_rcode(xfr->response, KNOT_RCODE_NOERROR); + /*! \todo Probably rename the function. */ + ns_xfr_send_and_clear(xfr, knot_ns_tsig_required(xfr->packet_nr)); + + res = knot_response_add_rrset_answer(xfr->response, + rrset, 0, 0, 0); + } + + if (res != KNOT_EOK) { + dbg_ns("Error putting origin SOA to IXFR reply: %s\n", + knot_strerror(res)); + /*! \todo Probably send back AXFR instead. */ + knot_response_set_rcode(xfr->response, + KNOT_RCODE_SERVFAIL); + /*! \todo Probably rename the function. */ + ns_xfr_send_and_clear(xfr, 1); + //socket_close(xfr->session); /*! \todo Remove for UDP.*/ + return KNOT_ERROR; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int ns_ixfr_put_changeset(knot_ns_xfr_t *xfr, const knot_changeset_t *chgset) +{ + // 1) put origin SOA + int res = ns_ixfr_put_rrset(xfr, chgset->soa_from); + if (res != KNOT_EOK) { + return res; + } + + // 2) put remove RRSets + for (int i = 0; i < chgset->remove_count; ++i) { + res = ns_ixfr_put_rrset(xfr, chgset->remove[i]); + if (res != KNOT_EOK) { + return res; + } + } + + // 1) put target SOA + res = ns_ixfr_put_rrset(xfr, chgset->soa_to); + if (res != KNOT_EOK) { + return res; + } + + // 2) put remove RRSets + for (int i = 0; i < chgset->add_count; ++i) { + res = ns_ixfr_put_rrset(xfr, chgset->add[i]); + if (res != KNOT_EOK) { + return res; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) +{ + assert(xfr != NULL); + assert(xfr->zone != NULL); + assert(xfr->query != NULL); + assert(xfr->response != NULL); + assert(knot_packet_authority_rrset_count(xfr->query) > 0); + assert(xfr->data != NULL); + + /*! \todo REMOVE start */ +// const knot_rrset_t *zone_soa = +// knot_node_rrset(knot_zone_contents_apex( +// knot_zone_contents(xfr->zone)), +// KNOT_RRTYPE_SOA); +// // retrieve origin (xfr) serial and target (zone) serial +// uint32_t zone_serial = knot_rdata_soa_serial( +// knot_rrset_rdata(zone_soa)); +// uint32_t xfr_serial = knot_rdata_soa_serial(knot_rrset_rdata( +// knot_packet_authority_rrset(xfr->query, 0))); + +// // 3) load changesets from journal +// knot_changesets_t *chgsets = (knot_changesets_t *) +// calloc(1, sizeof(knot_changesets_t)); +// int res = xfr_load_changesets(xfr->zone, chgsets, xfr_serial, +// zone_serial); +// if (res != KNOT_EOK) { +// dbg_ns("IXFR query cannot be answered: %s.\n", +// knot_strerror(res)); +// /*! \todo Probably send back AXFR instead. */ +// knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL); +// /*! \todo Probably rename the function. */ +// ns_axfr_send_and_clear(xfr); +// //socket_close(xfr->session); /*! \todo Remove for UDP. */ +// return 1; +// } + + /*! \todo REMOVE end */ + + knot_changesets_t *chgsets = (knot_changesets_t *)xfr->data; + knot_zone_contents_t* contents = knot_zone_get_contents(xfr->zone); + assert(contents); + const knot_rrset_t *zone_soa = + knot_node_rrset(knot_zone_contents_apex(contents), + KNOT_RRTYPE_SOA); + + // 4) put the zone SOA as the first Answer RR + int res = knot_response_add_rrset_answer(xfr->response, zone_soa, 0, + 0, 0); + if (res != KNOT_EOK) { + dbg_ns("IXFR query cannot be answered: %s.\n", + knot_strerror(res)); + knot_response_set_rcode(xfr->response, + KNOT_RCODE_SERVFAIL); + /*! \todo Probably rename the function. */ + ns_xfr_send_and_clear(xfr, 1); +// socket_close(xfr->session); /*! \todo Remove for UDP.*/ + return 1; + } + + // 5) put the changesets into the response while they fit in + for (int i = 0; i < chgsets->count; ++i) { + res = ns_ixfr_put_changeset(xfr, &chgsets->sets[i]); + if (res != KNOT_EOK) { + // answer is sent, socket is closed + return KNOT_EOK; + } + } + + if (chgsets->count > 0) { + res = ns_ixfr_put_rrset(xfr, zone_soa); + } + + if (res == KNOT_EOK) { + /*! \todo Probably rename the function. */ + ns_xfr_send_and_clear(xfr, 1); + //socket_close(xfr->session); /*! \todo Remove for UDP.*/ + return 1; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int ns_ixfr(knot_ns_xfr_t *xfr) +{ + assert(xfr != NULL); + assert(xfr->query != NULL); + assert(xfr->response != NULL); + assert(knot_packet_qtype(xfr->response) == KNOT_RRTYPE_IXFR); + + // check if there is the required authority record + if ((knot_packet_authority_rrset_count(xfr->query) <= 0)) { + // malformed packet + dbg_ns("IXFR query does not contain authority record.\n"); + knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR); + /*! \todo Probably rename the function. */ + ns_xfr_send_and_clear(xfr, 1); + //socket_close(xfr->session); + return 1; + } + + const knot_rrset_t *soa = knot_packet_authority_rrset(xfr->query, 0); + const knot_dname_t *qname = knot_packet_qname(xfr->response); + + // check if XFR QNAME and SOA correspond + if (knot_packet_qtype(xfr->query) != KNOT_RRTYPE_IXFR + || knot_rrset_type(soa) != KNOT_RRTYPE_SOA + || knot_dname_compare(qname, knot_rrset_owner(soa)) != 0) { + // malformed packet + dbg_ns("IXFR query is malformed.\n"); + knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR); + /*! \todo Probably rename the function. */ + ns_xfr_send_and_clear(xfr, 1); + //socket_close(xfr->session); /*! \todo Remove for UDP. */ + return 1; + } + + return ns_ixfr_from_zone(xfr); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ns_prepare_response(knot_nameserver_t *nameserver, + knot_packet_t *query, knot_packet_t **resp, + size_t max_size) +{ + assert(max_size >= 500); + + // initialize response packet structure + *resp = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + if (*resp == NULL) { + dbg_ns("Failed to create packet structure.\n"); + return KNOT_ENOMEM; + } + + int ret = knot_packet_set_max_size(*resp, max_size); + //(*resp)->wireformat = response_wire;; + //(*resp)->max_size = max_size; + + if (ret != KNOT_EOK) { + dbg_ns("Failed to init response structure.\n"); + knot_packet_free(resp); + return ret; + } + + ret = knot_response_init_from_query(*resp, query); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to init response structure.\n"); + knot_packet_free(resp); + return ret; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int32_t ns_serial_difference(uint32_t s1, uint32_t s2) +{ + return (((int64_t)s1 - s2) % ((int64_t)1 << 32)); +} + +/*----------------------------------------------------------------------------*/ +/* Public functions */ +/*----------------------------------------------------------------------------*/ + +knot_nameserver_t *knot_ns_create() +{ + knot_nameserver_t *ns = malloc(sizeof(knot_nameserver_t)); + if (ns == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + ns->data = 0; + + // Create zone database structure + dbg_ns("Creating Zone Database structure...\n"); + ns->zone_db = knot_zonedb_new(); + if (ns->zone_db == NULL) { + ERR_ALLOC_FAILED; + free(ns); + return NULL; + } + + // prepare empty response with SERVFAIL error + knot_packet_t *err = knot_packet_new(KNOT_PACKET_PREALLOC_NONE); + if (err == NULL) { + ERR_ALLOC_FAILED; + free(ns); + return NULL; + } + + dbg_ns("Created default empty response...\n"); + + int rc = knot_packet_set_max_size(err, KNOT_WIRE_HEADER_SIZE); + if (rc != KNOT_EOK) { + dbg_ns("Error creating default error response: %s.\n", + knot_strerror(rc)); + free(ns); + knot_packet_free(&err); + return NULL; + } + + rc = knot_response_init(err); + if (rc != KNOT_EOK) { + dbg_ns("Error initializing default error response:" + " %s.\n", knot_strerror(rc)); + free(ns); + knot_packet_free(&err); + return NULL; + } + + knot_response_set_rcode(err, KNOT_RCODE_SERVFAIL); + ns->err_resp_size = 0; + + dbg_ns("Converting default empty response to wire format...\n"); + + uint8_t *error_wire = NULL; + + if (knot_packet_to_wire(err, &error_wire, &ns->err_resp_size) != 0) { + dbg_ns("Error while converting " + "default error response to " + "wire format \n"); + knot_packet_free(&err); + free(ns); + return NULL; + } + + ns->err_response = (uint8_t *)malloc(ns->err_resp_size); + if (ns->err_response == NULL) { + dbg_ns("Error while converting default " + "error response to wire format \n"); + knot_packet_free(&err); + free(ns); + return NULL; + } + + memcpy(ns->err_response, error_wire, ns->err_resp_size); + + dbg_ns("Done..\n"); + + knot_packet_free(&err); + + if (EDNS_ENABLED) { + ns->opt_rr = knot_edns_new(); + if (ns->opt_rr == NULL) { + dbg_ns("Error while preparing OPT RR of the" + " server.\n"); + knot_packet_free(&err); + free(ns); + return NULL; + } + knot_edns_set_version(ns->opt_rr, EDNS_VERSION); + knot_edns_set_payload(ns->opt_rr, MAX_UDP_PAYLOAD_EDNS); + } else { + ns->opt_rr = NULL; + } + + knot_packet_free(&err); + + return ns; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, + knot_packet_t *packet, knot_packet_type_t *type) +{ + if (packet == NULL || query_wire == NULL || type == NULL) { + dbg_ns("Missing parameter to query parsing.\n"); + return KNOT_EBADARG; + } + + dbg_ns("ns_parse_packet() called with query size %zu.\n", qsize); + //dbg_ns_hex((char *)query_wire, qsize); + + if (qsize < 2) { + return KNOT_EMALF; + } + + // 1) create empty response + dbg_ns("Parsing packet...\n"); + //parsed = knot_response_new_empty(NULL); + + int ret = 0; + + if ((ret = knot_packet_parse_from_wire(packet, query_wire, + qsize, 1)) != 0) { + dbg_ns("Error while parsing packet, " + "libknot error '%s'.\n", knot_strerror(ret)); +// knot_response_free(&parsed); + return KNOT_RCODE_FORMERR; + } + + dbg_ns("Parsed packet header and Question:\n"); + knot_packet_dump(packet); + + // 3) determine the query type + switch (knot_packet_opcode(packet)) { + case KNOT_OPCODE_QUERY: + switch (knot_packet_qtype(packet)) { + case KNOT_RRTYPE_AXFR: + *type = (knot_packet_is_query(packet)) + ? KNOT_QUERY_AXFR : KNOT_RESPONSE_AXFR; + break; + case KNOT_RRTYPE_IXFR: + *type = (knot_packet_is_query(packet)) + ? KNOT_QUERY_IXFR : KNOT_RESPONSE_IXFR; + break; + default: + *type = (knot_packet_is_query(packet)) + ? KNOT_QUERY_NORMAL : KNOT_RESPONSE_NORMAL; + } + + break; + case KNOT_OPCODE_NOTIFY: + *type = (knot_packet_is_query(packet)) + ? KNOT_QUERY_NOTIFY : KNOT_RESPONSE_NOTIFY; + break; + case KNOT_OPCODE_UPDATE: + if(knot_packet_is_query(packet)) { + *type = KNOT_QUERY_UPDATE; + } else { + return KNOT_RCODE_FORMERR; + } + break; + default: + return KNOT_RCODE_NOTIMPL; + } + +// knot_packet_free(&packet); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +void knot_ns_error_response(const knot_nameserver_t *nameserver, uint16_t query_id, + uint8_t rcode, uint8_t *response_wire, size_t *rsize) +{ + //dbg_ns("Error response: \n"); + //dbg_ns_hex((const char *)nameserver->err_response, + // nameserver->err_resp_size); + + memcpy(response_wire, nameserver->err_response, + nameserver->err_resp_size); + // copy ID of the query + knot_wire_set_id(response_wire, query_id); + // set the RCODE + knot_wire_set_rcode(response_wire, rcode); + *rsize = nameserver->err_resp_size; +} + +/*----------------------------------------------------------------------------*/ + +void knot_ns_error_response_full(knot_nameserver_t *nameserver, + knot_packet_t *response, uint8_t rcode, + uint8_t *response_wire, size_t *rsize) +{ + knot_response_set_rcode(response, rcode); + + if (ns_error_response_to_wire(response, response_wire, rsize) != 0) { + knot_ns_error_response(nameserver, knot_packet_id( + knot_packet_query(response)), + KNOT_RCODE_SERVFAIL, response_wire, + rsize); + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_answer_normal(knot_nameserver_t *nameserver, knot_packet_t *query, + uint8_t *response_wire, size_t *rsize) +{ + dbg_ns("ns_answer_normal()\n"); + + // first, parse the rest of the packet + assert(knot_packet_is_query(query)); + dbg_ns("Query - parsed: %zu, total wire size: %zu\n", + knot_packet_parsed(query), knot_packet_size(query)); + int ret; + + ret = knot_packet_parse_rest(query); + if (ret != KNOT_EOK) { + dbg_ns("Failed to parse rest of the query: " + "%s.\n", knot_strerror(ret)); + knot_ns_error_response(nameserver, knot_packet_id(query), + (ret == KNOT_EMALF) + ? KNOT_RCODE_FORMERR + : KNOT_RCODE_SERVFAIL, response_wire, + rsize); + return KNOT_EOK; + } + + /* + * Semantic checks - if ANCOUNT > 0 or NSCOUNT > 0, return FORMERR. + * + * If any xxCOUNT is less or more than actual RR count + * the previously called knot_packet_parse_rest() will recognize this. + * + * Check the QDCOUNT and in case of anything but 1 send back + * FORMERR + */ + if (knot_packet_ancount(query) > 0 + || knot_packet_nscount(query) > 0 + || knot_packet_qdcount(query) != 1) { + dbg_ns("ANCOUNT or NSCOUNT not 0 in query, reply FORMERR.\n"); + knot_ns_error_response(nameserver, knot_packet_id(query), + KNOT_RCODE_FORMERR, response_wire, + rsize); + return KNOT_EOK; + } + + size_t resp_max_size = 0; + + assert(*rsize >= MAX_UDP_PAYLOAD); + + knot_packet_dump(query); + + if (knot_query_edns_supported(query)) { + if (knot_edns_get_payload(&query->opt_rr) < + knot_edns_get_payload(nameserver->opt_rr)) { + resp_max_size = knot_edns_get_payload(&query->opt_rr); + } else { + resp_max_size = knot_edns_get_payload( + nameserver->opt_rr); + } + } + + if (resp_max_size < MAX_UDP_PAYLOAD) { + resp_max_size = MAX_UDP_PAYLOAD; + } + + knot_packet_t *response; + ret = knot_ns_prepare_response(nameserver, query, &response, + resp_max_size); + if (ret != KNOT_EOK) { + knot_ns_error_response(nameserver, knot_packet_id(query), + KNOT_RCODE_SERVFAIL, response_wire, + rsize); + return KNOT_EOK; + } + + dbg_ns("Query - parsed: %zu, total wire size: %zu\n", + query->parsed, query->size); + dbg_ns("Opt RR: version: %d, payload: %d\n", + query->opt_rr.version, query->opt_rr.payload); + + // get the answer for the query + rcu_read_lock(); + knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); + + dbg_ns("EDNS supported in query: %d\n", + knot_query_edns_supported(query)); + + // set the OPT RR to the response + if (knot_query_edns_supported(query)) { + /*! \todo API. */ +// if (knot_edns_get_payload(&query->opt_rr) > MAX_UDP_PAYLOAD) { +// ret = knot_packet_set_max_size(response, +// knot_edns_get_payload(&query->opt_rr)); +// } else { +// ret = knot_packet_set_max_size(response, +// MAX_UDP_PAYLOAD); +// } + +// if (ret != KNOT_EOK) { +// dbg_ns("Failed to set max size.\n"); +// knot_ns_error_response_full(nameserver, response, +// KNOT_RCODE_SERVFAIL, +// response_wire, rsize); +// return KNOT_EOK; +// } + + ret = knot_response_add_opt(response, nameserver->opt_rr, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to set OPT RR to the response" + ": %s\n",knot_strerror(ret)); + } else { + // copy the DO bit from the query + if (knot_query_dnssec_requested(query)) { + /*! \todo API for this. */ + knot_edns_set_do(&response->opt_rr); + } + } + }/* else { + dbg_ns("Setting max size to %u.\n", MAX_UDP_PAYLOAD); + ret = knot_packet_set_max_size(response, MAX_UDP_PAYLOAD); + if (ret != KNOT_EOK) { + dbg_ns("Failed to set max size to %u\n", + MAX_UDP_PAYLOAD); + knot_ns_error_response_full(nameserver, response, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); + return KNOT_EOK; + } + }*/ + + dbg_ns("Response max size: %zu\n", response->max_size); + + ret = ns_answer(zonedb, response); + if (ret != 0) { + // now only one type of error (SERVFAIL), later maybe more + knot_ns_error_response_full(nameserver, response, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); + } else { + dbg_ns("Created response packet.\n"); + //knot_response_dump(resp); + knot_packet_dump(response); + + // 4) Transform the packet into wire format + if (ns_response_to_wire(response, response_wire, rsize) != 0) { + // send back SERVFAIL (as this is our problem) + knot_ns_error_response_full(nameserver, response, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); + } + } + + rcu_read_unlock(); + knot_packet_free(&response); + + dbg_ns("Returning response with wire size %zu\n", *rsize); + //dbg_ns_hex((char *)response_wire, *rsize); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) +{ + dbg_ns("knot_ns_init_xfr()\n"); + + if (nameserver == NULL || xfr == NULL) { + return KNOT_EBADARG; + } + + // no need to parse rest of the packet + /*! \todo Parse rest of packet because of EDNS. */ + int ret = knot_packet_parse_rest(xfr->query); + if (ret != KNOT_EOK) { + dbg_ns("Failed to parse rest of the query: %s\n", + knot_strerror(ret)); + knot_ns_error_response(nameserver, xfr->query->header.id, + (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR + : KNOT_RCODE_SERVFAIL, + xfr->wire, &xfr->wire_size); + ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); + return ret; + } + + dbg_packet("Parsed XFR query:\n"); + knot_packet_dump(xfr->query); + + // initialize response packet structure + knot_packet_t *response = knot_packet_new( + KNOT_PACKET_PREALLOC_RESPONSE); + if (response == NULL) { + dbg_ns("Failed to create packet structure.\n"); + /*! \todo xfr->wire is not NULL, will fail on assert! */ + knot_ns_error_response(nameserver, xfr->query->header.id, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); + ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); + knot_packet_free(&response); + return ret; + } + + //int ret = knot_packet_set_max_size(response, xfr->wire_size); + response->wireformat = xfr->wire; + response->max_size = xfr->wire_size; + +// if (ret != KNOT_EOK) { +// dbg_ns("Failed to init response structure.\n"); +// /*! \todo xfr->wire is not NULL, will fail on assert! */ +// knot_ns_error_response(nameserver, xfr->query->header.id, +// KNOT_RCODE_SERVFAIL, xfr->wire, +// &xfr->wire_size); +// int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, +// xfr->wire_size); +// knot_packet_free(&response); +// return res; +// } + + ret = knot_response_init_from_query(response, xfr->query); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to init response structure.\n"); + /*! \todo xfr->wire is not NULL, will fail on assert! */ + knot_ns_error_response(nameserver, xfr->query->header.id, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); + int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); + knot_packet_free(&response); + return res; + } + + xfr->response = response; + + knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); + + const knot_dname_t *qname = knot_packet_qname(xfr->response); + + assert(knot_packet_qtype(xfr->response) == KNOT_RRTYPE_AXFR || + knot_packet_qtype(xfr->response) == KNOT_RRTYPE_IXFR); + +dbg_ns_exec( + char *name_str = knot_dname_to_str(qname); + dbg_ns("Trying to find zone with name %s\n", name_str); + free(name_str); +); + // find zone in which to search for the name + knot_zone_t *zone = knot_zonedb_find_zone(zonedb, qname); + + // if no zone found, return NotAuth + if (zone == NULL) { + dbg_ns("No zone found.\n"); + knot_response_set_rcode(xfr->response, KNOT_RCODE_NOTAUTH); + ns_xfr_send_and_clear(xfr, 1); + return KNOT_ENOZONE; + } + +dbg_ns_exec( + char *name2_str = knot_dname_to_str(qname); + dbg_ns("Found zone for name %s\n", name2_str); + free(name2_str); +); + xfr->zone = zone; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int ns_serial_compare(uint32_t s1, uint32_t s2) +{ + int32_t diff = ns_serial_difference(s1, s2); + return (s1 == s2) /* s1 equal to s2 */ + ? 0 + :((diff >= 1 && diff < ((uint32_t)1 << 31)) + ? 1 /* s1 larger than s2 */ + : -1); /* s1 less than s2 */ +} + +/*----------------------------------------------------------------------------*/ + +int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from, + uint32_t *serial_to) +{ + if (xfr == NULL || xfr->zone == NULL || serial_from == NULL + || serial_to == NULL) { + dbg_ns_detail("Wrong parameters: xfr=%p," + " xfr->zone = %p\n", xfr, xfr->zone); + return KNOT_EBADARG; + } + + const knot_zone_t *zone = xfr->zone; + const knot_zone_contents_t *contents = knot_zone_contents(zone); + if (!contents) { + dbg_ns_detail("Missing contents\n"); + return KNOT_EBADARG; + } + + if (knot_zone_contents_apex(contents) == NULL) { + dbg_ns_detail("No apex.\n"); + return KNOT_EBADARG; + } + + const knot_rrset_t *zone_soa = + knot_node_rrset(knot_zone_contents_apex(contents), + KNOT_RRTYPE_SOA); + if (zone_soa == NULL) { + dbg_ns_verb("No SOA.\n"); + return KNOT_EBADARG; + } + + if (knot_packet_nscount(xfr->query) < 1) { + dbg_ns_verb("No Authority record.\n"); + return KNOT_EMALF; + } + + if (knot_packet_authority_rrset(xfr->query, 0) == NULL) { + dbg_ns_verb("Authority record missing.\n"); + return KNOT_ERROR; + } + + // retrieve origin (xfr) serial and target (zone) serial + *serial_to = knot_rdata_soa_serial(knot_rrset_rdata(zone_soa)); + *serial_from = knot_rdata_soa_serial(knot_rrset_rdata( + knot_packet_authority_rrset(xfr->query, 0))); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_xfr_send_error(const knot_nameserver_t *nameserver, + knot_ns_xfr_t *xfr, knot_rcode_t rcode) +{ + /*! \todo Handle TSIG errors differently. */ + knot_response_set_rcode(xfr->response, rcode); + + /*! \todo Probably rename the function. */ + int ret = 0; + if ((ret = ns_xfr_send_and_clear(xfr, 1)) != KNOT_EOK) { + size_t size = 0; + knot_ns_error_response(nameserver, xfr->query->header.id, + KNOT_RCODE_SERVFAIL, xfr->wire, &size); + ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) +{ + if (xfr == NULL || nameserver == NULL || xfr->zone == NULL) { + return KNOT_EBADARG; + } + + rcu_read_lock(); + + // take the contents and answer from them + int ret = 0; + knot_zone_contents_t *contents = knot_zone_get_contents(xfr->zone); + if (!contents) { + dbg_ns("AXFR failed on stub zone\n"); + /*! \todo replace with knot_ns_xfr_send_error() */ + knot_ns_error_response(nameserver, xfr->query->header.id, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); + ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); + rcu_read_unlock(); + knot_packet_free(&xfr->response); + return KNOT_EOK; + } + + /*! + * \todo [TSIG] The TSIG data should already be stored in 'xfr'. + * Now just count the expected size of the TSIG RR and save it + * to the response structure. + */ + + /*! \todo [TSIG] Get the TSIG size from some API function. */ + if (xfr->tsig_size > 0) { + dbg_ns_detail("Setting TSIG size in packet: %zu\n", + xfr->tsig_size); + knot_packet_set_tsig_size(xfr->response, xfr->tsig_size); + } + + ret = ns_axfr_from_zone(contents, xfr); + + /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL + * and when it does not. E.g. if there was problem in sending + * packet, it will probably fail when sending the SERVFAIL also. + */ + if (ret < 0) { + dbg_ns("AXFR failed, sending SERVFAIL.\n"); + // now only one type of error (SERVFAIL), later maybe more + /*! \todo xfr->wire is not NULL, will fail on assert! */ + /*! \todo replace with knot_ns_xfr_send_error() */ + knot_ns_error_response(nameserver, xfr->query->header.id, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); + ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); + } else if (ret > 0) { + ret = KNOT_ERROR; + } + + rcu_read_unlock(); + + knot_packet_free(&xfr->response); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) +{ + if (nameserver == NULL || xfr == NULL || xfr->zone == NULL + || xfr->response == NULL) { + return KNOT_EBADARG; + } + + //uint8_t *wire = NULL; + //size_t size = xfr->wire_size; + + // parse rest of the packet (we need the Authority record) + int ret = knot_packet_parse_rest(xfr->query); + if (ret != KNOT_EOK) { + dbg_ns("Failed to parse rest of the packet. Reply FORMERR.\n"); +// knot_ns_error_response_full(nameserver, xfr->response, +// KNOT_RCODE_FORMERR, xfr->wire, +// &size); + knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_FORMERR); + + //ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size); + knot_packet_free(&xfr->response); + return ret; + } + + // check if the zone has contents + if (knot_zone_contents(xfr->zone) == NULL) { + dbg_ns("Zone expired or not bootstrapped. Reply SERVFAIL.\n"); + ret = knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); +// knot_ns_error_response_full(nameserver, xfr->response, +// KNOT_RCODE_SERVFAIL, xfr->wire, +// &size); + +// ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size); + knot_packet_free(&xfr->response); + return ret; + } + + /*! + * \todo [TSIG] The TSIG data should already be stored in 'xfr'. + * Now just count the expected size of the TSIG RR and save it + * to the response structure. This should be optional, only if + * the request contained TSIG, i.e. if there is the data in 'xfr'. + */ + + /*! \todo [TSIG] Get the TSIG size from some API function. */ + if (xfr->tsig_size > 0) { + knot_packet_set_tsig_size(xfr->response, xfr->tsig_size); + } + + ret = ns_ixfr(xfr); + + /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL + * and when it does not. E.g. if there was problem in sending + * packet, it will probably fail when sending the SERVFAIL also. + */ + if (ret < 0) { + dbg_ns("IXFR failed, sending SERVFAIL.\n"); + // now only one type of error (SERVFAIL), later maybe more + + /*! \todo Extract this to some function. */ +// knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL); +// uint8_t *wire = NULL; +// ret = knot_packet_to_wire(xfr->response, &wire, &size); +// if (ret != KNOT_EOK) { +//// knot_ns_error_response(nameserver, +//// xfr->query->header.id, +//// KNOT_RCODE_SERVFAIL, xfr->wire, +//// &size); +//// ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, +//// size); +// knot_ns_xfr_send_error(xfr, KNOT_RCODE_SERVFAIL); +// knot_packet_free(&xfr->response); +// return ret; +// } else { +// ret = xfr->send(xfr->session, &xfr->addr, wire, size); +// } + knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); + } /*else if (ret > 0) { + ret = KNOT_ERROR; + }*/ + + knot_packet_free(&xfr->response); + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) +{ + /*! + * \todo [TSIG] Here we assume that 'xfr' contains TSIG information + * and the digest of the query sent to the master or the previous + * digest. + */ + + dbg_ns("ns_process_axfrin: incoming packet, wire size: %zu\n", + xfr->wire_size); + + int ret = xfrin_process_axfr_packet(/*xfr->wire, xfr->wire_size,*/ + /*(xfrin_constructed_zone_t **)(&xfr->data)*/ + xfr); + + if (ret > 0) { // transfer finished + dbg_ns("ns_process_axfrin: AXFR finished, zone created.\n"); + /* + * Adjust zone so that node count is set properly and nodes are + * marked authoritative / delegation point. + */ + xfrin_constructed_zone_t *constr_zone = + (xfrin_constructed_zone_t *)xfr->data; + knot_zone_contents_t *zone = constr_zone->contents; + assert(zone != NULL); + + dbg_ns("ns_process_axfrin: adjusting zone.\n"); + knot_zone_contents_adjust(zone, 0); + + /* Create and fill hash table */ + dbg_ns("ns_process_axfrin: filling hash table.\n"); + int rc = knot_zone_contents_create_and_fill_hash_table(zone); + if (rc != KNOT_EOK) { + return KNOT_ERROR; // TODO: change error code + } + + // save the zone contents to the xfr->data + xfr->data = zone; + + // free the structure used for processing XFR + assert(constr_zone->rrsigs == NULL); + free(constr_zone); + + //knot_zone_contents_dump(zone, 0); + } + + /*! + * \todo In case of error, shouldn't the zone be destroyed here? + */ + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_switch_zone(knot_nameserver_t *nameserver, + knot_ns_xfr_t *xfr) +{ + if (xfr == NULL || nameserver == NULL || xfr->data == NULL) { + return KNOT_EBADARG; + } + + knot_zone_contents_t *zone = (knot_zone_contents_t *)xfr->data; + + dbg_ns("Replacing zone by new one: %p\n", zone); + + // find the zone in the zone db + knot_zone_t *z = knot_zonedb_find_zone(nameserver->zone_db, + knot_node_owner(knot_zone_contents_apex(zone))); + if (z == NULL) { + char *name = knot_dname_to_str(knot_node_owner( + knot_zone_contents_apex(zone))); + dbg_ns("Failed to replace zone %s, old zone " + "not found\n", name); + free(name); + } else { + zone->zone = z; + } + + knot_zone_contents_t *old = rcu_xchg_pointer(&z->contents, zone); + +// knot_zone_t *old = knot_zonedb_replace_zone(nameserver->zone_db, +// zone); + dbg_ns("Old zone: %p\n", old); +// if (old == NULL) { +// char *name = knot_dname_to_str( +// knot_node_owner(knot_zone_apex(zone))); +// dbg_ns("Failed to replace zone %s\n", name); +// free(name); +// } + + // wait for readers to finish + dbg_ns("Waiting for readers to finish...\n"); + synchronize_rcu(); + // destroy the old zone + dbg_ns("Freeing old zone: %p\n", old); + knot_zone_contents_deep_free(&old, 0); + +dbg_ns_exec( + dbg_ns("Zone db contents: (zone count: %zu)\n", + nameserver->zone_db->zone_count); + + const knot_zone_t **zones = knot_zonedb_zones(nameserver->zone_db); + for (int i = 0; i < knot_zonedb_zone_count + (nameserver->zone_db); i++) { + dbg_ns("%d. zone: %p", i, zones[i]); + char *name = knot_dname_to_str(zones[i]->name); + dbg_ns(" zone name: %s\n", name); + free(name); + } + free(zones); +); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! \todo In this function, xfr->zone is properly set. If this is so, we do not + * have to search for the zone after the transfer has finished. + */ +int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, + knot_ns_xfr_t *xfr) +{ + dbg_ns("ns_process_ixfrin: incoming packet\n"); + + /*! + * \todo [TSIG] Here we assume that 'xfr' contains TSIG information + * and the digest of the query sent to the master or the previous + * digest. + */ + + int ret = xfrin_process_ixfr_packet(xfr/*xfr->wire, xfr->wire_size, + (knot_changesets_t **)(&xfr->data)*/); + + if (ret == XFRIN_RES_FALLBACK) { + dbg_ns("ns_process_ixfrin: Fallback to AXFR.\n"); + assert(xfr->data == NULL); +// dbg_ns("xfr->zone = %p\n", xfr->zone); +// dbg_ns("Zone name: %.*s\n", +// xfr->zone->name->size, xfr->zone->name->name); +// assert(xfr->zone == NULL); + knot_packet_free(&xfr->query); + return KNOT_ENOIXFR; + } + + if (ret > 0) { + dbg_ns("ns_process_ixfrin: IXFR finished\n"); + + knot_changesets_t *chgsets = (knot_changesets_t *)xfr->data; + if (chgsets == NULL || chgsets->first_soa == NULL) { + // nothing to be done?? + dbg_ns("No changesets created for incoming IXFR!\n"); + return ret; + } + + // find zone associated with the changesets + knot_zone_t *zone = knot_zonedb_find_zone( + nameserver->zone_db, + knot_rrset_owner(chgsets->first_soa)); + if (zone == NULL) { + dbg_ns("No zone found for incoming IXFR!\n"); + knot_free_changesets( + (knot_changesets_t **)(&xfr->data)); + return KNOT_ENOZONE; /*! \todo Other error code? */ + } + + switch (ret) { + case XFRIN_RES_COMPLETE: + xfr->zone = zone; + break; + case XFRIN_RES_SOA_ONLY: { + // compare the SERIAL from the changeset with the zone's + // serial + const knot_node_t *apex = knot_zone_contents_apex( + knot_zone_contents(zone)); + if (apex == NULL) { + return KNOT_ERROR; + } + + const knot_rrset_t *zone_soa = knot_node_rrset( + apex, KNOT_RRTYPE_SOA); + if (zone_soa == NULL) { + return KNOT_ERROR; + } + + if (knot_rdata_soa_serial(knot_rrset_rdata( + chgsets->first_soa)) + != knot_rdata_soa_serial(knot_rrset_rdata( + zone_soa))) { + dbg_ns("Update did not fit.\n"); + return KNOT_EAGAIN; + } else { + // free changesets + dbg_ns("No update needed.\n"); + knot_free_changesets( + (knot_changesets_t **)(&xfr->data)); + return KNOT_ENOXFR; + } + } break; + } + } + + /*! + * \todo In case of error, shouldn't the zone be destroyed here? + */ + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, + uint8_t *response_wire, size_t *rsize, + knot_zone_t **zone, knot_changeset_t **changeset) +{ + // 1) Parse the rest of the packet + assert(knot_packet_is_query(query)); + + knot_packet_t *response; + assert(*rsize >= MAX_UDP_PAYLOAD); + int ret = knot_ns_prepare_response(nameserver, query, &response, + MAX_UDP_PAYLOAD); + if (ret != KNOT_EOK) { + knot_ns_error_response(nameserver, knot_packet_id(query), + KNOT_RCODE_SERVFAIL, response_wire, + rsize); + return KNOT_EOK; + } + + assert(response != NULL); + + dbg_ns("Query - parsed: %zu, total wire size: %zu\n", + query->parsed, query->size); + + if (knot_packet_parsed(query) < knot_packet_size(query)) { + ret = knot_packet_parse_rest(query); + if (ret != KNOT_EOK) { + dbg_ns("Failed to parse rest of the query: " + "%s.\n", knot_strerror(ret)); + knot_ns_error_response_full(nameserver, response, + (ret == KNOT_EMALF) + ? KNOT_RCODE_FORMERR + : KNOT_RCODE_SERVFAIL, + response_wire, rsize); + knot_packet_free(&response); + return KNOT_EOK; + } + } + + dbg_ns("Query - parsed: %zu, total wire size: %zu\n", + knot_packet_parsed(query), knot_packet_size(query)); + + /*! \todo API for EDNS values. */ + dbg_ns("Opt RR: version: %d, payload: %d\n", + query->opt_rr.version, query->opt_rr.payload); + + // 2) Find zone for the query + // we do not check if there is only one entry in the Question section + // because the packet structure does not allow it + /*! \todo Check number of Question entries while parsing. */ + if (knot_packet_qtype(query) != KNOT_RRTYPE_SOA) { + dbg_ns("Question is not of type SOA.\n"); + knot_ns_error_response_full(nameserver, response, + KNOT_RCODE_FORMERR, + response_wire, rsize); + knot_packet_free(&response); + return KNOT_EOK; + } + + *zone = knot_zonedb_find_zone(nameserver->zone_db, + knot_packet_qname(query)); + if (*zone == NULL) { + dbg_ns("Zone not found for the update.\n"); + knot_ns_error_response_full(nameserver, response, + KNOT_RCODE_NOTAUTH, + response_wire, rsize); + knot_packet_free(&response); + return KNOT_EOK; + } + + uint8_t rcode = 0; + // 3) Check zone + ret = knot_ddns_check_zone(*zone, query, &rcode); + if (ret == KNOT_EBADZONE) { + // zone is slave, forward the request + /*! \todo Implement forwarding. */ + return KNOT_EBADZONE; + } else if (ret != KNOT_EOK) { + dbg_ns("Failed to check zone for update: " + "%s.\n", knot_strerror(ret)); + knot_ns_error_response_full(nameserver, response, rcode, + response_wire, rsize); + knot_packet_free(&response); + return KNOT_EOK; + } + + // 4) Convert prerequisities + knot_ddns_prereq_t *prereqs = NULL; + ret = knot_ddns_process_prereqs(query, &prereqs, &rcode); + if (ret != KNOT_EOK) { + dbg_ns("Failed to check zone for update: " + "%s.\n", knot_strerror(ret)); + knot_ns_error_response_full(nameserver, response, rcode, + response_wire, rsize); + knot_packet_free(&response); + return KNOT_EOK; + } + + assert(prereqs != NULL); + + // 5) Check prerequisities + /*! \todo Somehow ensure the zone will not be changed until the update + * is finished. + */ + ret = knot_ddns_check_prereqs(knot_zone_contents(*zone), &prereqs, + &rcode); + if (ret != KNOT_EOK) { + dbg_ns("Failed to check zone for update: " + "%s.\n", knot_strerror(ret)); + knot_ns_error_response_full(nameserver, response, rcode, + response_wire, rsize); + knot_ddns_prereqs_free(&prereqs); + knot_packet_free(&response); + return KNOT_EOK; + } + + // 6) Convert update to changeset + ret = knot_ddns_process_update(query, changeset, &rcode); + if (ret != KNOT_EOK) { + dbg_ns("Failed to check zone for update: " + "%s.\n", knot_strerror(ret)); + knot_ns_error_response_full(nameserver, response, rcode, + response_wire, rsize); + knot_ddns_prereqs_free(&prereqs); + knot_packet_free(&response); + return KNOT_EOK; + } + + assert(changeset != NULL); + + // 7) Create response + dbg_ns("Update converted successfuly.\n"); + + /*! \todo No response yet. Distinguish somehow in the caller. + * Maybe only this case will be EOK, other cases some error. + */ + + knot_packet_free(&response); + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_create_forward_query(const knot_packet_t *query, + uint8_t *query_wire, size_t *size) +{ + // just copy the wireformat of the query and set a new random ID to it + if (knot_packet_size(query) > *size) { + return KNOT_ESPACE; + } + + memcpy(query_wire, knot_packet_wireformat(query), + knot_packet_size(query)); + *size = knot_packet_size(query); + + knot_wire_set_id(query_wire, knot_random_id()); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_process_forward_response(const knot_packet_t *response, + uint16_t original_id, + uint8_t *response_wire, size_t *size) +{ + // just copy the wireformat of the response and set the original ID + + if (knot_packet_size(response) > *size) { + return KNOT_ESPACE; + } + + memcpy(response_wire, knot_packet_wireformat(response), + knot_packet_size(response)); + *size = knot_packet_size(response); + + knot_wire_set_id(response_wire, original_id); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +void *knot_ns_data(knot_nameserver_t *nameserver) +{ + return nameserver->data; +} + +/*----------------------------------------------------------------------------*/ + +void *knot_ns_get_data(knot_nameserver_t *nameserver) +{ + return nameserver->data; +} + +/*----------------------------------------------------------------------------*/ + +void knot_ns_set_data(knot_nameserver_t *nameserver, void *data) +{ + nameserver->data = data; +} + +/*----------------------------------------------------------------------------*/ + +void knot_ns_destroy(knot_nameserver_t **nameserver) +{ + synchronize_rcu(); + + free((*nameserver)->err_response); + if ((*nameserver)->opt_rr != NULL) { + knot_edns_free(&(*nameserver)->opt_rr); + } + + // destroy the zone db + knot_zonedb_deep_free(&(*nameserver)->zone_db); + + free(*nameserver); + *nameserver = NULL; +} diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h new file mode 100644 index 0000000..0d93df6 --- /dev/null +++ b/src/libknot/nameserver/name-server.h @@ -0,0 +1,358 @@ +/*! + * \file name-server.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * Contains the "name server" structure and interface for the main DNS + * functions. Currently only supports answering simple queries, without any + * extensions. + * + * \todo Consider saving pointer to the zdb_find_name() function in the + * nameserver structure. Probably not needed, these modules can be + * inter-connected. + * \todo Provide interface for other DNS functions - zone transfers, dynamic + * updates, etc. + * + * \addtogroup query_processing + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_NAME_SERVER_H_ +#define _KNOT_NAME_SERVER_H_ + +#include <stdint.h> +#include <string.h> + +#include "zone/zonedb.h" +#include "edns.h" +#include "consts.h" +#include "tsig.h" +#include "packet/packet.h" +#include "common/sockaddr.h" +#include "updates/changesets.h" + +struct conf_t; +struct server_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Name server structure. Holds all important data needed for the + * supported DNS functions. + * + * Currently only holds pointer to the zone database for answering queries. + */ +typedef struct knot_nameserver { + /*! + * \brief Pointer to the zone database structure used for answering + * queries. + */ + knot_zonedb_t *zone_db; + uint8_t *err_response; /*!< Prepared generic error response. */ + size_t err_resp_size; /*!< Size of the prepared error response. */ + knot_opt_rr_t *opt_rr; /*!< OPT RR with the server's EDNS0 info. */ + + void *data; +} knot_nameserver_t; + +/*! \brief Callback for sending one packet back through a TCP connection. */ +typedef int (*xfr_callback_t)(int session, sockaddr_t *addr, + uint8_t *packet, size_t size); + +/*! + * \brief Single XFR operation structure. + * + * Used for communication with XFR handler. + */ +typedef struct knot_ns_xfr { + int type; + int flags; + sockaddr_t addr; + knot_packet_t *query; + knot_packet_t *response; + xfr_callback_t send; + int session; + + /*! + * XFR-out: Output buffer. + * XFR-in: Buffer for query or incoming packet. + */ + uint8_t *wire; + + /*! + * XFR-out: Size of the output buffer. + * XFR-in: Size of the current packet. + */ + size_t wire_size; + void *data; + knot_zone_t *zone; + void *owner; + + /*! \note [TSIG] TSIG fields */ + /*! \brief Message(s) to sign in wireformat. + * + * This field should be allocated at the start of transfer and + * freed at the end. During the transfer it is only rewritten. + */ + uint8_t *tsig_data; + size_t tsig_data_size; /*!< Size of the message(s) in bytes */ +// const knot_rrset_t *tsig; /*!< Response TSIG. +// \todo [TSIG] Replace with separate data. */ + size_t tsig_size; /*!< Size of the TSIG RR wireformat in bytes.*/ + knot_key_t *tsig_key; /*!< Associated TSIG key for signing. */ + + uint8_t *digest; /*!< Buffer for counting digest. */ + size_t digest_size; /*!< Size of the digest. */ + size_t digest_max_size; /*!< Size of the buffer. */ + + /*! \brief Previous digest or request digest. + * + * Should be allocated before the transfer (known size). + */ +// uint8_t *prev_digest; +// size_t prev_digest_size; /*!< Size of previous digest in bytes. */ + + /*! + * \brief Number of the packet currently assembled. + * + * In case of XFR-in, this is not the overall number of packet, just + * number counted from last TSIG check. + */ + int packet_nr; +} knot_ns_xfr_t; + + +static const int KNOT_NS_TSIG_FREQ = 100; + +static const size_t KNOT_NS_TSIG_DATA_MAX_SIZE = 100 * 64 * 1024; + +/*! + * \brief XFR request flags. + */ +enum knot_ns_xfr_flag_t { + XFR_FLAG_TCP = 1 << 0, /*!< XFR request is on TCP. */ + XFR_FLAG_UDP = 1 << 1 /*!< XFR request is on UDP. */ +}; + +/*! + * \brief XFR request types. + */ +typedef enum knot_ns_xfr_type_t { + /* Special events. */ + XFR_TYPE_CLOSE = -1, /*!< Close connection event. */ + + /* DNS events. */ + XFR_TYPE_AIN = 0, /*!< AXFR-IN request (start transfer). */ + XFR_TYPE_AOUT, /*!< AXFR-OUT request (incoming transfer). */ + XFR_TYPE_IIN, /*!< IXFR-IN request (start transfer). */ + XFR_TYPE_IOUT, /*!< IXFR-OUT request (incoming transfer). */ + XFR_TYPE_SOA, /*!< Pending SOA request. */ + XFR_TYPE_NOTIFY /*!< Pending NOTIFY query. */ +} knot_ns_xfr_type_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Allocates and initializes the name server structure. + * + * \return Pointer to the name server structure. + */ +knot_nameserver_t *knot_ns_create(); + +/*! + * \brief Parses the given query into the response structure and recognizes + * type of the query. + * + * Some query types are distinguished by OPCODE (NOTIFY, UPDATE, etc.), some + * by QTYPE (AXFR, IXFR). As these information are needed on the same layer + * to decide what to do with the query, the knot_query_t type is used for this + * purpose. + * + * \param query_wire Wire format of the query. + * \param qsize Size of the query in octets. + * \param packet Packet structure to be filled with the parsed query. + * \param type Type of the query. + * + * \retval KNOT_EOK + * \retval KNOT_EMALF if the query is totally unusable. Such query must be + * ignored. + * \retval KNOT_RCODE_SERVFAIL if there was some internal error. Call + * ns_error_response() with \a rcode set to this + * value to get proper error response. + * \retval KNOT_RCODE_FORMERR if the query was malformed, but can be used to + * construct an error response. Call + * ns_error_response() with \a rcode set to this + * value to get proper error response. + * \retval KNOT_RCODE_NOTIMPL if the query has an unsupported type. Call + * ns_error_response() with \a rcode set to this + * value to get proper error response. + */ +int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, + knot_packet_t *packet, knot_packet_type_t *type); + +/*! + * \brief Prepares wire format of an error response using generic error template + * stored in the nameserver structure. + * + * The error response will not contain the Question section from the query, just + * a header with ID copied from the query and the given RCODE. + * + * \param nameserver Nameserver structure containing the error template. + * \param query_id ID of the query. + * \param rcode RCODE to set in the response. + * \param response_wire Place for wire format of the response. + * \param rsize Size of the error response will be stored here. + */ +void knot_ns_error_response(const knot_nameserver_t *nameserver, uint16_t query_id, + uint8_t rcode, uint8_t *response_wire, size_t *rsize); + +/*! + * \brief Creates a response for the given normal query using the data of the + * nameserver. + * + * \param nameserver Name server structure to provide the needed data. + * \param resp Response structure with parsed query. + * \param response_wire Place for the response in wire format. + * \param rsize Input: maximum acceptable size of the response. Output: real + * size of the response. + * + * \retval KNOT_EOK if a valid response was created. + * \retval KNOT_EMALF if an error occured and the response is not valid. + */ +int knot_ns_answer_normal(knot_nameserver_t *nameserver, knot_packet_t *query, + uint8_t *response_wire, size_t *rsize); + +int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); + +/*! + * \brief Compares two zone serials. + * + * \retval < 0 if s1 is less than s2. + * \retval > 0 if s1 is larger than s2. + * \retval == 0 if s1 is equal to s2. + */ +int ns_serial_compare(uint32_t s1, uint32_t s2); + +int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from, + uint32_t *serial_to); + +int knot_ns_xfr_send_error(const knot_nameserver_t *nameserver, + knot_ns_xfr_t *xfr, knot_rcode_t rcode); + +/*! + * \brief Processes an AXFR query. + * + * This function sequentially creates DNS packets to be sent as a response + * to the AXFR query and sends each packet using the given callback (\a + * send_packet). + * + * \param nameserver Name server structure to provide the data for answering. + * \param xfr Persistent transfer-specific data. + * + * \note Currently only a stub which sends one error response using the given + * callback. + * + * \retval KNOT_EOK + * \retval KNOT_EINVAL + * \retval KNOT_ENOMEM + * \retval KNOT_ERROR + * + * \todo Maybe the place for the wire format should be passed in as in + * the ns_answer_request() function...? + */ +int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); + +/*! + * \brief Processes an IXFR query. + * + * \param nameserver Name server structure to provide the data for answering. + * \param xfr Persistent transfer-specific data. + * + * \todo Document properly. + */ +int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); + +/*! + * \brief Processes an AXFR-IN packet. + * + * \param nameserver Name server structure to provide the data for answering. + * \param xfr Persistent transfer-specific data. + * + * \todo Document me. + */ +int knot_ns_process_axfrin(knot_nameserver_t *nameserver, + knot_ns_xfr_t *xfr); + +int knot_ns_switch_zone(knot_nameserver_t *nameserver, + knot_ns_xfr_t *xfr); + +/*! + * \brief Processes an IXFR-IN packet. + * + * \param nameserver Name server structure to provide the data for answering. + * \param xfr Persistent transfer-specific data. + * + * \retval KNOT_EOK If this packet was processed successfuly and another packet + * is expected. (RFC1995bis, case c) + * \retval KNOT_ENOXFR If the transfer is not taking place because server's + * SERIAL is the same as this client's SERIAL. The client + * should close the connection and do no further processing. + * (RFC1995bis case a). + * \retval KNOT_EAGAIN If the server could not fit the transfer into the packet. + * This should happen only if UDP was used. In this case + * the client should retry the request via TCP. If UDP was + * not used, it should be considered that the transfer was + * malformed and the connection should be closed. + * (RFC1995bis case b). + * \retval >0 Transfer successully finished. Changesets are created and furter + * processing is needed. + * \retval Other If any other error occured. The connection should be closed. + * + * \todo Document me. + */ +int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, + knot_ns_xfr_t *xfr); + +int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, + uint8_t *response_wire, size_t *rsize, + knot_zone_t **zone, knot_changeset_t **changeset); + +int knot_ns_create_forward_query(const knot_packet_t *query, + uint8_t *query_wire, size_t *size); + +int knot_ns_process_forward_response(const knot_packet_t *response, + uint16_t original_id, + uint8_t *response_wire, size_t *size); + +void *knot_ns_data(knot_nameserver_t *nameserver); + +void *knot_ns_get_data(knot_nameserver_t *nameserver); + +void knot_ns_set_data(knot_nameserver_t *nameserver, void *data); + +int knot_ns_tsig_required(int packet_nr); + +/*! + * \brief Properly destroys the name server structure. + * + * \param nameserver Nameserver to destroy. + */ +void knot_ns_destroy(knot_nameserver_t **nameserver); + + +#endif /* _KNOTNAME_SERVER_H_ */ + +/*! @} */ diff --git a/src/libknot/nsec3.c b/src/libknot/nsec3.c new file mode 100644 index 0000000..303d2e6 --- /dev/null +++ b/src/libknot/nsec3.c @@ -0,0 +1,265 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> +#include <assert.h> +#include <stdlib.h> +#include <sys/time.h> + +#include <openssl/evp.h> +#include <openssl/sha.h> + +#include "nsec3.h" +#include "common.h" +#include "util/descriptor.h" +#include "util/utils.h" +#include "util/tolower.h" +#include "util/error.h" +#include "util/debug.h" + +/*----------------------------------------------------------------------------*/ + +int knot_nsec3_params_from_wire(knot_nsec3_params_t *params, + const knot_rrset_t *nsec3param) +{ + if (params == NULL || nsec3param == NULL) { + return KNOT_EBADARG; + } + + assert(knot_rrset_type(nsec3param) == KNOT_RRTYPE_NSEC3PARAM); + const knot_rdata_t *rdata = knot_rrset_rdata(nsec3param); + + assert(rdata->count == 4); + + params->algorithm = *(uint8_t *) + (&knot_rdata_item(rdata, 0)->raw_data[1]); + params->flags = *(uint8_t *) + (&knot_rdata_item(rdata, 1)->raw_data[1]); + params->iterations = knot_wire_read_u16( + (uint8_t *)(knot_rdata_item(rdata, 2)->raw_data + 1)); + + params->salt_length = + ((uint8_t *)knot_rdata_item(rdata, 3)->raw_data)[2]; + + if (params->salt_length > 0) { + params->salt = (uint8_t *)malloc(params->salt_length); + CHECK_ALLOC_LOG(params->salt, -1); + memcpy(params->salt, + (uint8_t *)knot_rdata_item(rdata, 3)->raw_data + 3, + params->salt_length); + } else { + params->salt = NULL; + } + + dbg_nsec3("Parsed NSEC3PARAM:\n"); + dbg_nsec3("Algorithm: %hu\n", params->algorithm); + dbg_nsec3("Flags: %hu\n", params->flags); + dbg_nsec3("Iterations: %hu\n", params->iterations); + dbg_nsec3("Salt length: %hu\n", params->salt_length); + dbg_nsec3("Salt: "); + if (params->salt != NULL) { + dbg_nsec3_hex((char *)params->salt, + params->salt_length); + dbg_nsec3("\n"); + } else { + dbg_nsec3("none\n"); + } + + return KNOT_EOK; +} + +static uint8_t *knot_nsec3_to_lowercase(const uint8_t *data, size_t size) +{ + uint8_t *out = (uint8_t *)malloc(size); + CHECK_ALLOC_LOG(out, NULL); + + for (int i = 0; i < size; ++i) { + out[i] = knot_tolower(data[i]); + } + + return out; +} + +/*----------------------------------------------------------------------------*/ +#if KNOT_NSEC3_SHA_USE_EVP +int knot_nsec3_sha1(const knot_nsec3_params_t *params, + const uint8_t *data, size_t size, uint8_t **digest, + size_t *digest_size) +{ + if (digest == NULL || digest_size == NULL || data == NULL) { + return KNOT_EBADARG; + } + + uint8_t *salt = params->salt; + uint8_t salt_length = params->salt_length; + uint16_t iterations = params->iterations; + + EVP_MD_CTX mdctx; + EVP_MD_CTX_init(&mdctx); + + *digest = (uint8_t *)malloc(EVP_MD_size(EVP_sha1())); + if (*digest == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + uint8_t *data_low = knot_nsec3_to_lowercase(data, size); + if (data_low == NULL) { + free(*digest); + return -1; + } + + const uint8_t *in = data_low; + unsigned in_size = size; + + int res = 0; + +#ifdef KNOT_NSEC3_DEBUG + unsigned long long total_time = 0; + unsigned long calls = 0; + long time = 0; +#endif + + for (int i = 0; i <= iterations; ++i) { +#ifdef KNOT_NSEC3_DEBUG + perf_begin(); +#endif + + EVP_DigestInit_ex(&mdctx, EVP_sha1(), NULL); + + res = EVP_DigestUpdate(&mdctx, in, in_size); + + if (salt_length > 0) { + res = EVP_DigestUpdate(&mdctx, salt, salt_length); + } + + EVP_DigestFinal_ex(&mdctx, *digest, digest_size); + in = *digest; + in_size = *digest_size; + +#ifdef KNOT_NSEC3_DEBUG + perf_end(time); + total_time += time; + ++calls; +#endif + + if (res != 1) { + dbg_nsec3("Error calculating SHA-1 hash.\n"); + free(data_low); + free(*digest); + return -2; + } + } + + EVP_MD_CTX_cleanup(&mdctx); + + dbg_nsec3("NSEC3 hashing: calls: %lu, avg time per call: %f." + "\n", calls, (double)(total_time) / calls); + + free(data_low); + return 0; +} + +/*----------------------------------------------------------------------------*/ +#else + +int knot_nsec3_sha1(const knot_nsec3_params_t *params, + const uint8_t *data, size_t size, uint8_t **digest, + size_t *digest_size) +{ + if (params == NULL || digest == NULL || digest_size == NULL + || data == NULL) { + return KNOT_EBADARG; + } + + uint8_t *salt = params->salt; + uint8_t salt_length = params->salt_length; + uint16_t iterations = params->iterations; + + dbg_nsec3("Hashing: \n"); + dbg_nsec3(" Data: %.*s \n", size, data); + dbg_nsec3_hex((const char *)data, size); + dbg_nsec3(" (size %d)\n Iterations: %u\n", (int)size, iterations); + dbg_nsec3(" Salt length: %u\n", salt_length); + dbg_nsec3(" Salt: "); + if (salt_length > 0) { + dbg_nsec3_hex((char *)salt, salt_length); + dbg_nsec3("\n"); + } else { + dbg_nsec3("none\n"); + } + + SHA_CTX ctx; + + *digest = (uint8_t *)malloc(SHA_DIGEST_LENGTH); + if (*digest == NULL) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + uint8_t *data_low = knot_nsec3_to_lowercase(data, size); + if (data_low == NULL) { + free(*digest); + return KNOT_ENOMEM; + } + + const uint8_t *in = data_low; + unsigned in_size = size; + + int res = 0; + + // other iterations + for (int i = 0; i <= iterations; ++i) { + SHA1_Init(&ctx); + + res = SHA1_Update(&ctx, in, in_size); + + if (salt_length > 0) { + res = SHA1_Update(&ctx, salt, salt_length); + } + + SHA1_Final(*digest, &ctx); + + in = *digest; + in_size = SHA_DIGEST_LENGTH; + + if (res != 1) { + dbg_nsec3("Error calculating SHA-1 hash.\n"); + free(data_low); + free(*digest); + return KNOT_ECRYPTO; + } + } + + *digest_size = SHA_DIGEST_LENGTH; + + dbg_nsec3("Hash: %.*s\n", *digest_size, *digest); + dbg_nsec3_hex((const char *)*digest, *digest_size); + dbg_nsec3("\n"); + + free(data_low); + return KNOT_EOK; +} +#endif + +/*----------------------------------------------------------------------------*/ + +void knot_nsec3_params_free(knot_nsec3_params_t *params) +{ + if (params->salt != NULL) { + free(params->salt); + } +} diff --git a/src/libknot/nsec3.h b/src/libknot/nsec3.h new file mode 100644 index 0000000..0ce6899 --- /dev/null +++ b/src/libknot/nsec3.h @@ -0,0 +1,92 @@ +/*! + * \file nsec3.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Functions for calcularing NSEC3 hashes. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_NSEC3_H_ +#define _KNOT_NSEC3_H_ + +#include <stdint.h> +#include <string.h> + +#include "rrset.h" + +#define KNOT_NSEC3_SHA_USE_EVP 0 + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure representing the NSEC3PARAM resource record. + */ +struct knot_nsec3_params { + uint8_t algorithm; /*!< Hash algorithm. */ + uint8_t flags; /*!< Flags. */ + uint16_t iterations; /*!< Additional iterations of the hash function.*/ + uint8_t salt_length; /*!< Length of the salt field in bytes. */ + uint8_t *salt; /*!< Salt used in hashing. */ +}; + +typedef struct knot_nsec3_params knot_nsec3_params_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Initializes the NSEC3PARAM structure. + * + * \param params NSEC3PARAM structure to initialize. + * \param nsec3param The NSEC3PARAM RRset. + * + * \retval KNOT_EOK on success (always). + */ +int knot_nsec3_params_from_wire(knot_nsec3_params_t *params, + const knot_rrset_t *nsec3param); + +/*! + * \brief Hashes the given data using the SHA1 hash and the given parameters. + * + * \param[in] params NSEC3PARAM structure with the required parameters for + * hashing. + * \param[in] data Data to hash. + * \param[in] size Size of the data in bytes. + * \param[out] digest Result will be store here. + * \param[out] digest_size Size of the result in octets will be stored here. + * + * \retval KNOT_EOK if successful. + * \retval KNOT_ENOMEM + * \retval KNOT_EBADARG + * \retval KNOT_ECRYPTO + */ +int knot_nsec3_sha1(const knot_nsec3_params_t *params, const uint8_t *data, + size_t size, uint8_t **digest, size_t *digest_size); + +/*! + * \brief Properly cleans up (but does not deallocate) the NSEC3PARAM structure. + * + * \param params NSEC3PARAMS structure to clean up. + */ +void knot_nsec3_params_free(knot_nsec3_params_t *params); + +/*----------------------------------------------------------------------------*/ + +#endif /* _KNOT_NSEC3_H_ */ + +/*! @} */ diff --git a/src/libknot/packet/packet.c b/src/libknot/packet/packet.c new file mode 100644 index 0000000..82e818f --- /dev/null +++ b/src/libknot/packet/packet.c @@ -0,0 +1,1532 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "packet/packet.h" +#include "util/error.h" +#include "util/debug.h" +#include "common.h" +#include "util/descriptor.h" +#include "util/wire.h" + +/*----------------------------------------------------------------------------*/ + +#define DEFAULT_RRCOUNT_QUERY(type) DEFAULT_##type##COUNT_QUERY +#define DEFAULT_RRCOUNT(type) DEFAULT_##type##COUNT + +#define DEFAULT_RRSET_COUNT(type, packet) \ + ((packet->prealloc_type == KNOT_PACKET_PREALLOC_NONE) \ + ? 0 \ + : (packet->prealloc_type == KNOT_PACKET_PREALLOC_QUERY) \ + ? DEFAULT_##type##_QUERY \ + : DEFAULT_##type) + + + +typedef enum { + KNOT_PACKET_DUPL_IGNORE, + KNOT_PACKET_DUPL_SKIP, + KNOT_PACKET_DUPL_MERGE +} knot_packet_duplicate_handling_t; +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets all the pointers in the packet structure to the respective + * parts of the pre-allocated space. + */ +static void knot_packet_init_pointers_response(knot_packet_t *pkt) +{ + dbg_packet("Packet pointer: %p\n", pkt); + + char *pos = (char *)pkt + PREALLOC_PACKET; + + // put QNAME directly after the structure + pkt->question.qname = (knot_dname_t *)pos; + pos += PREALLOC_QNAME_DNAME; + + dbg_packet("QNAME: %p\n", pkt->question.qname); + + pkt->question.qname->name = (uint8_t *)pos; + pos += PREALLOC_QNAME_NAME; + pkt->question.qname->labels = (uint8_t *)pos; + pos += PREALLOC_QNAME_LABELS; + + pkt->owner_tmp = (uint8_t *)pos; + dbg_packet("Tmp owner: %p\n", pkt->owner_tmp); + pos += PREALLOC_RR_OWNER; + + // then answer, authority and additional sections + if (DEFAULT_ANCOUNT == 0) { + pkt->answer = NULL; + } else { + pkt->answer = (const knot_rrset_t **)pos; + pos += DEFAULT_ANCOUNT * sizeof(const knot_rrset_t *); + } + + if (DEFAULT_NSCOUNT == 0) { + pkt->authority = NULL; + } else { + pkt->authority = (const knot_rrset_t **)pos; + pos += DEFAULT_NSCOUNT * sizeof(const knot_rrset_t *); + } + + if (DEFAULT_ARCOUNT == 0) { + pkt->additional = NULL; + } else { + pkt->additional = (const knot_rrset_t **)pos; + pos += DEFAULT_ARCOUNT * sizeof(const knot_rrset_t *); + } + + dbg_packet("Answer section: %p\n", pkt->answer); + dbg_packet("Authority section: %p\n", pkt->authority); + dbg_packet("Additional section: %p\n", pkt->additional); + + pkt->max_an_rrsets = DEFAULT_ANCOUNT; + pkt->max_ns_rrsets = DEFAULT_NSCOUNT; + pkt->max_ar_rrsets = DEFAULT_ARCOUNT; + + // then domain names for compression and offsets + pkt->compression.dnames = (const knot_dname_t **)pos; + pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(const knot_dname_t *); + pkt->compression.offsets = (size_t *)pos; + pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t); + + dbg_packet("Compression dnames: %p\n", pkt->compression.dnames); + dbg_packet("Compression offsets: %p\n", pkt->compression.offsets); + + pkt->compression.max = DEFAULT_DOMAINS_IN_RESPONSE; + + pkt->tmp_rrsets = (const knot_rrset_t **)pos; + pos += DEFAULT_TMP_RRSETS * sizeof(const knot_rrset_t *); + + dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets); + + pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS; + + assert((char *)pos == (char *)pkt + PREALLOC_RESPONSE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets all the pointers in the packet structure to the respective + * parts of the pre-allocated space. + */ +static void knot_packet_init_pointers_query(knot_packet_t *pkt) +{ + dbg_packet("Packet pointer: %p\n", pkt); + + char *pos = (char *)pkt + PREALLOC_PACKET; + + // put QNAME directly after the structure + pkt->question.qname = (knot_dname_t *)pos; + pos += PREALLOC_QNAME_DNAME; + + dbg_packet("QNAME: %p (%zu after start of packet)\n", + pkt->question.qname, + (void *)pkt->question.qname - (void *)pkt); + + pkt->question.qname->name = (uint8_t *)pos; + pos += PREALLOC_QNAME_NAME; + pkt->question.qname->labels = (uint8_t *)pos; + pos += PREALLOC_QNAME_LABELS; + +// pkt->owner_tmp = (uint8_t *)((char *)pkt->question.qname->labels +// + PREALLOC_QNAME_LABELS); + + // then answer, authority and additional sections + if (DEFAULT_ANCOUNT_QUERY == 0) { + pkt->answer = NULL; + } else { + pkt->answer = (const knot_rrset_t **)pos; + pos += DEFAULT_ANCOUNT_QUERY * sizeof(const knot_rrset_t *); + } + + if (DEFAULT_NSCOUNT_QUERY == 0) { + pkt->authority = NULL; + } else { + pkt->authority = (const knot_rrset_t **)pos; + pos += DEFAULT_NSCOUNT_QUERY * sizeof(const knot_rrset_t *); + } + + if (DEFAULT_ARCOUNT_QUERY == 0) { + pkt->additional = NULL; + } else { + pkt->additional = (const knot_rrset_t **)pos; + pos += DEFAULT_ARCOUNT_QUERY * sizeof(const knot_rrset_t *); + } + + dbg_packet("Answer section: %p\n", pkt->answer); + dbg_packet("Authority section: %p\n", pkt->authority); + dbg_packet("Additional section: %p\n", pkt->additional); + + pkt->max_an_rrsets = DEFAULT_ANCOUNT_QUERY; + pkt->max_ns_rrsets = DEFAULT_NSCOUNT_QUERY; + pkt->max_ar_rrsets = DEFAULT_ARCOUNT_QUERY; + + pkt->tmp_rrsets = (const knot_rrset_t **)pos; + pos += DEFAULT_TMP_RRSETS_QUERY * sizeof(const knot_rrset_t *); + + dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets); + + pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS_QUERY; + +// dbg_packet("End of data: %p (%zu after start of packet)\n", +// pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY, +// (void *)(pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY) +// - (void *)pkt); + dbg_packet("Allocated total: %u\n", PREALLOC_QUERY); + + assert(pos == (char *)pkt + PREALLOC_QUERY); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Parses DNS header from the wire format. + * + * \note This function also adjusts the position (\a pos) and size of remaining + * bytes in the wire format (\a remaining) according to what was parsed + * (though it actually always parses the 12 bytes of the header). + * + * \param[in,out] pos Wire format to parse the header from. + * \param[in,out] remaining Remaining size of the wire format. + * \param[out] header Header structure to fill in. + * + * \retval KNOT_EOK + * \retval KNOT_EFEWDATA + */ +static int knot_packet_parse_header(const uint8_t *wire, size_t *pos, + size_t size, knot_header_t *header) +{ + assert(wire != NULL); + assert(pos != NULL); + assert(header != NULL); + + if (size - *pos < KNOT_WIRE_HEADER_SIZE) { + dbg_response("Not enough data to parse header.\n"); + return KNOT_EFEWDATA; + } + + header->id = knot_wire_get_id(wire); + // copy some of the flags: OPCODE and RD + // do this by copying flags1 and setting QR to 1, AA to 0 and TC to 0 + header->flags1 = knot_wire_get_flags1(wire); +// knot_wire_flags_set_qr(&header->flags1); +// knot_wire_flags_clear_aa(&header->flags1); +// knot_wire_flags_clear_tc(&header->flags1); + // do not copy flags2 (all set by server) + header->qdcount = knot_wire_get_qdcount(wire); + header->ancount = knot_wire_get_ancount(wire); + header->nscount = knot_wire_get_nscount(wire); + header->arcount = knot_wire_get_arcount(wire); + + *pos += KNOT_WIRE_HEADER_SIZE; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Parses DNS Question entry from the wire format. + * + * \note This function also adjusts the position (\a pos) and size of remaining + * bytes in the wire format (\a remaining) according to what was parsed. + * + * \param[in,out] pos Wire format to parse the Question from. + * \param[in,out] remaining Remaining size of the wire format. + * \param[out] question DNS Question structure to be filled. + * + * \retval KNOT_EOK + * \retval KNOT_EFEWDATA + * \retval KNOT_ENOMEM + */ +static int knot_packet_parse_question(const uint8_t *wire, size_t *pos, + size_t size, + knot_question_t *question, int alloc) +{ + assert(pos != NULL); + assert(wire != NULL); + assert(question != NULL); + + if (size - *pos < KNOT_WIRE_QUESTION_MIN_SIZE) { + dbg_response("Not enough data to parse question.\n"); + return KNOT_EFEWDATA; // malformed + } + + dbg_response("Parsing Question starting on position %zu.\n", + *pos); + + // domain name must end with 0, so just search for 0 + int i = *pos; + while (i < size && wire[i] != 0) { + ++i; + } + + if (size - i - 1 < 4) { + dbg_response("Not enough data to parse question.\n"); + return KNOT_EFEWDATA; // no 0 found or not enough data left + } + + dbg_response("Parsing dname starting on position %zu and " + "%zu bytes long.\n", *pos, i - *pos + 1); + dbg_response("Alloc: %d\n", alloc); + if (alloc) { + question->qname = knot_dname_new_from_wire( + wire + *pos, i - *pos + 1, NULL); + if (question->qname == NULL) { + return KNOT_ENOMEM; + } + } else { + int res = knot_dname_from_wire(wire + *pos, i - *pos + 1, + NULL, question->qname); + if (res != KNOT_EOK) { + assert(res != KNOT_EBADARG); + return res; + } + } + + *pos = i + 1; + question->qtype = knot_wire_read_u16(wire + i + 1); + //*pos += 2; + question->qclass = knot_wire_read_u16(wire + i + 3); + //*pos += 2; + + *pos += 4; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Reallocate space for RRSets. + * + * \param rrsets Space for RRSets. + * \param max_count Size of the space available for the RRSets. + * \param default_max_count Size of the space pre-allocated for the RRSets when + * the response structure was initialized. + * \param step How much the space should be increased. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +static int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets, + short *max_count, + short default_max_count, short step) +{ + dbg_packet("Max count: %d, default max count: %d\n", + *max_count, default_max_count); + int free_old = (*max_count) != default_max_count; + const knot_rrset_t **old = *rrsets; + + short new_max_count = *max_count + step; + const knot_rrset_t **new_rrsets = (const knot_rrset_t **)malloc( + new_max_count * sizeof(knot_rrset_t *)); + CHECK_ALLOC_LOG(new_rrsets, KNOT_ENOMEM); + + memcpy(new_rrsets, *rrsets, (*max_count) * sizeof(knot_rrset_t *)); + + *rrsets = new_rrsets; + *max_count = new_max_count; + + if (free_old) { + free(old); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire, + size_t *pos, size_t total_size, size_t rdlength, + const knot_rrtype_descriptor_t *desc) +{ +// if (desc->type == 0) { +// dbg_packet("Unknown RR type.\n"); +// return NULL; +// } + + knot_rdata_t *rdata = knot_rdata_new(); + if (rdata == NULL) { + return NULL; + } + + int rc = knot_rdata_from_wire(rdata, wire, pos, total_size, rdlength, + desc); + + if (rc != KNOT_EOK) { + dbg_packet("rdata_from_wire() returned: %s\n", + knot_strerror(rc)); + knot_rdata_free(&rdata); + return NULL; + } + + return rdata; +} + +/*----------------------------------------------------------------------------*/ + +static knot_rrset_t *knot_packet_parse_rr(const uint8_t *wire, size_t *pos, + size_t size) +{ +// knot_rrset_t *rrset = +// (knot_rrset_t *)malloc(sizeof(knot_rrset_t)); +// CHECK_ALLOC_LOG(rrset, NULL); + + dbg_packet("Parsing RR from position: %zu, total size: %zu\n", + *pos, size); + + knot_dname_t *owner = knot_dname_parse_from_wire(wire, pos, size, + NULL); + dbg_packet("Created owner: %p, actual position: %zu\n", owner, + *pos); + if (owner == NULL) { + return NULL; + } + +dbg_packet_exec( + char *name = knot_dname_to_str(owner); + dbg_packet("Parsed name: %s\n", name); + free(name); +); + + //*remaining -= knot_dname_size(rrset->owner); + + /*! @todo Get rid of the numerical constant. */ + if (size - *pos < 10) { + dbg_packet("Malformed RR: Not enough data to parse RR" + " header.\n"); + knot_dname_release(owner); + return NULL; + } + + dbg_packet("Reading type from position %zu\n", *pos); + + uint16_t type = knot_wire_read_u16(wire + *pos); + uint16_t rclass = knot_wire_read_u16(wire + *pos + 2); + uint32_t ttl = knot_wire_read_u32(wire + *pos + 4); + + knot_rrset_t *rrset = knot_rrset_new(owner, type, rclass, ttl); + + /* Owner is either referenced in rrset or rrset creation failed. */ + knot_dname_release(owner); + + /* Check rrset allocation. */ + if (rrset == NULL) { + return NULL; + } + + uint16_t rdlength = knot_wire_read_u16(wire + *pos + 8); + + dbg_packet("Read RR header: type %u, class %u, ttl %u, " + "rdlength %u\n", rrset->type, rrset->rclass, + rrset->ttl, rdlength); + + *pos += 10; + + if (size - *pos < rdlength) { + dbg_packet("Malformed RR: Not enough data to parse RR" + " RDATA (size: %zu, position: %zu).\n", + size, *pos); + knot_rrset_deep_free(&rrset, 1, 1, 0); +// free(rrset); + return NULL; + } + + rrset->rrsigs = NULL; + + if (rdlength == 0) { + return rrset; + } + + // parse RDATA + knot_rdata_t *rdata = knot_packet_parse_rdata(wire, pos, size, + rdlength, + knot_rrtype_descriptor_by_type(rrset->type)); + if (rdata == NULL) { + dbg_packet("Malformed RR: Could not parse RDATA.\n"); + knot_rrset_deep_free(&rrset, 1, 1, 0); +// free(rrset); + return NULL; + } + + if (knot_rrset_add_rdata(rrset, rdata) != KNOT_EOK) { + dbg_packet("Malformed RR: Could not add RDATA to RRSet" + ".\n"); + knot_rdata_free(&rdata); + knot_rrset_deep_free(&rrset, 1, 1, 0); +// free(rrset); + return NULL; + } + + return rrset; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_packet_add_rrset(knot_rrset_t *rrset, + const knot_rrset_t ***rrsets, + short *rrset_count, + short *max_rrsets, + short default_rrsets, + const knot_packet_t *packet, + knot_packet_duplicate_handling_t dupl) +{ + + assert(rrset != NULL); + assert(rrsets != NULL); + assert(rrset_count != NULL); + assert(max_rrsets != NULL); + +dbg_packet_exec( + char *name = knot_dname_to_str(rrset->owner); + dbg_packet("packet_add_rrset(), owner: %s, type: %s\n", + name, knot_rrtype_to_string(rrset->type)); + free(name); +); + + if (*rrset_count == *max_rrsets + && knot_packet_realloc_rrsets(rrsets, max_rrsets, default_rrsets, + STEP_ANCOUNT) != KNOT_EOK) { + return KNOT_ENOMEM; + } + + if (dupl == KNOT_PACKET_DUPL_SKIP && + knot_packet_contains(packet, rrset, KNOT_RRSET_COMPARE_PTR)) { + /*! \todo This should also return > 0, as it means that the + RRSet was not used actually. */ + return KNOT_EOK; + } + + if (dupl == KNOT_PACKET_DUPL_MERGE) { + // try to find the RRSet in this array of RRSets + for (int i = 0; i < *rrset_count; ++i) { + +dbg_packet_exec( + char *name = knot_dname_to_str((*rrsets)[i]->owner); + dbg_packet("Comparing to RRSet: owner: %s, " + "type: %s\n", name, + knot_rrtype_to_string( + (*rrsets)[i]->type)); + free(name); +); + + if (knot_rrset_compare((*rrsets)[i], rrset, + KNOT_RRSET_COMPARE_HEADER)) { + //const knot_rrset_t *r = (*rrsets) + /*! \todo Test this!!! */ + int rc = knot_rrset_merge( + (void **)((*rrsets) + i), (void **)&rrset); + if (rc != KNOT_EOK) { + return rc; + } + return 1; + } + } + } + + (*rrsets)[*rrset_count] = rrset; + ++(*rrset_count); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, + size_t size, uint16_t rr_count, + const knot_rrset_t ***rrsets, + short *rrset_count, short *max_rrsets, + short default_rrsets, + knot_packet_t *packet) +{ + assert(pos != NULL); + assert(wire != NULL); + assert(rrsets != NULL); + assert(rrset_count != NULL); + assert(max_rrsets != NULL); + assert(packet != NULL); + + dbg_packet("Parsing RRSets starting on position: %zu\n", + *pos); + +// if (*rrsets == NULL) { +// knot_packet_realloc_rrsets(rrsets, max_rrsets, 0, 1); +// } + + /* + * The RRs from one RRSet may be scattered in the current section. + * We must parse all RRs separately and try to add them to already + * parsed RRSets. + */ + int err = KNOT_EOK; + knot_rrset_t *rrset = NULL; + + for (int i = 0; i < rr_count; ++i) { + rrset = knot_packet_parse_rr(wire, pos, size); + if (rrset == NULL) { + dbg_packet("Failed to parse RR!\n"); + err = KNOT_EMALF; + break; + } + + err = knot_packet_add_rrset(rrset, rrsets, rrset_count, + max_rrsets, default_rrsets, packet, + KNOT_PACKET_DUPL_MERGE); + if (err < 0) { + break; + } else if (err > 0) { // merged + dbg_packet("RRSet merged, freeing.\n"); + knot_rrset_deep_free(&rrset, 1, 0, 0); // TODO: ok?? + continue; + } + + err = knot_packet_add_tmp_rrset(packet, rrset); + if (err != KNOT_EOK) { + // remove the last RRSet from the list of RRSets + // - just decrement the count + --(*rrset_count); + knot_rrset_deep_free(&rrset, 1, 1, 1); + break; + } + } + + return (err < 0) ? err : KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Deallocates all space which was allocated additionally to the + * pre-allocated space of the response structure. + * + * \param resp Response structure that holds pointers to the allocated space. + */ +static void knot_packet_free_allocated_space(knot_packet_t *pkt) +{ + dbg_packet("Freeing additional space in packet.\n"); + if (pkt->prealloc_type == KNOT_PACKET_PREALLOC_NONE) { + dbg_packet("Freeing QNAME.\n"); + knot_dname_release(pkt->question.qname); + } + + if (pkt->max_an_rrsets > DEFAULT_RRSET_COUNT(ANCOUNT, pkt)) { + free(pkt->answer); + } + if (pkt->max_ns_rrsets > DEFAULT_RRSET_COUNT(NSCOUNT, pkt)) { + free(pkt->authority); + } + if (pkt->max_ar_rrsets > DEFAULT_RRSET_COUNT(ARCOUNT, pkt)) { + free(pkt->additional); + } + + if (pkt->compression.max > DEFAULT_DOMAINS_IN_RESPONSE) { + free(pkt->compression.dnames); + free(pkt->compression.offsets); + } + + if (pkt->tmp_rrsets_max > DEFAULT_RRSET_COUNT(TMP_RRSETS, pkt)) { + free(pkt->tmp_rrsets); + } +} + +/*----------------------------------------------------------------------------*/ + +static int knot_packet_parse_rr_sections(knot_packet_t *packet, + size_t *pos) +{ + assert(packet != NULL); + assert(packet->wireformat != NULL); + assert(packet->size > 0); + assert(pos != NULL); + assert(*pos > 0); + + int err; + + dbg_packet("Parsing Answer RRs...\n"); + if ((err = knot_packet_parse_rrs(packet->wireformat, pos, + packet->size, packet->header.ancount, &packet->answer, + &packet->an_rrsets, &packet->max_an_rrsets, + DEFAULT_RRSET_COUNT(ANCOUNT, packet), packet)) != KNOT_EOK) { + return err; + } + + dbg_packet("Parsing Authority RRs...\n"); + if ((err = knot_packet_parse_rrs(packet->wireformat, pos, + packet->size, packet->header.nscount, &packet->authority, + &packet->ns_rrsets, &packet->max_ns_rrsets, + DEFAULT_RRSET_COUNT(NSCOUNT, packet), packet)) != KNOT_EOK) { + return err; + } + + dbg_packet("Parsing Additional RRs...\n"); + if ((err = knot_packet_parse_rrs(packet->wireformat, pos, + packet->size, packet->header.arcount, &packet->additional, + &packet->ar_rrsets, &packet->max_ar_rrsets, + DEFAULT_RRSET_COUNT(ARCOUNT, packet), packet)) != KNOT_EOK) { + return err; + } + + dbg_packet("Trying to find OPT RR in the packet.\n"); + + for (int i = 0; i < packet->ar_rrsets; ++i) { + assert(packet->additional[i] != NULL); + if (knot_rrset_type(packet->additional[i]) + == KNOT_RRTYPE_OPT) { + dbg_packet("Found OPT RR, filling.\n"); + err = knot_edns_new_from_rr(&packet->opt_rr, + packet->additional[i]); + if (err != KNOT_EOK) { + return err; + } + break; + } + } + + packet->parsed = *pos; + + if (*pos < packet->size) { + // some trailing garbage; ignore, but log + dbg_response("Packet: %zu bytes of trailing garbage " + "in packet.\n", packet->size - (*pos)); + return KNOT_EMALF; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc) +{ + knot_packet_t *pkt; + void (*init_pointers)(knot_packet_t *pkt) = NULL; + size_t size = 0; + + switch (prealloc) { + case KNOT_PACKET_PREALLOC_NONE: + size = sizeof(knot_packet_t); + break; + case KNOT_PACKET_PREALLOC_QUERY: + size = PREALLOC_QUERY; + init_pointers = knot_packet_init_pointers_query; + break; + case KNOT_PACKET_PREALLOC_RESPONSE: + size = PREALLOC_RESPONSE; + init_pointers = knot_packet_init_pointers_response; + break; + } + + pkt = (knot_packet_t *)malloc(size); + CHECK_ALLOC_LOG(pkt, NULL); + memset(pkt, 0, size); + if (init_pointers != NULL) { + init_pointers(pkt); + } + + pkt->prealloc_type = prealloc; + + // set EDNS version to not supported + pkt->opt_rr.version = EDNS_NOT_SUPPORTED; + + return pkt; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_parse_from_wire(knot_packet_t *packet, + const uint8_t *wireformat, size_t size, + int question_only) +{ + if (packet == NULL || wireformat == NULL) { + return KNOT_EBADARG; + } + + int err; + + // save the wireformat in the packet + // TODO: can we just save the pointer, or we have to copy the data?? + assert(packet->wireformat == NULL); + packet->wireformat = (uint8_t*)wireformat; + packet->size = size; + packet->free_wireformat = 0; + + //uint8_t *pos = wireformat; + size_t pos = 0; + //size_t remaining = size; + + dbg_packet("Parsing wire format of packet (size %zu).\nHeader\n", + size); + if ((err = knot_packet_parse_header(wireformat, &pos, size, + &packet->header)) != KNOT_EOK) { + return err; + } + + packet->parsed = pos; + + dbg_packet("Question (prealloc type: %d)...\n", packet->prealloc_type); + + if (packet->header.qdcount > 1) { + dbg_packet("QDCOUNT larger than 1, FORMERR.\n"); + return KNOT_EMALF; + } + + knot_packet_dump(packet); + + if (packet->header.qdcount == 1) { + if ((err = knot_packet_parse_question(wireformat, &pos, size, + &packet->question, packet->prealloc_type + == KNOT_PACKET_PREALLOC_NONE) + ) != KNOT_EOK) { + return err; + } + packet->parsed = pos; + } + + knot_packet_dump(packet); + + if (question_only) { + return KNOT_EOK; + } + + /*! \todo Replace by call to parse_rest()? */ + err = knot_packet_parse_rr_sections(packet, &pos); + +#ifdef KNOT_PACKET_DEBUG + knot_packet_dump(packet); +#endif /* KNOT_RESPONSE_DEBUG */ + + return err; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_parse_rest(knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + +// if (packet->parsed >= packet->size) { +// return KNOT_EOK; +// } + + if (packet->parsed == packet->size) { + return KNOT_EOK; + } + + size_t pos = packet->parsed; + + return knot_packet_parse_rr_sections(packet, &pos); +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_parse_next_rr_answer(knot_packet_t *packet, + knot_rrset_t **rr) +{ + if (packet == NULL || rr == NULL) { + return KNOT_EBADARG; + } + + *rr = NULL; + + if (packet->parsed >= packet->size) { + assert(packet->an_rrsets <= packet->header.ancount); + if (packet->an_rrsets != packet->header.ancount) { + dbg_packet("Parsed less RRs than expected.\n"); + return KNOT_EMALF; + } else { + dbg_packet("Whole packet parsed\n"); + return KNOT_EOK; + } + } + + if (packet->an_rrsets == packet->header.ancount) { + assert(packet->parsed < packet->size); + //dbg_packet("Trailing garbage, ignoring...\n"); + // there may be other data in the packet + // (authority or additional). + return KNOT_EOK; + } + + size_t pos = packet->parsed; + + dbg_packet("Parsing next Answer RR (pos: %zu)...\n", pos); + *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size); + if (*rr == NULL) { + dbg_packet("Failed to parse RR!\n"); + return KNOT_EMALF; + } + + dbg_packet("Parsed. Pos: %zu.\n", pos); + + packet->parsed = pos; + // increment the number of answer RRSets, though there are no saved + // in the packet; it is OK, because packet->answer is NULL + ++packet->an_rrsets; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_parse_next_rr_additional(knot_packet_t *packet, + knot_rrset_t **rr) +{ + /*! \todo Implement. */ + if (packet == NULL || rr == NULL) { + return KNOT_EBADARG; + } + + *rr = NULL; + + if (packet->parsed >= packet->size) { + assert(packet->ar_rrsets <= packet->header.arcount); + if (packet->ar_rrsets != packet->header.arcount) { + dbg_packet("Parsed less RRs than expected.\n"); + return KNOT_EMALF; + } else { + dbg_packet("Whole packet parsed\n"); + return KNOT_EOK; + } + } + + if (packet->ar_rrsets == packet->header.arcount) { + assert(packet->parsed < packet->size); + dbg_packet("Trailing garbage, ignoring...\n"); + /*! \todo Do not ignore. */ + return KNOT_EOK; + } + + size_t pos = packet->parsed; + + dbg_packet("Parsing next Additional RR (pos: %zu)...\n", pos); + *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size); + if (*rr == NULL) { + dbg_packet("Failed to parse RR!\n"); + return KNOT_EMALF; + } + + dbg_packet("Parsed. Pos: %zu.\n", pos); + + packet->parsed = pos; + // increment the number of answer RRSets, though there are no saved + // in the packet; it is OK, because packet->answer is NULL + ++packet->ar_rrsets; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +size_t knot_packet_size(const knot_packet_t *packet) +{ + return packet->size; +} + +/*----------------------------------------------------------------------------*/ + +size_t knot_packet_question_size(const knot_packet_t *packet) +{ + return (KNOT_WIRE_HEADER_SIZE + 4 + + knot_dname_size(packet->question.qname)); +} + +/*----------------------------------------------------------------------------*/ + +size_t knot_packet_parsed(const knot_packet_t *packet) +{ + return packet->parsed; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_set_max_size(knot_packet_t *packet, int max_size) +{ + if (packet == NULL || max_size <= 0) { + return KNOT_EBADARG; + } + + if (packet->max_size < max_size) { + // reallocate space for the wire format (and copy anything + // that might have been there before + uint8_t *wire_new = (uint8_t *)malloc(max_size); + if (wire_new == NULL) { + return KNOT_ENOMEM; + } + + uint8_t *wire_old = packet->wireformat; + + memcpy(wire_new, packet->wireformat, packet->max_size); + packet->wireformat = wire_new; + + if (packet->max_size > 0 && packet->free_wireformat) { + free(wire_old); + } + + packet->free_wireformat = 1; + } + + // set max size + packet->max_size = max_size; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_packet_id(const knot_packet_t *packet) +{ + assert(packet != NULL); + return packet->header.id; +} + +/*----------------------------------------------------------------------------*/ + +void knot_packet_set_id(knot_packet_t *packet, uint16_t id) +{ + if (packet == NULL) { + return; + } + + packet->header.id = id; +} + +/*----------------------------------------------------------------------------*/ + +void knot_packet_set_random_id(knot_packet_t *packet) +{ + if (packet == NULL) { + return; + } + + packet->header.id = knot_random_id(); +} + +/*----------------------------------------------------------------------------*/ + +uint8_t knot_packet_opcode(const knot_packet_t *packet) +{ + assert(packet != NULL); + return knot_wire_flags_get_opcode(packet->header.flags1); +} + +/*----------------------------------------------------------------------------*/ + +const knot_dname_t *knot_packet_qname(const knot_packet_t *packet) +{ + if (packet == NULL) { + return NULL; + } + + return packet->question.qname; +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_packet_qtype(const knot_packet_t *packet) +{ + assert(packet != NULL); + return packet->question.qtype; +} + +/*----------------------------------------------------------------------------*/ + +void knot_packet_set_qtype(knot_packet_t *packet, knot_rr_type_t qtype) +{ + assert(packet != NULL); + packet->question.qtype = qtype; +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_packet_qclass(const knot_packet_t *packet) +{ + assert(packet != NULL); + return packet->question.qclass; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_is_query(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return (knot_wire_flags_get_qr(packet->header.flags1) == 0); +} + +/*----------------------------------------------------------------------------*/ + +const knot_packet_t *knot_packet_query(const knot_packet_t *packet) +{ + if (packet == NULL) { + return NULL; + } + + return packet->query; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_rcode(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return knot_wire_flags_get_rcode(packet->header.flags2); +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_tc(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return knot_wire_flags_get_tc(packet->header.flags1); +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_qdcount(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return packet->header.qdcount; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_ancount(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return packet->header.ancount; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_nscount(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return packet->header.nscount; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_arcount(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return packet->header.arcount; +} + +/*----------------------------------------------------------------------------*/ + +void knot_packet_set_tsig_size(knot_packet_t *packet, size_t tsig_size) +{ + packet->tsig_size = tsig_size; +} + +/*----------------------------------------------------------------------------*/ + +short knot_packet_answer_rrset_count(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return packet->an_rrsets; +} + +/*----------------------------------------------------------------------------*/ + +short knot_packet_authority_rrset_count(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return packet->ns_rrsets; +} + +/*----------------------------------------------------------------------------*/ + +short knot_packet_additional_rrset_count(const knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + return packet->ar_rrsets; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rrset_t *knot_packet_answer_rrset( + const knot_packet_t *packet, short pos) +{ + if (packet == NULL || pos > packet->an_rrsets) { + return NULL; + } + + return packet->answer[pos]; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rrset_t *knot_packet_authority_rrset( + knot_packet_t *packet, short pos) +{ + if (packet == NULL || pos > packet->ns_rrsets) { + return NULL; + } + + return packet->authority[pos]; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rrset_t *knot_packet_additional_rrset( + knot_packet_t *packet, short pos) +{ + if (packet == NULL || pos > packet->ar_rrsets) { + return NULL; + } + + return packet->additional[pos]; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_contains(const knot_packet_t *packet, + const knot_rrset_t *rrset, + knot_rrset_compare_type_t cmp) +{ + if (packet == NULL || rrset == NULL) { + return KNOT_EBADARG; + } + + for (int i = 0; i < packet->header.ancount; ++i) { + if (knot_rrset_compare(packet->answer[i], rrset, cmp)) { + return 1; + } + } + + for (int i = 0; i < packet->header.nscount; ++i) { + if (knot_rrset_compare(packet->authority[i], rrset, cmp)) { + return 1; + } + } + + for (int i = 0; i < packet->header.arcount; ++i) { + if (knot_rrset_compare(packet->additional[i], rrset, cmp)) { + return 1; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_add_tmp_rrset(knot_packet_t *packet, + knot_rrset_t *tmp_rrset) +{ + if (packet == NULL || tmp_rrset == NULL) { + return KNOT_EBADARG; + } + + if (packet->tmp_rrsets_count == packet->tmp_rrsets_max + && knot_packet_realloc_rrsets(&packet->tmp_rrsets, + &packet->tmp_rrsets_max, + DEFAULT_RRSET_COUNT(TMP_RRSETS, packet), + STEP_TMP_RRSETS) != KNOT_EOK) { + return KNOT_ENOMEM; + } + + packet->tmp_rrsets[packet->tmp_rrsets_count++] = tmp_rrset; + dbg_packet("Current tmp RRSets count: %d, max count: %d\n", + packet->tmp_rrsets_count, packet->tmp_rrsets_max); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Frees all temporary RRSets stored in the response structure. + * + * \param resp Response structure to free the temporary RRSets from. + */ +void knot_packet_free_tmp_rrsets(knot_packet_t *pkt) +{ + if (pkt == NULL) { + return; + } + + for (int i = 0; i < pkt->tmp_rrsets_count; ++i) { +dbg_packet_exec( + char *name = knot_dname_to_str( + (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->owner); + dbg_packet("Freeing tmp RRSet on ptr: %p (ptr to ptr:" + " %p, type: %s, owner: %s)\n", + (((knot_rrset_t **)(pkt->tmp_rrsets))[i]), + &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]), + knot_rrtype_to_string( + (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->type), + name); + free(name); +); + // TODO: this is quite ugly, but better than copying whole + // function (for reallocating rrset array) + knot_rrset_deep_free( + &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]), 1, 1, 1); + } +} + +/*----------------------------------------------------------------------------*/ + +void knot_packet_header_to_wire(const knot_header_t *header, + uint8_t **pos, size_t *size) +{ + if (header == NULL || pos == NULL || *pos == NULL || size == NULL) { + return; + } + + knot_wire_set_id(*pos, header->id); + knot_wire_set_flags1(*pos, header->flags1); + knot_wire_set_flags2(*pos, header->flags2); + knot_wire_set_qdcount(*pos, header->qdcount); + knot_wire_set_ancount(*pos, header->ancount); + knot_wire_set_nscount(*pos, header->nscount); + knot_wire_set_arcount(*pos, header->arcount); + + *pos += KNOT_WIRE_HEADER_SIZE; + *size += KNOT_WIRE_HEADER_SIZE; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_question_to_wire(knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + if (packet->size > KNOT_WIRE_HEADER_SIZE) { + return KNOT_ERROR; + } + + // TODO: get rid of the numeric constants + size_t qsize = 4 + knot_dname_size(packet->question.qname); + if (qsize > packet->max_size - KNOT_WIRE_HEADER_SIZE) { + return KNOT_ESPACE; + } + + // create the wireformat of Question + uint8_t *pos = packet->wireformat + KNOT_WIRE_HEADER_SIZE; + memcpy(pos, knot_dname_name(packet->question.qname), + knot_dname_size(packet->question.qname)); + + pos += knot_dname_size(packet->question.qname); + knot_wire_write_u16(pos, packet->question.qtype); + pos += 2; + knot_wire_write_u16(pos, packet->question.qclass); + +// int err = 0; + // TODO: put the qname into the compression table +// // TODO: get rid of the numeric constants +// if ((err = knot_response_store_dname_pos(&packet->compression, +// packet->question.qname,0, 12, 12)) != KNOT_EOK) { +// return err; +// } + + packet->size += knot_dname_size(packet->question.qname) + 4; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_edns_to_wire(knot_packet_t *packet) +{ + if (packet == NULL) { + return KNOT_EBADARG; + } + + packet->size += knot_edns_to_wire(&packet->opt_rr, + packet->wireformat + packet->size, + packet->max_size - packet->size); + + packet->header.arcount += 1; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_packet_to_wire(knot_packet_t *packet, + uint8_t **wire, size_t *wire_size) +{ + if (packet == NULL || wire == NULL || wire_size == NULL + || *wire != NULL) { + return KNOT_EBADARG; + } + + assert(packet->size <= packet->max_size); + + // if there are no additional RRSets, add EDNS OPT RR + if (packet->header.arcount == 0 + && packet->opt_rr.version != EDNS_NOT_SUPPORTED) { + knot_packet_edns_to_wire(packet); + } + + // set QDCOUNT (in response it is already set, in query it is needed) + knot_wire_set_qdcount(packet->wireformat, packet->header.qdcount); + // set ANCOUNT to the packet + knot_wire_set_ancount(packet->wireformat, packet->header.ancount); + // set NSCOUNT to the packet + knot_wire_set_nscount(packet->wireformat, packet->header.nscount); + // set ARCOUNT to the packet + knot_wire_set_arcount(packet->wireformat, packet->header.arcount); + + //assert(response->size == size); + *wire = packet->wireformat; + *wire_size = packet->size; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +const uint8_t *knot_packet_wireformat(const knot_packet_t *packet) +{ + return packet->wireformat; +} + +/*----------------------------------------------------------------------------*/ + +void knot_packet_free(knot_packet_t **packet) +{ + if (packet == NULL || *packet == NULL) { + return; + } + + // free temporary domain names + dbg_packet("Freeing tmp RRSets...\n"); + knot_packet_free_tmp_rrsets(*packet); + + // check if some additional space was allocated for the packet + dbg_packet("Freeing additional allocated space...\n"); + knot_packet_free_allocated_space(*packet); + + // free the space for wireformat +// assert((*packet)->wireformat != NULL); +// free((*packet)->wireformat); + if ((*packet)->wireformat != NULL && (*packet)->free_wireformat) { + free((*packet)->wireformat); + } + + dbg_packet("Freeing packet structure\n"); + free(*packet); + *packet = NULL; +} + +/*----------------------------------------------------------------------------*/ +#ifdef KNOT_PACKET_DEBUG +static void knot_packet_dump_rrsets(const knot_rrset_t **rrsets, + int count) +{ + assert((rrsets != NULL && *rrsets != NULL) || count < 1); + + for (int i = 0; i < count; ++i) { + knot_rrset_dump(rrsets[i], 0); + } +} +#endif +/*----------------------------------------------------------------------------*/ + +void knot_packet_dump(const knot_packet_t *packet) +{ + if (packet == NULL) { + return; + } + +#ifdef KNOT_PACKET_DEBUG + dbg_packet("DNS packet:\n-----------------------------\n"); + + dbg_packet("\nHeader:\n"); + dbg_packet(" ID: %u", packet->header.id); + dbg_packet(" FLAGS: %s %s %s %s %s %s %s\n", + knot_wire_flags_get_qr(packet->header.flags1) ? "qr" : "", + knot_wire_flags_get_aa(packet->header.flags1) ? "aa" : "", + knot_wire_flags_get_tc(packet->header.flags1) ? "tc" : "", + knot_wire_flags_get_rd(packet->header.flags1) ? "rd" : "", + knot_wire_flags_get_ra(packet->header.flags2) ? "ra" : "", + knot_wire_flags_get_ad(packet->header.flags2) ? "ad" : "", + knot_wire_flags_get_cd(packet->header.flags2) ? "cd" : ""); + dbg_packet(" QDCOUNT: %u\n", packet->header.qdcount); + dbg_packet(" ANCOUNT: %u\n", packet->header.ancount); + dbg_packet(" NSCOUNT: %u\n", packet->header.nscount); + dbg_packet(" ARCOUNT: %u\n", packet->header.arcount); + + if (knot_packet_qdcount(packet) > 0) { + dbg_packet("\nQuestion:\n"); + char *qname = knot_dname_to_str(packet->question.qname); + dbg_packet(" QNAME: %s\n", qname); + free(qname); + dbg_packet(" QTYPE: %u (%s)\n", packet->question.qtype, + knot_rrtype_to_string(packet->question.qtype)); + dbg_packet(" QCLASS: %u (%s)\n", packet->question.qclass, + knot_rrclass_to_string(packet->question.qclass)); + } + + dbg_packet("\nAnswer RRSets:\n"); + knot_packet_dump_rrsets(packet->answer, packet->an_rrsets); + dbg_packet("\nAuthority RRSets:\n"); + knot_packet_dump_rrsets(packet->authority, packet->ns_rrsets); + dbg_packet("\nAdditional RRSets:\n"); + knot_packet_dump_rrsets(packet->additional, packet->ar_rrsets); + + /*! \todo Dumping of Answer, Authority and Additional sections. */ + + dbg_packet("\nEDNS:\n"); + dbg_packet(" Version: %u\n", packet->opt_rr.version); + dbg_packet(" Payload: %u\n", packet->opt_rr.payload); + dbg_packet(" Extended RCODE: %u\n", + packet->opt_rr.ext_rcode); + + dbg_packet("\nPacket size: %zu\n", packet->size); + dbg_packet("\n-----------------------------\n"); +#endif +} + diff --git a/src/libknot/packet/packet.h b/src/libknot/packet/packet.h new file mode 100644 index 0000000..1bf74a9 --- /dev/null +++ b/src/libknot/packet/packet.h @@ -0,0 +1,538 @@ +/*! + * \file packet.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Structure for holding DNS packet data and metadata. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_PACKET_H_ +#define _KNOT_PACKET_H_ + +#include <stdint.h> +#include <string.h> + +#include "dname.h" +#include "rrset.h" +#include "edns.h" + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure for holding information needed for compressing domain names. + * + * It's a simple table of domain names and their offsets in wire format of the + * packet. + * + * \todo Consider using some better lookup structure, such as skip-list. + */ +struct knot_compressed_dnames { + const knot_dname_t **dnames; /*!< Domain names present in packet. */ + size_t *offsets; /*!< Offsets of domain names in the packet. */ + short count; /*!< Count of items in the previous arrays. */ + short max; /*!< Capacity of the structure (allocated). */ +}; + +typedef struct knot_compressed_dnames knot_compressed_dnames_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure representing the DNS packet header. + */ +struct knot_header { + uint16_t id; /*!< ID stored in host byte order. */ + uint8_t flags1; /*!< First octet of header flags. */ + uint8_t flags2; /*!< Second octet of header flags. */ + uint16_t qdcount; /*!< Number of Question RRs, in host byte order. */ + uint16_t ancount; /*!< Number of Answer RRs, in host byte order. */ + uint16_t nscount; /*!< Number of Authority RRs, in host byte order. */ + uint16_t arcount; /*!< Number of Additional RRs, in host byte order. */ +}; + +typedef struct knot_header knot_header_t; + +/*! + * \brief Structure representing one Question entry in the DNS packet. + */ +struct knot_question { + knot_dname_t *qname; /*!< Question domain name. */ + uint16_t qtype; /*!< Question TYPE. */ + uint16_t qclass; /*!< Question CLASS. */ +}; + +typedef struct knot_question knot_question_t; + +enum knot_packet_prealloc_type { + KNOT_PACKET_PREALLOC_NONE, + KNOT_PACKET_PREALLOC_QUERY, + KNOT_PACKET_PREALLOC_RESPONSE +}; + +typedef enum knot_packet_prealloc_type knot_packet_prealloc_type_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure representing a DNS packet. + * + * \note QNAME, Answer, Authority and Additonal sections are by default put to + * preallocated space after the structure with default sizes. If the + * space is not enough, more space is allocated dynamically. + */ +struct knot_packet { + /*! \brief DNS header. */ + knot_header_t header; + + /*! + * \brief Question section. + * + * \note Only one Question is supported! + */ + knot_question_t question; + + uint8_t *owner_tmp; /*!< Allocated space for RRSet owner wire format.*/ + + const knot_rrset_t **answer; /*!< Answer RRSets. */ + const knot_rrset_t **authority; /*!< Authority RRSets. */ + const knot_rrset_t **additional; /*!< Additional RRSets. */ + + short an_rrsets; /*!< Count of Answer RRSets in the response. */ + short ns_rrsets; /*!< Count of Authority RRSets in the response. */ + short ar_rrsets; /*!< Count of Additional RRSets in the response. */ + + short max_an_rrsets; /*!< Allocated space for Answer RRsets. */ + short max_ns_rrsets; /*!< Allocated space for Authority RRsets. */ + short max_ar_rrsets; /*!< Allocated space for Additional RRsets. */ + + knot_opt_rr_t opt_rr; /*!< OPT RR included in the packet. */ + + uint8_t *wireformat; /*!< Wire format of the packet. */ + + short free_wireformat; + size_t parsed; + + size_t size; /*!< Current wire size of the packet. */ + size_t max_size; /*!< Maximum allowed size of the packet. */ + + /*! \brief Information needed for compressing domain names in packet. */ + knot_compressed_dnames_t compression; + + /*! \brief RRSets to be destroyed with the packet structure. */ + const knot_rrset_t **tmp_rrsets; + short tmp_rrsets_count; /*!< Count of temporary RRSets. */ + short tmp_rrsets_max; /*!< Allocated space for temporary RRSets. */ + + struct knot_packet *query; /*!< Associated query. */ + + knot_packet_prealloc_type_t prealloc_type; + + size_t tsig_size; /*!< Space to reserve for the TSIG RR. */ +}; + +typedef struct knot_packet knot_packet_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Default sizes for response structure parts and steps for increasing + * them. + */ +enum { + DEFAULT_ANCOUNT = 6, /*!< Default count of Answer RRSets. */ + DEFAULT_NSCOUNT = 8, /*!< Default count of Authority RRSets. */ + DEFAULT_ARCOUNT = 28, /*!< Default count of Additional RRSets. */ + + DEFAULT_ANCOUNT_QUERY = 1, /*!< Default count of Answer RRSets. */ + DEFAULT_NSCOUNT_QUERY = 0, /*!< Default count of Authority RRSets. */ + DEFAULT_ARCOUNT_QUERY = 1, /*!< Default count of Additional RRSets. */ + /*! + * \brief Default count of all domain names in response. + * + * Used for compression table. + */ + DEFAULT_DOMAINS_IN_RESPONSE = 22, + + /*! \brief Default count of temporary RRSets stored in response. */ + DEFAULT_TMP_RRSETS = 5, + + /*! \brief Default count of temporary RRSets stored in query. */ + DEFAULT_TMP_RRSETS_QUERY = 2, + + STEP_ANCOUNT = 6, /*!< Step for increasing space for Answer RRSets. */ + STEP_NSCOUNT = 8, /*!< Step for increasing space for Authority RRSets.*/ + STEP_ARCOUNT = 8,/*!< Step for increasing space for Additional RRSets.*/ + STEP_DOMAINS = 10, /*!< Step for resizing compression table. */ + STEP_TMP_RRSETS = 5 /*!< Step for increasing temorary RRSets count. */ +}; + +/*----------------------------------------------------------------------------*/ +#define PREALLOC_RRSETS(count) (count * sizeof(knot_rrset_t *)) + +/*! \brief Sizes for preallocated space in the response structure. */ +enum { + /*! \brief Size of the response structure itself. */ + PREALLOC_PACKET = sizeof(knot_packet_t), + /*! \brief Space for QNAME dname structure. */ + PREALLOC_QNAME_DNAME = sizeof(knot_dname_t), + /*! \brief Space for QNAME name (maximum domain name size). */ + PREALLOC_QNAME_NAME = 256, + /*! \brief Space for QNAME labels (maximum label count). */ + PREALLOC_QNAME_LABELS = 127, + /*! \brief Total space for QNAME. */ + PREALLOC_QNAME = PREALLOC_QNAME_DNAME + + PREALLOC_QNAME_NAME + + PREALLOC_QNAME_LABELS, + /*! + * \brief Space for RR owner wire format. + * + * Temporary buffer, used when putting RRSets to the response. + */ + PREALLOC_RR_OWNER = 256, + +// /*! \brief Space for Answer RRSets. */ +// PREALLOC_ANSWER = DEFAULT_ANCOUNT * sizeof(knot_dname_t *), +// /*! \brief Space for Authority RRSets. */ +// PREALLOC_AUTHORITY = DEFAULT_NSCOUNT * sizeof(knot_dname_t *), +// /*! \brief Space for Additional RRSets. */ +// PREALLOC_ADDITIONAL = DEFAULT_ARCOUNT * sizeof(knot_dname_t *), +// /*! \brief Total size for Answer, Authority and Additional RRSets. */ +// PREALLOC_RRSETS = PREALLOC_ANSWER +// + PREALLOC_AUTHORITY +// + PREALLOC_ADDITIONAL, + /*! \brief Space for one part of the compression table (domain names).*/ + PREALLOC_DOMAINS = + DEFAULT_DOMAINS_IN_RESPONSE * sizeof(knot_dname_t *), + /*! \brief Space for other part of the compression table (offsets). */ + PREALLOC_OFFSETS = + DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t), + PREALLOC_COMPRESSION = PREALLOC_DOMAINS + PREALLOC_OFFSETS, + +// /*! \brief Space for temporary RRSets. */ +// PREALLOC_TMP_RRSETS = +// DEFAULT_TMP_RRSETS * sizeof(knot_rrset_t *), + + PREALLOC_QUERY = PREALLOC_PACKET + + PREALLOC_QNAME + + PREALLOC_RRSETS(DEFAULT_ANCOUNT_QUERY) + + PREALLOC_RRSETS(DEFAULT_NSCOUNT_QUERY) + + PREALLOC_RRSETS(DEFAULT_ARCOUNT_QUERY) + + PREALLOC_RRSETS(DEFAULT_TMP_RRSETS_QUERY), + + /*! \brief Total preallocated size for the response. */ + PREALLOC_RESPONSE = PREALLOC_PACKET + + PREALLOC_QNAME + + PREALLOC_RR_OWNER + + PREALLOC_RRSETS(DEFAULT_ANCOUNT) + + PREALLOC_RRSETS(DEFAULT_NSCOUNT) + + PREALLOC_RRSETS(DEFAULT_ARCOUNT) + + PREALLOC_COMPRESSION + + PREALLOC_RRSETS(DEFAULT_TMP_RRSETS) +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates new empty packet structure. + * + * \param prealloc What space should be preallocated in the structure. + * + * \return New packet structure or NULL if an error occured. + */ +knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc); + +/*! + * \brief Parses the DNS packet from wire format. + * + * \param packet Packet structure to parse into. + * \param wireformat Wire format of the DNS packet. + * \param size Size of the wire format in bytes. + * \param question_only Set to <> 0 if you do not want to parse the whole + * packet. In such case the parsing will end after the + * Question section. Set to 0 to parse the whole packet. + * + * \retval KNOT_EOK + */ +int knot_packet_parse_from_wire(knot_packet_t *packet, + const uint8_t *wireformat, size_t size, + int question_only); + +int knot_packet_parse_rest(knot_packet_t *packet); + +int knot_packet_parse_next_rr_answer(knot_packet_t *packet, + knot_rrset_t **rr); + +int knot_packet_parse_next_rr_additional(knot_packet_t *packet, + knot_rrset_t **rr); + +size_t knot_packet_size(const knot_packet_t *packet); + +/*! \brief Returns size of the wireformat of Header and Question sections. */ +size_t knot_packet_question_size(const knot_packet_t *packet); + +size_t knot_packet_parsed(const knot_packet_t *packet); + +/*! + * \brief Sets the maximum size of the packet and allocates space for wire + * format (if needed). + * + * This function also allocates space for the wireformat of the packet, if + * the given max size is larger than the current maximum size of the packet + * and copies the current wireformat over to the new space. + * + * \warning Do not call this function if you are not completely sure that the + * current wire format of the packet fits into the new space. + * It does not update the current size of the wire format, so the + * produced packet may be larger than the given max size. + * + * \param packet Packet to set the maximum size of. + * \param max_size Maximum size of the packet in bytes. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + * + * \todo Needs test. + */ +int knot_packet_set_max_size(knot_packet_t *packet, int max_size); + +uint16_t knot_packet_id(const knot_packet_t *packet); + +void knot_packet_set_id(knot_packet_t *packet, uint16_t id); + +void knot_packet_set_random_id(knot_packet_t *packet); + +/*! + * \brief Returns the OPCODE of the packet. + * + * \param packet Packet (with parsed query) to get the OPCODE from. + * + * \return OPCODE stored in the packet. + */ +uint8_t knot_packet_opcode(const knot_packet_t *packet); + +/*! + * \brief Returns the QNAME from the packet. + * + * \param packet Packet (with parsed query) to get the QNAME from. + * + * \return QNAME stored in the packet. + */ +const knot_dname_t *knot_packet_qname(const knot_packet_t *packet); + +/*! + * \brief Returns the QTYPE from the packet. + * + * \param packet Packet (with parsed query) to get the QTYPE from. + * + * \return QTYPE stored in the packet. + */ +uint16_t knot_packet_qtype(const knot_packet_t *packet); + +/*! + * \brief Set the QTYPE of the packet. + * + * \param packet Packet containing question. + * \param qtype New QTYPE for question. + */ +void knot_packet_set_qtype(knot_packet_t *packet, knot_rr_type_t qtype); + + +/*! + * \brief Returns the QCLASS from the packet. + * + * \param response Packet (with parsed query) to get the QCLASS from. + * + * \return QCLASS stored in the packet. + */ +uint16_t knot_packet_qclass(const knot_packet_t *packet); + +int knot_packet_is_query(const knot_packet_t *packet); + +const knot_packet_t *knot_packet_query(const knot_packet_t *packet); + +int knot_packet_rcode(const knot_packet_t *packet); + +int knot_packet_tc(const knot_packet_t *packet); + +int knot_packet_qdcount(const knot_packet_t *packet); + +int knot_packet_ancount(const knot_packet_t *packet); + +int knot_packet_nscount(const knot_packet_t *packet); + +int knot_packet_arcount(const knot_packet_t *packet); + +void knot_packet_set_tsig_size(knot_packet_t *packet, size_t tsig_size); + +/*! + * \brief Returns number of RRSets in Answer section of the packet. + * + * \param response Packet to get the Answer RRSet count from. + */ +short knot_packet_answer_rrset_count(const knot_packet_t *packet); + +/*! + * \brief Returns number of RRSets in Authority section of the packet. + * + * \param response Packet to get the Authority RRSet count from. + */ +short knot_packet_authority_rrset_count(const knot_packet_t *packet); + +/*! + * \brief Returns number of RRSets in Additional section of the packet. + * + * \param response Packet to get the Additional RRSet count from. + */ +short knot_packet_additional_rrset_count(const knot_packet_t *packet); + +/*! + * \brief Returns the requested Answer RRset. + * + * \param packet Packet to get the RRSet from. + * \param pos Position of the RRSet in the Answer section (RRSets are stored + * in the order they were added to the response or parsed from the + * query). + * + * \return The RRSet on position \a pos in the Answer section of \a packet + * or NULL if there is no such RRSet. + */ +const knot_rrset_t *knot_packet_answer_rrset( + const knot_packet_t *packet, short pos); + +/*! + * \brief Returns the requested Authority RRset. + * + * \param packet Packet to get the RRSet from. + * \param pos Position of the RRSet in the Authority section (RRSets are stored + * in the order they were added to the response or parsed from the + * query). + * + * \return The RRSet on position \a pos in the Authority section of \a packet + * or NULL if there is no such RRSet. + */ +const knot_rrset_t *knot_packet_authority_rrset( + knot_packet_t *packet, short pos); + +/*! + * \brief Returns the requested Additional RRset. + * + * \param packet Packet to get the RRSet from. + * \param pos Position of the RRSet in the Additional section (RRSets are stored + * in the order they were added to the response or parsed from the + * query). + * + * \return The RRSet on position \a pos in the Additional section of \a packet + * or NULL if there is no such RRSet. + */ +const knot_rrset_t *knot_packet_additional_rrset( + knot_packet_t *packet, short pos); + +/*! + * \brief Checks if the packet already contains the given RRSet. + * + * It searches for the RRSet in the three lists of RRSets corresponding to + * Answer, Authority and Additional sections of the packet. + * + * \note Only pointers are compared, i.e. two instances of knot_rrset_t with + * the same data will be considered different. + * + * \param packet Packet to look for the RRSet in. + * \param rrset RRSet to look for. + * + * \retval 0 if \a resp does not contain \a rrset. + * \retval <> 0 if \a resp does contain \a rrset. + */ +int knot_packet_contains(const knot_packet_t *packet, + const knot_rrset_t *rrset, + knot_rrset_compare_type_t cmp); + +/*! + * \brief Adds RRSet to the list of temporary RRSets. + * + * Temporary RRSets are fully freed when the response structure is destroyed. + * + * \param response Response to which the temporary RRSet should be added. + * \param tmp_rrset Temporary RRSet to be stored in the response. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +int knot_packet_add_tmp_rrset(knot_packet_t *response, + knot_rrset_t *tmp_rrset); + +void knot_packet_free_tmp_rrsets(knot_packet_t *pkt); + +/*! + * \brief Converts the header structure to wire format. + * + * \note This function also adjusts the position (\a pos) according to + * the size of the converted wire format. + * + * \param[in] header DNS header structure to convert. + * \param[out] pos Position where to put the converted header. The space has + * to be allocated before calling this function. + * \param[out] size Size of the wire format of the header in bytes. + */ +void knot_packet_header_to_wire(const knot_header_t *header, + uint8_t **pos, size_t *size); + +int knot_packet_question_to_wire(knot_packet_t *packet); + +/*! + * \brief Converts the stored response OPT RR to wire format and adds it to + * the response wire format. + * + * \param resp Response structure. + */ +int knot_packet_edns_to_wire(knot_packet_t *packet); + +/*! + * \brief Converts the packet to wire format. + * + * \param packet Packet to be converted to wire format. + * \param wire Here the wire format of the packet will be stored. + * Space for the packet will be allocated. *resp_wire must + * be set to NULL (to avoid leaks). + * \param wire_size The size of the packet in wire format will be stored here. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + */ +int knot_packet_to_wire(knot_packet_t *packet, uint8_t **wire, + size_t *wire_size); + +const uint8_t *knot_packet_wireformat(const knot_packet_t *packet); + +/*! + * \brief Properly destroys the packet structure. + * + * \param response Packet to be destroyed. + */ +void knot_packet_free(knot_packet_t **packet); + +/*! + * \brief Dumps the whole packet in human-readable form. + * + * \note This function is empty unless KNOT_PACKET_DEBUG is defined. + * + * \param resp Packet to dump. + */ +void knot_packet_dump(const knot_packet_t *packet); + +#endif /* _KNOT_PACKET_H_ */ + +/*! @} */ diff --git a/src/libknot/packet/query.c b/src/libknot/packet/query.c new file mode 100644 index 0000000..63e902a --- /dev/null +++ b/src/libknot/packet/query.c @@ -0,0 +1,228 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include "packet/query.h" + +#include "util/error.h" +#include "util/wire.h" + +/*----------------------------------------------------------------------------*/ + +int knot_query_rr_to_wire(const knot_rrset_t *rrset, const knot_rdata_t *rdata, + uint8_t **wire, uint8_t *endp) +{ + /* Store owner. */ + knot_dname_t *owner = rrset->owner; + if (*wire + owner->size > endp) { + return KNOT_ENOMEM; + } + memcpy(*wire, owner->name, owner->size); + *wire += owner->size; + + if (*wire + 10 > endp) { + return KNOT_ENOMEM; + } + + /* Write RR header. */ + knot_wire_write_u16(*wire, rrset->type); *wire += 2; + knot_wire_write_u16(*wire, rrset->rclass); *wire += 2; + knot_wire_write_u32(*wire, rrset->ttl); *wire += 4; + knot_wire_write_u16(*wire, 0); *wire += 2; /* RDLENGTH reserve. */ + uint8_t *rdlength_p = *wire - 2; + uint16_t rdlength = 0; + + /* Write data. */ + knot_dname_t *dname = 0; + uint16_t *raw_data = 0; + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + + for (int i = 0; i < rdata->count; ++i) { + switch (desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: + + /* Check space for dname. */ + dname = knot_rdata_item(rdata, i)->dname; + if (*wire + dname->size > endp) { + return KNOT_ESPACE; + } + + /* Save domain name. */ + memcpy(*wire, dname->name, dname->size); + *wire += dname->size; + rdlength += dname->size; + break; + default: + raw_data = knot_rdata_item(rdata, i)->raw_data; + if (*wire + raw_data[0] > endp) { + return KNOT_ESPACE; + } + + /* Copy data. */ + memcpy(*wire, raw_data + 1, raw_data[0]); + *wire += raw_data[0]; + rdlength += raw_data[0]; + break; + + } + } + + /* Store rdlength. */ + knot_wire_write_u16(rdlength_p, rdlength); + + return KNOT_EOK; +} +/*----------------------------------------------------------------------------*/ + +int knot_query_dnssec_requested(const knot_packet_t *query) +{ + if (query == NULL) { + return KNOT_EBADARG; + } + + return ((knot_edns_get_version(&query->opt_rr) != EDNS_NOT_SUPPORTED) + && knot_edns_do(&query->opt_rr)); +} + +/*----------------------------------------------------------------------------*/ + +int knot_query_nsid_requested(const knot_packet_t *query) +{ + if (query == NULL) { + return KNOT_EBADARG; + } + + return ((knot_edns_get_version(&query->opt_rr) != EDNS_NOT_SUPPORTED) + && knot_edns_has_option(&query->opt_rr, EDNS_OPTION_NSID)); +} + +/*----------------------------------------------------------------------------*/ + +int knot_query_edns_supported(const knot_packet_t *query) +{ + if (query == NULL) { + return KNOT_EBADARG; + } + + return (knot_edns_get_version(&query->opt_rr) != EDNS_NOT_SUPPORTED); +} + +/*----------------------------------------------------------------------------*/ + +int knot_query_init(knot_packet_t *query) +{ + if (query == NULL) { + return KNOT_EBADARG; + } + // set the qr bit to 0 + knot_wire_flags_clear_qr(&query->header.flags1); + + uint8_t *pos = query->wireformat; + knot_packet_header_to_wire(&query->header, &pos, &query->size); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_query_set_question(knot_packet_t *query, + const knot_question_t *question) +{ + if (query == NULL || question == NULL) { + return KNOT_EBADARG; + } + + query->question.qname = question->qname; + query->question.qclass = question->qclass; + query->question.qtype = question->qtype; + query->header.qdcount = 1; + + // convert the Question to wire format right away + knot_packet_question_to_wire(query); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_query_set_opcode(knot_packet_t *query, uint8_t opcode) +{ + if (query == NULL) { + return KNOT_EBADARG; + } + // set the OPCODE in the structure + knot_wire_flags_set_opcode(&query->header.flags1, opcode); + // set the OPCODE in the wire format + knot_wire_set_opcode(query->wireformat, opcode); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_query_add_rrset_authority(knot_packet_t *query, + const knot_rrset_t *rrset) +{ + if (query == NULL || rrset == NULL) { + return KNOT_EBADARG; + } + + if (query->ns_rrsets == query->max_ns_rrsets) { + size_t oldsize = query->max_ns_rrsets * sizeof(knot_rrset_t *); + ++query->max_ns_rrsets; + size_t newsize = query->max_ns_rrsets * sizeof(knot_rrset_t *); + const knot_rrset_t ** na = malloc(newsize); + if (na == 0) { + query->max_ns_rrsets = 0; + return KNOT_ENOMEM; + } else { + memcpy(na, query->authority, oldsize); + free(query->authority); + query->authority = na; + } + } + + /* Append to packet. */ + query->authority[query->ns_rrsets] = rrset; + + /* Write to wire. */ + uint8_t *startp = query->wireformat + query->size; + uint8_t *endp = query->wireformat + query->max_size; + + assert(endp - startp > query->opt_rr.size + query->tsig_size); + // reserve space for OPT RR + endp -= query->opt_rr.size; + /*! \note [TSIG] reserve space for TSIG RR */ + endp -= query->tsig_size; + + uint8_t *pos = startp; + + const knot_rdata_t *rdata = 0; + while ((rdata = knot_rrset_rdata_next(rrset, rdata))) { + knot_query_rr_to_wire(rrset, rdata, &pos, endp); + } + + size_t written = (pos - startp); + query->size += written; + ++query->ns_rrsets; + ++query->header.nscount; + + return KNOT_EOK; +} + diff --git a/src/libknot/packet/query.h b/src/libknot/packet/query.h new file mode 100644 index 0000000..a979641 --- /dev/null +++ b/src/libknot/packet/query.h @@ -0,0 +1,93 @@ +/*! + * \file query.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief API for manipulating queries. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_QUERY_H_ +#define _KNOT_QUERY_H_ + +#include <stdint.h> +#include <string.h> + +#include "packet/packet.h" +#include "dname.h" +#include "rrset.h" +#include "edns.h" + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks if DNSSEC was requested in the query (i.e. the DO bit was set). + * + * \param query Packet where the parsed query is stored. + * + * \retval 0 if the DO bit was not set in the query, or the query is not yet + * parsed. + * \retval > 0 if DO bit was set in the query. + */ +int knot_query_dnssec_requested(const knot_packet_t *query); + +/*! + * \brief Checks if NSID was requested in the query (i.e. the NSID option was + * present in the query OPT RR). + * + * \param query Packet where the parsed query is stored. + * + * \retval 0 if the NSID option was not present in the query, or the query is + * not yet parsed. + * \retval > 0 if the NSID option was present in the query. + */ +int knot_query_nsid_requested(const knot_packet_t *query); + +int knot_query_edns_supported(const knot_packet_t *query); + +//int knot_query_set_qname(knot_packet_t *query, const knot_dname_t *qname); + +//int knot_query_set_qtype(knot_packet_t *query, uint16_t qtype); + +//int knot_query_set_qclass(knot_packet_t *query, uint16_t qclass); + +int knot_query_init(knot_packet_t *query); + +int knot_query_set_question(knot_packet_t *query, + const knot_question_t *question); + +int knot_query_set_opcode(knot_packet_t *query, uint8_t opcode); + +/*! + * \brief Adds a RRSet to the Authority section of the query. + * + * \param query Query to add the RRSet into. + * \param rrset RRSet to be added. + * + * \retval KNOT_EOK if successful, or the RRSet was already in the query. + * \retval KNOT_ENOMEM + * \retval KNOT_ESPACE + */ +int knot_query_add_rrset_authority(knot_packet_t *query, + const knot_rrset_t *rrset); + + +#endif /* _KNOT_QUERY_H_ */ + +/*! @} */ diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c new file mode 100644 index 0000000..e6f89d0 --- /dev/null +++ b/src/libknot/packet/response.c @@ -0,0 +1,1170 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> + +#include "packet/response.h" +#include "util/wire.h" +#include "util/descriptor.h" +#include "common.h" +#include "util/error.h" +#include "util/debug.h" +#include "packet/packet.h" + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Holds information about compressed domain name. + * + * Used only to pass information between functions. + * + * \todo This description should be revised and clarified. + */ +struct knot_compr_owner { + /*! + * \brief Place where the name is stored in the wire format of the + * packet. + */ + uint8_t *wire; + short size; /*!< Size of the domain name in bytes. */ + /*! \brief Position of the name relative to the start of the packet. */ + size_t pos; +}; + +typedef struct knot_compr_owner knot_compr_owner_t; + +/*! + * \brief Holds information about compressed domain names in packet. + * + * Used only to pass information between functions. + * + * \todo This description should be revised and clarified. + */ +struct knot_compr { + knot_compressed_dnames_t *table; /*!< Compression table. */ + size_t wire_pos; /*!< Current position in the wire format. */ + knot_compr_owner_t owner; /*!< Information about the current name. */ +}; + +typedef struct knot_compr knot_compr_t; + +static const size_t KNOT_RESPONSE_MAX_PTR = 16383; + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Reallocates space for compression table. + * + * \param table Compression table to reallocate space for. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +static int knot_response_realloc_compr(knot_compressed_dnames_t *table) +{ + int free_old = table->max != DEFAULT_DOMAINS_IN_RESPONSE; + size_t *old_offsets = table->offsets; + const knot_dname_t **old_dnames = table->dnames; + + short new_max_count = table->max + STEP_DOMAINS; + + size_t *new_offsets = (size_t *)malloc(new_max_count * sizeof(size_t)); + CHECK_ALLOC_LOG(new_offsets, -1); + + const knot_dname_t **new_dnames = (const knot_dname_t **)malloc( + new_max_count * sizeof(knot_dname_t *)); + if (new_dnames == NULL) { + ERR_ALLOC_FAILED; + free(new_offsets); + return KNOT_ENOMEM; + } + + memcpy(new_offsets, table->offsets, table->max * sizeof(size_t)); + memcpy(new_dnames, table->dnames, + table->max * sizeof(knot_dname_t *)); + + table->offsets = new_offsets; + table->dnames = new_dnames; + table->max = new_max_count; + + if (free_old) { + free(old_offsets); + free(old_dnames); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Stores new mapping between domain name and offset in the compression + * table. + * + * If the domain name is already present in the table, it is not inserted again. + * + * \param table Compression table to save the mapping into. + * \param dname Domain name to insert. + * \param pos Position of the domain name in the packet's wire format. + */ +static void knot_response_compr_save(knot_compressed_dnames_t *table, + const knot_dname_t *dname, size_t pos) +{ + assert(table->count < table->max); + + for (int i = 0; i < table->count; ++i) { + if (table->dnames[i] == dname) { + dbg_response("Already present, skipping..\n"); + return; + } + } + + table->dnames[table->count] = dname; + table->offsets[table->count] = pos; + ++table->count; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Stores domain name position and positions of its parent domain names + * to the compression table. + * + * If part of the domain name (\a dname) was not found previously in the + * compression table, this part and all its parent domains is stored also, to + * maximize compression potential. + * + * \param table Compression table to save the information into. + * \param dname Domain name to save. + * \param not_matched Count of labels not matched when previously searching in + * the compression table for \a dname. + * \param pos Position of the domain name in the wire format of the packet. + * \param unmatched_offset Position of the unmatched parent domain of \a dname. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +static int knot_response_store_dname_pos(knot_compressed_dnames_t *table, + const knot_dname_t *dname, + int not_matched, size_t pos, + size_t unmatched_offset, + int compr_cs) +{ +dbg_response_exec( + char *name = knot_dname_to_str(dname); + dbg_response("Putting dname %s into compression table." + " Labels not matched: %d, position: %zu," + ", pointer: %p, unmatched off: %zu\n", name, + not_matched, pos, dname, unmatched_offset); + free(name); +); + if (pos > KNOT_RESPONSE_MAX_PTR) { + dbg_response("Pointer larger than it can be, not" + " saving\n"); + return KNOT_EDNAMEPTR; + } + + if (table->count == table->max && + knot_response_realloc_compr(table) != 0) { + return KNOT_ENOMEM; + } + + // store the position of the name +// table->dnames[table->count] = dname; +// table->offsets[table->count] = pos; +// ++table->count; + + /* + * Store positions of ancestors if more than 1 label was not matched. + * + * In case the name is not in the zone, the counting to not_matched + * may be limiting, because the search stopped before after the first + * label (i.e. not_matched == 1). So we do not store the parents in + * this case. However, storing them will require creating those domain + * names, as they do not exist. + * + * The same problem is with domain names synthetized from wildcards. + * These also do not have any node to follow. + * + * We accept this as performance has higher + * priority than the best possible compression. + */ + const knot_dname_t *to_save = dname; + size_t parent_pos = pos; + int i = 0; + + while (to_save != NULL && i < knot_dname_label_count(dname)) { + if (i == not_matched) { + parent_pos = unmatched_offset; + } + +dbg_response_exec( + char *name = knot_dname_to_str(to_save); + dbg_response("Putting dname %s into compression table." + " Position: %zu, pointer: %p\n", + name, parent_pos, to_save); + free(name); +); + + if (table->count == table->max && + knot_response_realloc_compr(table) != 0) { + dbg_response("Unable to realloc.\n"); + return KNOT_ENOMEM; + } + +// dbg_response("Saving..\n"); + knot_response_compr_save(table, to_save, parent_pos); + + /*! \todo Remove '!compr_cs'. */ + // This is a temporary hack to avoid the wrong behaviour + // when the wrong not_matched count is used to compare with i + // and resulting in using the 0 offset. + // If case-sensitive search is in place, we should not save the + // node's parent's positions. + + to_save = !compr_cs && (knot_dname_node(to_save, 1) != NULL + && knot_node_parent(knot_dname_node(to_save, 1), 1) + != NULL) ? knot_node_owner(knot_node_parent( + knot_dname_node(to_save, 1), 1)) + : NULL; + + dbg_response("i: %d\n", i); + parent_pos += knot_dname_label_size(dname, i) + 1; +// parent_pos += (i > 0) +// ? knot_dname_label_size(dname, i - 1) + 1 : 0; + ++i; + } + + return KNOT_EOK; +} + +/*---------------------------------------------------------------------------*/ +/*! + * \brief Tries to find offset of domain name in the compression table. + * + * \param table Compression table to search in. + * \param dname Domain name to search for. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. + * + * \return Offset of \a dname stored in the compression table or -1 if the name + * was not found in the table. + */ +static size_t knot_response_find_dname_pos( + const knot_compressed_dnames_t *table, + const knot_dname_t *dname, int compr_cs) +{ + for (int i = 0; i < table->count; ++i) { +// dbg_response("Comparing dnames %p and %p\n", +// dname, table->dnames[i]); +//dbg_response_exec( +// char *name = knot_dname_to_str(dname); +// dbg_response("(%s and ", name); +// name = knot_dname_to_str(table->dnames[i]); +// dbg_response("%s)\n", name); +// free(name); +//); + //if (table->dnames[i] == dname) { + int ret = (compr_cs) + ? knot_dname_compare_cs(table->dnames[i], dname) + : knot_dname_compare(table->dnames[i], dname); + if (ret == 0) { + dbg_response("Found offset: %zu\n", + table->offsets[i]); + return table->offsets[i]; + } + } + return 0; +} + +/*---------------------------------------------------------------------------*/ +/*! + * \brief Put a compressed domain name to the wire format of the packet. + * + * Puts the not matched part of the domain name to the wire format and puts + * a pointer to the rest of the name after that. + * + * \param dname Domain name to put to the wire format. + * \param not_matched Size of the part of domain name that cannot be compressed. + * \param offset Position of the rest of the domain name in the packet's wire + * format. + * \param wire Place where to put the wire format of the name. + * \param max Maximum available size of the place for the wire format. + * + * \return Size of the compressed domain name put into the wire format or + * KNOT_ESPACE if it did not fit. + */ +static int knot_response_put_dname_ptr(const knot_dname_t *dname, + int not_matched, size_t offset, + uint8_t *wire, size_t max) +{ + // put the not matched labels + short size = knot_dname_size_part(dname, not_matched); + if (size + 2 > max) { + return KNOT_ESPACE; + } + + memcpy(wire, knot_dname_name(dname), size); + knot_wire_put_pointer(wire + size, offset); + + dbg_response("Size of the dname with ptr: %d\n", size + 2); + + return size + 2; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tries to compress domain name and creates its wire format. + * + * \param dname Domain name to convert and compress. + * \param compr Compression table holding information about offsets of domain + * names in the packet. + * \param dname_wire Place where to put the wire format of the name. + * \param max Maximum available size of the place for the wire format. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. + * + * \return Size of the domain name's wire format or KNOT_ESPACE if it did not + * fit into the provided space. + */ +static int knot_response_compress_dname(const knot_dname_t *dname, + knot_compr_t *compr, uint8_t *dname_wire, size_t max, int compr_cs) +{ + int size = 0; + /*! + * \todo Compress!! + * + * if pos == 0, do not store the position! + */ + + // try to find the name or one of its ancestors in the compr. table +#ifdef COMPRESSION_PEDANTIC + //knot_dname_t *to_find = knot_dname_copy(dname); + knot_dname_t *to_find = (knot_dname_t *)dname; + int copied = 0; +#else + const knot_dname_t *to_find = dname; +#endif + size_t offset = 0; + int not_matched = 0; + + while (to_find != NULL && knot_dname_label_count(to_find) != 0) { +dbg_response_exec( + char *name = knot_dname_to_str(to_find); + dbg_response("Searching for name %s in the compression" + " table, not matched labels: %d\n", name, + not_matched); + free(name); +); + offset = knot_response_find_dname_pos(compr->table, to_find, + compr_cs); + if (offset == 0) { + ++not_matched; + } else { + break; + } +#ifdef COMPRESSION_PEDANTIC + if (compr_cs || to_find->node == NULL + || to_find->node->owner != to_find + || to_find->node->parent == NULL) { + if (!copied) { + to_find = knot_dname_left_chop(to_find); + copied = 1; + } else { + knot_dname_left_chop_no_copy(to_find); + } + } else { + assert(to_find->node != to_find->node->parent); + assert(to_find != to_find->node->parent->owner); + to_find = to_find->node->parent->owner; + } +#else + // if case-sensitive comparation, we cannot just take the parent + if (compr_cs || knot_dname_node(to_find, 1) == NULL + || knot_node_owner(knot_dname_node(to_find, 1)) != to_find + || knot_node_parent(knot_dname_node(to_find, 1), 1) + == NULL) { + dbg_response("compr_cs: %d\n", compr_cs); + dbg_response("knot_dname_node(to_find, 1) == %p" + "\n", knot_dname_node(to_find, 1)); + + if (knot_dname_node(to_find, 1) != NULL) { + dbg_response("knot_node_owner(knot_dname_node(" + "to_find, 1)) = %p, to_find = %p\n", + knot_node_owner(knot_dname_node(to_find, 1)), + to_find); + dbg_response("knot_node_parent(knot_dname_node(" + "to_find, 1), 1) = %p\n", + knot_node_parent(knot_dname_node(to_find, 1), 1)); + } + break; + } else { + assert(knot_dname_node(to_find, 1) != + knot_node_parent(knot_dname_node(to_find, 1), 1)); + assert(to_find != knot_node_owner( + knot_node_parent(knot_dname_node(to_find, 1), 1))); + to_find = knot_node_owner( + knot_node_parent(knot_dname_node(to_find, 1), 1)); + dbg_response("New to_find: %p\n", to_find); + } +#endif + } + +#ifdef COMPRESSION_PEDANTIC + if (copied) { + knot_dname_free(&to_find); + } +#endif + + dbg_response("Max size available for domain name: %zu\n", max); + + if (offset > 0) { // found such dname somewhere in the packet + dbg_response("Found name in the compression table.\n"); + assert(offset >= KNOT_WIRE_HEADER_SIZE); + size = knot_response_put_dname_ptr(dname, not_matched, offset, + dname_wire, max); + if (size <= 0) { + return KNOT_ESPACE; + } + } else { + dbg_response("Not found, putting whole name.\n"); + // now just copy the dname without compressing + if (dname->size > max) { + return KNOT_ESPACE; + } + + memcpy(dname_wire, dname->name, dname->size); + size = dname->size; + } + + // in either way, put info into the compression table + /*! \todo This is useless if the name was already in the table. + * It is meaningful only if the found name is the one from QNAME + * and thus its parents are not stored yet. + */ + assert(compr->wire_pos >= 0); + + if (knot_response_store_dname_pos(compr->table, dname, not_matched, + compr->wire_pos, offset, compr_cs) + != 0) { + dbg_response("Compression info could not be stored." + "\n"); + } + + return size; +} + +/*---------------------------------------------------------------------------*/ +/*! + * \brief Convert one RR into wire format. + * + * \param[in] rrset RRSet to which the RR belongs. + * \param[in] rdata The actual RDATA of this RR. + * \param[in] compr Information about compressed domain names in the packet. + * \param[out] rrset_wire Place to put the wire format of the RR into. + * \param[in] max_size Size of space available for the wire format. + * \param[in] compr_cs Set to <> 0 if dname compression should use case + * sensitive comparation. Set to 0 otherwise. + * + * \return Size of the RR's wire format or KNOT_ESPACE if it did not fit into + * the provided space. + */ +static int knot_response_rr_to_wire(const knot_rrset_t *rrset, + const knot_rdata_t *rdata, + knot_compr_t *compr, + uint8_t **rrset_wire, size_t max_size, + int compr_cs) +{ + int size = 0; + + dbg_response("Max size: %zu, owner pos: %zu, owner size: %d\n", + max_size, compr->owner.pos, compr->owner.size); + + if (size + ((compr->owner.pos == 0 + || compr->owner.pos > KNOT_RESPONSE_MAX_PTR) + ? compr->owner.size : 2) + 10 + > max_size) { + return KNOT_ESPACE; + } + + dbg_response("Owner position: %zu\n", compr->owner.pos); + + // put owner if needed (already compressed) + if (compr->owner.pos == 0 || compr->owner.pos > KNOT_RESPONSE_MAX_PTR) { + memcpy(*rrset_wire, compr->owner.wire, compr->owner.size); + compr->owner.pos = compr->wire_pos; + *rrset_wire += compr->owner.size; + size += compr->owner.size; + } else { + dbg_response("Putting pointer: %zu\n", + compr->owner.pos); + knot_wire_put_pointer(*rrset_wire, compr->owner.pos); + *rrset_wire += 2; + size += 2; + } + + dbg_response("Max size: %zu, size: %d\n", max_size, size); + + dbg_response("Wire format:\n"); + + // put rest of RR 'header' + knot_wire_write_u16(*rrset_wire, rrset->type); + dbg_response(" Type: %u\n", rrset->type); + dbg_response(" Type in wire: "); + dbg_response_hex((char *)*rrset_wire, 2); + *rrset_wire += 2; + + knot_wire_write_u16(*rrset_wire, rrset->rclass); + dbg_response(" Class: %u\n", rrset->rclass); + dbg_response(" Class in wire: "); + dbg_response_hex((char *)*rrset_wire, 2); + *rrset_wire += 2; + + knot_wire_write_u32(*rrset_wire, rrset->ttl); + dbg_response(" TTL: %u\n", rrset->ttl); + dbg_response(" TTL in wire: "); + dbg_response_hex((char *)*rrset_wire, 4); + *rrset_wire += 4; + + // save space for RDLENGTH + uint8_t *rdlength_pos = *rrset_wire; + *rrset_wire += 2; + + size += 10; + compr->wire_pos += size; + + dbg_response("Max size: %zu, size: %d\n", max_size, size); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + + uint16_t rdlength = 0; + + for (int i = 0; i < rdata->count; ++i) { + if (max_size < size + rdlength) { + return KNOT_ESPACE; + } + + switch (desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: { + int ret = knot_response_compress_dname( + knot_rdata_item(rdata, i)->dname, + compr, *rrset_wire, max_size - size - rdlength, + compr_cs); + + if (ret < 0) { + return KNOT_ESPACE; + } + + dbg_response("Compressed dname size: %d\n", + ret); + *rrset_wire += ret; + rdlength += ret; + compr->wire_pos += ret; + // TODO: compress domain name + break; + } + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: { + knot_dname_t *dname = + knot_rdata_item(rdata, i)->dname; + if (size + rdlength + dname->size > max_size) { + return KNOT_ESPACE; + } + + // save whole domain name + memcpy(*rrset_wire, dname->name, dname->size); + dbg_response("Uncompressed dname size: %d\n", + dname->size); + *rrset_wire += dname->size; + rdlength += dname->size; + compr->wire_pos += dname->size; + break; + } +// case KNOT_RDATA_WF_BINARYWITHLENGTH: { +// uint16_t *raw_data = +// knot_rdata_item(rdata, i)->raw_data; + +// if (size + raw_data[0] + 1 > max_size) { +// return KNOT_ESPACE; +// } + +// // copy also the rdata item size +// assert(raw_data[0] < 256); +// **rrset_wire = raw_data[0]; +// *rrset_wire += 1; +// memcpy(*rrset_wire, raw_data + 1, raw_data[0]); +// dbg_response("Raw data size: %d\n", +// raw_data[0] + 1); +// *rrset_wire += raw_data[0]; +// rdlength += raw_data[0] + 1; +// compr->wire_pos += raw_data[0] + 1; +// break; +// } + default: { + uint16_t *raw_data = + knot_rdata_item(rdata, i)->raw_data; + + if (size + rdlength + raw_data[0] > max_size) { + return KNOT_ESPACE; + } + + // copy just the rdata item data (without size) + memcpy(*rrset_wire, raw_data + 1, raw_data[0]); + dbg_response("Raw data size: %d\n", + raw_data[0]); + *rrset_wire += raw_data[0]; + rdlength += raw_data[0]; + compr->wire_pos += raw_data[0]; + break; + } + } + } + + dbg_response("Max size: %zu, size: %d\n", max_size, size); + + assert(size + rdlength <= max_size); + size += rdlength; + knot_wire_write_u16(rdlength_pos, rdlength); + + return size; +} + +/*---------------------------------------------------------------------------*/ +/*! + * \brief Convert whole RRSet into wire format. + * + * \param[in] rrset RRSet to convert + * \param[out] pos Place where to put the wire format. + * \param[out] size Size of the converted wire format. + * \param[in] max_size Maximum available space for the wire format. + * \param wire_pos Current position in the wire format of the whole packet. + * \param owner_tmp Wire format of the RRSet's owner, possibly compressed. + * \param compr Information about compressed domain names in the packet. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. + * + * \return Size of the RRSet's wire format or KNOT_ESPACE if it did not fit + * into the provided space. + */ +static int knot_response_rrset_to_wire(const knot_rrset_t *rrset, + uint8_t **pos, size_t *size, + size_t max_size, size_t wire_pos, + uint8_t *owner_tmp, + knot_compressed_dnames_t *compr, + int compr_cs) +{ +dbg_response_exec( + char *name = knot_dname_to_str(rrset->owner); + dbg_response("Converting RRSet with owner %s, type %s\n", + name, knot_rrtype_to_string(rrset->type)); + free(name); + dbg_response(" Size before: %zu\n", *size); +); + + // if no RDATA in RRSet, return + if (rrset->rdata == NULL) { + return KNOT_EOK; + } + + //uint8_t *rrset_wire = (uint8_t *)malloc(PREALLOC_RRSET_WIRE); + //short rrset_size = 0; + + //uint8_t *owner_wire = (uint8_t *)malloc(rrset->owner->size); + /* + * We may pass the current position to the compression function + * because if the owner will be put somewhere, it will be on the + * current position (first item of a RR). If it will not be put into + * the wireformat, we may remove the dname (and possibly its parents) + * from the compression table. + */ + + knot_compr_t compr_info; + //compr_info.new_entries = 0; + compr_info.table = compr; + compr_info.wire_pos = wire_pos; + compr_info.owner.pos = 0; + compr_info.owner.wire = owner_tmp; + compr_info.owner.size = + knot_response_compress_dname(rrset->owner, &compr_info, + owner_tmp, max_size, compr_cs); + + dbg_response(" Owner size: %d, position: %zu\n", + compr_info.owner.size, compr_info.owner.pos); + if (compr_info.owner.size < 0) { + return KNOT_ESPACE; + } + + int rrs = 0; + short rrset_size = 0; + + const knot_rdata_t *rdata = rrset->rdata; + do { + int ret = knot_response_rr_to_wire(rrset, rdata, &compr_info, + pos, max_size - rrset_size, + compr_cs); + + assert(ret != 0); + + if (ret < 0) { + // some RR didn't fit in, so no RRs should be used + // TODO: remove last entries from compression table + dbg_response("Some RR didn't fit in.\n"); + return KNOT_ESPACE; + } + + dbg_response("RR of size %d added.\n", ret); + rrset_size += ret; + ++rrs; + } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL); + + //memcpy(*pos, rrset_wire, rrset_size); + //*size += rrset_size; + //*pos += rrset_size; + + // the whole RRSet did fit in + assert (rrset_size <= max_size); + *size += rrset_size; + + dbg_response(" Size after: %zu\n", *size); + + return rrs; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tries to add RRSet to the response. + * + * This function tries to convert the RRSet to wire format and add it to the + * wire format of the response and if successful, adds the RRSet to the given + * list (and updates its size). If the RRSet did not fit into the available + * space (\a max_size), it is omitted as a whole and the TC bit may be set + * (according to \a tc). + * + * \param rrsets Lists of RRSets to which this RRSet should be added. + * \param rrset_count Number of RRSets in the list. + * \param resp Response structure where the RRSet should be added. + * \param max_size Maximum available space in wire format of the response. + * \param rrset RRSet to add. + * \param tc Set to <> 0 if omitting the RRSet should cause the TC bit to be + * set in the response. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. + * + * \return Count of RRs added to the response or KNOT_ESPACE if the RRSet did + * not fit in the available space. + */ +static int knot_response_try_add_rrset(const knot_rrset_t **rrsets, + short *rrset_count, + knot_packet_t *resp, + size_t max_size, + const knot_rrset_t *rrset, int tc, + int compr_cs) +{ + //short size = knot_response_rrset_size(rrset, &resp->compression); + +dbg_response_exec( + char *name = knot_dname_to_str(rrset->owner); + dbg_response("\nAdding RRSet with owner %s and type %s: \n", + name, knot_rrtype_to_string(rrset->type)); + free(name); +); + + uint8_t *pos = resp->wireformat + resp->size; + size_t size = 0; + int rrs = knot_response_rrset_to_wire(rrset, &pos, &size, max_size, + resp->size, resp->owner_tmp, + &resp->compression, compr_cs); + + if (rrs >= 0) { + rrsets[(*rrset_count)++] = rrset; + resp->size += size; + dbg_response("RRset added, size: %zu, RRs: %d, total " + "size of response: %zu\n\n", size, rrs, + resp->size); + } else if (tc) { + dbg_response("Setting TC bit.\n"); + knot_wire_flags_set_tc(&resp->header.flags1); + knot_wire_set_tc(resp->wireformat); + } + + return rrs; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Reallocate space for RRSets. + * + * \param rrsets Space for RRSets. + * \param max_count Size of the space available for the RRSets. + * \param default_max_count Size of the space pre-allocated for the RRSets when + * the response structure was initialized. + * \param step How much the space should be increased. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +static int knot_response_realloc_rrsets(const knot_rrset_t ***rrsets, + short *max_count, + short default_max_count, short step) +{ + int free_old = (*max_count) != default_max_count; + const knot_rrset_t **old = *rrsets; + + short new_max_count = *max_count + step; + const knot_rrset_t **new_rrsets = (const knot_rrset_t **)malloc( + new_max_count * sizeof(knot_rrset_t *)); + CHECK_ALLOC_LOG(new_rrsets, KNOT_ENOMEM); + + memcpy(new_rrsets, *rrsets, (*max_count) * sizeof(knot_rrset_t *)); + + *rrsets = new_rrsets; + *max_count = new_max_count; + + if (free_old) { + free(old); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +int knot_response_init(knot_packet_t *response) +{ + if (response == NULL) { + return KNOT_EBADARG; + } + + if (response->max_size < KNOT_WIRE_HEADER_SIZE) { + return KNOT_ESPACE; + } + + // set the qr bit to 1 + knot_wire_flags_set_qr(&response->header.flags1); + + uint8_t *pos = response->wireformat; + knot_packet_header_to_wire(&response->header, &pos, + &response->size); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_response_init_from_query(knot_packet_t *response, + knot_packet_t *query) +{ + + if (response == NULL || query == NULL) { + return KNOT_EBADARG; + } + + // copy the header from the query + memcpy(&response->header, &query->header, sizeof(knot_header_t)); +// memmove(&response->header, &query->header, sizeof(knot_header_t)); + + // copy the Question section (but do not copy the QNAME) + memcpy(&response->question, &query->question, + sizeof(knot_question_t)); +// memmove(&response->question, &query->question, +// sizeof(knot_question_t)); + + int err = 0; + // put the qname into the compression table + // TODO: get rid of the numeric constants + if ((err = knot_response_store_dname_pos(&response->compression, + response->question.qname, 0, 12, 12, 0)) != KNOT_EOK) { + return err; + } + + // copy the wireformat of Header and Question from the query + // TODO: get rid of the numeric constants + size_t to_copy = 12 + 4 + knot_dname_size(response->question.qname); + + assert(response->max_size >= to_copy); +// printf("Resp init from query: Copying from: %p to: %p size: %d\n", +// response->wireformat, query->wireformat, +// to_copy); +// printf("Resp init from query: Question name size: %d Query name size: %d\n", +// knot_dname_size(response->question.qname), +// knot_dname_size(query->question.qname)); + memcpy(response->wireformat, query->wireformat, to_copy); + response->size = to_copy; + + // set the qr bit to 1 + knot_wire_flags_set_qr(&response->header.flags1); + knot_wire_set_qr(response->wireformat); + + // clear AD flag + knot_wire_flags_clear_ad(&response->header.flags2); + knot_wire_clear_ad(response->wireformat); + + // clear RA flag + knot_wire_flags_clear_ra(&response->header.flags2); + knot_wire_clear_ad(response->wireformat); + + // set counts to 0 + response->header.ancount = 0; + response->header.nscount = 0; + response->header.arcount = 0; + + response->query = query; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +void knot_response_clear(knot_packet_t *resp, int clear_question) +{ + if (resp == NULL) { + return; + } + + resp->size = (clear_question) ? KNOT_WIRE_HEADER_SIZE + : KNOT_WIRE_HEADER_SIZE + 4 + + knot_dname_size(resp->question.qname); + resp->an_rrsets = 0; + resp->ns_rrsets = 0; + resp->ar_rrsets = 0; + resp->compression.count = 0; + knot_packet_free_tmp_rrsets(resp); + resp->tmp_rrsets_count = 0; + resp->header.ancount = 0; + resp->header.nscount = 0; + resp->header.arcount = 0; +} + +/*----------------------------------------------------------------------------*/ + +int knot_response_add_opt(knot_packet_t *resp, + const knot_opt_rr_t *opt_rr, + int override_max_size) +{ + if (resp == NULL || opt_rr == NULL) { + return KNOT_EBADARG; + } + + // copy the OPT RR + resp->opt_rr.version = opt_rr->version; + resp->opt_rr.ext_rcode = opt_rr->ext_rcode; + resp->opt_rr.payload = opt_rr->payload; + resp->opt_rr.size = opt_rr->size; + + // if max size is set, it means there is some reason to be that way, + // so we can't just set it to higher value + + if (override_max_size && resp->max_size > 0 + && resp->max_size < opt_rr->payload) { + return KNOT_EPAYLOAD; + } + + // set max size (less is OK) + if (override_max_size) { + dbg_response("Overriding max size to: %u\n", + resp->opt_rr.payload); + return knot_packet_set_max_size(resp, resp->opt_rr.payload); + //resp->max_size = resp->opt_rr.payload; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_response_add_rrset_answer(knot_packet_t *response, + const knot_rrset_t *rrset, int tc, + int check_duplicates, int compr_cs) +{ + if (response == NULL || rrset == NULL) { + return KNOT_EBADARG; + } + + dbg_response("add_rrset_answer()\n"); + assert(response->header.arcount == 0); + assert(response->header.nscount == 0); + + if (response->an_rrsets == response->max_an_rrsets + && knot_response_realloc_rrsets(&response->answer, + &response->max_an_rrsets, DEFAULT_ANCOUNT, STEP_ANCOUNT) + != KNOT_EOK) { + return KNOT_ENOMEM; + } + + if (check_duplicates && knot_packet_contains(response, rrset, + KNOT_RRSET_COMPARE_PTR)) { + return KNOT_EOK; + } + + dbg_response("Trying to add RRSet to Answer section.\n"); + dbg_response("RRset: %p\n", rrset); + dbg_response("Owner: %p\n", rrset->owner); + + int rrs = knot_response_try_add_rrset(response->answer, + &response->an_rrsets, response, + response->max_size + - response->size + - response->opt_rr.size + - response->tsig_size, + rrset, tc, compr_cs); + + if (rrs >= 0) { + response->header.ancount += rrs; + return KNOT_EOK; + } + + return KNOT_ESPACE; +} + +/*----------------------------------------------------------------------------*/ + +int knot_response_add_rrset_authority(knot_packet_t *response, + const knot_rrset_t *rrset, int tc, + int check_duplicates, int compr_cs) +{ + if (response == NULL || rrset == NULL) { + return KNOT_EBADARG; + } + + assert(response->header.arcount == 0); + + if (response->ns_rrsets == response->max_ns_rrsets + && knot_response_realloc_rrsets(&response->authority, + &response->max_ns_rrsets, DEFAULT_NSCOUNT, STEP_NSCOUNT) + != 0) { + return KNOT_ENOMEM; + } + + if (check_duplicates && knot_packet_contains(response, rrset, + KNOT_RRSET_COMPARE_PTR)) { + return KNOT_EOK; + } + + dbg_response("Trying to add RRSet to Authority section.\n"); + + int rrs = knot_response_try_add_rrset(response->authority, + &response->ns_rrsets, response, + response->max_size + - response->size + - response->opt_rr.size + - response->tsig_size, + rrset, tc, compr_cs); + + if (rrs >= 0) { + response->header.nscount += rrs; + return KNOT_EOK; + } + + return KNOT_ESPACE; +} + +/*----------------------------------------------------------------------------*/ + +int knot_response_add_rrset_additional(knot_packet_t *response, + const knot_rrset_t *rrset, int tc, + int check_duplicates, int compr_cs) +{ + if (response == NULL || rrset == NULL) { + return KNOT_EBADARG; + } + + int ret; + + // if this is the first additional RRSet, add EDNS OPT RR first + if (response->header.arcount == 0 + && response->opt_rr.version != EDNS_NOT_SUPPORTED + && (ret = knot_packet_edns_to_wire(response)) != KNOT_EOK) { + return ret; + } + + if (response->ar_rrsets == response->max_ar_rrsets + && knot_response_realloc_rrsets(&response->additional, + &response->max_ar_rrsets, DEFAULT_ARCOUNT, STEP_ARCOUNT) + != 0) { + return KNOT_ENOMEM; + } + + if (check_duplicates && knot_packet_contains(response, rrset, + KNOT_RRSET_COMPARE_PTR)) { + return KNOT_EOK; + } + + dbg_response("Trying to add RRSet to Additional section.\n"); + + int rrs = knot_response_try_add_rrset(response->additional, + &response->ar_rrsets, response, + response->max_size + - response->size + - response->tsig_size, rrset, + tc, compr_cs); + + if (rrs >= 0) { + response->header.arcount += rrs; + return KNOT_EOK; + } + + return KNOT_ESPACE; +} + +/*----------------------------------------------------------------------------*/ + +void knot_response_set_rcode(knot_packet_t *response, short rcode) +{ + if (response == NULL) { + return; + } + + knot_wire_flags_set_rcode(&response->header.flags2, rcode); + knot_wire_set_rcode(response->wireformat, rcode); +} + +/*----------------------------------------------------------------------------*/ + +void knot_response_set_aa(knot_packet_t *response) +{ + if (response == NULL) { + return; + } + + knot_wire_flags_set_aa(&response->header.flags1); + knot_wire_set_aa(response->wireformat); +} + +/*----------------------------------------------------------------------------*/ + +void knot_response_set_tc(knot_packet_t *response) +{ + if (response == NULL) { + return; + } + + knot_wire_flags_set_tc(&response->header.flags1); + knot_wire_set_tc(response->wireformat); +} + +/*----------------------------------------------------------------------------*/ + +int knot_response_add_nsid(knot_packet_t *response, const uint8_t *data, + uint16_t length) +{ + if (response == NULL) { + return KNOT_EBADARG; + } + + return knot_edns_add_option(&response->opt_rr, + EDNS_OPTION_NSID, length, data); +} diff --git a/src/libknot/packet/response.h b/src/libknot/packet/response.h new file mode 100644 index 0000000..38bd9a8 --- /dev/null +++ b/src/libknot/packet/response.h @@ -0,0 +1,198 @@ +/*! + * \file response.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief API for response manipulation. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_response_H_ +#define _KNOT_response_H_ + +#include <stdint.h> +#include <string.h> + +#include "packet/packet.h" + +#include "dname.h" +#include "rrset.h" +#include "edns.h" + +/*! + * \brief Default maximum DNS response size + * + * This size must be supported by all servers and clients. + */ +static const short KNOT_MAX_RESPONSE_SIZE = 512; + +/*----------------------------------------------------------------------------*/ +int knot_response_init(knot_packet_t *response); + +/*! + * \brief Initializes response from the given query. + * + * Copies the header, Changes QR bit to 1, copies the Question section and + * stores pointer to the query packet structure in the response packet + * structure. + * + * \warning Never free the query packet structure after calling this function, + * it will be freed when the response structure is freed. + * + * \param response Packet structure representing the response. + * \param query Packet structure representing the query. + * + * \retval KNOT_EOK + */ +int knot_response_init_from_query(knot_packet_t *response, + knot_packet_t *query); + +/*! + * \brief Clears the response structure for reuse. + * + * After call to this function, the response will be in the same state as if + * knot_response_new() was called. The maximum wire size is retained. + * + * \param response Response structure to clear. + * + * \todo Replace the use of this function with something else maybe? + */ +void knot_response_clear(knot_packet_t *resp, int clear_question); + +/*! + * \brief Sets the OPT RR of the response. + * + * This function also allocates space for the wireformat of the response, if + * the payload in the OPT RR is larger than the current maximum size of the + * response and copies the current wireformat over to the new space. + * + * \note The contents of the OPT RR are copied. + * + * \param resp Response to set the OPT RR to. + * \param opt_rr OPT RR to set. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + * + * \todo Needs test. + */ +int knot_response_add_opt(knot_packet_t *resp, + const knot_opt_rr_t *opt_rr, + int override_max_size); + +/*! + * \brief Adds a RRSet to the Answer section of the response. + * + * \param response Response to add the RRSet into. + * \param rrset RRSet to be added. + * \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set. + * Otherwise set to 0. + * \param check_duplicates Set to <> 0 if the RRSet should not be added to the + * response in case it is already there. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. + * + * \retval KNOT_EOK if successful, or the RRSet was already in the answer. + * \retval KNOT_ENOMEM + * \retval KNOT_ESPACE + */ +int knot_response_add_rrset_answer(knot_packet_t *response, + const knot_rrset_t *rrset, int tc, + int check_duplicates, int compr_cs); + +/*! + * \brief Adds a RRSet to the Authority section of the response. + * + * \param response Response to add the RRSet into. + * \param rrset RRSet to be added. + * \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set. + * Otherwise set to 0. + * \param check_duplicates Set to <> 0 if the RRSet should not be added to the + * response in case it is already there. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. + * + * \retval KNOT_EOK if successful, or the RRSet was already in the answer. + * \retval KNOT_ENOMEM + * \retval KNOT_ESPACE + */ +int knot_response_add_rrset_authority(knot_packet_t *response, + const knot_rrset_t *rrset, int tc, + int check_duplicates, int compr_cs); + +/*! + * \brief Adds a RRSet to the Additional section of the response. + * + * \param response Response to add the RRSet into. + * \param rrset RRSet to be added. + * \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set. + * Otherwise set to 0. + * \param check_duplicates Set to <> 0 if the RRSet should not be added to the + * response in case it is already there. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. + * + * \retval KNOT_EOK if successful, or the RRSet was already in the answer. + * \retval KNOT_ENOMEM + * \retval KNOT_ESPACE + */ +int knot_response_add_rrset_additional(knot_packet_t *response, + const knot_rrset_t *rrset, int tc, + int check_duplicates, int compr_cs); + +/*! + * \brief Sets the RCODE of the response. + * + * \param response Response to set the RCODE in. + * \param rcode RCODE to set. + */ +void knot_response_set_rcode(knot_packet_t *response, short rcode); + +/*! + * \brief Sets the AA bit of the response to 1. + * + * \param response Response in which the AA bit should be set. + */ +void knot_response_set_aa(knot_packet_t *response); + +/*! + * \brief Sets the TC bit of the response to 1. + * + * \param response Response in which the TC bit should be set. + */ +void knot_response_set_tc(knot_packet_t *response); + +/*! + * \brief Adds NSID option to the response. + * + * \param response Response to add the NSID option into. + * \param data NSID data. + * \param length Size of NSID data in bytes. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +int knot_response_add_nsid(knot_packet_t *response, const uint8_t *data, + uint16_t length); + +#endif /* _KNOT_response_H_ */ + +/*! @} */ diff --git a/src/libknot/rdata.c b/src/libknot/rdata.c new file mode 100644 index 0000000..0c51f5b --- /dev/null +++ b/src/libknot/rdata.c @@ -0,0 +1,838 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdint.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <stdio.h> + +#include "common.h" +#include "rdata.h" +#include "util/descriptor.h" +#include "dname.h" +#include "util/error.h" +#include "zone/node.h" +#include "util/utils.h" +#include "util/debug.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Compares two RDATA items as binary data. + * + * \param d1 First item. + * \param d2 Second item. + * \param count1 Size of the first item in bytes. If set to < 0, the size will + * be taken from the first two bytes of \a d1. + * \param count2 Size of the second item in bytes. If set to < 0, the size will + * be taken from the first two bytes of \a d2. + * + * \retval 0 if the items are identical. + * \retval < 0 if \a d1 goes before \a d2 in canonical order. + * \retval > 0 if \a d1 goes after \a d2 in canonical order. + */ +static int knot_rdata_compare_binary(const uint8_t *d1, const uint8_t *d2, + int count1, int count2) +{ + int i1 = 0, i2 = 0; + + // length stored in the first octet + if (count1 < 0) { + // take count from the first two bytes + count1 = (int)(*(uint16_t *)d1); + // and start from the third byte + i1 = 2; + } + if (count2 < 0) { // dtto + count2 = (int)(*(uint16_t *)d2); + i2 = 2; + } + + + while (i1 < count1 && i2 < count2 && d1[i1] == d2[i2]) { + ++i1; + ++i2; + } + + if (i1 == count1 && i2 == count2) { + return 0; + } + + if (i1 == count1 && i2 < count2) { + return -1; + } else if (i2 == count2 && i1 < count1) { + return 1; + } else { + assert(i1 < count1 && i2 < count2); + return (d1[i1] < d2[i2]) ? -1 : 1; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Retrieves the domain name from MX RDATA. + * + * \note This is only convenience function. It does not (and cannot) check if + * the given RDATA is of the right type, so it always returns the second + * RDATA item, even if it is not a domain name. + * + * \param rdata RDATA to get the MX domain name from. + * + * \return MX domain name stored in \a rdata or NULL if \a rdata has less than 2 + * items. + */ +static const knot_dname_t *knot_rdata_mx_name(const knot_rdata_t *rdata) +{ + if (rdata->count < 2) { + return NULL; + } + return rdata->items[1].dname; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Retrieves the domain name from NS RDATA. + * + * \note This is only convenience function. It does not (and cannot) check if + * the given RDATA is of the right type, so it always returns the first + * RDATA item, even if it is not a domain name. + * + * \param rdata RDATA to get the NS domain name from. + * + * \return NS domain name stored in \a rdata or NULL if \a rdata has no items. + */ +static const knot_dname_t *knot_rdata_ns_name(const knot_rdata_t *rdata) +{ + if (rdata->count < 1) { + return NULL; + } + return rdata->items[0].dname; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Retrieves the domain name from SRV RDATA. + * + * \note This is only convenience function. It does not (and cannot) check if + * the given RDATA is of the right type, so it always returns the fourth + * RDATA item, even if it is not a domain name. + * + * \param rdata RDATA to get the SRV domain name from. + * + * \return SRV domain name stored in \a rdata or NULL if \a rdata has less than + * 4 items. + */ +static const knot_dname_t *knot_rdata_srv_name(const knot_rdata_t *rdata) +{ + if (rdata->count < 4) { + return NULL; + } + return rdata->items[3].dname; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_rdata_t *knot_rdata_new() +{ + knot_rdata_t *rdata = + (knot_rdata_t *)malloc(sizeof(knot_rdata_t)); + if (rdata == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + rdata->items = NULL; + rdata->count = 0; + rdata->next = NULL; + + return rdata; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, + size_t *pos, size_t total_size, size_t rdlength, + const knot_rrtype_descriptor_t *desc) +{ + int i = 0; + uint8_t item_type; + size_t parsed = 0; + + if (rdlength == 0) { + rdata->items = NULL; + return KNOT_EOK; + } + + knot_rdata_item_t *items = (knot_rdata_item_t *)malloc( + desc->length * sizeof(knot_rdata_item_t)); + CHECK_ALLOC_LOG(items, KNOT_ENOMEM); + + size_t item_size = 0; + uint8_t gateway_type = 0; // only to handle IPSECKEY record + knot_dname_t *dname = NULL; + + while (i < desc->length && (desc->fixed_items || parsed < rdlength)) { + + item_type = desc->wireformat[i]; + item_size = 0; + + size_t pos2; + + switch (item_type) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: + pos2 = *pos; + dname = knot_dname_parse_from_wire( + wire, &pos2, total_size, NULL); + if (dname == NULL) { + free(items); + return KNOT_ERROR; + } + items[i].dname = dname; + //*pos += dname->size; + parsed += pos2 - *pos; + *pos = pos2; + dname = 0; + break; + case KNOT_RDATA_WF_BYTE: + if (desc->type == KNOT_RRTYPE_IPSECKEY && i == 1) { + gateway_type = *(wire + *pos); + } + item_size = 1; + break; + case KNOT_RDATA_WF_SHORT: + item_size = 2; + break; + case KNOT_RDATA_WF_LONG: + item_size = 4; + break; + case KNOT_RDATA_WF_UINT48: + item_size = 6; + break; + case KNOT_RDATA_WF_TEXT: + item_size = rdlength - parsed; + break; + case KNOT_RDATA_WF_TEXT_SINGLE: + item_size = *(wire + *pos) + 1; + break; + case KNOT_RDATA_WF_A: + item_size = 4; + break; + case KNOT_RDATA_WF_AAAA: + item_size = 16; + break; + case KNOT_RDATA_WF_BINARY: + item_size = rdlength - parsed; + break; + case KNOT_RDATA_WF_BINARYWITHLENGTH: + item_size = *(wire + *pos) + 1; + break; + case KNOT_RDATA_WF_BINARYWITHSHORT: + item_size = knot_wire_read_u16(wire + *pos) + 2; + break; + case KNOT_RDATA_WF_APL: + // WTF? what to do with this?? + // Same as TXT, I guess. + item_size = rdlength - parsed; + break; + case KNOT_RDATA_WF_IPSECGATEWAY: + // determine size based on the 'gateway type' field + switch (gateway_type) { + case 0: + item_size = 0; + break; + case 1: + item_size = 4; + break; + case 2: + item_size = 16; + break; + case 3: + pos2 = *pos; + fprintf(stderr, "reading dname from pos: %zu\n", pos2); + dname = + knot_dname_parse_from_wire( + wire, &pos2, total_size, NULL); + if (dname == NULL) { + return KNOT_ERROR; + } + items[i].dname = dname; + //*pos += dname->size; + parsed += pos2 - *pos; + + fprintf(stderr, "read %zu bytes.\n", parsed); + *pos = pos2; + dname = 0; + break; + default: + assert(0); + } + + break; + default: + return KNOT_EMALF; + + } + + if (item_size != 0) { + if (parsed + item_size > rdlength) { + free(items); + return KNOT_EFEWDATA; + } + + items[i].raw_data = (uint16_t *)malloc(item_size + 2); + if (items[i].raw_data == NULL) { + free(items); + return KNOT_ENOMEM; + } + memcpy(items[i].raw_data, &item_size, 2); + memcpy(items[i].raw_data + 1, wire + *pos, item_size); + *pos += item_size; + parsed += item_size; + } else if (item_type == KNOT_RDATA_WF_BINARY + || item_type == KNOT_RDATA_WF_IPSECGATEWAY) { + fprintf(stderr, "item_size was 0, creating empty rdata item.\n"); + // in this case we are at the end of the RDATA + // and should create an empty RDATA item + items[i].raw_data = (uint16_t *)malloc(2); + if (items[i].raw_data == NULL) { + free(items); + return KNOT_ENOMEM; + } + memcpy(items[i].raw_data, &item_size, 2); + } else if (item_type != KNOT_RDATA_WF_COMPRESSED_DNAME + && item_type != KNOT_RDATA_WF_UNCOMPRESSED_DNAME + && item_type != KNOT_RDATA_WF_LITERAL_DNAME) { + fprintf(stderr, "RDATA item not set (i: %d), type: %u" + " RDATA item type: %d\n", i, desc->type ,item_type); + assert(0); + } + + ++i; + } + + assert(!desc->fixed_items || i == desc->length); + + // all items are parsed, insert into the RDATA + int rc; + rc = knot_rdata_set_items(rdata, items, i); + + for (int j = 0; j < i; ++j) { + assert(rdata->items[j].raw_data != NULL); + } + + free(items); + return rc; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rdata_set_item(knot_rdata_t *rdata, uint pos, + knot_rdata_item_t item) +{ + if (pos >= rdata->count) { + return KNOT_EBADARG; + } + + /*! \todo As in set_items() we should increment refcounter for dnames, + * but we don't know the item type. + */ + + rdata->items[pos] = item; // this should copy the union; or use memcpy? + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +unsigned int knot_rdata_item_count(const knot_rdata_t *rdata) +{ + return rdata->count; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rdata_set_items(knot_rdata_t *rdata, + const knot_rdata_item_t *items, uint count) +{ + if (rdata == NULL || items == NULL || count == 0 || + rdata->items != NULL) { + return KNOT_EBADARG; + } + + assert(rdata->count == 0); + if ((rdata->items = (knot_rdata_item_t *)malloc( + count * sizeof(knot_rdata_item_t))) == NULL) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + memcpy(rdata->items, items, count * sizeof(knot_rdata_item_t)); + rdata->count = count; + + /*! \todo Cannot determine items type, so the dname + * refcounters should be increased in caller. + */ + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rdata_item_t *knot_rdata_item(const knot_rdata_t *rdata, + uint pos) +{ + if (pos >= rdata->count) { + return NULL; + } else { + return &rdata->items[pos]; + } +} + +/*----------------------------------------------------------------------------*/ + +knot_rdata_item_t *knot_rdata_get_item(const knot_rdata_t *rdata, + uint pos) +{ + if (pos >= rdata->count) { + return NULL; + } else { + return &rdata->items[pos]; + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_rdata_item_set_dname(knot_rdata_t *rdata, uint pos, + knot_dname_t *dname) +{ + if (pos >= rdata->count) { + return KNOT_EBADARG; + } + + /* Retain dname. */ + knot_dname_retain(dname); + + rdata->items[pos].dname = dname; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, uint pos, + uint16_t *raw_data) +{ + if (pos >= rdata->count) { + return KNOT_EBADARG; + } + + rdata->items[pos].raw_data = raw_data; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +void knot_rdata_free(knot_rdata_t **rdata) +{ + if (rdata == NULL || *rdata == NULL) { + return; + } + + if ((*rdata)->items) { + free((*rdata)->items); + } + free(*rdata); + *rdata = NULL; +} + +/*----------------------------------------------------------------------------*/ + +void knot_rdata_deep_free(knot_rdata_t **rdata, uint type, + int free_all_dnames) +{ + if (rdata == NULL || *rdata == NULL) { + return; + } + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + assert(desc != NULL); + + assert((*rdata)->count <= desc->length); + + for (int i = 0; i < (*rdata)->count; i++) { + if (&((*rdata)->items[i]) == NULL) { + continue; + } + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) { + if (((*rdata)->items[i].dname != NULL)) { + /*! \todo This is hack to prevent memory errors, + * as the rdata_set_items() cannot determine + * items type and so cannot increment + * reference count in case of dname type. + * Free would then release dnames that + * aren't referenced by the rdata. + */ + if (free_all_dnames) { + knot_dname_release((*rdata)->items[i].dname); + } + } + } else { + free((*rdata)->items[i].raw_data); + } + } + + if ((*rdata)->items) { + free((*rdata)->items); + } + free(*rdata); + *rdata = NULL; +} + +/*----------------------------------------------------------------------------*/ +/* CLEANUP */ +//uint knot_rdata_wire_size(const knot_rdata_t *rdata, +// const uint8_t *format) +//{ +// uint size = 0; + +// for (int i = 0; i < rdata->count; ++i) { +// switch (format[i]) { +// case KNOT_RDATA_WF_COMPRESSED_DNAME: +// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: +// case KNOT_RDATA_WF_LITERAL_DNAME: +// size += knot_dname_size(rdata->items[i].dname); +// break; +// case KNOT_RDATA_WF_BYTE: +// size += 1; +// break; +// case KNOT_RDATA_WF_SHORT: +// size += 2; +// break; +// case KNOT_RDATA_WF_LONG: +// size += 4; +// break; +// case KNOT_RDATA_WF_A: +// size += 4; +// break; +// case KNOT_RDATA_WF_AAAA: +// size += 16; +// break; +// case KNOT_RDATA_WF_BINARY: +// case KNOT_RDATA_WF_APL: // saved as binary +// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary +// size += rdata->items[i].raw_data[0]; +// break; +// case KNOT_RDATA_WF_TEXT: +// case KNOT_RDATA_WF_BINARYWITHLENGTH: +// size += rdata->items[i].raw_data[0] + 1; +// break; +// default: +// assert(0); +// } +// } +// return size; +//} + +/*----------------------------------------------------------------------------*/ + +//int knot_rdata_to_wire(const knot_rdata_t *rdata, const uint8_t *format, +// uint8_t *buffer, uint buf_size) +//{ +// uint copied = 0; +// uint8_t tmp[KNOT_MAX_RDATA_WIRE_SIZE]; +// uint8_t *to = tmp; + +// for (int i = 0; i < rdata->count; ++i) { +// assert(copied < KNOT_MAX_RDATA_WIRE_SIZE); + +// const uint8_t *from = (uint8_t *)rdata->items[i].raw_data; +// uint size = 0; + +// switch (format[i]) { +// case KNOT_RDATA_WF_COMPRESSED_DNAME: +// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: +// case KNOT_RDATA_WF_LITERAL_DNAME: +// size = knot_dname_size(rdata->items[i].dname); +// from = knot_dname_name(rdata->items[i].dname); + +// break; +// case KNOT_RDATA_WF_BYTE: +// size = 1; +// break; +// case KNOT_RDATA_WF_SHORT: +// size = 2; +// break; +// case KNOT_RDATA_WF_LONG: +// size = 4; +// break; +// case KNOT_RDATA_WF_A: +// size = 4; +// break; +// case KNOT_RDATA_WF_AAAA: +// size = 16; +// break; +// case KNOT_RDATA_WF_TEXT: +// case KNOT_RDATA_WF_BINARYWITHLENGTH: +// // size stored in the first two bytes, but in little +// // endian and we need only the lower byte from it +// *to = *from; // lower byte is the first in little endian +// to += 1; +// case KNOT_RDATA_WF_BINARY: +// case KNOT_RDATA_WF_APL: // saved as binary +// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary +// // size stored in the first two bytes, those bytes +// // must not be copied +// size = rdata->items[i].raw_data[0]; +// from += 2; // skip the first two bytes +// break; +// default: +// assert(0); +// } + +// assert(size != 0); +// assert(copied + size < KNOT_MAX_RDATA_WIRE_SIZE); + +// memcpy(to, from, size); +// to += size; +// copied += size; +// } + +// if (copied > buf_size) { +// dbg_rdata("Not enough place allocated for function " +// "knot_rdata_to_wire(). Allocated %u, need %u\n", +// buf_size, copied); +// return -1; +// } + +// memcpy(buffer, tmp, copied); +// return 0; +//} + +/*----------------------------------------------------------------------------*/ + +knot_rdata_t *knot_rdata_deep_copy(const knot_rdata_t *rdata, + uint16_t type) +{ + knot_rdata_t *copy = knot_rdata_new(); + CHECK_ALLOC_LOG(copy, NULL); + + + if ((copy->items = (knot_rdata_item_t *)malloc( + rdata->count * sizeof(knot_rdata_item_t))) == NULL) { + knot_rdata_free(©); + ERR_ALLOC_FAILED; + return NULL; + } + + copy->count = rdata->count; + + knot_rrtype_descriptor_t *d = knot_rrtype_descriptor_by_type(type); + + assert(copy->count <= d->length); + + // copy all items one by one + for (int i = 0; i < copy->count; ++i) { + if (d->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME + || d->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || d->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME) { + copy->items[i].dname = + knot_dname_deep_copy(rdata->items[i].dname); + } else { + copy->items[i].raw_data = (uint16_t *)malloc( + rdata->items[i].raw_data[0] + 2); + if (copy->items[i].raw_data == NULL) { + knot_rdata_deep_free(©, type, 1); + return NULL; + } + memcpy(copy->items[i].raw_data, + rdata->items[i].raw_data, + rdata->items[i].raw_data[0] + 2); + } + } + + return copy; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rdata_compare(const knot_rdata_t *r1, const knot_rdata_t *r2, + const uint8_t *format) +{ + uint count = (r1->count < r2->count) ? r1->count : r2->count; + + int cmp = 0; + + for (int i = 0; i < count; ++i) { + /* CLEANUP */ +// const uint8_t *data1, *data2; +// int size1, size2; + + if (format[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + format[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + format[i] == KNOT_RDATA_WF_LITERAL_DNAME) { + cmp = knot_dname_compare(r1->items[i].dname, + r2->items[i].dname); +// data1 = knot_dname_name(r1->items[i].dname); +// data2 = knot_dname_name(r2->items[i].dname); +// size1 = knot_dname_size(r2->items[i].dname); +// size2 = knot_dname_size(r2->items[i].dname); + } else { + cmp = knot_rdata_compare_binary( + (uint8_t *)(r1->items[i].raw_data + 1), + (uint8_t *)(r2->items[i].raw_data + 1), + r1->items[i].raw_data[0], + r1->items[i].raw_data[0]); +// data1 = (uint8_t *)(r1->items[i].raw_data + 1); +// data2 = (uint8_t *)(r2->items[i].raw_data + 1); +// size1 = r1->items[i].raw_data[0]; +// size2 = r1->items[i].raw_data[0]; + } + +// cmp = + + if (cmp != 0) { + return cmp; + } + } + + assert(cmp == 0); + return 0; +} + +/*----------------------------------------------------------------------------*/ + +const knot_dname_t *knot_rdata_cname_name(const knot_rdata_t *rdata) +{ + if (rdata->count < 1) { + return NULL; + } + return rdata->items[0].dname; +} + +/*----------------------------------------------------------------------------*/ + +const knot_dname_t *knot_rdata_dname_target(const knot_rdata_t *rdata) +{ + if (rdata->count < 1) { + return NULL; + } + return rdata->items[0].dname; +} + +/*---------------------------------------------------------------------------*/ + +const knot_dname_t *knot_rdata_get_name(const knot_rdata_t *rdata, + uint16_t type) +{ + // iterate over the rdata items or act as if we knew where the name is? + + switch (type) { + case KNOT_RRTYPE_NS: + return knot_rdata_ns_name(rdata); + case KNOT_RRTYPE_MX: + return knot_rdata_mx_name(rdata); + case KNOT_RRTYPE_SRV: + return knot_rdata_srv_name(rdata); + case KNOT_RRTYPE_CNAME: + return knot_rdata_cname_name(rdata); + } + + return NULL; +} + +/*---------------------------------------------------------------------------*/ +int64_t knot_rdata_soa_serial(const knot_rdata_t *rdata) +{ + if (!rdata) { + return -1; + } + + if (rdata->count < 3) { + return -1; + } + + // the number is in network byte order, transform it + return knot_wire_read_u32((uint8_t *)(rdata->items[2].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint32_t knot_rdata_soa_refresh(const knot_rdata_t *rdata) +{ + if (!rdata) { + return 0; + } + + if (rdata->count < 4) { + return 0; /*! \todo Some other error value. */ + } + + // the number is in network byte order, transform it + return knot_wire_read_u32((uint8_t *)(rdata->items[3].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint32_t knot_rdata_soa_retry(const knot_rdata_t *rdata) +{ + if (!rdata) { + return 0; + } + + if (rdata->count < 5) { + return 0; /*! \todo Some other error value. */ + } + + // the number is in network byte order, transform it + return knot_wire_read_u32((uint8_t *)(rdata->items[4].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint32_t knot_rdata_soa_expire(const knot_rdata_t *rdata) +{ + if (!rdata) { + return -1; + } + + if (rdata->count < 6) { + return 0; /*! \todo Some other error value. */ + } + + // the number is in network byte order, transform it + return knot_wire_read_u32((uint8_t *)(rdata->items[5].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata) +{ + if (rdata->count < 1) { + return 0; + } + + return knot_wire_read_u16((uint8_t *)(rdata->items[0].raw_data + 1)); +} diff --git a/src/libknot/rdata.h b/src/libknot/rdata.h new file mode 100644 index 0000000..5d328c9 --- /dev/null +++ b/src/libknot/rdata.h @@ -0,0 +1,339 @@ +/*! + * \file rdata.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Structures representing RDATA and its items and API for manipulating + * both. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_RDATA_H_ +#define _KNOT_RDATA_H_ + +#include <stdint.h> +#include <string.h> + +#include "dname.h" +#include "util/descriptor.h" + +/*----------------------------------------------------------------------------*/ +/*! + * \brief RDATA item structure. + * + * Each RDATA may be logically divided into items, each of possible different + * type. This structure distinguishes between general data (\a raw_data) + * represented as an array of octets, and domain name (\a dname) as domain names + * require special treatment within some RDATA (e.g. compressing in packets). + */ +union knot_rdata_item { + knot_dname_t *dname; /*!< RDATA item represented as a domain name. */ + + /*! + * \brief RDATA item represented as raw array of octets. + * + * The first two bytes hold the length of the item in bytes. The length + * is stored in little endian. + * + * In some cases the stored length is also used in the wire format of + * RDATA (e.g. character-data as defined in RFC1035). In such case, + * the length should be less than 256, so that it fits into one byte + * in the wireformat. + * + * \todo Store the length in system byte order. + */ + uint16_t *raw_data; +}; + +typedef union knot_rdata_item knot_rdata_item_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief RDATA structure. + * + * Each RDATA may be logically divided into items, each of possible different + * type (see knot_rdata_item). This structure stores an array of such items. + * It is not dynamic, so any RDATA structure may hold either 0 or one specified + * number of items which cannot be changed later. However, the number of items + * may be different for each RDATA structure. The number of items should be + * given by descriptors for each RR type. Some types may have variable number + * of items. In such cases, the last item in the array will be set tu NULL + * to distinguish the actual count of items. + * + * This structure does not hold information about the RDATA items, such as + * what type is which item or how long are they. This information should be + * stored elsewhere (in descriptors) as it is RR-specific and given for each + * RR type. + * + * \todo Find out whether NULL is appropriate value. If it is a possible + * value for some of the items, we must find some other way to deal with + * this. + * \todo Add some function for freeing particular item? Or a non-const getter? + */ +struct knot_rdata { + knot_rdata_item_t *items; /*!< RDATA items comprising this RDATA. */ + unsigned int count; /*! < Count of RDATA items in this RDATA. */ + struct knot_rdata *next; /*!< Next RDATA item in a linked list. */ +}; + +typedef struct knot_rdata knot_rdata_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates an empty RDATA structure. + * + * \return Pointer to the new RDATA structure or NULL if an error occured. + */ +knot_rdata_t *knot_rdata_new(); + +/*! + * \brief Parses RDATA from the given data in wire format. + * + * \param rdata RDATA to fill. + * \param wire Wire format of the whole data in which the RDATA are present. + * \param pos Position in \a wire where to start parsing. + * \param total_size Size of the whole data. + * \param rdlength Size of the RDATA to parse in bytes. + * \param desc RR type descriptor for the RDATA type. + * + * \retval KNOT_ENOMEM + * \retval KNOT_EFEWDATA + * \retval KNOT_EMALF + * \retval KNOT_ERROR + * \retval KNOT_EOK + */ +int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, + size_t *pos, size_t total_size, size_t rdlength, + const knot_rrtype_descriptor_t *desc); + +/*! + * \brief Sets the RDATA item on position \a pos. + * + * \param rdata RDATA structure in which the item should be set. + * \param pos Position of the RDATA item to be set. + * \param item RDATA item value to be set. + * + * \retval KNOT_EOK if successful. + * \retval KNOT_EBADARG if \a pos is not a valid position. + * + * \todo Use the union or a pointer to it as parameter? IMHO there is always + * only one pointer that is copied, so it doesn't matter. + */ +int knot_rdata_set_item(knot_rdata_t *rdata, unsigned int pos, + knot_rdata_item_t item); + +/*! + * \brief Sets all RDATA items within the given RDATA structure. + * + * \a rdata must be empty so far (\a rdata->count == 0). The necessary space + * is allocated. + * + * This function copies the array of RDATA items from \a items to \a rdata. + * + * \param rdata RDATA structure to store the items in. + * \param items An array of RDATA items to be stored in this RDATA structure. + * \param count Count of RDATA items to be stored. + * + * \retval 0 if successful. + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + */ +int knot_rdata_set_items(knot_rdata_t *rdata, + const knot_rdata_item_t *items, + unsigned int count); + +unsigned int knot_rdata_item_count(const knot_rdata_t *rdata); + +/*! + * \brief Returns the RDATA item on position \a pos. + * + * \note Although returning union would be OK (no overhead), we need to be able + * to distinguish errors (in this case by returning NULL). + * + * \param rdata RDATA structure to get the item from. + * \param pos Position of the item to retrieve. + * + * \return The RDATA item on position \a pos, or NULL if such position does not + * exist within the given RDATA structure. + */ +knot_rdata_item_t *knot_rdata_get_item(const knot_rdata_t *rdata, + unsigned int pos); + +/*! + * \brief Returns the RDATA item on position \a pos. + * + * \note Although returning union would be OK (no overhead), we need to be able + * to distinguish errors (in this case by returning NULL). + * \note This function is identical to knot_rdata_get_item(), only it returns + * constant data. + * + * \param rdata RDATA structure to get the item from. + * \param pos Position of the item to retrieve. + * + * \return The RDATA item on position \a pos, or NULL if such position does not + * exist within the given RDATA structure. + */ +const knot_rdata_item_t *knot_rdata_item(const knot_rdata_t *rdata, + unsigned int pos); + +/*! + * \brief Sets the given domain name as a value of RDATA item on position + * \a pos. + * + * \param rdata RDATA structure to set the item in. + * \param pos Position of the RDATA item to set. + * \param dname Domain name to set to the item. + * + * \retval KNOT_EOK if successful. + * \retval KNOT_EBADARG + */ +int knot_rdata_item_set_dname(knot_rdata_t *rdata, unsigned int pos, + knot_dname_t *dname); + +/*! + * \brief Sets the given raw data as a value of RDATA item on position \a pos. + * + * \param rdata RDATA structure to set the item in. + * \param pos Position of the RDATA item to set. + * \param raw_data Raw data to set to the item. + * + * \retval KNOT_EOK if successful. + * \retval KNOT_EBADARG + */ +int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, unsigned int pos, + uint16_t *raw_data); + +/*! + * \brief Copies the given RDATA. + * + * \param rdata RDATA to copy. + * \param type RR type of the RDATA. + * + * \return Copy of \a rdata. + */ +knot_rdata_t *knot_rdata_deep_copy(const knot_rdata_t *rdata, + uint16_t type); + +/*! + * \brief Destroys the RDATA structure without deleting RDATA items. + * + * Also sets the given pointer to NULL. + * + * \param rdata RDATA structure to be destroyed. + */ +void knot_rdata_free(knot_rdata_t **rdata); + +/*! + * \brief Destroys the RDATA structure and all its RDATA items. + * + * RDATA items are deleted according to the given RR Type. In case of domain + * name, it is deallocated only if either the free_all_dnames parameter is set + * to <> 0 or the name does not contain reference to a node (i.e. it is not an + * owner of some node) or if it does contain a reference to a node, but is + * not equal to its owner. (If free_all_dnames is set to <> 0, no other + * condition is evaluated.) + * + * Also sets the given pointer to NULL. + * + * \param rdata RDATA structure to be destroyed. + * \param type RR Type of the RDATA. + * \param free_all_dnames Set to <> 0 if you want to delete ALL domain names + * from the RDATA. Set to 0 otherwise. + */ +void knot_rdata_deep_free(knot_rdata_t **rdata, unsigned int type, + int free_all_dnames); + +/*! + * \brief Compares two RDATAs of the same type. + * + * \note Compares domain names normally (dname_compare()), i.e. + * case-insensitive. + * + * \param r1 First RDATA. + * \param r2 Second RDATA. + * \param format Descriptor of the RDATA format. + * + * \retval 0 if RDATAs are equal. + * \retval < 0 if \a r1 goes before \a r2 in canonical order. + * \retval > 0 if \a r1 goes after \a r2 in canonical order. + */ +int knot_rdata_compare(const knot_rdata_t *r1, const knot_rdata_t *r2, + const uint8_t *format); + +/*! + * \brief Retrieves the domain name from CNAME RDATA. + * + * \note This is only convenience function. It does not (and cannot) check if + * the given RDATA is of the right type, so it always returns the first + * RDATA item, even if it is not a domain name. + * + * \param rdata RDATA to get the CNAME domain name from. + * + * \return Canonical name stored in \a rdata or NULL if \a rdata has no items. + */ +const knot_dname_t *knot_rdata_cname_name(const knot_rdata_t *rdata); + +/*! + * \brief Retrieves the domain name from DNAME RDATA. + * + * \note This is only convenience function. It does not (and cannot) check if + * the given RDATA is of the right type, so it always returns the first + * RDATA item, even if it is not a domain name. + * + * \param rdata RDATA to get the DNAME domain name from. + * + * \return Target domain name stored in \a rdata or NULL if \a rdata has no + * items. + */ +const knot_dname_t *knot_rdata_dname_target(const knot_rdata_t *rdata); + +/*! + * \brief Retrieves the domain name from RDATA of given type. + * + * Supported types: + * - KNOT_RRTYPE_NS + * - KNOT_RRTYPE_MX + * - KNOT_RRTYPE_SRV + * - KNOT_RRTYPE_CNAME + * + * \note This is only convenience function. It does not (and cannot) check if + * the given RDATA is of the right type, so it always returns the RDATA + * item according to the given type, even if it is not a domain name. + * + * \param rdata RDATA to get the domain name from. + * \param type RR type of the RDATA. + * + * \return Domain name stored in \a rdata or NULL if \a rdata has not enough + * items. + */ +const knot_dname_t *knot_rdata_get_name(const knot_rdata_t *rdata, + uint16_t type); + +int64_t knot_rdata_soa_serial(const knot_rdata_t *rdata); + +uint32_t knot_rdata_soa_refresh(const knot_rdata_t *rdata); +uint32_t knot_rdata_soa_retry(const knot_rdata_t *rdata); +uint32_t knot_rdata_soa_expire(const knot_rdata_t *rdata); + +uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata); + +#endif /* _KNOT_RDATA_H */ + +/*! @} */ diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c new file mode 100644 index 0000000..6083f77 --- /dev/null +++ b/src/libknot/rrset.c @@ -0,0 +1,719 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdint.h> +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> + +#include "common.h" +#include "rrset.h" +#include "util/descriptor.h" +#include "util/error.h" +#include "util/utils.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ + +static void knot_rrset_disconnect_rdata(knot_rrset_t *rrset, + knot_rdata_t *prev, knot_rdata_t *rdata) +{ + if (prev == NULL) { + // find the previous RDATA in the series, as its pointer must + // be changed + prev = rdata->next; + while (prev->next != rdata) { + prev = prev->next; + } + } + + assert(prev); + assert(prev->next == rdata); + + prev->next = rdata->next; + + if (rrset->rdata == rdata) { + if (rdata->next == rdata) { + rrset->rdata = NULL; + } else { + rrset->rdata = rdata->next; + } + } +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type, + uint16_t rclass, uint32_t ttl) +{ + knot_rrset_t *ret = malloc(sizeof(knot_rrset_t)); + if (ret == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + ret->rdata = NULL; + + /* Retain reference to owner. */ + knot_dname_retain(owner); + + ret->owner = owner; + ret->type = type; + ret->rclass = rclass; + ret->ttl = ttl; + ret->rrsigs = NULL; + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata) +{ + if (rrset == NULL || rdata == NULL) { + return KNOT_EBADARG; + } + + if (rrset->rdata == NULL) { + rrset->rdata = rdata; + rrset->rdata->next = rrset->rdata; + } else { + knot_rdata_t *tmp; + + tmp = rrset->rdata; + + while (tmp->next != rrset->rdata) { + tmp = tmp->next; + } + rdata->next = tmp->next; + tmp->next = rdata; + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +knot_rdata_t *knot_rrset_remove_rdata(knot_rrset_t *rrset, + const knot_rdata_t *rdata) +{ + if (rrset == NULL || rdata == NULL) { + return NULL; + } + + knot_rdata_t *prev = NULL; + knot_rdata_t *rr = rrset->rdata; + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + + if (desc == NULL) { + return NULL; + } + + while (rr != NULL) { + /*! \todo maybe the dnames should be compared case-insensitive*/ + if (knot_rdata_compare(rr, rdata, desc->wireformat) == 0) { + knot_rrset_disconnect_rdata(rrset, prev, rr); + return rr; + } + prev = rr; + rr = knot_rrset_rdata_get_next(rrset, rr); + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_set_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs) +{ + if (rrset == NULL) { + return KNOT_EBADARG; + } + + rrset->rrsigs = rrsigs; + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs, + knot_rrset_dupl_handling_t dupl) +{ + if (rrset == NULL || rrsigs == NULL + || knot_dname_compare(rrset->owner, rrsigs->owner) != 0) { + return KNOT_EBADARG; + } + + int rc; + if (rrset->rrsigs != NULL) { + if (dupl == KNOT_RRSET_DUPL_MERGE) { + rc = knot_rrset_merge((void **)&rrset->rrsigs, + (void **)&rrsigs); + if (rc != KNOT_EOK) { + return rc; + } else { + return 1; + } + } else if (dupl == KNOT_RRSET_DUPL_SKIP) { + return 2; + } else if (dupl == KNOT_RRSET_DUPL_REPLACE) { + rrset->rrsigs = rrsigs; + } + } else { + rrset->rrsigs = rrsigs; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +const knot_dname_t *knot_rrset_owner(const knot_rrset_t *rrset) +{ + return rrset->owner; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_rrset_get_owner(const knot_rrset_t *rrset) +{ + return rrset->owner; +} + +/*----------------------------------------------------------------------------*/ + +void knot_rrset_set_owner(knot_rrset_t *rrset, knot_dname_t* owner) +{ + if (rrset) { + /* Retain new owner and release old owner. */ + knot_dname_retain(owner); + knot_dname_release(rrset->owner); + rrset->owner = owner; + } +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_rrset_type(const knot_rrset_t *rrset) +{ + return rrset->type; +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_rrset_class(const knot_rrset_t *rrset) +{ + return rrset->rclass; +} + +/*----------------------------------------------------------------------------*/ + +uint32_t knot_rrset_ttl(const knot_rrset_t *rrset) +{ + return rrset->ttl; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rdata_t *knot_rrset_rdata(const knot_rrset_t *rrset) +{ + return rrset->rdata; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rdata_t *knot_rrset_rdata_next(const knot_rrset_t *rrset, + const knot_rdata_t *rdata) +{ + if (rdata == NULL) { + return rrset->rdata; + } + if (rdata->next == rrset->rdata) { + return NULL; + } else { + return rdata->next; + } +} + +/*----------------------------------------------------------------------------*/ + +knot_rdata_t *knot_rrset_get_rdata(knot_rrset_t *rrset) +{ + if (rrset == NULL) { + return NULL; + } else { + return rrset->rdata; + } +} + +/*----------------------------------------------------------------------------*/ + +knot_rdata_t *knot_rrset_rdata_get_next(knot_rrset_t *rrset, + knot_rdata_t *rdata) +{ + if (rdata->next == rrset->rdata) { + return NULL; + } else { + return rdata->next; + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset) +{ + int count = 0; + const knot_rdata_t *rdata = rrset->rdata; + + while (rdata != NULL) { + ++count; + rdata = knot_rrset_rdata_next(rrset, rdata); + } + + return count; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rrset_t *knot_rrset_rrsigs(const knot_rrset_t *rrset) +{ + if (rrset == NULL) { + assert(0); + return NULL; + } else { + return rrset->rrsigs; + } +} + +/*----------------------------------------------------------------------------*/ + +knot_rrset_t *knot_rrset_get_rrsigs(knot_rrset_t *rrset) +{ + if (rrset == NULL) { + assert(0); + return NULL; + } else { + return rrset->rrsigs; + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2) +{ + if (r1 == NULL || r2 == NULL) { + return KNOT_EBADARG; + } + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(r1->type); + if (desc == NULL) { + return KNOT_EBADARG; + } + + // compare RDATA sets (order is not significant) + const knot_rdata_t *rdata1= knot_rrset_rdata(r1); + const knot_rdata_t *rdata2; + + // find all RDATA from r1 in r2 + while (rdata1 != NULL) { + rdata2 = knot_rrset_rdata(r2); + while (rdata2 != NULL && knot_rdata_compare(rdata1, rdata2, + desc->wireformat)) { + rdata2 = knot_rrset_rdata_next(r2, rdata2); + } + + if (rdata2 == NULL) { + // RDATA from r1 not found in r2 + return 0; + } + + // otherwise it was found, continue with next r1 RDATA + rdata1 = knot_rrset_rdata_next(r1, rdata1); + } + + // find all RDATA from r2 in r1 (this can be done in a better way) + rdata2 = knot_rrset_rdata(r2); + while (rdata2 != NULL) { + rdata1 = knot_rrset_rdata(r1); + while (rdata2 != NULL && knot_rdata_compare(rdata1, rdata2, + desc->wireformat)) { + rdata1 = knot_rrset_rdata_next(r1, rdata1); + } + + if (rdata1 == NULL) { + // RDATA from r1 not found in r2 + return 0; + } + + // otherwise it was found, continue with next r1 RDATA + rdata2 = knot_rrset_rdata_next(r2, rdata2); + } + + // all RDATA found + return 1; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset, + const knot_rdata_t *rdata, uint8_t **pos, + size_t max_size) +{ + int size = 0; + + assert(rrset != NULL); + assert(rrset->owner != NULL); + assert(rdata != NULL); + assert(pos != NULL); + assert(*pos != NULL); + + fprintf(stderr, "Max size: %zu, owner: %p, owner size: %d\n", + max_size, rrset->owner, rrset->owner->size); + + // check if owner fits + if (size + knot_dname_size(rrset->owner) + 10 > max_size) { + return KNOT_ESPACE; + } + + memcpy(*pos, knot_dname_name(rrset->owner), + knot_dname_size(rrset->owner)); + *pos += knot_dname_size(rrset->owner); + size += knot_dname_size(rrset->owner); + + fprintf(stderr, "Max size: %zu, size: %d\n", max_size, size); + + fprintf(stderr, "Wire format:\n"); + + // put rest of RR 'header' + knot_wire_write_u16(*pos, rrset->type); + fprintf(stderr, " Type: %u\n", rrset->type); + *pos += 2; + + knot_wire_write_u16(*pos, rrset->rclass); + fprintf(stderr, " Class: %u\n", rrset->rclass); + *pos += 2; + + knot_wire_write_u32(*pos, rrset->ttl); + fprintf(stderr, " TTL: %u\n", rrset->ttl); + *pos += 4; + + // save space for RDLENGTH + uint8_t *rdlength_pos = *pos; + *pos += 2; + + size += 10; +// compr->wire_pos += size; + + fprintf(stderr, "Max size: %zu, size: %d\n", max_size, size); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + + uint16_t rdlength = 0; + + for (int i = 0; i < rdata->count; ++i) { + if (max_size < size + rdlength) { + return KNOT_ESPACE; + } + + switch (desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: { + knot_dname_t *dname = + knot_rdata_item(rdata, i)->dname; + if (size + rdlength + dname->size > max_size) { + return KNOT_ESPACE; + } + + // save whole domain name + memcpy(*pos, knot_dname_name(dname), + knot_dname_size(dname)); + fprintf(stderr, "Uncompressed dname size: %d\n", + knot_dname_size(dname)); + *pos += knot_dname_size(dname); + rdlength += knot_dname_size(dname); +// compr->wire_pos += dname->size; + break; + } + default: { + uint16_t *raw_data = + knot_rdata_item(rdata, i)->raw_data; + + if (size + rdlength + raw_data[0] > max_size) { + return KNOT_ESPACE; + } + + // copy just the rdata item data (without size) + memcpy(*pos, raw_data + 1, raw_data[0]); + fprintf(stderr, "Raw data size: %d\n", raw_data[0]); + *pos += raw_data[0]; + rdlength += raw_data[0]; +// compr->wire_pos += raw_data[0]; + break; + } + } + } + + fprintf(stderr, "Max size: %zu, size: %d\n", max_size, size); + + assert(size + rdlength <= max_size); + size += rdlength; + knot_wire_write_u16(rdlength_pos, rdlength); + + return size; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size, + int *rr_count) +{ + // if no RDATA in RRSet, return + if (rrset->rdata == NULL) { + *size = 0; + *rr_count = 0; + return KNOT_EOK; + } + + + uint8_t *pos = wire; + int rrs = 0; + short rrset_size = 0; + + const knot_rdata_t *rdata = rrset->rdata; + do { + int ret = knot_rrset_rr_to_wire(rrset, rdata, &pos, + *size - rrset_size); + + assert(ret != 0); + + if (ret < 0) { + // some RR didn't fit in, so no RRs should be used + // TODO: remove last entries from compression table + fprintf(stderr, "Some RR didn't fit in.\n"); + return KNOT_ESPACE; + } + + fprintf(stderr, "RR of size %d added.\n", ret); + rrset_size += ret; + ++rrs; + } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL); + + // the whole RRSet did fit in + assert(rrset_size <= *size); + assert(pos - wire == rrset_size); + *size = rrset_size; + + fprintf(stderr, " Size after: %zu\n", *size); + + *rr_count = rrs; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_compare(const knot_rrset_t *r1, + const knot_rrset_t *r2, + knot_rrset_compare_type_t cmp) +{ + if (cmp == KNOT_RRSET_COMPARE_PTR) { + return (r1 == r2); + } + + int res = ((r1->rclass == r2->rclass) + && (r1->type == r2->type) + && (r1->ttl == r2->ttl) + && knot_dname_compare(r1->owner, r2->owner) == 0); + + if (cmp == KNOT_RRSET_COMPARE_WHOLE && res) { + res = knot_rrset_compare_rdata(r1, r2); + if (res < 0) { + return 0; + } + } + + return res; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to) +{ + if (from == NULL || to == NULL) { + return KNOT_EBADARG; + } + + int ret; + + *to = (knot_rrset_t *)calloc(1, sizeof(knot_rrset_t)); + CHECK_ALLOC_LOG(*to, KNOT_ENOMEM); + + (*to)->owner = knot_dname_deep_copy(from->owner); + (*to)->rclass = from->rclass; + (*to)->ttl = from->ttl; + (*to)->type = from->type; + if (from->rrsigs != NULL) { + ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(to, 1, 0, 0); + return ret; + } + } + assert((*to)->rrsigs == NULL || from->rrsigs != NULL); + + const knot_rdata_t *rdata = knot_rrset_rdata(from); + + /*! \note Order of RDATA will be reversed. */ + while (rdata != NULL) { + ret = knot_rrset_add_rdata(*to, knot_rdata_deep_copy(rdata, + knot_rrset_type(from))); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(to, 1, 1, 1); + return ret; + } + rdata = knot_rrset_rdata_next(from, rdata); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to) +{ + *to = (knot_rrset_t *)malloc(sizeof(knot_rrset_t)); + CHECK_ALLOC_LOG(*to, KNOT_ENOMEM); + + memcpy(*to, from, sizeof(knot_rrset_t)); + + /* Retain owner. */ + knot_dname_retain((*to)->owner); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +void knot_rrset_free(knot_rrset_t **rrset) +{ + if (rrset == NULL || *rrset == NULL) { + return; + } + + /*! \todo Shouldn't we always release owner reference? */ + knot_dname_release((*rrset)->owner); + + free(*rrset); + *rrset = NULL; +} + +/*----------------------------------------------------------------------------*/ + +void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, + int free_rdata, int free_rdata_dnames) +{ + if (rrset == NULL || *rrset == NULL) { + return; + } + + if (free_rdata) { + knot_rdata_t *tmp_rdata; + knot_rdata_t *next_rdata; + tmp_rdata = (*rrset)->rdata; + + while ((tmp_rdata != NULL) + && (tmp_rdata->next != (*rrset)->rdata) + && (tmp_rdata->next != NULL)) { + next_rdata = tmp_rdata->next; + knot_rdata_deep_free(&tmp_rdata, (*rrset)->type, + free_rdata_dnames); + tmp_rdata = next_rdata; + } + + assert(tmp_rdata == NULL + || tmp_rdata->next == (*rrset)->rdata); + + knot_rdata_deep_free(&tmp_rdata, (*rrset)->type, + free_rdata_dnames); + } + + // RRSIGs should have the same owner as this RRSet, so do not delete it + if ((*rrset)->rrsigs != NULL) { + knot_rrset_deep_free(&(*rrset)->rrsigs, 0, 1, + free_rdata_dnames); + } + + /*! \todo Release owner every time? */ + //if (free_owner) { + knot_dname_release((*rrset)->owner); + //} + + free(*rrset); + *rrset = NULL; +} + +/*----------------------------------------------------------------------------*/ + +int knot_rrset_merge(void **r1, void **r2) +{ + knot_rrset_t *rrset1 = (knot_rrset_t *)(*r1); + knot_rrset_t *rrset2 = (knot_rrset_t *)(*r2); + + if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0) + || rrset1->rclass != rrset2->rclass + || rrset1->type != rrset2->type + || rrset1->ttl != rrset2->ttl) { + return KNOT_EBADARG; + } + + // add all RDATAs from rrset2 to rrset1 (i.e. concatenate linked lists) + + // no RDATA in RRSet 1 + assert(rrset1 && rrset2); + if (rrset1->rdata == NULL) { + rrset1->rdata = rrset2->rdata; + return KNOT_EOK; + } + + knot_rdata_t *tmp_rdata = rrset1->rdata; + + if (!tmp_rdata) { + return KNOT_EOK; + } + + while (tmp_rdata->next != rrset1->rdata) { + tmp_rdata = tmp_rdata->next; + } + + tmp_rdata->next = rrset2->rdata; + + tmp_rdata = rrset2->rdata; //maybe unnecessary, but is clearer + + while (tmp_rdata->next != rrset2->rdata) { + tmp_rdata = tmp_rdata->next; + } + + tmp_rdata->next = rrset1->rdata; + + return KNOT_EOK; +} diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h new file mode 100644 index 0000000..7754c7f --- /dev/null +++ b/src/libknot/rrset.h @@ -0,0 +1,306 @@ +/*! + * \file rrset.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief RRSet structure and API for manipulating it. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_RRSET_H_ +#define _KNOT_RRSET_H_ + +#include <stdint.h> + +#include "dname.h" +#include "rdata.h" + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure for representing an RRSet. + * + * For definition of a RRSet see RFC2181, Section 5. + * + * As all RRs within a RRSet share the same OWNER, TYPE, CLASS and TTL (see + * Section 5.2 of RFC2181), there is no need to duplicate these data in the + * program. Distinct Resource Records are thus represented only as distinct + * RDATA sections of corresponding RRs. + */ +struct knot_rrset { + /*! \brief Domain name being the owner of the RRSet. */ + knot_dname_t *owner; + uint16_t type; /*!< TYPE of the RRset. */ + uint16_t rclass; /*!< CLASS of the RRSet. */ + uint32_t ttl; /*!< TTL of the RRSet. */ + /*! + * \brief First item in an ordered cyclic list of RDATA items. + * + * \note The fact that the list is cyclic will easily allow for + * possible round-robin rotation of RRSets. + */ + knot_rdata_t *rdata; + struct knot_rrset *rrsigs; /*!< Set of RRSIGs covering this RRSet. */ +}; + +typedef struct knot_rrset knot_rrset_t; + +/*----------------------------------------------------------------------------*/ + +typedef enum { + KNOT_RRSET_COMPARE_PTR, + KNOT_RRSET_COMPARE_HEADER, + KNOT_RRSET_COMPARE_WHOLE +} knot_rrset_compare_type_t; + +typedef enum { + KNOT_RRSET_DUPL_MERGE, + KNOT_RRSET_DUPL_REPLACE, + KNOT_RRSET_DUPL_SKIP +} knot_rrset_dupl_handling_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a new RRSet with the given properties. + * + * The created RRSet contains no RDATAs (i.e. is actually empty). + * + * \param owner OWNER of the RRSet. + * \param type TYPE of the RRSet. + * \param rclass CLASS of the RRSet. + * \param ttl TTL of the RRset. + * + * \return New RRSet structure with the given OWNER, TYPE, CLASS and TTL or NULL + * if an error occured. + */ +knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type, + uint16_t rclass, uint32_t ttl); + +/*! + * \brief Adds the given RDATA to the RRSet. + * + * \param rrset RRSet to add the RDATA to. + * \param rdata RDATA to add to the RRSet. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * + * \todo Provide some function for comparing RDATAs. + */ +int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata); + +knot_rdata_t * knot_rrset_remove_rdata(knot_rrset_t *rrset, + const knot_rdata_t *rdata); + +/*! + * \brief Adds RRSIG signatures to this RRSet. + * + * \param rrset RRSet to add the signatures into. + * \param rrsigs Set of RRSIGs covering this RRSet. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + */ +int knot_rrset_set_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs); + +int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs, + knot_rrset_dupl_handling_t dupl); + +/*! + * \brief Returns the Owner of the RRSet. + * + * \param rrset RRSet to get the Owner of. + * + * \return Owner of the given RRSet. + */ +const knot_dname_t *knot_rrset_owner(const knot_rrset_t *rrset); + +/*! + * \todo Document me. + */ +knot_dname_t *knot_rrset_get_owner(const knot_rrset_t *rrset); + +/*! + * \brief Set rrset owner to specified dname. + * + * Previous owner will be replaced if exist. + * + * \param rrset Specified RRSet. + * \param owner New owner dname. + */ +void knot_rrset_set_owner(knot_rrset_t *rrset, knot_dname_t* owner); + +/*! + * \brief Returns the TYPE of the RRSet. + * + * \param rrset RRSet to get the TYPE of. + * + * \return TYPE of the given RRSet. + */ +uint16_t knot_rrset_type(const knot_rrset_t *rrset); + +/*! + * \brief Returns the CLASS of the RRSet. + * + * \param rrset RRSet to get the CLASS of. + * + * \return CLASS of the given RRSet. + */ +uint16_t knot_rrset_class(const knot_rrset_t *rrset); + +/*! + * \brief Returns the TTL of the RRSet. + * + * \param rrset RRSet to get the TTL of. + * + * \return TTL of the given RRSet. + */ +uint32_t knot_rrset_ttl(const knot_rrset_t *rrset); + +/*! + * \brief Returns the first RDATA in the RRSet. + * + * RDATAs in a RRSet are stored in a ordered cyclic list. + * + * \note If later a round-robin rotation of RRSets is employed, the RDATA + * returned by this function may not be the first RDATA in canonical + * order. + * + * \param rrset RRSet to get the RDATA from. + * + * \return First RDATA in the given RRSet. + */ +const knot_rdata_t *knot_rrset_rdata(const knot_rrset_t *rrset); + +const knot_rdata_t *knot_rrset_rdata_next(const knot_rrset_t *rrset, + const knot_rdata_t *rdata); + +/*! + * \brief Returns the first RDATA in the RRSet (non-const version). + * + * RDATAs in a RRSet are stored in a ordered cyclic list. + * + * \note If later a round-robin rotation of RRSets is employed, the RDATA + * returned by this function may not be the first RDATA in canonical + * order. + * + * \param rrset RRSet to get the RDATA from. + * + * \return First RDATA in the given RRSet or NULL if there is none or if no + * rrset was provided (\a rrset is NULL). + */ +knot_rdata_t *knot_rrset_get_rdata(knot_rrset_t *rrset); + +knot_rdata_t *knot_rrset_rdata_get_next(knot_rrset_t *rrset, + knot_rdata_t *rdata); + +int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset); + +/*! + * \brief Returns the set of RRSIGs covering the given RRSet. + * + * \param rrset RRSet to get the signatures for. + * + * \return Set of RRSIGs which cover the given RRSet or NULL if there is none or + * if no rrset was provided (\a rrset is NULL). + */ +const knot_rrset_t *knot_rrset_rrsigs(const knot_rrset_t *rrset); + +knot_rrset_t *knot_rrset_get_rrsigs(knot_rrset_t *rrset); + +int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2); + +int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size, + int *rr_count); + +/*! + * \brief Compares two RRSets. + * + * \note This function does not return 'standard' compare return values, because + * there is no way to define which RRSet is 'larger'. + * + * \param r1 First RRSet. + * \param r2 Second RRSet. + * \param cmp Type of comparison to perform. + * + * \retval <> 0 If RRSets are equal. + * \retval 0 if RRSets are not equal. + */ +int knot_rrset_compare(const knot_rrset_t *r1, + const knot_rrset_t *r2, + knot_rrset_compare_type_t cmp); + +/*! \todo Add unit test. */ +int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to); + +/*! \todo Add unit test. */ +int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to); + +/*! + * \brief Destroys the RRSet structure. + * + * Does not destroy the OWNER domain name structure, nor the signatures, as + * these may be used elsewhere. + * + * Does not destroy RDATA structures neither, as they need special processing. + * + * Also sets the given pointer to NULL. + * + * \param rrset RRset to be destroyed. + */ +void knot_rrset_free(knot_rrset_t **rrset); + +/*! + * \brief Destroys the RRSet structure and all its substructures. + * + * Also sets the given pointer to NULL. + * + * \param rrset RRset to be destroyed. + * \param free_owner Set to 0 if you do not want the owner domain name to be + * destroyed also. Set to <> 0 otherwise. + * \param free_rdata ***\todo DOCUMENT ME*** + * \param free_rdata_dnames Set to <> 0 if you want to delete ALL domain names + * present in RDATA. Set to 0 otherwise. (See + * knot_rdata_deep_free().) + */ +void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, + int free_rdata, int free_rdata_dnames); + +/*! + * \brief Merges two RRSets. + * + * Merges \a r1 into \a r2 by concatenating the list of RDATAs in \a r2 after + * the list of RDATAs in \a r1. \a r2 is unaffected by this, though you must not + * destroy the RDATAs in \a r2 as they are now also in \a r1. (You may use + * function knot_rrset_free() though, as it does not touch RDATAs). + * + * \note Member \a rrsigs is preserved from the first RRSet. + * + * \param r1 Pointer to RRSet to be merged into. + * \param r2 Poitner to RRSet to be merged. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG if the RRSets could not be merged, because their + * Owner, Type, Class or TTL does not match. + */ +int knot_rrset_merge(void **r1, void **r2); + +#endif /* _KNOT_RRSET_H_ */ + +/*! @} */ diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c new file mode 100644 index 0000000..3178a23 --- /dev/null +++ b/src/libknot/tsig-op.c @@ -0,0 +1,1089 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <stdint.h> +#include <openssl/hmac.h> +#include <openssl/evp.h> +#include <time.h> +#include <ctype.h> + +#include "common.h" +#include "tsig.h" +#include "tsig-op.h" +#include "util/wire.h" +#include "util/error.h" +#include "util/debug.h" + + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + + +static int b64rmap_initialized = 0; +static uint8_t b64rmap[256]; + +static const uint8_t b64rmap_special = 0xf0; +static const uint8_t b64rmap_end = 0xfd; +static const uint8_t b64rmap_space = 0xfe; +static const uint8_t b64rmap_invalid = 0xff; + +/** + * Initializing the reverse map is not thread safe. + * Which is fine for NSD. For now... + **/ +void b64_initialize_rmap() +{ + int i; + char ch; + + /* Null: end of string, stop parsing */ + b64rmap[0] = b64rmap_end; + + for (i = 1; i < 256; ++i) { + ch = (char)i; + /* Whitespaces */ + if (isspace(ch)) { + b64rmap[i] = b64rmap_space; + } + /* Padding: stop parsing */ + else if (ch == Pad64) { + b64rmap[i] = b64rmap_end; + } + /* Non-base64 char */ + else { + b64rmap[i] = b64rmap_invalid; + } + } + + /* Fill reverse mapping for base64 chars */ + for (i = 0; Base64[i] != '\0'; ++i) { + b64rmap[(uint8_t)Base64[i]] = i; + } + + b64rmap_initialized = 1; +} + +int b64_pton_do(char const *src, uint8_t *target, size_t targsize) +{ + int tarindex, state, ch; + uint8_t ofs; + + state = 0; + tarindex = 0; + + while (1) { + ch = *src++; + ofs = b64rmap[ch]; + + if (ofs >= b64rmap_special) { + /* Ignore whitespaces */ + if (ofs == b64rmap_space) { + continue; + } + /* End of base64 characters */ + if (ofs == b64rmap_end) { + break; + } + /* A non-base64 character. */ + return (-1); + } + + switch (state) { + case 0: + if ((size_t)tarindex >= targsize) { + return (-1); + } + target[tarindex] = ofs << 2; + state = 1; + break; + case 1: + if ((size_t)tarindex + 1 >= targsize) { + return (-1); + } + target[tarindex] |= ofs >> 4; + target[tarindex+1] = (ofs & 0x0f) + << 4 ; + tarindex++; + state = 2; + break; + case 2: + if ((size_t)tarindex + 1 >= targsize) { + return (-1); + } + target[tarindex] |= ofs >> 2; + target[tarindex+1] = (ofs & 0x03) + << 6; + tarindex++; + state = 3; + break; + case 3: + if ((size_t)tarindex >= targsize) { + return (-1); + } + target[tarindex] |= ofs; + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + break; + } + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) { + return (-1); + } + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + return (-1); + } + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target[tarindex] != 0) { + return (-1); + } + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) { + return (-1); + } + } + + return (tarindex); +} + + +int b64_pton_len(char const *src) +{ + int tarindex, state, ch; + uint8_t ofs; + + state = 0; + tarindex = 0; + + while (1) { + ch = *src++; + ofs = b64rmap[ch]; + + if (ofs >= b64rmap_special) { + /* Ignore whitespaces */ + if (ofs == b64rmap_space) { + continue; + } + /* End of base64 characters */ + if (ofs == b64rmap_end) { + break; + } + /* A non-base64 character. */ + return (-1); + } + + switch (state) { + case 0: + state = 1; + break; + case 1: + tarindex++; + state = 2; + break; + case 2: + tarindex++; + state = 3; + break; + case 3: + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + break; + } + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) { + return (-1); + } + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + return (-1); + } + + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) { + return (-1); + } + } + + return (tarindex); +} + +int b64_pton(char const *src, uint8_t *target, size_t targsize) +{ + if (!b64rmap_initialized) { + b64_initialize_rmap(); + } + + if (target) { + return b64_pton_do(src, target, targsize); + } else { + return b64_pton_len(src); + } +} + +#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ + + + + + + + + + + + + +const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest + + +static int knot_tsig_check_algorithm(const knot_rrset_t *tsig_rr) +{ + const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr); + if (!alg_name) { + return KNOT_EMALF; + } + + tsig_algorithm_t alg = tsig_alg_from_name(alg_name); + if (alg == 0) { + /*!< \todo is this error OK? */ + dbg_tsig("TSIG: unknown algorithm.\n"); + return KNOT_TSIG_EBADSIG; + } + + return KNOT_EOK; +} + +static int knot_tsig_check_key(const knot_rrset_t *tsig_rr, + const knot_key_t *tsig_key) +{ + const knot_dname_t *tsig_name = knot_rrset_owner(tsig_rr); + if (!tsig_name) { + return KNOT_EMALF; + } + + const char *name = knot_dname_to_str(tsig_name); + if (!name) { + return KNOT_EMALF; + } + + if (knot_dname_compare(tsig_name, tsig_key->name) != 0) { + /*!< \todo which error. */ + dbg_tsig("TSIG: unknown key: %s\n", name); + return KNOT_TSIG_EBADKEY; + } + + return KNOT_EOK; +} + +static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len, + uint8_t *digest, size_t *digest_len, + const knot_key_t *key) +{ + if (!wire || !digest || !digest_len || !key) { + dbg_tsig("TSIG: digest: bad args.\n"); + return KNOT_EBADARG; + } + + if (!key->name) { + dbg_tsig("TSIG: digest: no algorithm\n"); + return KNOT_EMALF; + } + + tsig_algorithm_t tsig_alg = key->algorithm; + if (tsig_alg == 0) { + dbg_tsig("TSIG: digest: unknown algorithm\n"); + return KNOT_TSIG_EBADSIG; + } + + /* Create digest, using length of the algorithm. */ +// *digest = malloc(sizeof(uint8_t) * tsig_alg_digest_length(tsig_alg)); +// if (!digest) { +// ERR_ALLOC_FAILED; +// return KNOT_ENOMEM; +// } + + /* Decode key from Base64. */ + char decoded_key[B64BUFSIZE]; + + int decoded_key_size = b64_pton(key->secret, (uint8_t *)decoded_key, + B64BUFSIZE); + if (decoded_key_size < 0) { + dbg_tsig("TSIG: Could not decode Base64\n"); + return KNOT_EMALF; + } + + dbg_tsig("TSIG: decoded key size: %d\n", decoded_key_size); + dbg_tsig("TSIG: decoded key: '%*s'\n", decoded_key_size, decoded_key); + + dbg_tsig("TSIG: using this wire for digest calculation\n"); + + //dbg_tsig_hex(wire, wire_len); + + /* Compute digest. */ + HMAC_CTX ctx; + + switch (tsig_alg) { + case KNOT_TSIG_ALG_HMAC_MD5: + HMAC_Init(&ctx, decoded_key, + decoded_key_size, EVP_md5()); + break; + default: + return KNOT_ENOTSUP; + } /* switch */ + + unsigned tmp_dig_len = *digest_len; + HMAC_Update(&ctx, (const unsigned char *)wire, wire_len); + HMAC_Final(&ctx, digest, &tmp_dig_len); + *digest_len = tmp_dig_len; + + return KNOT_EOK; +} + +static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr) +{ + if (!tsig_rr) { + return KNOT_EBADARG; + } + + /* Get the time signed and fudge values. */ + uint64_t time_signed = tsig_rdata_time_signed(tsig_rr); + if (time_signed == 0) { + return KNOT_TSIG_EBADTIME; + } + uint16_t fudge = tsig_rdata_fudge(tsig_rr); + if (fudge == 0) { + return KNOT_TSIG_EBADTIME; + } + + /* Get the current time. */ + time_t curr_time = time(NULL); + + /*!< \todo bleeding eyes. */ + if (difftime(curr_time, (time_t)time_signed) > fudge) { + return KNOT_TSIG_EBADTIME; + } + + return KNOT_EOK; +} + +static int knot_tsig_write_tsig_timers(uint8_t *wire, + const knot_rrset_t *tsig_rr) +{ + // put time signed + knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr)); + + // put fudge + knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr)); + + return KNOT_EOK; +} + +static int knot_tsig_write_tsig_variables(uint8_t *wire, + const knot_rrset_t *tsig_rr) +{ + /* Copy TSIG variables - starting with key name. */ + const knot_dname_t *tsig_owner = knot_rrset_owner(tsig_rr); + if (!tsig_owner) { + dbg_tsig("TSIG: write variables: no owner.\n"); + return KNOT_EBADARG; + } + + int offset = 0; + + memcpy(wire + offset, knot_dname_name(tsig_owner), + sizeof(uint8_t) * knot_dname_size(tsig_owner)); + dbg_tsig("TSIG: write variables: written owner (tsig alg): \n"); + /*knot_rrset_class(tsig_rr));*/ + dbg_tsig_hex_detail(wire + offset, knot_dname_size(tsig_owner)); + offset += knot_dname_size(tsig_owner); + + /*!< \todo which order? */ + + /* Copy class. */ + knot_wire_write_u16(wire + offset, knot_rrset_class(tsig_rr)); + dbg_tsig("TSIG: write variables: written CLASS: %u - ", + knot_rrset_class(tsig_rr)); + dbg_tsig_hex_detail(wire + offset, sizeof(uint16_t)); + offset += sizeof(uint16_t); + + /* Copy TTL - always 0. */ + knot_wire_write_u32(wire + offset, knot_rrset_ttl(tsig_rr)); + dbg_tsig("TSIG: write variables: written TTL: %u - ", + knot_rrset_ttl(tsig_rr)); + dbg_tsig_hex_detail(wire + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + /* Copy alg name. */ + const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr); + if (!alg_name) { + dbg_tsig("TSIG: write variables: no algorithm name.\n"); + return KNOT_EBADARG; + } +// alg_name = knot_dname_new_from_str("HMAC-MD5.SIG-ALG.REG.INT.", + //strlen("HMAC-MD5.SIG-ALG.REG.INT."), + //NULL); + + memcpy(wire + offset, knot_dname_name(alg_name), + sizeof(uint8_t) * knot_dname_size(alg_name)); + offset += knot_dname_size(alg_name); + dbg_tsig_detail("TSIG: write variables: written alg name: %s\n", + knot_dname_to_str(alg_name)); + + /* Following data are written in network order. */ + /* Time signed. */ + knot_wire_write_u48(wire + offset, tsig_rdata_time_signed(tsig_rr)); + offset += 6; + dbg_tsig_detail("TSIG: write variables: time signed: %llu - ", + tsig_rdata_time_signed(tsig_rr)); + dbg_tsig_hex_detail(wire + offset - 6, 6); + /* Fudge. */ + knot_wire_write_u16(wire + offset, tsig_rdata_fudge(tsig_rr)); + offset += sizeof(uint16_t); + dbg_tsig_detail("TSIG: write variables: fudge: %hu\n", + tsig_rdata_fudge(tsig_rr)); + /* TSIG error. */ + knot_wire_write_u16(wire + offset, tsig_rdata_error(tsig_rr)); + offset += sizeof(uint16_t); + /* Get other data length. */ + uint16_t other_data_length = tsig_rdata_other_data_length(tsig_rr); + /* Get other data. */ + const uint8_t *other_data = tsig_rdata_other_data(tsig_rr); + if (!other_data) { + dbg_tsig("TSIG: write variables: no other data.\n"); + return KNOT_EBADARG; + } + + /* + * We cannot write the whole other_data, as it contains its length in + * machine order. + */ + knot_wire_write_u16(wire + offset, other_data_length); + offset += sizeof(uint16_t); + + /* Skip the length. */ + dbg_tsig_detail("Copying other data.\n"); + memcpy(wire + offset, other_data, other_data_length); + + return KNOT_EOK; +} + +static int knot_tsig_wire_write_timers(uint8_t *wire, + const knot_rrset_t *tsig_rr) +{ + knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr)); + knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr)); + + return KNOT_EOK; +} + +int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len, + /*size_t msg_max_len, */const uint8_t *request_mac, + size_t request_mac_len, + uint8_t *digest, size_t *digest_len, + const knot_rrset_t *tmp_tsig, + const knot_key_t *key) +{ + if (!msg || !key || digest_len == NULL) { + dbg_tsig("TSIG: create wire: bad args.\n"); + return KNOT_EBADARG; + } + + /* Create tmp TSIG. */ + int ret = KNOT_EOK; +// knot_rrset_t *tmp_tsig = +// knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); +// if (!tmp_tsig) { +// return KNOT_ENOMEM; +// } + +// tsig_rdata_store_current_time(tmp_tsig); + + /* + * Create tmp wire, it should contain message + * plus request mac plus tsig varibles. + */ + dbg_tsig("Counting wire size: %zu, %zu, %zu.\n", + msg_len, request_mac_len, + tsig_rdata_tsig_variables_length(tmp_tsig)); + size_t wire_len = sizeof(uint8_t) * + (msg_len + request_mac_len + ((request_mac_len > 0) + ? 2 : 0) + + tsig_rdata_tsig_variables_length(tmp_tsig)); + uint8_t *wire = malloc(wire_len); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + memset(wire, 0, wire_len); + + uint8_t *pos = wire; + + /* Copy the request MAC - should work even if NULL. */ + if (request_mac_len > 0) { + dbg_tsig_detail("Copying request MAC size\n"); + knot_wire_write_u16(pos, request_mac_len); + pos += 2; + } + dbg_tsig("Copying request mac.\n"); + memcpy(pos, request_mac, sizeof(uint8_t) * request_mac_len); + dbg_tsig_detail("TSIG: create wire: request mac: "); + dbg_tsig_hex_detail(pos, request_mac_len); + pos += request_mac_len; + /* Copy the original message. */ + dbg_tsig("Copying original message.\n"); + memcpy(pos, msg, msg_len); + dbg_tsig_detail("TSIG: create wire: original message: \n"); + //dbg_tsig_hex_detail(pos, msg_len); + pos += msg_len; + /* Copy TSIG variables. */ + dbg_tsig("Writing TSIG variables.\n"); + ret = knot_tsig_write_tsig_variables(pos, tmp_tsig); + if (ret != KNOT_EOK) { + dbg_tsig("TSIG: create wire: failed to write TSIG " + "variables: %s\n", knot_strerror(ret)); + return ret; + } + + /* Compute digest. */ + ret = knot_tsig_compute_digest(wire, wire_len, + digest, digest_len, key); + if (ret != KNOT_EOK) { + dbg_tsig("TSIG: create wire: failed to compute digest: %s\n", + knot_strerror(ret)); + *digest_len = 0; + return ret; + } + +// assert(digest_tmp_len > 0); + free(wire); + +// if (digest_tmp_len > *digest_len) { +// *digest_len = 0; +// return KNOT_ESPACE; +// } + +// knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); + + // everything went ok, save the digest to the output parameter +// memcpy(digest, digest_tmp, digest_tmp_len); +// *digest_len = digest_tmp_len; + + return KNOT_EOK; +} + +static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len, + const uint8_t *prev_mac, + size_t prev_mac_len, + uint8_t *digest, size_t *digest_len, + const knot_rrset_t *tmp_tsig, + const knot_key_t *key) +{ + if (!msg || !key || digest_len == NULL) { + dbg_tsig("TSIG: create wire: bad args.\n"); + return KNOT_EBADARG; + } + + /* Create tmp TSIG. */ + int ret = KNOT_EOK; + + /* + * Create tmp wire, it should contain message + * plus request mac plus tsig varibles. + */ + dbg_tsig("Counting wire size: %zu, %zu, %zu.\n", + msg_len, prev_mac_len, + tsig_rdata_tsig_timers_length()); + size_t wire_len = sizeof(uint8_t) * + (msg_len + prev_mac_len + + tsig_rdata_tsig_timers_length()); + uint8_t *wire = malloc(wire_len); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + memset(wire, 0, wire_len); + + /* Copy the request MAC - should work even if NULL. */ + dbg_tsig("Copying request mac.\n"); + memcpy(wire, prev_mac, sizeof(uint8_t) * prev_mac_len); + dbg_tsig_detail("TSIG: create wire: request mac: "); + dbg_tsig_hex_detail(wire, prev_mac_len); + /* Copy the original message. */ + dbg_tsig("Copying original message.\n"); + memcpy(wire + prev_mac_len, msg, msg_len); + dbg_tsig_detail("TSIG: create wire: original message: \n"); + //dbg_tsig_hex_detail(wire + prev_mac_len, msg_len); + /* Copy TSIG variables. */ + + dbg_tsig("Writing TSIG timers.\n"); + ret = knot_tsig_write_tsig_timers(wire + prev_mac_len + msg_len, + tmp_tsig); +// ret = knot_tsig_write_tsig_variables(wire + prev_mac_len + msg_len, +// tmp_tsig); + if (ret != KNOT_EOK) { + dbg_tsig("TSIG: create wire: failed to write TSIG " + "timers: %s\n", knot_strerror(ret)); + return ret; + } + + /* Compute digest. */ + ret = knot_tsig_compute_digest(wire, wire_len, + digest, digest_len, key); + if (ret != KNOT_EOK) { + dbg_tsig("TSIG: create wire: failed to compute digest: %s\n", + knot_strerror(ret)); + *digest_len = 0; + return ret; + } + + free(wire); + + return KNOT_EOK; +} + +int knot_tsig_sign(uint8_t *msg, size_t *msg_len, + size_t msg_max_len, const uint8_t *request_mac, + size_t request_mac_len, + uint8_t *digest, size_t *digest_len, + const knot_key_t *key) +{ + if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) { + return KNOT_EBADARG; + } + + knot_dname_t *key_name_copy = knot_dname_deep_copy(key->name); + if (!key_name_copy) { + dbg_tsig_detail("TSIG: key_name_copy = NULL\n"); + return KNOT_ENOMEM; + } + + knot_rrset_t *tmp_tsig = + knot_rrset_new(key_name_copy, + KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); + if (!tmp_tsig) { + dbg_tsig_detail("TSIG: tmp_tsig = NULL\n"); + return KNOT_ENOMEM; + } + + /* Create rdata for TSIG RR. */ + knot_rdata_t *rdata = knot_rdata_new(); + if (!rdata) { + dbg_tsig_detail("TSIG: rdata = NULL\n"); + return KNOT_ENOMEM; + } + + knot_rrset_add_rdata(tmp_tsig, rdata); + + /* Create items for TSIG RR. */ + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(KNOT_RRTYPE_TSIG); + assert(desc); + + knot_rdata_item_t *items = + malloc(sizeof(knot_rdata_item_t) * desc->length); + if (!items) { + dbg_tsig_detail("TSIG: items = NULL\n"); + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + memset(items, 0, sizeof(knot_rdata_item_t) * desc->length); + + int ret = knot_rdata_set_items(rdata, items, desc->length); + if (ret != KNOT_EOK) { + dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret)); + return ret; + } + free(items); + + tsig_rdata_set_alg(tmp_tsig, key->algorithm); + tsig_rdata_store_current_time(tmp_tsig); + tsig_rdata_set_fudge(tmp_tsig, 300); + + /* Set original ID */ + tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); + + /* Set error */ + /*! \todo [TSIG] Set error and other data if appropriate. */ + tsig_rdata_set_tsig_error(tmp_tsig, 0); + + /* Set other len. */ + tsig_rdata_set_other_data(tmp_tsig, 0, 0); + + uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; + size_t digest_tmp_len = 0; + + dbg_tsig_detail("tmp_tsig before sign_wire():\n"); + knot_rrset_dump(tmp_tsig, 0); + + ret = knot_tsig_create_sign_wire(msg, *msg_len, /*msg_max_len,*/ + request_mac, request_mac_len, + digest_tmp, &digest_tmp_len, + tmp_tsig, key); + if (ret != KNOT_EOK) { + dbg_tsig("TSIG: could not create wire or sign wire: %s\n", + knot_strerror(ret)); + return ret; + } + + /* Set the digest. */ + size_t tsig_wire_len = msg_max_len - *msg_len; + int rr_count = 0; + tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp); + + //knot_rrset_dump(tmp_tsig, 1); + + /* Write RRSet to wire */ + ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, + &tsig_wire_len, &rr_count); + if (ret != KNOT_EOK) { + dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); + *digest_len = 0; + return ret; + } + + knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); + + *msg_len += tsig_wire_len; + + uint16_t arcount = knot_wire_get_arcount(msg); + knot_wire_set_arcount(msg, ++arcount); + + // everything went ok, save the digest to the output parameter + memcpy(digest, digest_tmp, digest_tmp_len); + *digest_len = digest_tmp_len; + + return KNOT_EOK; +} + +int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, + const uint8_t *prev_digest, size_t prev_digest_len, + uint8_t *digest, size_t *digest_len, + const knot_key_t *key) +{ + if (!msg || !msg_len || !key || !key || !digest || !digest_len) { + return KNOT_EBADARG; + } + + uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; + size_t digest_tmp_len = 0; + + /* Create tmp TSIG. */ + knot_rrset_t *tmp_tsig = + knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); + if (!tmp_tsig) { + return KNOT_ENOMEM; + } + + tsig_rdata_store_current_time(tmp_tsig); + + /* Create wire to be signed. */ + size_t wire_len = prev_digest_len + *msg_len + KNOT_TSIG_TIMERS_LENGTH; + uint8_t *wire = malloc(wire_len); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + memset(wire, 0, wire_len); + + /* Write previous digest. */ + memcpy(wire, prev_digest, sizeof(uint8_t) * prev_digest_len); + /* Write original message. */ + memcpy(msg + prev_digest_len, msg, *msg_len); + /* Write timers. */ + knot_tsig_wire_write_timers(msg + prev_digest_len + *msg_len, tmp_tsig); + + int ret = 0; + ret = knot_tsig_compute_digest(wire, wire_len, + digest_tmp, &digest_tmp_len, key); + if (ret != KNOT_EOK) { + *digest_len = 0; + return ret; + } + + if (digest_tmp_len > *digest_len) { + *digest_len = 0; + return KNOT_ESPACE; + } + + free(wire); + + /* Set the MAC. */ + tsig_rdata_set_mac(tmp_tsig, *digest_len, digest); + + size_t tsig_wire_size = msg_max_len - *msg_len; + int rr_count = 0; + ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, + &tsig_wire_size, &rr_count); + if (ret != KNOT_EOK) { + *digest_len = 0; + return ret; + } + + knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); + + *msg_len += tsig_wire_size; + uint16_t arcount = knot_wire_get_arcount(msg); + knot_wire_set_arcount(msg, ++arcount); + + memcpy(digest, digest_tmp, digest_tmp_len); + *digest_len = digest_tmp_len; + + return KNOT_EOK; +} + +static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, + const uint8_t *wire, size_t size, + const uint8_t *request_mac, + size_t request_mac_len, + const knot_key_t *tsig_key, + int use_times) +{ + if (!tsig_rr || !wire || !tsig_key) { + return KNOT_EBADARG; + } + + /* Check time signed. */ + int ret = knot_tsig_check_time_signed(tsig_rr); + if (ret != KNOT_EOK) { + return ret; + } + + dbg_tsig("TSIG: time checked.\n"); + + /* Check that libknot knows the algorithm. */ + ret = knot_tsig_check_algorithm(tsig_rr); + if (ret != KNOT_EOK) { + return ret; + } + + dbg_tsig("TSIG: algorithm checked.\n"); + + /* Check that key is valid, ie. the same as given in args. */ + ret = knot_tsig_check_key(tsig_rr, tsig_key); + if (ret != KNOT_EOK) { + return ret; + } + + dbg_tsig("TSIG: key validity checked.\n"); + + /* Time OK algorithm OK, key name OK - do digest. */ + /* Calculate the size of TSIG RR. */ + size_t tsig_len = tsig_wire_actsize(tsig_rr); + + dbg_tsig_detail("TSIG: check digest: wire before strip: \n"); + //dbg_tsig_hex_detail(wire, size); + + /* Strip the TSIG. */ + size -= tsig_len; + + dbg_tsig_detail("TSIG: check digest: wire after strip (stripped %zu):\n", + tsig_len); + //dbg_tsig_hex_detail(wire, size); + + uint8_t *wire_to_sign = malloc(sizeof(uint8_t) * size); + if (!wire_to_sign) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + memset(wire_to_sign, 0, sizeof(uint8_t) * size); + memcpy(wire_to_sign, wire, size); + + /* Decrease arcount. */ + knot_wire_set_arcount(wire_to_sign, + knot_wire_get_arcount(wire_to_sign) - 1); + + uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; + size_t digest_tmp_len = 0; + assert(tsig_rr->rdata); + + if (use_times) { + ret = knot_tsig_create_sign_wire_next(wire_to_sign, size, + request_mac, request_mac_len, + digest_tmp, &digest_tmp_len, + tsig_rr, tsig_key); + } else { + ret = knot_tsig_create_sign_wire(wire_to_sign, size, + request_mac, request_mac_len, + digest_tmp, &digest_tmp_len, + tsig_rr, tsig_key); + } + + assert(tsig_rr->rdata); + free(wire_to_sign); + + if (ret != KNOT_EOK) { + dbg_tsig("Failed to create wire format for checking: %s.\n", + knot_strerror(ret)); + return ret; + } + +// uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; +// size_t digest_tmp_len = 0; +// ret = knot_tsig_compute_digest(wire, size, digest_tmp, +// &digest_tmp_len, tsig_key); +// if (ret != KNOT_EOK) { +// dbg_tsig("TSIG: digest could not be calculated\n"); +// return ret; +// } + + dbg_tsig("TSIG: digest calculated\n"); + + /* Compare MAC from TSIG RR RDATA with just computed digest. */ + + /*!< \todo move to function. */ + const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr); + tsig_algorithm_t alg = tsig_alg_from_name(alg_name); + + /*! \todo [TSIG] TRUNCATION */ + uint16_t mac_length = tsig_rdata_mac_length(tsig_rr); + const uint8_t *tsig_mac = tsig_rdata_mac(tsig_rr); + + if (mac_length != tsig_alg_digest_length(alg)) { + dbg_tsig("TSIG: calculated digest length and given length do not match!\n"); + return KNOT_TSIG_EBADSIG; + } + +// assert(tsig_alg_digest_length(alg) == mac_length); + + dbg_tsig("TSIG: calc digest : "); + dbg_tsig_hex(digest_tmp, digest_tmp_len); + + dbg_tsig("TSIG: given digest: "); + dbg_tsig_hex(tsig_mac, mac_length); + + if (strncasecmp((char *)(tsig_mac), (char *)digest_tmp, + mac_length) != 0) { + return KNOT_TSIG_EBADSIG; + } + + return KNOT_EOK; +} + +int knot_tsig_server_check(const knot_rrset_t *tsig_rr, + const uint8_t *wire, size_t size, + const knot_key_t *tsig_key) +{ + dbg_tsig_verb("tsig_server_check()\n"); + return knot_tsig_check_digest(tsig_rr, wire, size, NULL, 0, tsig_key, 0); +} + +int knot_tsig_client_check(const knot_rrset_t *tsig_rr, + const uint8_t *wire, size_t size, + const uint8_t *request_mac, size_t request_mac_len, + const knot_key_t *tsig_key) +{ + dbg_tsig_verb("tsig_client_check()\n"); + return knot_tsig_check_digest(tsig_rr, wire, size, request_mac, + request_mac_len, tsig_key, 0); +} + +int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr, + const uint8_t *wire, size_t size, + const uint8_t *prev_digest, + size_t prev_digest_len, + const knot_key_t *tsig_key) +{ +// return knot_tsig_client_check(tsig_rr, wire, size, prev_digest, +// prev_digest_len, tsig_key); + dbg_tsig_verb("tsig_client_check_next()\n"); + return knot_tsig_check_digest(tsig_rr, wire, size, prev_digest, + prev_digest_len, tsig_key, 1); + return KNOT_ENOTSUP; +} diff --git a/src/libknot/tsig-op.h b/src/libknot/tsig-op.h new file mode 100644 index 0000000..b206dc7 --- /dev/null +++ b/src/libknot/tsig-op.h @@ -0,0 +1,161 @@ +/*! + * \file tsig-op.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief TSIG signing and validating. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_TSIG_OP_H_ +#define _KNOT_TSIG_OP_H_ + +#include <stdint.h> + +#include "tsig.h" +#include "rrset.h" + +/*! + * \brief Generate TSIG signature of a message. + * + * This function generates TSIG digest of the given message prepended with the + * given Request MAC (if any) and appended with TSIG Variables. It also appends + * the resulting TSIG RR to the message wire format and accordingly adjusts + * the message size. + * + * \note This function does not save the new digest to the 'digest' parameter + * unless everything went OK. This allows to sent the same buffer to + * the 'request_mac' and 'digest' parameters. + * + * \param msg Message to be signed. + * \param msg_len Size of the message in bytes. + * \param msg_max_len Maximum size of the message in bytes. + * \param request_mac Request MAC. (may be NULL). + * \param request_mac_len Size of the request MAC in bytes. + * \param digest Buffer to save the digest in. + * \param digest_len In: size of the buffer. Out: real size of the digest saved. + * \param tsig_rr RRSet containing the TSIG RR to be used. Data from the RR are + * appended to the signed message. + * + * \retval KNOT_EOK if everything went OK. + * \retval TODO + * + * \todo This function should return TSIG errors by their codes which are + * positive values - this will be recognized by the caller. + */ +int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_len, + const uint8_t *request_mac, size_t request_mac_len, + uint8_t *digest, size_t *digest_len, + const knot_key_t *key); + +/*! + * \brief Generate TSIG signature of a 2nd or later message in a TCP session. + * + * This function generates TSIG digest of the given message prepended with the + * given Request MAC (if any) and appended with TSIG Variables. It also appends + * the resulting TSIG RR to the message wire format and accordingly adjusts + * the message size. + * + * \note This function does not save the new digest to the 'digest' parameter + * unless everything went OK. This allows to sent the same buffer to + * the 'request_mac' and 'digest' parameters. + * + * \param msg Message to be signed. + * \param msg_len Size of the message in bytes. + * \param msg_max_len Maximum size of the message in bytes. + * \param prev_digest Previous digest sent by the server in the session. + * \param prev_digest_len Size of the previous digest in bytes. + * \param digest Buffer to save the digest in. + * \param digest_len In: size of the buffer. Out: real size of the digest saved. + * \param tsig_rr RRSet containing the TSIG RR to be used. Data from the RR are + * appended to the signed message. + * + * \retval KNOT_EOK if successful. + * \retval TODO + * + * \todo This function should return TSIG errors by their codes which are + * positive values - this will be recognized by the caller. + */ +int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, + const uint8_t *prev_digest, size_t prev_digest_len, + uint8_t *digest, size_t *digest_len, + const knot_key_t *key); + +/*! + * \brief Checks incoming request. + * + * \param tsig_rr TSIG extracted from the packet. + * \param wire Wire format of the packet (including the TSIG RR). + * \param size Size of the wire format of packet in bytes. + * + * \retval KNOT_EOK If the signature is valid. + * \retval TODO + * + * \todo This function should return TSIG errors by their codes which are + * positive values - this will be recognized by the caller. + */ +int knot_tsig_server_check(const knot_rrset_t *tsig_rr, + const uint8_t *wire, size_t size, + const knot_key_t *tsig_key); + +/*! + * \brief Checks incoming response. + * + * \param tsig_rr TSIG extracted from the packet. + * \param wire Wire format of the packet (including the TSIG RR). + * \param size Size of the wire format of packet in bytes. + * \param request_mac Request MAC. (may be NULL). + * \param request_mac_len Size of the request MAC in bytes. + * + * \retval KNOT_EOK If the signature is valid. + * \retval TODO + * + * \todo This function should return TSIG errors by their codes which are + * positive values - this will be recognized by the caller. + */ +int knot_tsig_client_check(const knot_rrset_t *tsig_rr, + const uint8_t *wire, size_t size, + const uint8_t *request_mac, size_t request_mac_len, + const knot_key_t *key); + +/*! + * \brief Checks signature of 2nd or next packet in a TCP session. + * + * \param tsig_rr TSIG extracted from the packet. + * \param wire Wire format of the packet (including the TSIG RR). + * \param size Size of the wire format of packet in bytes. + * \param prev_digest Previous digest sent by the server in the session. + * \param prev_digest_len Size of the previous digest in bytes. + * + * \retval KNOT_EOK If the signature is valid. + * \retval TODO + * + * \todo This function should return TSIG errors by their codes which are + * positive values - this will be recognized by the caller. + */ +int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr, + const uint8_t *wire, size_t size, + const uint8_t *prev_digest, + size_t prev_digest_len, + const knot_key_t *key); + +#endif /* _KNOT_TSIG_H_ */ + +/*! @} */ diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c new file mode 100644 index 0000000..432539f --- /dev/null +++ b/src/libknot/tsig.c @@ -0,0 +1,618 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <assert.h> +#include <time.h> + +#include "tsig.h" +#include "util/error.h" +#include "util/debug.h" +#include "common.h" +#include "util/utils.h" +#include "rrset.h" +#include "rdata.h" +#include "dname.h" + +/*! \brief TSIG algorithms table. */ +#define TSIG_ALG_TABLE_SIZE 8 +static knot_lookup_table_t tsig_alg_table[TSIG_ALG_TABLE_SIZE] = { + { KNOT_TSIG_ALG_GSS_TSIG, "gss-tsig." }, + { KNOT_TSIG_ALG_HMAC_MD5, "hmac-md5.sig-alg.reg.int." }, + { KNOT_TSIG_ALG_HMAC_SHA1, "hmac-sha1." }, + { KNOT_TSIG_ALG_HMAC_SHA224, "hmac-sha224." }, + { KNOT_TSIG_ALG_HMAC_SHA256, "hmac-sha256." }, + { KNOT_TSIG_ALG_HMAC_SHA384, "hmac-sha384." }, + { KNOT_TSIG_ALG_HMAC_SHA512, "hmac-sha512." }, + { KNOT_TSIG_ALG_NULL, NULL } +}; + +int tsig_rdata_init(knot_rrset_t *tsig) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + /* Initializes rdata. */ + tsig->rdata = knot_rdata_new(); + if (!tsig->rdata) { + return KNOT_ENOMEM; + } + + tsig->rdata->items = + malloc(sizeof(knot_rdata_item_t) * KNOT_TSIG_ITEM_COUNT); + if (!tsig->rdata->items) { + return KNOT_ENOMEM; + } + + memset(tsig->rdata->items, 0, + sizeof(knot_rdata_item_t) * KNOT_TSIG_ITEM_COUNT); + + return KNOT_EOK; +} + +int tsig_rdata_set_alg_name(knot_rrset_t *tsig, knot_dname_t *alg_name) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 1); + + knot_dname_t *alg_name_copy = knot_dname_deep_copy(alg_name); + if (!alg_name_copy) { + return KNOT_ENOMEM; + } + + knot_rdata_item_set_dname(rdata, 0, alg_name_copy); + + return KNOT_EOK; +} + +int tsig_rdata_set_alg(knot_rrset_t *tsig, tsig_algorithm_t alg) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 1); + + const char *alg_str = tsig_alg_to_str(alg); + knot_dname_t *alg_name_copy = knot_dname_new_from_str(alg_str, + strlen(alg_str), + 0); + if (!alg_name_copy) { + return KNOT_ENOMEM; + } + + knot_rdata_item_set_dname(rdata, 0, alg_name_copy); + + return KNOT_EOK; +} + +int tsig_rdata_set_time_signed(knot_rrset_t *tsig, uint64_t time) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 2); + + /* Create the wire format. */ + uint16_t *wire = malloc(sizeof(uint8_t) * 6 + sizeof(uint16_t)); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + /* Write the length - 6. */ + wire[0] = 6; + knot_wire_write_u48((uint8_t *)(wire + 1), time); + + knot_rdata_item_set_raw_data(rdata, 1, wire); + + return KNOT_EOK; +} + +int tsig_rdata_set_fudge(knot_rrset_t *tsig, uint16_t fudge) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 3); + + /* Create the wire format. */ + uint16_t *wire = malloc(sizeof(uint8_t) * 2 + sizeof(uint16_t)); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + /* Write the length - 2. */ + wire[0] = sizeof(uint16_t); + knot_wire_write_u16((uint8_t *)(wire + 1), fudge); + + knot_rdata_item_set_raw_data(rdata, 2, wire); + + return KNOT_EOK; +} + +int tsig_rdata_set_mac(knot_rrset_t *tsig, uint16_t length, const uint8_t *mac) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 4); + + /* Create the wire format. */ + uint16_t *wire = malloc(sizeof(uint8_t) * length + 2 * sizeof(uint16_t)); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + /* Write the length. */ + wire[0] = length + sizeof(uint16_t); + knot_wire_write_u16((uint8_t *)(wire + 1), length); + /* Copy the actual MAC. */ + memcpy((uint8_t *)(wire + 2), mac, sizeof(uint8_t) * length); + knot_rdata_item_set_raw_data(rdata, 3, wire); + + return KNOT_EOK; +} + +int tsig_rdata_set_orig_id(knot_rrset_t *tsig, uint16_t id) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 5); + + /* Create the wire format. */ + uint16_t *wire = malloc(sizeof(uint8_t) * 2 + sizeof(uint16_t)); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + /* Write the length - 2. */ + wire[0] = sizeof(uint16_t); + knot_wire_write_u16((uint8_t *)(wire + 1), id); + + knot_rdata_item_set_raw_data(rdata, 4, wire); + + return KNOT_EOK; +} + +int tsig_rdata_set_tsig_error(knot_rrset_t *tsig, uint16_t tsig_error) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 6); + + /* Create the wire format. */ + uint16_t *wire = malloc(sizeof(uint8_t) * 2 + sizeof(uint16_t)); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + /* Write the length - 2. */ + wire[0] = sizeof(uint16_t); + knot_wire_write_u16((uint8_t *)(wire + 1), tsig_error); + + knot_rdata_item_set_raw_data(rdata, 5, wire); + + return KNOT_EOK; +} + +int tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t length, + const uint8_t *other_data) +{ + if (!tsig) { + return KNOT_EBADARG; + } + + knot_rdata_t *rdata = knot_rrset_get_rdata(tsig); + if (!rdata) { + return KNOT_EBADARG; + } + assert(knot_rdata_item_count(rdata) >= 6); + + /* Create the wire format. */ + uint16_t *wire = malloc(sizeof(uint8_t) * length + 2 * sizeof(uint16_t)); + if (!wire) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + /* Write the length. */ + wire[0] = length + 2; + knot_wire_write_u16((uint8_t *)(wire + 1), length); + /* Copy the actual data. */ + memcpy(wire + 2, other_data, sizeof(uint8_t) * length); + knot_rdata_item_set_raw_data(rdata, 6, wire); + + return KNOT_EOK; +} + +const knot_dname_t *tsig_rdata_alg_name(const knot_rrset_t *tsig) +{ + if (!tsig) { + return NULL; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + dbg_tsig("TSIG: rdata: alg name: no rdata.\n"); + return NULL; + } + + if (knot_rdata_item_count(rdata) < 1) { + dbg_tsig("TSIG: rdata: alg name: not enough items.\n"); + return NULL; + } + + return knot_rdata_item(rdata, 0)->dname; +} + +tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig) +{ + /*! \todo [TSIG] Implement me. */ + return KNOT_TSIG_ALG_HMAC_MD5; +} + +uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig) +{ + /*!< \note How about assert. Or maybe change API??? */ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + return 0; + } + + if (knot_rdata_item_count(rdata) < 2) { + return 0; + } + + uint16_t *wire = knot_rdata_item(rdata, 1)->raw_data; + assert(wire[0] == 6); + /* Skip the size. */ + wire++; + + return knot_wire_read_u48((uint8_t *)wire); +} + +uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig) +{ + /*!< \note How about assert. Or maybe change API??? */ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + return 0; + } + + if (knot_rdata_item_count(rdata) < 3) { + return 0; + } + + uint16_t *wire = knot_rdata_item(rdata, 2)->raw_data; + assert(wire[0] == 2); + /* Skip the size. */ + wire++; + + return knot_wire_read_u16((uint8_t *)wire); +} + +const uint8_t *tsig_rdata_mac(const knot_rrset_t *tsig) +{ + /*!< \note How about assert. Or maybe change API??? */ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + return 0; + } + + if (knot_rdata_item_count(rdata) < 4) { + return 0; + } + + return (uint8_t*)(knot_rdata_item(rdata, 3)->raw_data + 2); +} + +size_t tsig_rdata_mac_length(const knot_rrset_t *tsig) +{ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata || knot_rdata_item_count(rdata) < 4) { + return 0; + } + + return knot_wire_read_u16( + (uint8_t *)(knot_rdata_item(rdata, 3)->raw_data + 1)); +} + +uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig) +{ + /*!< \note How about assert. Or maybe change API??? */ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + return 0; + } + + if (knot_rdata_item_count(rdata) < 5) { + return 0; + } + + uint16_t *wire = knot_rdata_item(rdata, 4)->raw_data; + assert(wire[0] == 2); + /* Skip the size. */ + wire++; + + return knot_wire_read_u16((uint8_t *)wire); +} + +uint16_t tsig_rdata_error(const knot_rrset_t *tsig) +{ + /*!< \note How about assert. Or maybe change API??? */ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + return 0; + } + + if (knot_rdata_item_count(rdata) < 6) { + return 0; + } + + uint16_t *wire = knot_rdata_item(rdata, 5)->raw_data; + assert(wire[0] == 2); + /* Skip the size. */ + wire++; + + return knot_wire_read_u16((uint8_t *)wire); +} + +const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig) +{ + /*!< \note How about assert. Or maybe change API??? */ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + return 0; + } + + if (knot_rdata_item_count(rdata) < 7) { + return 0; + } + + return (uint8_t *)(knot_rdata_item(rdata, 6)->raw_data + 2); +} + +uint16_t tsig_rdata_other_data_length(const knot_rrset_t *tsig) +{ + /*!< \note How about assert. Or maybe change API??? */ + if (!tsig) { + return 0; + } + + const knot_rdata_t *rdata = knot_rrset_rdata(tsig); + if (!rdata) { + return 0; + } + + if (knot_rdata_item_count(rdata) < 7) { + return 0; + } + + return knot_wire_read_u16((uint8_t *) + (knot_rdata_item(rdata, 6)->raw_data + 1)); +} + +int tsig_alg_from_name(const knot_dname_t *alg_name) +{ + if (!alg_name) { + return 0; + } + + char *name = knot_dname_to_str(alg_name); + if (!name) { + return 0; + } + + knot_lookup_table_t *found = + knot_lookup_by_name(tsig_alg_table, name); + + if (!found) { + dbg_tsig("Unknown algorithm: %s \n", name); + free(name); + return 0; + } + + free(name); + + return found->id; +} + +uint16_t tsig_alg_digest_length(tsig_algorithm_t alg) +{ + switch (alg) { + case KNOT_TSIG_ALG_GSS_TSIG: + return KNOT_TSIG_ALG_DIG_LENGTH_GSS_TSIG; + case KNOT_TSIG_ALG_HMAC_MD5: + return KNOT_TSIG_ALG_DIG_LENGTH_HMAC_MD5; + case KNOT_TSIG_ALG_HMAC_SHA1: + return KNOT_TSIG_ALG_DIG_LENGTH_SHA1; + case KNOT_TSIG_ALG_HMAC_SHA224: + return KNOT_TSIG_ALG_DIG_LENGTH_SHA224; + case KNOT_TSIG_ALG_HMAC_SHA256: + return KNOT_TSIG_ALG_DIG_LENGTH_SHA384; + case KNOT_TSIG_ALG_HMAC_SHA512: + return KNOT_TSIG_ALG_DIG_LENGTH_SHA512; + default: + return 0; + } /* switch(alg) */ +} + +size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig) +{ + /* Key name, Algorithm name and Other data have variable lengths. */ + const knot_dname_t *key_name = knot_rrset_owner(tsig); + if (!key_name) { + return 0; + } + + const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig); + if (!alg_name) { + return 0; + } + +// dbg_tsig_detail("key_name: %.*s (size: %u) alg_name: %.*s (size: %u)\n", knot_dname_size(key_name), +// key_name->name, alg_name->size, alg_name->name, +// key_name->size, alg_name->size); + +// dbg_tsig_hex_detail(key_name->name, key_name->size); +// dbg_tsig_hex_detail(alg_name->name, alg_name->size); + + uint16_t other_data_length = tsig_rdata_other_data_length(tsig); + + return knot_dname_size(key_name) + knot_dname_size(alg_name) + + other_data_length + KNOT_TSIG_VARIABLES_LENGTH; +} + +size_t tsig_rdata_tsig_timers_length() +{ + return KNOT_TSIG_TIMERS_LENGTH; +} + + +int tsig_rdata_store_current_time(knot_rrset_t *tsig) +{ + if (!tsig) { + return KNOT_EBADARG; + } + time_t curr_time = time(NULL); + /*!< \todo bleeding eyes. */ + tsig_rdata_set_time_signed(tsig, (uint64_t)curr_time); + return KNOT_EOK; +} + +const char* tsig_alg_to_str(tsig_algorithm_t alg) +{ + for (unsigned i = 0; i < TSIG_ALG_TABLE_SIZE; ++i) { + if (tsig_alg_table[i].id == alg) { + return tsig_alg_table[i].name; + } + } + + return ""; +} + +size_t tsig_wire_maxsize(const knot_key_t* key) +{ + size_t alg_name_size = strlen(tsig_alg_to_str(key->algorithm)) + 1; + + return knot_dname_size(key->name) + + sizeof(uint16_t) + /* TYPE */ + sizeof(uint16_t) + /* CLASS */ + sizeof(uint32_t) + /* TTL */ + sizeof(uint16_t) + /* RDLENGTH */ + alg_name_size + /* Alg. name */ + 6 * sizeof(uint8_t) + /* Time signed */ + sizeof(uint16_t) + /* Fudge */ + sizeof(uint16_t) + /* MAC size */ + tsig_alg_digest_length(key->algorithm) + /* MAC */ + sizeof(uint16_t) + /* Original ID */ + sizeof(uint16_t) + /* Error */ + sizeof(uint16_t) + /* Other len */ + 6* sizeof(uint8_t); /* uint48_t in case of BADTIME RCODE */ +} + +size_t tsig_wire_actsize(const knot_rrset_t *tsig) +{ + return knot_dname_size(knot_rrset_owner(tsig)) + + sizeof(uint16_t) + /* TYPE */ + sizeof(uint16_t) + /* CLASS */ + sizeof(uint32_t) + /* TTL */ + sizeof(uint16_t) + /* RDLENGTH */ + knot_dname_size(tsig_rdata_alg_name(tsig)) + + 6 * sizeof(uint8_t) + /* Time signed */ + sizeof(uint16_t) + /* Fudge */ + sizeof(uint16_t) + /* MAC size */ + tsig_rdata_mac_length(tsig) + + sizeof(uint16_t) + /* Original ID */ + sizeof(uint16_t) + /* Error */ + sizeof(uint16_t) + /* Other len */ + tsig_rdata_other_data_length(tsig); +} + diff --git a/src/libknot/tsig.h b/src/libknot/tsig.h new file mode 100644 index 0000000..eafcfab --- /dev/null +++ b/src/libknot/tsig.h @@ -0,0 +1,145 @@ +/*! + * \file tsig.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief TSIG manipulation. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_TSIG_H_ +#define _KNOT_TSIG_H_ + +#include <stdint.h> + +#include "rrset.h" +#include "util/utils.h" + +/* The assigned numbers should not begin with 0 - reserved for error. */ +enum tsig_algorithm { + KNOT_TSIG_ALG_NULL = 0, + KNOT_TSIG_ALG_GSS_TSIG = 128, /*!< \brief gss-tsig. */ + KNOT_TSIG_ALG_HMAC_MD5, /*!< \brief HMAC-MD5.SIG-ALG.REG.INT. */ + KNOT_TSIG_ALG_HMAC_SHA1, /*!< \brief hmac-sha1. */ + KNOT_TSIG_ALG_HMAC_SHA224, /*!< \brief hmac-sha224. */ + KNOT_TSIG_ALG_HMAC_SHA256, /*!< \brief hmac-sha256. */ + KNOT_TSIG_ALG_HMAC_SHA384, /*!< \brief hmac-sha384. */ + KNOT_TSIG_ALG_HMAC_SHA512 /*!< \brief hmac-sha512. */ +}; + +typedef enum tsig_algorithm tsig_algorithm_t; + +struct knot_key { + knot_dname_t *name; /*!< Key name. */ + tsig_algorithm_t algorithm; /*!< Key algorithm. */ + char *secret; /*!< Key data. */ + size_t secret_size; /*!< Key length. */ +}; + +typedef struct knot_key knot_key_t; + +/*!< \todo FIND ALG LENGTHS */ +enum tsig_algorithm_digest_length { + KNOT_TSIG_ALG_DIG_LENGTH_GSS_TSIG = 0, + KNOT_TSIG_ALG_DIG_LENGTH_HMAC_MD5 = 16, + KNOT_TSIG_ALG_DIG_LENGTH_SHA1 = 0, + KNOT_TSIG_ALG_DIG_LENGTH_SHA224 = 0, + KNOT_TSIG_ALG_DIG_LENGTH_SHA256 = 0, + KNOT_TSIG_ALG_DIG_LENGTH_SHA384 = 0, + KNOT_TSIG_ALG_DIG_LENGTH_SHA512 = 0 +}; + +enum tsig_consts { + KNOT_TSIG_ITEM_COUNT = 7, + KNOT_TSIG_VARIABLES_LENGTH = sizeof(uint16_t) // class + + sizeof(uint32_t) // ttl + + 6 // time signed + + sizeof(uint16_t) // fudge + + sizeof(uint16_t) // error + + sizeof(uint16_t),// other data length + KNOT_TSIG_TIMERS_LENGTH = sizeof(uint16_t) //fugde + + 6 // time signed +}; + +/*! TSIG errors are defined in util/error.h + * and present negative value of the TSIG error to + * comply with other parts of the library. + * + * KNOT_TSIG_EBADSIG = -16 + * KNOT_TSIG_EBADKEY = -17 + * KNOT_TSIG_EBADTIME = -18 + */ + +/*! + * \note Uses the given domain name, do not deallocate it! + */ +int tsig_rdata_set_alg_name(knot_rrset_t *tsig, knot_dname_t *alg_name); +int tsig_rdata_set_alg(knot_rrset_t *tsig, tsig_algorithm_t alg); +int tsig_rdata_set_time_signed(knot_rrset_t *tsig, uint64_t time); +int tsig_rdata_store_current_time(knot_rrset_t *tsig); +int tsig_rdata_set_fudge(knot_rrset_t *tsig, uint16_t fudge); +int tsig_rdata_set_mac(knot_rrset_t *tsig, uint16_t length, + const uint8_t *mac); +int tsig_rdata_set_orig_id(knot_rrset_t *tsig, uint16_t id); +int tsig_rdata_set_tsig_error(knot_rrset_t *tsig, uint16_t tsig_error); +int tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t length, + const uint8_t *other_data); + +const knot_dname_t *tsig_rdata_alg_name(const knot_rrset_t *tsig); +tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig); +uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig); +uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig); +const uint8_t *tsig_rdata_mac(const knot_rrset_t *tsig); +size_t tsig_rdata_mac_length(const knot_rrset_t *tsig); +uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig); +uint16_t tsig_rdata_error(const knot_rrset_t *tsig); +const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig); +uint16_t tsig_rdata_other_data_length(const knot_rrset_t *tsig); +size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig); + +size_t tsig_rdata_tsig_timers_length(); + +int tsig_alg_from_name(const knot_dname_t *name); + +/*! + * \brief Convert TSIG algorithm identifier to name. + * + * \param alg TSIG algorithm identifier. + * + * \retval TSIG algorithm string name. + * \retval Empty string if undefined. + */ +const char* tsig_alg_to_str(tsig_algorithm_t alg); + +uint16_t tsig_alg_digest_length(tsig_algorithm_t alg); + +/*! + * \brief Return TSIG RRSET maximum wire size for given algorithm. + * + * \param key Signing key descriptor. + * + * \return RRSET wire size. + */ +size_t tsig_wire_maxsize(const knot_key_t *key); +size_t tsig_wire_actsize(const knot_rrset_t *tsig); + +#endif /* _KNOT_TSIG_H_ */ + +/*! @} */ diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c new file mode 100644 index 0000000..cf9e6a0 --- /dev/null +++ b/src/libknot/updates/changesets.c @@ -0,0 +1,296 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#include "updates/changesets.h" + +#include "rrset.h" +#include "util/error.h" + +static const size_t KNOT_CHANGESET_COUNT = 5; +static const size_t KNOT_CHANGESET_STEP = 5; +static const size_t KNOT_CHANGESET_RRSET_COUNT = 5; +static const size_t KNOT_CHANGESET_RRSET_STEP = 5; + +/*----------------------------------------------------------------------------*/ + +static int knot_changeset_check_count(knot_rrset_t ***rrsets, size_t count, + size_t *allocated) +{ + /* Check if allocated is sufficient. */ + if (count <= *allocated) { + return KNOT_EOK; + } + + /* How many steps is needed to content count? */ + size_t extra = (count - *allocated) % KNOT_CHANGESET_RRSET_STEP; + extra = (extra + 1) * KNOT_CHANGESET_RRSET_STEP; + + /* Allocate new memory block. */ + const size_t item_len = sizeof(knot_rrset_t *); + const size_t new_count = *allocated + extra; + knot_rrset_t **rrsets_new = malloc(new_count * item_len); + if (rrsets_new == NULL) { + return KNOT_ENOMEM; + } + + /* Clear old memory block and copy old data. */ + memset(rrsets_new, 0, new_count * item_len); + memcpy(rrsets_new, *rrsets, (*allocated) * item_len); + + /* Replace old rrsets. */ + free(*rrsets); + *rrsets = rrsets_new; + *allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_changeset_rrsets_match(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2) +{ + return knot_rrset_compare(rrset1, rrset2, KNOT_RRSET_COMPARE_HEADER) + && (knot_rrset_type(rrset1) != KNOT_RRTYPE_RRSIG + || knot_rdata_rrsig_type_covered( + knot_rrset_rdata(rrset1)) + == knot_rdata_rrsig_type_covered( + knot_rrset_rdata(rrset2))); +} + +/*----------------------------------------------------------------------------*/ + +int knot_changeset_allocate(knot_changesets_t **changesets) +{ + // create new changesets + *changesets = (knot_changesets_t *)(malloc(sizeof(knot_changesets_t))); + if (*changesets == NULL) { + return KNOT_ENOMEM; + } + + memset(*changesets, 0, sizeof(knot_changesets_t)); + + return knot_changesets_check_size(*changesets); +} + +/*----------------------------------------------------------------------------*/ + +int knot_changeset_add_rrset(knot_rrset_t ***rrsets, + size_t *count, size_t *allocated, + knot_rrset_t *rrset) +{ + int ret = knot_changeset_check_count(rrsets, *count + 1, allocated); + if (ret != KNOT_EOK) { + return ret; + } + + (*rrsets)[*count] = rrset; + *count = *count + 1; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_changeset_add_rr(knot_rrset_t ***rrsets, size_t *count, + size_t *allocated, knot_rrset_t *rr) +{ + // try to find the RRSet in the list of RRSets, but search backwards + // as it is probable that the last RRSet is the one to which the RR + // belongs + int i = *count - 1; + + while (i >= 0 && !knot_changeset_rrsets_match((*rrsets)[i], rr)) { + --i; + } + + if (i >= 0) { + // found RRSet to merge the new one into + if (knot_rrset_merge((void **)&(*rrsets)[i], + (void **)&rr) != KNOT_EOK) { + return KNOT_ERROR; + } + + // remove the RR + /*! \todo does this make sense? */ + knot_rrset_free(&rr); // used to be deep free with all 1's + + return KNOT_EOK; + } else { + return knot_changeset_add_rrset(rrsets, count, allocated, rr); + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_changeset_add_new_rr(knot_changeset_t *changeset, + knot_rrset_t *rrset, + xfrin_changeset_part_t part) +{ + knot_rrset_t ***rrsets = NULL; + size_t *count = NULL; + size_t *allocated = NULL; + + switch (part) { + case XFRIN_CHANGESET_ADD: + rrsets = &changeset->add; + count = &changeset->add_count; + allocated = &changeset->add_allocated; + break; + case XFRIN_CHANGESET_REMOVE: + rrsets = &changeset->remove; + count = &changeset->remove_count; + allocated = &changeset->remove_allocated; + break; + default: + assert(0); + } + + assert(rrsets != NULL); + assert(count != NULL); + assert(allocated != NULL); + + int ret = knot_changeset_add_rr(rrsets, count, allocated, rrset); + if (ret != KNOT_EOK) { + return ret; + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +void knot_changeset_store_soa(knot_rrset_t **chg_soa, + uint32_t *chg_serial, knot_rrset_t *soa) +{ + *chg_soa = soa; + *chg_serial = knot_rdata_soa_serial(knot_rrset_rdata(soa)); +} + +/*----------------------------------------------------------------------------*/ + +int knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa, + xfrin_changeset_part_t part) +{ + switch (part) { + case XFRIN_CHANGESET_ADD: + knot_changeset_store_soa(&changeset->soa_to, + &changeset->serial_to, soa); + break; + case XFRIN_CHANGESET_REMOVE: + knot_changeset_store_soa(&changeset->soa_from, + &changeset->serial_from, soa); + break; + default: + assert(0); + } + + /*! \todo Remove return value? */ + return KNOT_EOK; +} + +/*---------------------------------------------------------------------------*/ + +int knot_changesets_check_size(knot_changesets_t *changesets) +{ + /* Check if allocated is sufficient. */ + if (changesets->count <= changesets->allocated) { + return KNOT_EOK; + } + + /* How many steps is needed to content count? */ + size_t extra = (changesets->count - changesets->allocated) % KNOT_CHANGESET_STEP; + extra = (extra + 1) * KNOT_CHANGESET_STEP; + + /* Allocate new memory block. */ + const size_t item_len = sizeof(knot_changeset_t); + size_t new_count = (changesets->allocated + extra); + knot_changeset_t *sets = malloc(new_count * item_len); + if (sets == NULL) { + return KNOT_ENOMEM; + } + + /* Clear old memory block and copy old data. */ + memset(sets, 0, new_count * item_len); + memcpy(sets, changesets->sets, changesets->allocated * item_len); + + /* Replace old changesets. */ + free(changesets->sets); + changesets->sets = sets; + changesets->allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +void knot_free_changeset(knot_changeset_t **changeset) +{ + /* XXX XXX investigate wrong frees. */ + assert((*changeset)->add_allocated >= (*changeset)->add_count); + assert((*changeset)->remove_allocated >= (*changeset)->remove_count); + assert((*changeset)->allocated >= (*changeset)->size); + + int j; + for (j = 0; j < (*changeset)->add_count; ++j) { + knot_rrset_deep_free(&(*changeset)->add[j], 1, 1, 1); + } + free((*changeset)->add); + + for (j = 0; j < (*changeset)->remove_count; ++j) { + knot_rrset_deep_free(&(*changeset)->remove[j], 1, 1, 1); + } + free((*changeset)->remove); + + knot_rrset_deep_free(&(*changeset)->soa_from, 1, 1, 1); + knot_rrset_deep_free(&(*changeset)->soa_to, 1, 1, 1); + + free((*changeset)->data); + + + *changeset = NULL; +} + +/*----------------------------------------------------------------------------*/ + +void knot_free_changesets(knot_changesets_t **changesets) +{ + if (changesets == NULL || *changesets == NULL) { + return; + } + + assert((*changesets)->allocated >= (*changesets)->count); + + for (int i = 0; i < (*changesets)->count; ++i) { + knot_changeset_t *ch = &(*changesets)->sets[i]; + knot_free_changeset(&ch); + } + + free((*changesets)->sets); + + knot_rrset_deep_free(&(*changesets)->first_soa, 1, 1, 1); + + free(*changesets); + *changesets = NULL; +} + +/*---------------------------------------------------------------------------*/ + + diff --git a/src/libknot/updates/changesets.h b/src/libknot/updates/changesets.h new file mode 100644 index 0000000..e8d5e39 --- /dev/null +++ b/src/libknot/updates/changesets.h @@ -0,0 +1,102 @@ +/*! + * \file changesets.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Structure for representing IXFR/DDNS changeset and its API. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_CHANGESETS_H_ +#define _KNOT_CHANGESETS_H_ + +#include "rrset.h" + +/*! \todo Changeset must be serializable/deserializable, so + * all data and pointers have to be changeset-exclusive, + * or more advanced structure serialization scheme has to be + * implemented. + * + * \todo Preallocation of space for changeset. + */ +typedef struct { + knot_rrset_t *soa_from; + knot_rrset_t **remove; + size_t remove_count; + size_t remove_allocated; + + knot_rrset_t *soa_to; + knot_rrset_t **add; + size_t add_count; + size_t add_allocated; + + uint8_t *data; + size_t size; + size_t allocated; + uint32_t serial_from; + uint32_t serial_to; +} knot_changeset_t; + +/*----------------------------------------------------------------------------*/ + +typedef struct { + knot_changeset_t *sets; + size_t count; + size_t allocated; + knot_rrset_t *first_soa; +} knot_changesets_t; + +/*----------------------------------------------------------------------------*/ + +typedef enum { + XFRIN_CHANGESET_ADD, + XFRIN_CHANGESET_REMOVE +} xfrin_changeset_part_t; + +/*----------------------------------------------------------------------------*/ + +int knot_changeset_allocate(knot_changesets_t **changesets); + +int knot_changeset_add_rrset(knot_rrset_t ***rrsets, + size_t *count, size_t *allocated, + knot_rrset_t *rrset); + +int knot_changeset_add_rr(knot_rrset_t ***rrsets, size_t *count, + size_t *allocated, knot_rrset_t *rr); + +int knot_changeset_add_new_rr(knot_changeset_t *changeset, + knot_rrset_t *rrset, + xfrin_changeset_part_t part); + +void knot_changeset_store_soa(knot_rrset_t **chg_soa, + uint32_t *chg_serial, knot_rrset_t *soa); + +int knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa, + xfrin_changeset_part_t part); + +int knot_changesets_check_size(knot_changesets_t *changesets); + +void knot_free_changeset(knot_changeset_t **changeset); + +void knot_free_changesets(knot_changesets_t **changesets); + +#endif /* _KNOT_CHANGESETS_H_ */ + +/*! @} */ diff --git a/src/libknot/updates/ddns.c b/src/libknot/updates/ddns.c new file mode 100644 index 0000000..4c6ab7b --- /dev/null +++ b/src/libknot/updates/ddns.c @@ -0,0 +1,638 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "updates/ddns.h" +#include "updates/changesets.h" +#include "util/debug.h" +#include "packet/packet.h" +#include "util/error.h" +#include "consts.h" + +/*----------------------------------------------------------------------------*/ +// Copied from XFR - maybe extract somewhere else +static int knot_ddns_prereq_check_rrsets(knot_rrset_t ***rrsets, + size_t *count, size_t *allocated) +{ + int new_count = 0; + if (*count == *allocated) { + new_count = *allocated * 2; + } + + knot_rrset_t **rrsets_new = + (knot_rrset_t **)calloc(new_count, sizeof(knot_rrset_t *)); + if (rrsets_new == NULL) { + return KNOT_ENOMEM; + } + + memcpy(rrsets_new, *rrsets, *count); + *rrsets = rrsets_new; + *allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_prereq_check_dnames(knot_dname_t ***dnames, + size_t *count, size_t *allocated) +{ + int new_count = 0; + if (*count == *allocated) { + new_count = *allocated * 2; + } + + knot_dname_t **dnames_new = + (knot_dname_t **)calloc(new_count, sizeof(knot_dname_t *)); + if (dnames_new == NULL) { + return KNOT_ENOMEM; + } + + memcpy(dnames_new, *dnames, *count); + *dnames = dnames_new; + *allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_add_prereq_rrset(const knot_rrset_t *rrset, + knot_rrset_t ***rrsets, + size_t *count, size_t *allocd) +{ + // check if such RRSet is not already there and merge if needed + int ret; + for (int i = 0; i < *count; ++i) { + if (knot_rrset_compare(rrset, (*rrsets)[i], + KNOT_RRSET_COMPARE_HEADER) == 0) { + ret = knot_rrset_merge((void **)&((*rrsets)[i]), + (void **)&rrset); + if (ret != KNOT_EOK) { + return ret; + } else { + return KNOT_EOK; + } + } + } + + // if we are here, the RRSet was not found + ret = knot_ddns_prereq_check_rrsets(rrsets, count, allocd); + if (ret != KNOT_EOK) { + return ret; + } + + knot_rrset_t *new_rrset = NULL; + ret = knot_rrset_deep_copy(rrset, &new_rrset); + if (ret != KNOT_EOK) { + return ret; + } + + (*rrsets)[(*count)++] = new_rrset; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_add_prereq_dname(const knot_dname_t *dname, + knot_dname_t ***dnames, + size_t *count, size_t *allocd) +{ + // we do not have to check if the name is not already there + // if it is, we will just check it twice in the zone + + int ret = knot_ddns_prereq_check_dnames(dnames, count, allocd); + if (ret != KNOT_EOK) { + return ret; + } + + knot_dname_t *dname_new = knot_dname_deep_copy(dname); + if (dname_new == NULL) { + return KNOT_ENOMEM; + } + + (*dnames)[(*count)++] = dname_new; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs, + const knot_rrset_t *rrset, uint16_t qclass) +{ + assert(prereqs != NULL); + assert(rrset != NULL); + + if (knot_rrset_ttl(rrset) != 0) { + return KNOT_EMALF; + } + + int ret; + + if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) { + if (knot_rrset_rdata(rrset) != NULL) { + return KNOT_EMALF; + } + if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) { + ret = knot_ddns_add_prereq_dname( + knot_rrset_owner(rrset), &prereqs->in_use, + &prereqs->in_use_count, + &prereqs->in_use_allocd); + } else { + ret = knot_ddns_add_prereq_rrset(rrset, + &prereqs->exist, + &prereqs->exist_count, + &prereqs->exist_allocd); + } + } else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) { + if (knot_rrset_rdata(rrset) != NULL) { + return KNOT_EMALF; + } + if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) { + ret = knot_ddns_add_prereq_dname( + knot_rrset_owner(rrset), &prereqs->not_in_use, + &prereqs->not_in_use_count, + &prereqs->not_in_use_allocd); + } else { + ret = knot_ddns_add_prereq_rrset(rrset, + &prereqs->not_exist, + &prereqs->not_exist_count, + &prereqs->not_exist_allocd); + } + } else if (knot_rrset_class(rrset) == qclass) { + ret = knot_ddns_add_prereq_rrset(rrset, + &prereqs->exist_full, + &prereqs->exist_full_count, + &prereqs->exist_full_allocd); + } else { + return KNOT_EMALF; + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_add_update(knot_changeset_t *changeset, + const knot_rrset_t *rrset, uint16_t qclass) +{ + assert(changeset != NULL); + assert(rrset != NULL); + + int ret; + + // create a copy of the RRSet + /*! \todo If the packet was not parsed all at once, we could save this + * copy. + */ + knot_rrset_t *rrset_copy; + ret = knot_rrset_deep_copy(rrset, &rrset_copy); + if (ret != KNOT_EOK) { + return ret; + } + + /*! \todo What about the SOAs? */ + + if (knot_rrset_class(rrset) == qclass) { + // this RRSet should be added to the zone + ret = knot_changeset_add_rr(&changeset->add, + &changeset->add_count, + &changeset->add_allocated, + rrset_copy); + } else { + // this RRSet marks removal of something from zone + // what should be removed is distinguished when applying + ret = knot_changeset_add_rr(&changeset->remove, + &changeset->remove_count, + &changeset->remove_allocated, + rrset_copy); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_check_exist(const knot_zone_contents_t *zone, + const knot_rrset_t *rrset, uint8_t *rcode) +{ + assert(zone != NULL); + assert(rrset != NULL); + assert(rcode != NULL); + assert(knot_rrset_rdata(rrset) == NULL); + assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); + assert(knot_rrset_ttl(rrset) == 0); + assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY); + + if (!knot_dname_is_subdomain(knot_rrset_owner(rrset), + knot_node_owner(knot_zone_contents_apex(zone)))) { + *rcode = KNOT_RCODE_NOTZONE; + return KNOT_EBADZONE; + } + + const knot_node_t *node; + node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset)); + if (node == NULL) { + *rcode = KNOT_RCODE_NXRRSET; + return KNOT_ENONODE; + } else if (knot_node_rrset(node, knot_rrset_type(rrset)) == NULL) { + *rcode = KNOT_RCODE_NXRRSET; + return KNOT_ENORRSET; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, + const knot_rrset_t *rrset, uint8_t *rcode) +{ + assert(zone != NULL); + assert(rrset != NULL); + assert(rcode != NULL); + assert(knot_rrset_rdata(rrset) == NULL); + assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); + assert(knot_rrset_ttl(rrset) == 0); + assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY); + + if (!knot_dname_is_subdomain(knot_rrset_owner(rrset), + knot_node_owner(knot_zone_contents_apex(zone)))) { + *rcode = KNOT_RCODE_NOTZONE; + return KNOT_EBADZONE; + } + + const knot_node_t *node; + const knot_rrset_t *found; + + node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset)); + if (node == NULL) { + *rcode = KNOT_RCODE_NXRRSET; + return KNOT_EPREREQ; + } else if ((found = knot_node_rrset(node, knot_rrset_type(rrset))) + == NULL) { + *rcode = KNOT_RCODE_NXRRSET; + return KNOT_EPREREQ; + } else { + // do not have to compare the header, it is already done + assert(knot_rrset_type(found) == knot_rrset_type(rrset)); + assert(knot_dname_compare(knot_rrset_owner(found), + knot_rrset_owner(rrset)) == 0); + if (knot_rrset_compare_rdata(found, rrset) <= 0) { + *rcode = KNOT_RCODE_NXRRSET; + return KNOT_EPREREQ; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone, + const knot_rrset_t *rrset, uint8_t *rcode) +{ + assert(zone != NULL); + assert(rrset != NULL); + assert(rcode != NULL); + assert(knot_rrset_rdata(rrset) == NULL); + assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); + assert(knot_rrset_ttl(rrset) == 0); + assert(knot_rrset_class(rrset) == KNOT_CLASS_NONE); + + if (!knot_dname_is_subdomain(knot_rrset_owner(rrset), + knot_node_owner(knot_zone_contents_apex(zone)))) { + *rcode = KNOT_RCODE_NOTZONE; + return KNOT_EBADZONE; + } + + const knot_node_t *node; + const knot_rrset_t *found; + + node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset)); + if (node == NULL) { + return KNOT_EOK; + } else if ((found = knot_node_rrset(node, knot_rrset_type(rrset))) + == NULL) { + return KNOT_EOK; + } else { + // do not have to compare the header, it is already done + assert(knot_rrset_type(found) == knot_rrset_type(rrset)); + assert(knot_dname_compare(knot_rrset_owner(found), + knot_rrset_owner(rrset)) == 0); + if (knot_rrset_compare_rdata(found, rrset) <= 0) { + return KNOT_EOK; + } + } + + *rcode = KNOT_RCODE_YXRRSET; + return KNOT_EPREREQ; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_check_in_use(const knot_zone_contents_t *zone, + const knot_dname_t *dname, uint8_t *rcode) +{ + assert(zone != NULL); + assert(dname != NULL); + assert(rcode != NULL); + + if (!knot_dname_is_subdomain(dname, + knot_node_owner(knot_zone_contents_apex(zone)))) { + *rcode = KNOT_RCODE_NOTZONE; + return KNOT_EBADZONE; + } + + const knot_node_t *node; + + node = knot_zone_contents_find_node(zone, dname); + if (node == NULL) { + *rcode = KNOT_RCODE_NXDOMAIN; + return KNOT_EPREREQ; + } else if (knot_node_rrset_count(node) == 0) { + *rcode = KNOT_RCODE_NXDOMAIN; + return KNOT_EPREREQ; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone, + const knot_dname_t *dname, uint8_t *rcode) +{ + assert(zone != NULL); + assert(dname != NULL); + assert(rcode != NULL); + + if (!knot_dname_is_subdomain(dname, + knot_node_owner(knot_zone_contents_apex(zone)))) { + *rcode = KNOT_RCODE_NOTZONE; + return KNOT_EBADZONE; + } + + const knot_node_t *node; + + node = knot_zone_contents_find_node(zone, dname); + if (node == NULL) { + return KNOT_EOK; + } else if (knot_node_rrset_count(node) == 0) { + return KNOT_EOK; + } + + *rcode = KNOT_RCODE_YXDOMAIN; + return KNOT_EPREREQ; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +int knot_ddns_check_zone(const knot_zone_t *zone, knot_packet_t *query, + uint8_t *rcode) +{ + if (zone == NULL || query == NULL || rcode == NULL) { + return KNOT_EBADARG; + } + + if (knot_packet_qtype(query) != KNOT_RRTYPE_SOA) { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; + } + + if(!knot_zone_contents(zone)) { + *rcode = KNOT_RCODE_REFUSED; + return KNOT_ENOZONE; + } + + // 1) check if the zone is master or slave + if (!knot_zone_is_master(zone)) { + return KNOT_EBADZONE; + } + + // 2) check zone CLASS + if (knot_zone_contents_class(knot_zone_contents(zone)) != + knot_packet_qclass(query)) { + *rcode = KNOT_RCODE_NOTAUTH; + return KNOT_ENOZONE; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ddns_process_prereqs(knot_packet_t *query, + knot_ddns_prereq_t **prereqs, uint8_t *rcode) +{ + /*! \todo Consider not parsing the whole packet at once, but + * parsing one RR at a time - could save some memory and time. + */ + + if (query == NULL || prereqs == NULL || rcode == NULL) { + return KNOT_EBADARG; + } + + // allocate space for the prerequisities + *prereqs = (knot_ddns_prereq_t *)calloc(1, sizeof(knot_ddns_prereq_t)); + CHECK_ALLOC_LOG(*prereqs, KNOT_ENOMEM); + + int ret; + + for (int i = 0; i < knot_packet_answer_rrset_count(query); ++i) { + // we must copy the RRSets, because all those stored in the + // packet will be destroyed + ret = knot_ddns_add_prereq(*prereqs, + knot_packet_answer_rrset(query, i), + knot_packet_qclass(query)); + if (ret != KNOT_EOK) { + dbg_ddns("Failed to add prerequisity RRSet:%s\n", + knot_strerror(ret)); + *rcode = (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR + : KNOT_RCODE_SERVFAIL; + knot_ddns_prereqs_free(prereqs); + return ret; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, + knot_ddns_prereq_t **prereqs, uint8_t *rcode) +{ + int i, ret; + + for (i = 0; i < (*prereqs)->exist_count; ++i) { + ret = knot_ddns_check_exist(zone, (*prereqs)->exist[i], rcode); + if (ret != KNOT_EOK) { + return ret; + } + } + + for (i = 0; i < (*prereqs)->exist_full_count; ++i) { + ret = knot_ddns_check_exist_full(zone, + (*prereqs)->exist_full[i], + rcode); + if (ret != KNOT_EOK) { + return ret; + } + } + + for (i = 0; i < (*prereqs)->not_exist_count; ++i) { + ret = knot_ddns_check_not_exist(zone, (*prereqs)->not_exist[i], + rcode); + if (ret != KNOT_EOK) { + return ret; + } + } + + for (i = 0; i < (*prereqs)->in_use_count; ++i) { + ret = knot_ddns_check_in_use(zone, (*prereqs)->in_use[i], + rcode); + if (ret != KNOT_EOK) { + return ret; + } + } + + for (i = 0; i < (*prereqs)->not_in_use_count; ++i) { + ret = knot_ddns_check_not_in_use(zone, + (*prereqs)->not_in_use[i], + rcode); + if (ret != KNOT_EOK) { + return ret; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_ddns_check_update(const knot_rrset_t *rrset, + const knot_packet_t *query, uint8_t *rcode) +{ + if (!knot_dname_is_subdomain(knot_rrset_owner(rrset), + knot_packet_qname(query))) { + *rcode = KNOT_RCODE_NOTZONE; + return KNOT_EBADZONE; + } + + if (knot_rrset_class(rrset) == knot_packet_qclass(query)) { + if (knot_rrtype_is_metatype(knot_rrset_type(rrset))) { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; + } + } else if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) { + if (knot_rrset_rdata(rrset) != NULL + || (knot_rrtype_is_metatype(knot_rrset_type(rrset)) + && knot_rrset_type(rrset) != KNOT_RRTYPE_ANY)) { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; + } + } else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) { + if (knot_rrset_ttl(rrset) != 0 + || knot_rrtype_is_metatype(knot_rrset_type(rrset))) { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; + } + } else { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ddns_process_update(knot_packet_t *query, + knot_changeset_t **changeset, uint8_t *rcode) +{ + // just put all RRSets from query's Authority section + // it will be distinguished when applying to the zone + + if (query == NULL || changeset == NULL || rcode == NULL) { + return KNOT_EBADARG; + } + + *changeset = (knot_changeset_t *)calloc(1, sizeof(knot_changeset_t)); + CHECK_ALLOC_LOG(*changeset, KNOT_ENOMEM); + + int ret; + + for (int i = 0; i < knot_packet_authority_rrset_count(query); ++i) { + + const knot_rrset_t *rrset = + knot_packet_authority_rrset(query, i); + + ret = knot_ddns_check_update(rrset, query, rcode); + if (ret != KNOT_EOK) { + return ret; + } + + ret = knot_ddns_add_update(*changeset, rrset, + knot_packet_qclass(query)); + + if (ret != KNOT_EOK) { + dbg_ddns("Failed to add update RRSet:%s\n", + knot_strerror(ret)); + *rcode = (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR + : KNOT_RCODE_SERVFAIL; + knot_free_changeset(changeset); + return ret; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq) +{ + int i; + + for (i = 0; i < (*prereq)->exist_count; ++i) { + knot_rrset_deep_free(&(*prereq)->exist[i], 1, 1, 1); + } + + for (i = 0; i < (*prereq)->exist_full_count; ++i) { + knot_rrset_deep_free(&(*prereq)->exist_full[i], 1, 1, 1); + } + + for (i = 0; i < (*prereq)->not_exist_count; ++i) { + knot_rrset_deep_free(&(*prereq)->not_exist[i], 1, 1, 1); + } + + for (i = 0; i < (*prereq)->in_use_count; ++i) { + knot_dname_free(&(*prereq)->in_use[i]); + } + + for (i = 0; i < (*prereq)->not_in_use_count; ++i) { + knot_dname_free(&(*prereq)->not_in_use[i]); + } + + free(*prereq); + *prereq = NULL; +} diff --git a/src/libknot/updates/ddns.h b/src/libknot/updates/ddns.h new file mode 100644 index 0000000..dceebed --- /dev/null +++ b/src/libknot/updates/ddns.h @@ -0,0 +1,74 @@ +/*! + * \file ddns.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Dynamic updates processing. + * + * \addtogroup query_processing + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_DDNS_H_ +#define _KNOT_DDNS_H_ + +#include "updates/changesets.h" +#include "zone/zone.h" +#include "packet/packet.h" +#include "rrset.h" +#include "dname.h" + +typedef struct knot_ddns_prereq_t { + knot_rrset_t **exist; + size_t exist_count; + size_t exist_allocd; + + knot_rrset_t **exist_full; + size_t exist_full_count; + size_t exist_full_allocd; + + knot_rrset_t **not_exist; + size_t not_exist_count; + size_t not_exist_allocd; + + knot_dname_t **in_use; + size_t in_use_count; + size_t in_use_allocd; + + knot_dname_t **not_in_use; + size_t not_in_use_count; + size_t not_in_use_allocd; +} knot_ddns_prereq_t; + +int knot_ddns_check_zone(const knot_zone_t *zone, knot_packet_t *query, + uint8_t *rcode); + +int knot_ddns_process_prereqs(knot_packet_t *query, + knot_ddns_prereq_t **prereqs, uint8_t *rcode); + +int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, + knot_ddns_prereq_t **prereqs, uint8_t *rcode); + +int knot_ddns_process_update(knot_packet_t *query, + knot_changeset_t **changeset, uint8_t *rcode); + +void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq); + +#endif /* _KNOT_DDNS_H_ */ + +/*! @} */ diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c new file mode 100644 index 0000000..51be430 --- /dev/null +++ b/src/libknot/updates/xfr-in.c @@ -0,0 +1,3013 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <urcu.h> + +#include "updates/xfr-in.h" + +#include "nameserver/name-server.h" +#include "util/wire.h" +#include "util/debug.h" +// #include "knot/zone/zone-dump.h" +// #include "knot/zone/zone-load.h" +#include "packet/packet.h" +#include "dname.h" +#include "zone/zone.h" +#include "packet/query.h" +#include "packet/response.h" +#include "util/error.h" +#include "updates/changesets.h" +#include "tsig.h" +#include "tsig-op.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ + +static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype, + uint16_t qclass, knot_ns_xfr_t *xfr, size_t *size, + const knot_rrset_t *soa, int use_tsig) +{ + knot_packet_t *pkt = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + CHECK_ALLOC_LOG(pkt, KNOT_ENOMEM); + + /*! \todo Get rid of the numeric constant. */ + int rc = knot_packet_set_max_size(pkt, 512); + if (rc != KNOT_EOK) { + knot_packet_free(&pkt); + return KNOT_ERROR; + } + + rc = knot_query_init(pkt); + if (rc != KNOT_EOK) { + knot_packet_free(&pkt); + return KNOT_ERROR; + } + + knot_question_t question; + + /* Retain qname until the question is freed. */ + knot_dname_retain(qname); + + /* Set random query ID. */ + knot_packet_set_random_id(pkt); + knot_wire_set_id(pkt->wireformat, pkt->header.id); + + // this is ugly!! + question.qname = (knot_dname_t *)qname; + question.qtype = qtype; + question.qclass = qclass; + + rc = knot_query_set_question(pkt, &question); + if (rc != KNOT_EOK) { + knot_dname_release(question.qname); + knot_packet_free(&pkt); + return KNOT_ERROR; + } + + /* Reserve space for TSIG. */ + if (use_tsig && xfr->tsig_key) { + dbg_xfrin_detail("xfrin: setting packet TSIG size to %zu\n", + xfr->tsig_size); + knot_packet_set_tsig_size(pkt, xfr->tsig_size); + } + + /* Add SOA RR to authority section for IXFR. */ + if (qtype == KNOT_RRTYPE_IXFR && soa) { + knot_query_add_rrset_authority(pkt, soa); + } + + /*! \todo OPT RR ?? */ + + uint8_t *wire = NULL; + size_t wire_size = 0; + rc = knot_packet_to_wire(pkt, &wire, &wire_size); + if (rc != KNOT_EOK) { + dbg_xfrin("Failed to write packet to wire.\n"); + knot_dname_release(question.qname); + knot_packet_free(&pkt); + return KNOT_ERROR; + } + + if (wire_size > *size) { + dbg_xfrin("Not enough space provided for the wire " + "format of the query.\n"); + knot_packet_free(&pkt); + return KNOT_ESPACE; + } + + // wire format created, sign it with TSIG if required + if (use_tsig && xfr->tsig_key) { + char *name = knot_dname_to_str(xfr->tsig_key->name); + dbg_xfrin_detail("Signing XFR query with key (name %s): \n", + name); + free(name); + dbg_xfrin_hex_detail(xfr->tsig_key->secret, + xfr->tsig_key->secret_size); + + xfr->digest_size = xfr->digest_max_size; + rc = knot_tsig_sign(wire, &wire_size, *size, NULL, 0, + xfr->digest, &xfr->digest_size, xfr->tsig_key); + if (rc != KNOT_EOK) { + /*! \todo [TSIG] Handle TSIG errors. */ + knot_packet_free(&pkt); + return rc; + } + + dbg_xfrin_detail("Signed XFR query, new wire size: %zu, digest:" + "\n", wire_size); + dbg_xfrin_hex_detail((const char*)xfr->digest, xfr->digest_size); + } + + memcpy(xfr->wire, wire, wire_size); + *size = wire_size; + + dbg_xfrin("Created query of size %zu.\n", *size); + knot_packet_dump(pkt); + + knot_packet_free(&pkt); + + /* Release qname. */ + knot_dname_release(question.qname); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +int xfrin_create_soa_query(knot_dname_t *owner, knot_ns_xfr_t *xfr, + size_t *size) +{ + /*! \todo [TSIG] Should TSIG apply for SOA query too? */ + return xfrin_create_query(owner, KNOT_RRTYPE_SOA, + KNOT_CLASS_IN, xfr, size, 0, 0); +} + +/*----------------------------------------------------------------------------*/ + +int xfrin_transfer_needed(const knot_zone_contents_t *zone, + knot_packet_t *soa_response) +{ + // first, parse the rest of the packet + assert(!knot_packet_is_query(soa_response)); + dbg_xfrin("Response - parsed: %zu, total wire size: %zu\n", + soa_response->parsed, soa_response->size); + int ret; + + if (soa_response->parsed < soa_response->size) { + ret = knot_packet_parse_rest(soa_response); + if (ret != KNOT_EOK) { + return KNOT_EMALF; + } + } + + /* + * Retrieve the local Serial + */ + const knot_rrset_t *soa_rrset = + knot_node_rrset(knot_zone_contents_apex(zone), + KNOT_RRTYPE_SOA); + if (soa_rrset == NULL) { + char *name = knot_dname_to_str(knot_node_owner( + knot_zone_contents_apex(zone))); + dbg_xfrin("SOA RRSet missing in the zone %s!\n", name); + free(name); + return KNOT_ERROR; + } + + int64_t local_serial = knot_rdata_soa_serial( + knot_rrset_rdata(soa_rrset)); + if (local_serial < 0) { +dbg_xfrin_exec( + char *name = knot_dname_to_str(knot_rrset_owner(soa_rrset)); + dbg_xfrin("Malformed data in SOA of zone %s\n", name); + free(name); +); + return KNOT_EMALF; // maybe some other error + } + + /* + * Retrieve the remote Serial + */ + // the SOA should be the first (and only) RRSet in the response + soa_rrset = knot_packet_answer_rrset(soa_response, 0); + if (soa_rrset == NULL + || knot_rrset_type(soa_rrset) != KNOT_RRTYPE_SOA) { + return KNOT_EMALF; + } + + int64_t remote_serial = knot_rdata_soa_serial( + knot_rrset_rdata(soa_rrset)); + if (remote_serial < 0) { + return KNOT_EMALF; // maybe some other error + } + + return (ns_serial_compare(local_serial, remote_serial) < 0); +} + +/*----------------------------------------------------------------------------*/ + +int xfrin_create_axfr_query(knot_dname_t *owner, knot_ns_xfr_t *xfr, + size_t *size, int use_tsig) +{ + return xfrin_create_query(owner, KNOT_RRTYPE_AXFR, + KNOT_CLASS_IN, xfr, size, 0, use_tsig); +} + +/*----------------------------------------------------------------------------*/ + +int xfrin_create_ixfr_query(const knot_zone_contents_t *zone, + knot_ns_xfr_t *xfr, size_t *size, int use_tsig) +{ + /*! + * \todo Implement properly. + */ + knot_node_t *apex = knot_zone_contents_get_apex(zone); + const knot_rrset_t *soa = knot_node_rrset(apex, KNOT_RRTYPE_SOA); + + return xfrin_create_query(knot_node_get_owner(apex), KNOT_RRTYPE_IXFR, + KNOT_CLASS_IN, xfr, size, soa, use_tsig); +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_add_orphan_rrsig(xfrin_orphan_rrsig_t *rrsigs, + knot_rrset_t *rr) +{ + // try to find similar RRSIGs (check owner and type covered) in the list + assert(knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG); + + int ret = 0; + xfrin_orphan_rrsig_t **last = &rrsigs; + while (*last != NULL) { + // check if the RRSIG is not similar to the one we want to add + assert((*last)->rrsig != NULL); + if (knot_rrset_compare((*last)->rrsig, rr, + KNOT_RRSET_COMPARE_HEADER) == 1 + && knot_rdata_rrsig_type_covered(knot_rrset_rdata( + (*last)->rrsig)) + == knot_rdata_rrsig_type_covered(knot_rrset_rdata(rr))) { + ret = knot_rrset_merge((void **)&(*last)->rrsig, + (void **)&rr); + if (ret != KNOT_EOK) { + return ret; + } else { + return 1; + } + } + last = &((*last)->next); + } + + assert(*last == NULL); + // we did not find the right RRSIGs, add to the end + *last = (xfrin_orphan_rrsig_t *)malloc(sizeof(xfrin_orphan_rrsig_t)); + CHECK_ALLOC_LOG(*last, KNOT_ENOMEM); + + (*last)->rrsig = rr; + (*last)->next = NULL; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_process_orphan_rrsigs(knot_zone_contents_t *zone, + xfrin_orphan_rrsig_t *rrsigs) +{ + xfrin_orphan_rrsig_t **last = &rrsigs; + int ret = 0; + while (*last != NULL) { + knot_rrset_t *rrset = NULL; + knot_node_t *node = NULL; + ret = knot_zone_contents_add_rrsigs(zone, (*last)->rrsig, + &rrset, &node, + KNOT_RRSET_DUPL_MERGE, 1); + if (ret > 0) { + knot_rrset_free(&(*last)->rrsig); + } else if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add orphan RRSIG to zone.\n"); + return ret; + } else { + (*last)->rrsig = NULL; + } + + last = &((*last)->next); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_free_orphan_rrsigs(xfrin_orphan_rrsig_t **rrsigs) +{ + xfrin_orphan_rrsig_t *r = *rrsigs; + while (r != NULL) { + xfrin_orphan_rrsig_t *prev = r; + r = r->next; + free(prev); + } + + *rrsigs = NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! \note [TSIG] */ +static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, + int tsig_req) +{ + assert(packet != NULL); + assert(xfr != NULL); + + dbg_xfrin_verb("xfrin_check_tsig(): packet nr: %d, required: %d\n", + xfr->packet_nr, tsig_req); + + /* + * If we are expecting it (i.e. xfr->prev_digest_size > 0) + * a) it should be there (first, last or each 100th packet) and it + * is not + * Then we should discard the changes and close the connection. + * b) it should be there and it is or it may not be there (other + * packets) and it is + * We validate the TSIG and reset packet number counting and + * data aggregation. + * + * If we are not expecting it (i.e. xfr->prev_digest_size <= 0) and + * it is there => it should probably be considered an error + */ + knot_rrset_t *tsig = NULL; + int ret = knot_packet_parse_next_rr_additional(packet, &tsig); + if (ret != KNOT_EOK) { + return ret; + } + + if (xfr->tsig_key) { + if (tsig_req && tsig == NULL) { + // TSIG missing!! + return KNOT_EMALF; + } else if (tsig != NULL) { + // TSIG there, either required or not, process + if (xfr->packet_nr == 0) { + ret = knot_tsig_client_check(tsig, + xfr->wire, xfr->wire_size, + xfr->digest, xfr->digest_size, + xfr->tsig_key); + } else { + ret = knot_tsig_client_check_next(tsig, + xfr->wire, xfr->wire_size, + xfr->digest, xfr->digest_size, + xfr->tsig_key); + } + + if (ret != KNOT_EOK) { + /*! \note [TSIG] No need to check TSIG error + * here, propagate and check elsewhere.*/ + return ret; + } + + // and reset the data storage + //xfr->packet_nr = 1; + xfr->tsig_data_size = 0; + + // Extract the digest from the TSIG RDATA and store it. + if (xfr->digest_max_size < tsig_rdata_mac_length(tsig)) { + return KNOT_ESPACE; + } + memcpy(xfr->digest, tsig_rdata_mac(tsig), + tsig_rdata_mac_length(tsig)); + xfr->digest_size = tsig_rdata_mac_length(tsig); + + } else { // TSIG not required and not there + // just append the wireformat to the TSIG data + assert(KNOT_NS_TSIG_DATA_MAX_SIZE - xfr->tsig_data_size + >= xfr->wire_size); + memcpy(xfr->tsig_data + xfr->tsig_data_size, + xfr->wire, xfr->wire_size); + xfr->tsig_data_size += xfr->wire_size; + } + } else if (tsig != NULL) { + // TSIG where it should not be + return KNOT_EMALF; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, + xfrin_constructed_zone_t **constr*/ + knot_ns_xfr_t *xfr) +{ + const uint8_t *pkt = xfr->wire; + size_t size = xfr->wire_size; + xfrin_constructed_zone_t **constr = + (xfrin_constructed_zone_t **)(&xfr->data); + + if (pkt == NULL || constr == NULL) { + dbg_xfrin("Wrong parameters supported.\n"); + return KNOT_EBADARG; + } + + dbg_xfrin("Processing AXFR packet of size %zu.\n", size); + + // check if the response is OK + if (knot_wire_get_rcode(pkt) != KNOT_RCODE_NOERROR) { + return KNOT_EXFRREFUSED; + } + + /*! \todo Should TC bit be checked? */ + + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_NONE); + if (packet == NULL) { + dbg_xfrin("Could not create packet structure.\n"); + return KNOT_ENOMEM; + } + + int ret = knot_packet_parse_from_wire(packet, pkt, size, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Could not parse packet: %s.\n", + knot_strerror(ret)); + knot_packet_free(&packet); + /*! \todo Cleanup. */ + return KNOT_EMALF; + } + + /*! \todo [TSIG] If packet RCODE is NOTAUTH(9), process as TSIG error. */ + + knot_rrset_t *rr = NULL; + ret = knot_packet_parse_next_rr_answer(packet, &rr); + + if (ret != KNOT_EOK) { + dbg_xfrin("Could not parse first Answer RR: %s.\n", + knot_strerror(ret)); + knot_packet_free(&packet); + /*! \todo Cleanup. */ + return KNOT_EMALF; + } + + if (rr == NULL) { + dbg_xfrin("No RRs in the packet.\n"); + knot_packet_free(&packet); + /*! \todo Cleanup. */ + return KNOT_EMALF; + } + + /*! \todo We should probably test whether the Question of the first + * message corresponds to the SOA RR. + */ + + knot_node_t *node = NULL; + int in_zone = 0; + knot_zone_contents_t *zone = NULL; + + if (*constr == NULL) { + // this should be the first packet + /*! \note [TSIG] Packet number for checking TSIG validation. */ + xfr->packet_nr = 0; + /*! \note [TSIG] Storing total size of data for TSIG digest. */ + xfr->tsig_data_size = 0; + + // create new zone + /*! \todo Ensure that the packet is the first one. */ + if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { + dbg_xfrin("No zone created, but the first RR in " + "Answer is not a SOA RR.\n"); + knot_packet_free(&packet); + knot_node_free(&node, 0, 0); + knot_rrset_deep_free(&rr, 1, 1, 1); + /*! \todo Cleanup. */ + return KNOT_EMALF; + } + + if (knot_dname_compare(knot_rrset_owner(rr), + knot_packet_qname(packet)) != 0) { +dbg_xfrin_exec( + char *rr_owner = + knot_dname_to_str(knot_rrset_owner(rr)); + char *qname = knot_dname_to_str( + knot_packet_qname(packet)); + + dbg_xfrin("Owner of the first SOA RR (%s) does not" + " match QNAME (%s).\n", rr_owner, qname); + + free(rr_owner); + free(qname); +); + /*! \todo Cleanup. */ + knot_packet_free(&packet); + knot_node_free(&node, 0, 0); + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_EMALF; + } + + node = knot_node_new(rr->owner, NULL, 0); + if (node == NULL) { + dbg_xfrin("Failed to create new node.\n"); + knot_packet_free(&packet); + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_ENOMEM; + } + + // the first RR is SOA and its owner and QNAME are the same + // create the zone + + *constr = (xfrin_constructed_zone_t *)malloc( + sizeof(xfrin_constructed_zone_t)); + if (*constr == NULL) { + dbg_xfrin("Failed to create new constr. zone.\n"); + knot_packet_free(&packet); + knot_node_free(&node, 0, 0); + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_ENOMEM; + } + + memset(*constr, 0, sizeof(xfrin_constructed_zone_t)); + + (*constr)->contents = knot_zone_contents_new(node, 0, 1, NULL); +// assert(0); + if ((*constr)->contents== NULL) { + dbg_xfrin("Failed to create new zone.\n"); + knot_packet_free(&packet); + knot_node_free(&node, 0, 0); + knot_rrset_deep_free(&rr, 1, 1, 1); + /*! \todo Cleanup. */ + return KNOT_ENOMEM; + } + + in_zone = 1; + assert(node->owner == rr->owner); + zone = (*constr)->contents; + assert(zone->apex == node); + assert(zone->apex->owner == rr->owner); + // add the RRSet to the node + //ret = knot_node_add_rrset(node, rr, 0); + ret = knot_zone_contents_add_rrset(zone, rr, &node, + KNOT_RRSET_DUPL_MERGE, 1); + if (ret < 0) { + dbg_xfrin("Failed to add RRSet to zone node: %s.\n", + knot_strerror(ret)); + knot_packet_free(&packet); + knot_node_free(&node, 0, 0); + knot_rrset_deep_free(&rr, 1, 1, 1); + /*! \todo Cleanup. */ + return KNOT_ERROR; + } else if (ret > 0) { + dbg_xfrin("Merged SOA RRSet.\n"); + // merged, free the RRSet + //knot_rrset_deep_free(&rr, 1, 0, 0); + knot_rrset_free(&rr); + } + + // take next RR + ret = knot_packet_parse_next_rr_answer(packet, &rr); + } else { + zone = (*constr)->contents; + ++xfr->packet_nr; + } + + /*! \note [TSIG] add the packet wire size to the data to be verified by + * TSIG + */ + if (xfr->tsig_key) { + dbg_xfrin("Adding packet wire to TSIG data (size till now: %zu," + " adding: %zu).\n", xfr->tsig_data_size, + xfr->wire_size); + assert(KNOT_NS_TSIG_DATA_MAX_SIZE - xfr->tsig_data_size + >= xfr->wire_size); + memcpy(xfr->tsig_data + xfr->tsig_data_size, xfr->wire, + xfr->wire_size); + xfr->tsig_data_size += xfr->wire_size; + } + + assert(zone != NULL); + + while (ret == KNOT_EOK && rr != NULL) { + // process the parsed RR + + dbg_xfrin("\nNext RR:\n\n"); + knot_rrset_dump(rr, 0); + + if (node != NULL + && knot_dname_compare(rr->owner, node->owner) != 0) { +dbg_xfrin_exec( + char *name = knot_dname_to_str(node->owner); + dbg_xfrin("Node owner: %s\n", name); + free(name); +); + if (!in_zone) { + // this should not happen + assert(0); + // the node is not in the zone and the RR has + // other owner, so a new node must be created + // insert the old node to the zone + } + + node = NULL; + } + + if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) { + // this must be the last SOA, do not do anything more + // discard the RR + assert(knot_zone_contents_apex((zone)) != NULL); + assert(knot_node_rrset(knot_zone_contents_apex((zone)), + KNOT_RRTYPE_SOA) != NULL); + dbg_xfrin("Found last SOA, transfer finished.\n"); + + dbg_xfrin("Verifying TSIG...\n"); + /*! \note [TSIG] Now check if there is not a TSIG record + * at the end of the packet. + */ + ret = xfrin_check_tsig(packet, xfr, 1); + + dbg_xfrin_detail("xfrin_check_tsig() returned %d\n", + ret); + + knot_packet_free(&packet); + knot_rrset_deep_free(&rr, 1, 1, 1); + + if (ret != KNOT_EOK) { + /*! \todo [TSIG] Handle TSIG errors. */ + return ret; + } + + // we must now find place for all orphan RRSIGs + ret = xfrin_process_orphan_rrsigs(zone, + (*constr)->rrsigs); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to process orphan " + "RRSIGs\n"); + /*! \todo Cleanup?? */ + return ret; + } + + xfrin_free_orphan_rrsigs(&(*constr)->rrsigs); + + return 1; + } + + if (knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG) { + // RRSIGs require special handling, as there are no + // nodes for them + knot_rrset_t *tmp_rrset = NULL; + ret = knot_zone_contents_add_rrsigs(zone, rr, + &tmp_rrset, &node, KNOT_RRSET_DUPL_MERGE, 1); + if (ret == KNOT_ENONODE || ret == KNOT_ENORRSET) { + dbg_xfrin("No node or RRSet for RRSIGs\n"); + dbg_xfrin("Saving for later insertion.\n"); + ret = xfrin_add_orphan_rrsig((*constr)->rrsigs, + rr); + if (ret > 0) { + dbg_xfrin("Merged RRSIGs.\n"); + knot_rrset_free(&rr); + } else if (ret != KNOT_EOK) { + dbg_xfrin("Failed to save orphan" + " RRSIGs.\n"); + knot_packet_free(&packet); + knot_node_free(&node, 1, 0); // ??? + knot_rrset_deep_free(&rr, 1, 1, 1); + return ret; + } + } else if (ret < 0) { + dbg_xfrin("Failed to add RRSIGs (%s).\n", + knot_strerror(ret)); + knot_packet_free(&packet); + knot_node_free(&node, 1, 0); // ??? + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_ERROR; /*! \todo Other error code. */ + } else if (ret == 1) { + assert(node != NULL); +dbg_xfrin_exec( + char *name = knot_dname_to_str(node->owner); + dbg_xfrin("Found node for the record in " + "zone: %s.\n", name); + free(name); +); + in_zone = 1; + knot_rrset_deep_free(&rr, 1, 0, 0); + } else if (ret == 2) { + // should not happen + assert(0); +// knot_rrset_deep_free(&rr, 1, 1, 1); + } else { + assert(node != NULL); +dbg_xfrin_exec( + char *name = knot_dname_to_str(node->owner); + dbg_xfrin("Found node for the record in " + "zone: %s.\n", name); + free(name); +); + in_zone = 1; + assert(tmp_rrset->rrsigs == rr); + } + + // parse next RR + ret = knot_packet_parse_next_rr_answer(packet, &rr); + + continue; + } + + /*! \note [TSIG] TSIG where it should not be - in Answer section.*/ + if (knot_rrset_type(rr) == KNOT_RRTYPE_TSIG) { + // not allowed here + dbg_xfrin(" in Answer section.\n"); + knot_packet_free(&packet); + knot_node_free(&node, 1, 0); // ??? + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_EMALF; + } + + knot_node_t *(*get_node)(const knot_zone_contents_t *, + const knot_dname_t *) = NULL; + int (*add_node)(knot_zone_contents_t *, knot_node_t *, int, + uint8_t, int) = NULL; + + if (knot_rrset_type(rr) == KNOT_RRTYPE_NSEC3) { + get_node = knot_zone_contents_get_nsec3_node; + add_node = knot_zone_contents_add_nsec3_node; + } else { + get_node = knot_zone_contents_get_node; + add_node = knot_zone_contents_add_node; + } + + if (node == NULL && (node = get_node(zone, + knot_rrset_owner(rr))) != NULL) { + // the node for this RR was found in the zone + dbg_xfrin("Found node for the record in zone.\n"); + in_zone = 1; + } + + if (node == NULL) { + // a new node for the RR is required but it is not + // in the zone + node = knot_node_new(rr->owner, NULL, 0); + if (node == NULL) { + dbg_xfrin("Failed to create new node.\n"); + knot_packet_free(&packet); + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_ENOMEM; + } + dbg_xfrin("Created new node for the record.\n"); + + // insert the RRSet to the node + ret = knot_node_add_rrset(node, rr, 1); + if (ret < 0) { + dbg_xfrin("Failed to add RRSet to node (%s" + ")\n", knot_strerror(ret)); + knot_packet_free(&packet); + knot_node_free(&node, 1, 0); // ??? + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_ERROR; + } else if (ret > 0) { + // should not happen, this is new node + assert(0); +// knot_rrset_deep_free(&rr, 1, 0, 0); + } + + // insert the node into the zone + ret = add_node(zone, node, 1, 0, 1); + assert(node != NULL); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add node to zone (%s)" + ".\n", knot_strerror(ret)); + knot_packet_free(&packet); + knot_node_free(&node, 1, 0); // ??? + knot_rrset_deep_free(&rr, 1, 1, 1); + return KNOT_ERROR; + } + + in_zone = 1; + } else { + assert(in_zone); + + ret = knot_zone_contents_add_rrset(zone, rr, &node, + KNOT_RRSET_DUPL_MERGE, 1); + if (ret < 0) { + dbg_xfrin("Failed to add RRSet to zone:" + "%s.\n", knot_strerror(ret)); + return KNOT_ERROR; + } else if (ret > 0) { + // merged, free the RRSet +// knot_rrset_deep_free(&rr, 1, 0, 0); + knot_rrset_free(&rr); + } + + } + + rr = NULL; + + // parse next RR + ret = knot_packet_parse_next_rr_answer(packet, &rr); + } + + assert(ret != KNOT_EOK || rr == NULL); + + if (ret < 0) { + // some error in parsing + dbg_xfrin("Could not parse next RR: %s.\n", + knot_strerror(ret)); + knot_packet_free(&packet); + knot_node_free(&node, 0, 0); + knot_rrset_deep_free(&rr, 1, 1, 1); + /*! \todo Cleanup. */ + return KNOT_EMALF; + } + + assert(ret == KNOT_EOK); + assert(rr == NULL); + + // if the last node is not yet in the zone, insert + if (!in_zone) { + assert(node != NULL); + ret = knot_zone_contents_add_node(zone, node, 1, 0, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add last node into zone (%s)" + ".\n", knot_strerror(ret)); + knot_packet_free(&packet); + knot_node_free(&node, 1, 0); + return KNOT_ERROR; /*! \todo Other error */ + } + } + + /*! \note [TSIG] Now check if there is not a TSIG record at the end of + * the packet. + */ + ret = xfrin_check_tsig(packet, xfr, + knot_ns_tsig_required(xfr->packet_nr)); + ++xfr->packet_nr; + + knot_packet_free(&packet); + dbg_xfrin("Processed one AXFR packet successfully.\n"); + + /*! \note [TSIG] TSIG errors are propagated and reported in a standard + * manner, as we're in response processing, no further error response + * should be sent. + */ + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_parse_first_rr(knot_packet_t **packet, const uint8_t *pkt, + size_t size, knot_rrset_t **rr) +{ + *packet = knot_packet_new(KNOT_PACKET_PREALLOC_NONE); + if (packet == NULL) { + dbg_xfrin("Could not create packet structure.\n"); + return KNOT_ENOMEM; + } + + int ret = knot_packet_parse_from_wire(*packet, pkt, size, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Could not parse packet: %s.\n", + knot_strerror(ret)); + knot_packet_free(packet); + return KNOT_EMALF; + } + + // check if the TC bit is set (it must not be) + if (knot_wire_get_tc(pkt)) { + dbg_xfrin("IXFR response has TC bit set.\n"); + knot_packet_free(packet); + return KNOT_EMALF; + } + + ret = knot_packet_parse_next_rr_answer(*packet, rr); + + if (ret != KNOT_EOK) { + dbg_xfrin("Could not parse first Answer RR: %s.\n", + knot_strerror(ret)); + knot_packet_free(packet); + return KNOT_EMALF; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int xfrin_process_ixfr_packet(/*const uint8_t *pkt, size_t size, + knot_changesets_t **chs*/knot_ns_xfr_t *xfr) +{ + size_t size = xfr->wire_size; + const uint8_t *pkt = xfr->wire; + knot_changesets_t **chs = (knot_changesets_t **)(&xfr->data); + + if (pkt == NULL || chs == NULL) { + dbg_xfrin("Wrong parameters supported.\n"); + return KNOT_EBADARG; + } + + // check if the response is OK + if (knot_wire_get_rcode(pkt) != KNOT_RCODE_NOERROR) { + return KNOT_EXFRREFUSED; + } + + knot_packet_t *packet = NULL; +// knot_rrset_t *soa1 = NULL; +// knot_rrset_t *soa2 = NULL; + knot_rrset_t *rr = NULL; + + int ret; + + if ((ret = xfrin_parse_first_rr(&packet, pkt, size, &rr)) != KNOT_EOK) { + return ret; + } + + assert(packet != NULL); + + // state of the transfer + // -1 .. a SOA is expected to create a new changeset + int state = 0; + + if (rr == NULL) { + dbg_xfrin("No RRs in the packet.\n"); + knot_packet_free(&packet); + /*! \todo Some other action??? */ + return KNOT_EMALF; + } + + if (*chs == NULL) { + dbg_xfrin("Changesets empty, creating new.\n"); + + ret = knot_changeset_allocate(chs); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&rr, 1, 1, 1); + knot_packet_free(&packet); + return ret; + } + + // the first RR must be a SOA + if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { + dbg_xfrin("First RR is not a SOA RR!\n"); + knot_rrset_deep_free(&rr, 1, 1, 1); + ret = KNOT_EMALF; + goto cleanup; + } + + // just store the first SOA for later use + (*chs)->first_soa = rr; + state = -1; + + dbg_xfrin("First SOA of IXFR saved, state set to -1.\n"); + + // parse the next one + ret = knot_packet_parse_next_rr_answer(packet, &rr); + if (ret != KNOT_EOK) { + return ret; + } + + /* + * If there is no other records in the response than the SOA, it + * means one of these two cases: + * + * 1) The server does not have newer zone than ours. + * This is indicated by serial equal to the one of our zone. + * 2) The server wants to send the transfer but is unable to fit + * it in the packet. This is indicated by serial different + * (newer) from the one of our zone. + * + * The serials must be compared in other parts of the server, so + * just indicate that the answer contains only one SOA. + */ + if (rr == NULL) { + dbg_xfrin("Response containing only SOA,\n"); + knot_packet_free(&packet); + return XFRIN_RES_SOA_ONLY; + } else if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { + knot_rrset_deep_free(&rr, 1, 1, 1); + dbg_xfrin("Fallback to AXFR.\n"); + ret = XFRIN_RES_FALLBACK; + knot_free_changesets(chs); + xfr->data = 0; + return ret; + } + } else { + if ((*chs)->first_soa == NULL) { + dbg_xfrin("Changesets don't contain frist SOA!\n"); + ret = KNOT_EBADARG; + goto cleanup; + } + dbg_xfrin("Changesets present.\n"); + } + + /* + * Process the next RR. Different requirements are in place in + * different cases: + * + * 1) Last changeset has both soa_from and soa_to. + * a) The next RR is a SOA. + * i) The next RR is equal to the first_soa saved in changesets. + * This denotes the end of the transfer. It may be dropped and + * the end should be signalised by returning positive value. + * + * ii) The next RR is some other SOA. + * This means a start of new changeset - create it and add it + * to the list. + * + * b) The next RR is not a SOA. + * Put the RR into the ADD part of the last changeset as this is + * not finished yet. Continue while SOA is not encountered. Then + * jump to 1-a. + * + * 2) Last changeset has only the soa_from and does not have soa_to. + * a) The next RR is a SOA. + * This means start of the ADD section. Put the SOA to the + * changeset. Continue adding RRs to the ADD section while SOA + * is not encountered. This is identical to 1-b. + * + * b) The next RR is not a SOA. + * This means the REMOVE part is not finished yet. Add the RR to + * the REMOVE part. Continue adding next RRs until a SOA is + * encountered. Then jump to 2-a. + */ + + // first, find out in what state we are + /*! \todo It would be more elegant to store the state in the + * changesets structure, or in some place persistent between + * calls to this function. + */ + if (state != -1) { + dbg_xfrin("State is not -1, deciding...\n"); + // there should be at least one started changeset right now + if ((*chs)->count <= 0) { + knot_rrset_deep_free(&rr, 1, 1, 1); + ret = KNOT_EMALF; + goto cleanup; + } + + // a changeset should be created only when there is a SOA + assert((*chs)->sets[(*chs)->count - 1].soa_from != NULL); + + if ((*chs)->sets[(*chs)->count - 1].soa_to == NULL) { + state = XFRIN_CHANGESET_REMOVE; + } else { + state = XFRIN_CHANGESET_ADD; + } + } + + dbg_xfrin("State before the loop: %d\n", state); + + /*! \todo This may be implemented with much less IFs! */ + + while (ret == KNOT_EOK && rr != NULL) { +dbg_xfrin_exec( + dbg_xfrin("Next loop, state: %d\n", state); + char *name = knot_dname_to_str(knot_rrset_owner(rr)); + dbg_xfrin("Actual RR: %s, type %s.\n", name, + knot_rrtype_to_string(knot_rrset_type(rr))); + free(name); +); + switch (state) { + case -1: + // a SOA is expected + // this may be either a start of a changeset or the + // last SOA (in case the transfer was empty, but that + // is quite weird in fact + if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { + dbg_xfrin("First RR is not a SOA RR!\n"); + dbg_xfrin("RR type: %s\n", + knot_rrtype_to_string(knot_rrset_type(rr))); + ret = KNOT_EMALF; + knot_rrset_deep_free(&rr, 1, 1, 1); + goto cleanup; + } + + if (knot_rdata_soa_serial(knot_rrset_rdata(rr)) + == knot_rdata_soa_serial( + knot_rrset_rdata((*chs)->first_soa))) { + + /*! \note [TSIG] Check TSIG, we're at the end of + * transfer. + */ + ret = xfrin_check_tsig(packet, xfr, 1); + + // last SOA, discard and end + knot_rrset_deep_free(&rr, 1, 1, 1); + knot_packet_free(&packet); + + /*! \note [TSIG] If TSIG validates, consider + * transfer complete. */ + if (ret == KNOT_EOK) { + ret = XFRIN_RES_COMPLETE; + } + + return ret; + } else { + // normal SOA, start new changeset + (*chs)->count++; + if ((ret = knot_changesets_check_size(*chs)) + != KNOT_EOK) { + (*chs)->count--; + knot_rrset_deep_free(&rr, 1, 1, 1); + goto cleanup; + } + + ret = knot_changeset_add_soa( + &(*chs)->sets[(*chs)->count - 1], rr, + XFRIN_CHANGESET_REMOVE); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&rr, 1, 1, 1); + goto cleanup; + } + + // change state to REMOVE + state = XFRIN_CHANGESET_REMOVE; + } + break; + case XFRIN_CHANGESET_REMOVE: + // if the next RR is SOA, store it and change state to + // ADD + if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) { + // we should not be here if soa_from is not set + assert((*chs)->sets[(*chs)->count - 1].soa_from + != NULL); + + ret = knot_changeset_add_soa( + &(*chs)->sets[(*chs)->count - 1], rr, + XFRIN_CHANGESET_ADD); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&rr, 1, 1, 1); + goto cleanup; + } + + state = XFRIN_CHANGESET_ADD; + } else { + // just add the RR to the REMOVE part and + // continue + if ((ret = knot_changeset_add_new_rr( + &(*chs)->sets[(*chs)->count - 1], rr, + XFRIN_CHANGESET_REMOVE)) != KNOT_EOK) { + knot_rrset_deep_free(&rr, 1, 1, 1); + goto cleanup; + } + } + break; + case XFRIN_CHANGESET_ADD: + // if the next RR is SOA change to state -1 and do not + // parse next RR + if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) { + state = -1; + continue; + } else { + + // just add the RR to the ADD part and continue + if ((ret = knot_changeset_add_new_rr( + &(*chs)->sets[(*chs)->count - 1], rr, + XFRIN_CHANGESET_ADD)) != KNOT_EOK) { + knot_rrset_deep_free(&rr, 1, 1, 1); + goto cleanup; + } + } + break; + default: + assert(0); + } + + // parse the next RR + dbg_xfrin("Parsing next RR..\n"); + ret = knot_packet_parse_next_rr_answer(packet, &rr); + dbg_xfrin("Returned %d, %p.\n", ret, rr); + } + + /*! \note Check TSIG, we're at the end of packet. It may not be + * required. + */ + ret = xfrin_check_tsig(packet, xfr, + knot_ns_tsig_required(xfr->packet_nr)); + dbg_xfrin_detail("xfrin_check_tsig() returned %d\n", ret); + ++xfr->packet_nr; + + /*! \note [TSIG] Cleanup and propagate error if TSIG validation fails.*/ + if (ret != KNOT_EOK) { + goto cleanup; + } + + // here no RRs remain in the packet but the transfer is not finished + // yet, return EOK + knot_packet_free(&packet); + return KNOT_EOK; + +cleanup: + /* We should go here only if some error occured. */ + assert(ret < 0); + + dbg_xfrin("Cleanup after processing IXFR/IN packet.\n"); + knot_free_changesets(chs); + knot_packet_free(&packet); + xfr->data = 0; + return ret; +} + +/*----------------------------------------------------------------------------*/ +/* Applying changesets to zone */ +/*----------------------------------------------------------------------------*/ + +typedef struct { + /*! + * Deleted (without owners and RDATA) after successful update. + */ + knot_rrset_t **old_rrsets; + int old_rrsets_count; + int old_rrsets_allocated; + + /*! + * Deleted after successful update. + */ + knot_rdata_t **old_rdata; + uint *old_rdata_types; + int old_rdata_count; + int old_rdata_allocated; + + /*! + * \brief Copied RRSets (i.e. modified by the update). + * + * Deleted (without owners and RDATA) after failed update. + */ + knot_rrset_t **new_rrsets; + int new_rrsets_count; + int new_rrsets_allocated; + + /*! + * Deleted (without contents) after successful update. + */ + knot_node_t **old_nodes; + int old_nodes_count; + int old_nodes_allocated; + + /*! + * Deleted (without contents) after failed update. + */ + knot_node_t **new_nodes; + int new_nodes_count; + int new_nodes_allocated; + + ck_hash_table_item_t **old_hash_items; + int old_hash_items_count; + int old_hash_items_allocated; +} xfrin_changes_t; + +/*----------------------------------------------------------------------------*/ + +static void xfrin_changes_free(xfrin_changes_t **changes) +{ + free((*changes)->old_nodes); + free((*changes)->old_rrsets); + free((*changes)->old_rdata); + free((*changes)->old_rdata_types); + free((*changes)->new_rrsets); + free((*changes)->new_nodes); + free((*changes)->old_hash_items); +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_changes_check_rrsets(knot_rrset_t ***rrsets, + int *count, int *allocated, int to_add) +{ + /* Ensure at least requested size is allocated. */ + int new_count = (*count + to_add); + assert(new_count >= 0); + if (new_count <= *allocated) { + return KNOT_EOK; + } + + /* Allocate new memory block. */ + knot_rrset_t **rrsets_new = malloc(new_count * sizeof(knot_rrset_t *)); + if (rrsets_new == NULL) { + return KNOT_ENOMEM; + } + + /* Initialize new memory and copy old data. */ + memset(rrsets_new, 0, new_count * sizeof(knot_rrset_t *)); + memcpy(rrsets_new, *rrsets, (*allocated) * sizeof(knot_rrset_t *)); + + /* Free old nodes and switch pointers. */ + free(*rrsets); + *rrsets = rrsets_new; + *allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_changes_check_nodes(knot_node_t ***nodes, + int *count, int *allocated) +{ + assert(nodes != NULL); + assert(count != NULL); + assert(allocated != 0); + + /* Ensure at least count and some reserve is allocated. */ + int new_count = *count + 2; + if (new_count <= *allocated) { + return KNOT_EOK; + } + + /* Allocate new memory block. */ + const size_t node_len = sizeof(knot_node_t *); + knot_node_t **nodes_new = malloc(new_count * node_len); + if (nodes_new == NULL) { + return KNOT_ENOMEM; + } + + /* Clear memory block and copy old data. */ + memset(nodes_new, 0, new_count * node_len); + memcpy(nodes_new, *nodes, (*allocated) * node_len); + + /* Free old nodes and switch pointers. */ + free(*nodes); + *nodes = nodes_new; + *allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, + int count, int *allocated, int to_add) +{ + /* Ensure at least requested size is allocated. */ + int new_count = (count + to_add); + assert(new_count >= 0); + if (new_count <= *allocated) { + return KNOT_EOK; + } + + /* Allocate new memory block. */ + knot_rdata_t **rdatas_new = malloc(new_count * sizeof(knot_rdata_t *)); + if (rdatas_new == NULL) { + return KNOT_ENOMEM; + } + + uint *types_new = malloc(new_count * sizeof(uint)); + if (types_new == NULL) { + return KNOT_ENOMEM; + } + + /* Initialize new memory and copy old data. */ + memset(rdatas_new, 0, new_count * sizeof(knot_rdata_t *)); + memcpy(rdatas_new, *rdatas, (*allocated) * sizeof(knot_rdata_t *)); + + memset(types_new, 0, new_count * sizeof(uint)); + memcpy(types_new, *types, (*allocated) * sizeof(uint)); + + /* Free old rdatas and switch pointers. */ + free(*rdatas); + free(*types); + *rdatas = rdatas_new; + *types = types_new; + *allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_changes_check_hash_items(ck_hash_table_item_t ***items, + int *count, int *allocated) +{ + /* Prevent infinite loop in case of allocated = 0. */ + int new_count = 0; + if (*allocated == 0) { + new_count = *count + 1; + } else { + if (*count == *allocated) { + new_count = *allocated * 2; + } + } + + const size_t item_len = sizeof(ck_hash_table_item_t *); + ck_hash_table_item_t **items_new = malloc(new_count * item_len); + if (items_new == NULL) { + return KNOT_ENOMEM; + } + + memset(items_new, 0, new_count * item_len); + memcpy(items_new, *items, (*count) * item_len); + free(*items); + *items = items_new; + *allocated = new_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_zone_contents_free(knot_zone_contents_t **contents) +{ + /*! \todo This should be all in some API!! */ + + if ((*contents)->table != NULL) { +// ck_destroy_table(&(*contents)->table, NULL, 0); + ck_table_free(&(*contents)->table); + } + + // free the zone tree, but only the structure + // (nodes are already destroyed) + dbg_zone("Destroying zone tree.\n"); + knot_zone_tree_free(&(*contents)->nodes); + dbg_zone("Destroying NSEC3 zone tree.\n"); + knot_zone_tree_free(&(*contents)->nsec3_nodes); + + knot_nsec3_params_free(&(*contents)->nsec3_params); + + knot_dname_table_deep_free(&(*contents)->dname_table); + + free(*contents); + *contents = NULL; +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_rollback_update(knot_zone_contents_t *contents, + xfrin_changes_t *changes) +{ + /* + * This function is called only when no references were actually set to + * the new nodes, just the new nodes reference other. + * We thus do not need to fix any references, just from the old nodes + * to the new ones. + */ + + // discard new nodes, but do not remove RRSets from them + for (int i = 0; i < changes->new_nodes_count; ++i) { + knot_node_free(&changes->new_nodes[i], 0, 0); + } + + // set references from old nodes to new nodes to NULL and remove the + // old flag + for (int i = 0; i < changes->old_nodes_count; ++i) { + knot_node_set_new_node(changes->old_nodes[i], NULL); + knot_node_clear_old(changes->old_nodes[i]); + } + + // discard new RRSets + for (int i = 0; i < changes->old_rrsets_count; ++i) { + knot_rrset_deep_free(&changes->new_rrsets[i], 0, 1, 0); + } + + // destroy the shallow copy of zone + xfrin_zone_contents_free(&contents); +} + +/*----------------------------------------------------------------------------*/ + +static knot_rdata_t *xfrin_remove_rdata(knot_rrset_t *from, + const knot_rrset_t *what) +{ + knot_rdata_t *old = NULL; + knot_rdata_t *old_actual = NULL; + + const knot_rdata_t *rdata = knot_rrset_rdata(what); + + while (rdata != NULL) { + old_actual = knot_rrset_remove_rdata(from, rdata); + if (old_actual != NULL) { + old_actual->next = old; + old = old_actual; + } + rdata = knot_rrset_rdata_next(what, rdata); + } + + return old; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_get_node_copy(knot_node_t **node, xfrin_changes_t *changes) +{ + knot_node_t *new_node = + knot_node_get_new_node(*node); + if (new_node == NULL) { + dbg_xfrin("Creating copy of node.\n"); + int ret = knot_node_shallow_copy(*node, &new_node); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to create node copy.\n"); + return KNOT_ENOMEM; + } + + dbg_xfrin_detail("Created copy of old node %p to new node %p\n", + *node, new_node); + + assert(changes); + +// changes->new_nodes_allocated = 0; + + // save the copy of the node + ret = xfrin_changes_check_nodes( + &changes->new_nodes, + &changes->new_nodes_count, + &changes->new_nodes_allocated); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add new node to list.\n"); + knot_node_free(&new_node, 0, 0); + return ret; + } + +// changes->old_nodes_allocated = 0; + + // save the old node to list of old nodes + ret = xfrin_changes_check_nodes( + &changes->old_nodes, + &changes->old_nodes_count, + &changes->old_nodes_allocated); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add old node to list.\n"); + knot_node_free(&new_node, 0, 0); + return ret; + } + + assert(changes->new_nodes); + assert(changes->old_nodes); + + changes->new_nodes[changes->new_nodes_count++] = new_node; + changes->old_nodes[changes->old_nodes_count++] = *node; + + // mark the old node as old + knot_node_set_old(*node); + + knot_node_set_new(new_node); + knot_node_set_new_node(*node, new_node); + } + + *node = new_node; + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, + xfrin_changes_t *changes) +{ + // create new RRSet by copying the old one + int ret = knot_rrset_shallow_copy(old, copy); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to create RRSet copy.\n"); + return KNOT_ENOMEM; + } + + // add the RRSet to the list of new RRSets + ret = xfrin_changes_check_rrsets(&changes->new_rrsets, + &changes->new_rrsets_count, + &changes->new_rrsets_allocated, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add new RRSet to list.\n"); + knot_rrset_free(copy); + return ret; + } + + changes->new_rrsets[changes->new_rrsets_count++] = *copy; + + // add the old RRSet to the list of old RRSets + ret = xfrin_changes_check_rrsets(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add old RRSet to list.\n"); + return ret; + } + + changes->old_rrsets[changes->old_rrsets_count++] = old; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type, + knot_rrset_t **rrset, xfrin_changes_t *changes) +{ + knot_rrset_t *old = knot_node_remove_rrset(node, type); + + if (old == NULL) { + dbg_xfrin("RRSet not found for RR to be removed.\n"); + return 1; + } + + int ret = xfrin_copy_old_rrset(old, rrset, changes); + if (ret != KNOT_EOK) { + return ret; + } + + dbg_xfrin_detail("Copied old rrset %p to new %p.\n", + old, *rrset); + + // replace the RRSet in the node copy by the new one + ret = knot_node_add_rrset(node, *rrset, 0); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add RRSet copy to node\n"); + return KNOT_ERROR; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_remove_rrsigs(xfrin_changes_t *changes, + const knot_rrset_t *remove, + knot_node_t *node, + knot_rrset_t **rrset) +{ + assert(changes != NULL); + assert(remove != NULL); + assert(node != NULL); + assert(rrset != NULL); + assert(knot_rrset_type(remove) == KNOT_RRTYPE_RRSIG); + + /*! \todo These optimalizations may be useless as there may be only + * one RRSet of each type and owner in the changeset. + */ + + int ret; + + if (!*rrset + || knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) != 0 + || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered( + knot_rrset_rdata(remove))) { + // find RRSet based on the Type Covered + knot_rr_type_t type = knot_rdata_rrsig_type_covered( + knot_rrset_rdata(remove)); + + // copy the rrset + ret = xfrin_copy_rrset(node, type, rrset, changes); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to copy rrset from changeset.\n"); + return ret; + } + } else { + // we should have the right RRSIG RRSet in *rrset + assert(knot_rrset_type(*rrset) + == knot_rdata_rrsig_type_covered( + knot_rrset_rdata(remove))); + // this RRSet should be the already copied RRSet so we may + // update it right away + } + + // get the old rrsigs + knot_rrset_t *old = knot_rrset_get_rrsigs(*rrset); + if (old == NULL) { + return 1; + } + + // copy the RRSIGs + /*! \todo This may be done unnecessarily more times. */ + knot_rrset_t *rrsigs; + ret = xfrin_copy_old_rrset(old, &rrsigs, changes); + if (ret != KNOT_EOK) { + return ret; + } + + // set the RRSIGs to the new RRSet copy + if (knot_rrset_set_rrsigs(*rrset, rrsigs) != KNOT_EOK) { + dbg_xfrin("Failed to set rrsigs.\n"); + return KNOT_ERROR; + } + + + + // now in '*rrset' we have a copy of the RRSet which holds the RRSIGs + // and in 'rrsigs' we have the copy of the RRSIGs + + knot_rdata_t *rdata = xfrin_remove_rdata(rrsigs, remove); + if (rdata == NULL) { + dbg_xfrin("Failed to remove RDATA from RRSet: %s.\n", + knot_strerror(ret)); + return 1; + } + + // if the RRSet is empty, remove from node and add to old RRSets + // check if there is no RRSIGs; if there are, leave the RRSet + // there; it may be eventually removed when the RRSIGs are removed + if (knot_rrset_rdata(rrsigs) == NULL) { + // remove the RRSIGs from the RRSet + knot_rrset_set_rrsigs(*rrset, NULL); + + ret = xfrin_changes_check_rrsets(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, + 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add empty RRSet to the " + "list of old RRSets."); + // delete the RRSet right away + knot_rrset_free(&rrsigs); + return ret; + } + + changes->old_rrsets[changes->old_rrsets_count++] = rrsigs; + + // now check if the RRSet is not totally empty + if (knot_rrset_rdata(*rrset) == NULL) { + assert(knot_rrset_rrsigs(*rrset) == NULL); + + // remove the whole RRSet from the node + knot_rrset_t *tmp = knot_node_remove_rrset(node, + knot_rrset_type(*rrset)); + assert(tmp == *rrset); + + ret = xfrin_changes_check_rrsets(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, + 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add empty RRSet to " + "the list of old RRSets."); + // delete the RRSet right away + knot_rrset_free(rrset); + return ret; + } + + changes->old_rrsets[changes->old_rrsets_count++] = + *rrset; + } + } + + // connect the RDATA to the list of old RDATA + ret = xfrin_changes_check_rdata(&changes->old_rdata, + &changes->old_rdata_types, + changes->old_rdata_count, + &changes->old_rdata_allocated, 1); + if (ret != KNOT_EOK) { + return ret; + } + + changes->old_rdata[changes->old_rdata_count] = rdata; + changes->old_rdata_types[changes->old_rdata_count] = + knot_rrset_type(remove); + ++changes->old_rdata_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_remove_normal(xfrin_changes_t *changes, + const knot_rrset_t *remove, + knot_node_t *node, + knot_rrset_t **rrset) +{ + assert(changes != NULL); + assert(remove != NULL); + assert(node != NULL); + assert(rrset != NULL); + + int ret; + + dbg_xfrin_detail("Removing RRSet: \n"); + knot_rrset_dump(remove, 0); + + // now we have the copy of the node, so lets get the right RRSet + // check if we do not already have it + if (!*rrset + || knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) != 0 + || knot_rrset_type(*rrset) + != knot_rrset_type(remove)) { + /*! + * \todo This may happen also with already + * copied RRSet. In that case it would be + * an unnecesary overhead but will + * probably not cause problems. TEST!! + */ + ret = xfrin_copy_rrset(node, + knot_rrset_type(remove), rrset, changes); + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); + if (ret != KNOT_EOK) { + return ret; + } + } + + if (*rrset == NULL) { + dbg_xfrin("RRSet not found for RR to be removed.\n"); + return 1; + } + +dbg_xfrin_exec( + char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); + dbg_xfrin("Updating RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); + free(name); +); + + // remove the specified RRs from the RRSet (de facto difference of + // sets) + knot_rdata_t *rdata = xfrin_remove_rdata(*rrset, remove); + if (rdata == NULL) { + dbg_xfrin("Failed to remove RDATA from RRSet: %s.\n", + knot_strerror(ret)); + return 1; + } + +dbg_xfrin_exec_detail( + dbg_xfrin_detail("Removed rdata: \n"); + knot_rdata_t *r = rdata; + if (r != NULL) { + do { + dbg_xfrin_detail("pointer: %p\n", r); + knot_rdata_dump(r, knot_rrset_type(remove), 0); + r = r->next; + } while (r != NULL && r != rdata); + } +); + + // if the RRSet is empty, remove from node and add to old RRSets + // check if there is no RRSIGs; if there are, leave the RRSet + // there; it may be eventually removed when the RRSIGs are removed + if (knot_rrset_rdata(*rrset) == NULL + && knot_rrset_rrsigs(*rrset) == NULL) { + + knot_rrset_t *tmp = knot_node_remove_rrset(node, + knot_rrset_type(*rrset)); + dbg_xfrin_detail("Removed whole RRSet (%p).\n", tmp); + + // add the removed RRSet to list of old RRSets + + assert(tmp == *rrset); + ret = xfrin_changes_check_rrsets(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, + 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add empty RRSet to the " + "list of old RRSets."); + // delete the RRSet right away + knot_rrset_free(rrset); + return ret; + } + + changes->old_rrsets[changes->old_rrsets_count++] = *rrset; + } + + // connect the RDATA to the list of old RDATA + ret = xfrin_changes_check_rdata(&changes->old_rdata, + &changes->old_rdata_types, + changes->old_rdata_count, + &changes->old_rdata_allocated, 1); + if (ret != KNOT_EOK) { + return ret; + } + + changes->old_rdata[changes->old_rdata_count] = rdata; + changes->old_rdata_types[changes->old_rdata_count] = + knot_rrset_type(remove); + ++changes->old_rdata_count; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_remove_all_rrsets(xfrin_changes_t *changes, + knot_node_t *node, uint16_t type) +{ + /*! \todo Implement. */ + int ret; + + if (type == KNOT_RRTYPE_ANY) { + // put all the RRSets to the changes structure + ret = xfrin_changes_check_rrsets(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, + knot_node_rrset_count(node)); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to check changeset rrsets.\n"); + return ret; + } + + knot_rrset_t **rrsets = knot_node_get_rrsets(node); + knot_rrset_t **place = changes->old_rrsets + + changes->old_rrsets_count; + /*! \todo Test this!!! */ + memcpy(place, rrsets, knot_node_rrset_count(node) * sizeof(knot_rrset_t *)); + + // remove all RRSets from the node + knot_node_remove_all_rrsets(node); + } else { + ret = xfrin_changes_check_rrsets(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, + 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to check changeset rrsets.\n"); + return ret; + } + // remove only RRSet with the given type + knot_rrset_t *rrset = knot_node_remove_rrset(node, type); + changes->old_rrsets[changes->old_rrsets_count++] = rrset; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_remove(knot_zone_contents_t *contents, + knot_changeset_t *chset, + xfrin_changes_t *changes) +{ + /* + * Iterate over removed RRSets, copy appropriate nodes and remove + * the rrsets from them. By default, the RRSet should be copied so that + * RDATA may be removed from it. + */ + int ret = 0; + knot_node_t *node = NULL; + knot_rrset_t *rrset = NULL; + + for (int i = 0; i < chset->remove_count; ++i) { + // check if the old node is not the one we should use + if (!node || knot_rrset_owner(chset->remove[i]) + != knot_node_owner(node)) { + node = knot_zone_contents_get_node(contents, + knot_rrset_owner(chset->remove[i])); + if (node == NULL) { + dbg_xfrin("Node not found for RR to be removed" + "!\n"); + continue; + } + } + + // create a copy of the node if not already created + if (!knot_node_is_new(node)) { + ret = xfrin_get_node_copy(&node, changes); + if (ret != KNOT_EOK) { + return ret; + } + } + + assert(node != NULL); + assert(knot_node_is_new(node)); + + // first check if all RRSets should be removed + if (knot_rrset_class(chset->remove[i]) == KNOT_CLASS_ANY) { + ret = xfrin_apply_remove_all_rrsets( + changes, node, + knot_rrset_type(chset->remove[i])); + } else if (knot_rrset_type(chset->remove[i]) + == KNOT_RRTYPE_RRSIG) { + // this should work also for UPDATE + ret = xfrin_apply_remove_rrsigs(changes, + chset->remove[i], + node, &rrset); + } else { + // this should work also for UPDATE + ret = xfrin_apply_remove_normal(changes, + chset->remove[i], + node, &rrset); + } + + dbg_xfrin("xfrin_apply_remove() ret = %d\n", ret); + + if (ret > 0) { + continue; + } else if (ret != KNOT_EOK) { + return ret; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static knot_node_t *xfrin_add_new_node(knot_zone_contents_t *contents, + knot_rrset_t *rrset) +{ + /*! \todo Why is the function disabled? */ + //return NULL; + + knot_node_t *node = knot_node_new(knot_rrset_get_owner(rrset), + NULL, KNOT_NODE_FLAGS_NEW); + if (node == NULL) { + dbg_xfrin("Failed to create a new node.\n"); + return NULL; + } + + int ret = 0; + + // insert the node into zone structures and create parents if + // necessary +// dbg_xfrin("Adding new node to zone. From owner: %s type %s\n", +// knot_dname_to_str(node->owner), +// knot_rrtype_to_string(rrset->type)); +// getchar(); + if (knot_rrset_type(rrset) == KNOT_RRTYPE_NSEC3) { + ret = knot_zone_contents_add_nsec3_node(contents, node, 1, 0, + 1); + } else { + ret = knot_zone_contents_add_node(contents, node, 1, + KNOT_NODE_FLAGS_NEW, 1); + } + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add new node to zone contents.\n"); + return NULL; + } + + // find previous node and connect the new one to it + knot_node_t *prev = NULL; + if (knot_rrset_type(rrset) == KNOT_RRTYPE_NSEC3) { + prev = knot_zone_contents_get_previous_nsec3(contents, + knot_rrset_owner(rrset)); + } else { + prev = knot_zone_contents_get_previous(contents, + knot_rrset_owner(rrset)); + } + + // fix prev and next pointers + if (prev != NULL) { + knot_node_set_previous(node, prev); + } + +// printf("contents owned by: %s (%p)\n", +// knot_dname_to_str(contents->apex->owner), +// contents); + assert(contents->zone != NULL); + knot_node_set_zone(node, contents->zone); + + return node; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_add_normal(xfrin_changes_t *changes, + knot_rrset_t *add, + knot_node_t *node, + knot_rrset_t **rrset) +{ + assert(changes != NULL); + assert(add != NULL); + assert(node != NULL); + assert(rrset != NULL); + + int ret; + + dbg_xfrin("applying rrset:\n"); + knot_rrset_dump(add, 0); +// getchar(); + + if (!*rrset + || knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) != 0 + || knot_rrset_type(*rrset) + != knot_rrset_type(add)) { + dbg_xfrin("Removing rrset!\n"); + *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); + } + + dbg_xfrin("Removed RRSet: \n"); + knot_rrset_dump(*rrset, 1); + + if (*rrset == NULL) { +dbg_xfrin_exec_verb( + char *name = knot_dname_to_str(add->owner); + dbg_xfrin_verb("RRSet to be added not found in zone.\n"); + dbg_xfrin_verb("owner: %s type: %s\n", name, + knot_rrtype_to_string(add->type)); + free(name); +); +// getchar(); + // add the RRSet from the changeset to the node + /*! \todo What about domain names?? Shouldn't we use the + * zone-contents' version of this function?? + */ + ret = knot_node_add_rrset(node, add, 0); +// ret = knot_zone_contents_add_rrset(node->zone->contents, +// rrset, node, +// KNOT_RRSET_DUPL_MERGE, +// 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add RRSet to node.\n"); + return KNOT_ERROR; + } + return 1; // return 1 to indicate the add RRSet was used + } + + knot_rrset_t *old = *rrset; + +dbg_xfrin_exec( + char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); + dbg_xfrin("Found RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); + free(name); +); + knot_rrset_dump(*rrset, 1); + ret = xfrin_copy_old_rrset(old, rrset, changes); + if (ret != KNOT_EOK) { + assert(0); + return ret; + } + +// dbg_xfrin("After copy: Found RRSet with owner %s, type %s\n", +// knot_dname_to_str((*rrset)->owner), +// knot_rrtype_to_string(knot_rrset_type(*rrset))); + + // merge the changeset RRSet to the copy + /* What if the update fails? + * The changesets will be destroyed - that will destroy 'add', + * and the copied RRSet will be destroyed because it is in the new + * rrsets list. + * + * If the update is successfull, the old RRSet will be destroyed, + * but the one from the changeset will be not!! + * + * TODO: add the 'add' rrset to list of old RRSets? + */ + dbg_xfrin("Merging RRSets with owners: %s %s types: %d %d\n", + (*rrset)->owner->name, add->owner->name, (*rrset)->type, + add->type); + dbg_xfrin_detail("RDATA in RRSet1: %p, RDATA in RRSet2: %p\n", + (*rrset)->rdata, add->rdata); + ret = knot_rrset_merge((void **)rrset, (void **)&add); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to merge changeset RRSet to copy.\n"); + return KNOT_ERROR; + } + dbg_xfrin("Merge returned: %d\n", ret); + knot_rrset_dump(*rrset, 1); + ret = knot_node_add_rrset(node, *rrset, 0); + + // return 2 so that the add RRSet is removed from + // the changeset (and thus not deleted) + // and put to list of new RRSets (is this ok?) + // and deleted + return 2; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_add_rrsig(xfrin_changes_t *changes, + knot_rrset_t *add, + knot_node_t *node, + knot_rrset_t **rrset) +{ + assert(changes != NULL); + assert(add != NULL); + assert(node != NULL); + assert(rrset != NULL); + assert(knot_rrset_type(add) == KNOT_RRTYPE_RRSIG); + + int ret; + + knot_rr_type_t type = knot_rdata_rrsig_type_covered( + knot_rrset_rdata(add)); + + if (!*rrset + || knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) != 0 + || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered( + knot_rrset_rdata(add))) { + // copy the rrset + ret = xfrin_copy_rrset(node, type, rrset, changes); + if (ret < 0) { + return ret; + } + } else { + // we should have the right RRSIG RRSet in *rrset + assert(knot_rrset_type(*rrset) == type); + // this RRSet should be the already copied RRSet so we may + // update it right away + } + + if (*rrset == NULL) { + dbg_xfrin("RRSet to be added not found in zone.\n"); + + // create a new RRSet to add the RRSIGs into + *rrset = knot_rrset_new(knot_node_get_owner(node), type, + knot_rrset_class(add), + knot_rrset_ttl(add)); + if (*rrset == NULL) { + dbg_xfrin("Failed to create new RRSet for RRSIGs.\n"); + return KNOT_ENOMEM; + } + + // add the RRSet from the changeset to the node + ret = knot_node_add_rrset(node, *rrset, 0); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add RRSet to node.\n"); + return KNOT_ERROR; + } + } + +dbg_xfrin_exec( + char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); + dbg_xfrin("Found RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); + free(name); +); + + if (knot_rrset_rrsigs(*rrset) == NULL) { + ret = knot_rrset_set_rrsigs(*rrset, add); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add RRSIGs to the RRSet.\n"); + return KNOT_ERROR; + } + + return 1; + } else { + knot_rrset_t *old = knot_rrset_get_rrsigs(*rrset); + assert(old != NULL); + knot_rrset_t *rrsig; + + ret = xfrin_copy_old_rrset(old, &rrsig, changes); + if (ret != KNOT_EOK) { + return ret; + } + + // replace the old RRSIGs with the new ones + knot_rrset_set_rrsigs(*rrset, rrsig); + + // merge the changeset RRSet to the copy + /*! \todo What if the update fails? + * + */ + ret = knot_rrset_merge((void **)&rrsig, (void **)&add); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to merge changeset RRSet to copy.\n"); + return KNOT_ERROR; + } + + return 2; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_add(knot_zone_contents_t *contents, + knot_changeset_t *chset, + xfrin_changes_t *changes) +{ + // iterate over removed RRSets, copy appropriate nodes and remove + // the rrsets from them + int ret = 0; + knot_node_t *node = NULL; + knot_rrset_t *rrset = NULL; + + for (int i = 0; i < chset->add_count; ++i) { + dbg_xfrin_detail("Adding RRSet:\n"); + knot_rrset_dump(chset->add[i], 0); + // check if the old node is not the one we should use + if (!node || knot_rrset_owner(chset->add[i]) + != knot_node_owner(node)) { + node = knot_zone_contents_get_node(contents, + knot_rrset_owner(chset->add[i])); + if (node == NULL) { + // create new node, connect it properly to the + // zone nodes + dbg_xfrin("Creating new node from.\n"); + node = xfrin_add_new_node(contents, + chset->add[i]); + if (node == NULL) { + dbg_xfrin("Failed to create new node " + "in zone.\n"); + return KNOT_ERROR; + } +// continue; // continue with another RRSet + } + } + + // create a copy of the node if not already created + if (!knot_node_is_new(node)) { + xfrin_get_node_copy(&node, changes); + } + + assert(node != NULL); + assert(knot_node_is_new(node)); + + if (knot_rrset_type(chset->add[i]) == KNOT_RRTYPE_RRSIG) { + ret = xfrin_apply_add_rrsig(changes, chset->add[i], + node, &rrset); + } else { + ret = xfrin_apply_add_normal(changes, chset->add[i], + node, &rrset); + } + + dbg_xfrin("xfrin_apply_..() returned %d, rrset: %p\n", ret, + rrset); + + if (ret == 1) { + // the ADD RRSet was used, i.e. it should be removed + // from the changeset and saved in the list of new + // RRSets + ret = xfrin_changes_check_rrsets( + &changes->new_rrsets, + &changes->new_rrsets_count, + &changes->new_rrsets_allocated, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add old RRSet to list.\n"); + return ret; + } + + changes->new_rrsets[changes->new_rrsets_count++] = + chset->add[i]; + + chset->add[i] = NULL; + } else if (ret == 2) { + // the copy of the RRSet was used, but it was already + // stored in the new RRSets list + // just delete the add RRSet, but without RDATA + // as these were merged to the copied RRSet + knot_rrset_free(&chset->add[i]); + } else if (ret != KNOT_EOK) { + + return ret; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \todo This must be tested!! Simulate failure somehow. + */ +static void xfrin_clean_changes_after_fail(xfrin_changes_t *changes) +{ + /* 1) Delete copies of RRSets created because they were updated. + * Do not delete their RDATA or owners. + */ + for (int i = 0; i < changes->new_rrsets_count; ++i) { + knot_rrset_free(&changes->new_rrsets[i]); + } + + /* 2) Delete copies of nodes created because they were updated. + * Do not delete their RRSets. + */ + for (int i = 0; i < changes->new_nodes_count; ++i) { + knot_node_free(&changes->new_nodes[i], 0, 1); + } + + // changesets will be deleted elsewhere + // so just delete the changes structure + xfrin_changes_free(&changes); +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_replace_soa(knot_zone_contents_t *contents, + xfrin_changes_t *changes, + knot_changeset_t *chset) +{ + knot_node_t *node = knot_zone_contents_get_apex(contents); + assert(node != NULL); + + int ret = 0; + + // create a copy of the node if not already created + if (!knot_node_is_new(node)) { + ret = xfrin_get_node_copy(&node, changes); + if (ret != KNOT_EOK) { + return ret; + } + } + + assert(knot_node_is_new(node)); + + // set the node copy as the apex of the contents + contents->apex = node; + + // remove the SOA RRSet from the apex + knot_rrset_t *rrset = knot_node_remove_rrset(node, KNOT_RRTYPE_SOA); + assert(rrset != NULL); + + // add the old RRSet to the list of old RRSets + ret = xfrin_changes_check_rrsets(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add old RRSet to list.\n"); + return ret; + } + + // save also the SOA RDATA, because RDATA are not deleted with the + // RRSet + ret = xfrin_changes_check_rdata(&changes->old_rdata, + &changes->old_rdata_types, + changes->old_rdata_count, + &changes->old_rdata_allocated, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add old RDATA to list.\n"); + return ret; + } + + // save the SOA to the new RRSet, so that it is deleted if the + // apply fails + ret = xfrin_changes_check_rrsets(&changes->new_rrsets, + &changes->new_rrsets_count, + &changes->new_rrsets_allocated, 1); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add old RRSet to list.\n"); + return ret; + } + + changes->old_rrsets[changes->old_rrsets_count++] = rrset; + + /*! \todo Maybe check if the SOA does not have more RDATA? */ + changes->old_rdata[changes->old_rdata_count] = rrset->rdata; + changes->old_rdata_types[changes->old_rdata_count] = KNOT_RRTYPE_SOA; + ++changes->old_rdata_count; + + // insert the new SOA RRSet to the node + dbg_xfrin_verb("Adding SOA.\n"); + ret = knot_node_add_rrset(node, chset->soa_to, 0); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to add RRSet to node.\n"); + return KNOT_ERROR; + } + + changes->new_rrsets[changes->new_rrsets_count++] = chset->soa_to; + + // remove the SOA from the changeset, so it will not be deleted after + // successful apply + chset->soa_to = NULL; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_apply_changeset(knot_zone_contents_t *contents, + xfrin_changes_t *changes, + knot_changeset_t *chset) +{ + /* + * Applies one changeset to the zone. Checks if the changeset may be + * applied (i.e. the origin SOA (soa_from) has the same serial as + * SOA in the zone apex. + */ + + // check if serial matches + /*! \todo Only if SOA is present? */ + const knot_rrset_t *soa = knot_node_rrset(contents->apex, + KNOT_RRTYPE_SOA); + if (soa == NULL || knot_rdata_soa_serial(knot_rrset_rdata(soa)) + != chset->serial_from) { + dbg_xfrin("SOA serials do not match!!\n"); + return KNOT_ERROR; + } + + int ret = xfrin_apply_remove(contents, chset, changes); + if (ret != KNOT_EOK) { + xfrin_clean_changes_after_fail(changes); + return ret; + } + + ret = xfrin_apply_add(contents, chset, changes); + if (ret != KNOT_EOK) { + xfrin_clean_changes_after_fail(changes); + return ret; + } + + /*! \todo Only if SOA is present? */ + return xfrin_apply_replace_soa(contents, changes, chset); +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_check_node_in_tree(knot_zone_tree_node_t *tnode, void *data) +{ + assert(tnode != NULL); + assert(data != NULL); + assert(tnode->node != NULL); + + xfrin_changes_t *changes = (xfrin_changes_t *)data; + + knot_node_t *node = knot_node_get_new_node(tnode->node); + + if (node == NULL) { + // no RRSets were removed from this node, thus it cannot be + // empty + return; + } + + dbg_xfrin("xfrin_check_node_in_tree: children of old node: %u, " + "children of new node: %u.\n", + knot_node_children(node), + knot_node_children(tnode->node)); + + + // check if the node is empty and has no children + // to be sure, check also the count of children of the old node + if (knot_node_rrset_count(node) == 0 + && knot_node_children(node) == 0 + && knot_node_children(tnode->node) == 0) { + // in this case the new node copy should be removed + // but it cannot be deleted because if a rollback happens, + // the node must be in the new nodes list + // just add it to the old nodes list so that it is deleted + // after successful update + + // set the new node of the old node to NULL + knot_node_set_new_node(tnode->node, NULL); + + // if the parent has a new copy, decrease the number of + // children of that copy + if (knot_node_new_node(knot_node_parent(node, 0))) { + /*! \todo Replace by some API. */ + --node->parent->new_node->children; + } + + // put the new node to te list of old nodes + if (xfrin_changes_check_nodes(&changes->old_nodes, + &changes->old_nodes_count, + &changes->old_nodes_allocated) + != KNOT_EOK) { + /*! \todo Notify about the error!!! */ + return; + } + + changes->old_nodes[changes->old_nodes_count++] = node; + + // leave the old node in the old node list, we will delete + // it later + } +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_finalize_remove_nodes(knot_zone_contents_t *contents, + xfrin_changes_t *changes) +{ + assert(contents != NULL); + assert(changes != NULL); + + knot_node_t *node; + knot_zone_tree_node_t *removed; + ck_hash_table_item_t *rem_hash; + int ret; + + for (int i = 0; i < changes->old_nodes_count; ++i) { + node = changes->old_nodes[i]; + + // if the node is marked as old and has no new node copy + // remove it from the zone structure but do not delete it + // that may be done only after the grace period + if (knot_node_is_old(node) + && knot_node_new_node(node) == NULL) { + + if (knot_node_rrset(node, KNOT_RRTYPE_NSEC3) + != NULL) { + ret = knot_zone_contents_remove_nsec3_node( + contents, node, &removed); + } else { + ret = knot_zone_contents_remove_node( + contents, node, &removed, &rem_hash); + } + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to remove node from zone" + "!\n"); + return KNOT_ENONODE; + } + + assert(removed != NULL); + assert(removed->node == node); + // delete the tree node (not needed) + free(removed); + + if (rem_hash != NULL) { + // save the removed hash table item + ret = xfrin_changes_check_hash_items( + &changes->old_hash_items, + &changes->old_hash_items_count, + &changes->old_hash_items_allocated); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to save the hash" + " table item to list of " + "old items.\n"); + return ret; + } + changes->old_hash_items[ + changes->old_hash_items_count++] + = rem_hash; + } + } + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_finalize_contents(knot_zone_contents_t *contents, + xfrin_changes_t *changes) +{ + // don't know what should have been done here, except for one thing: + // walk through the zone and remove empty nodes (save them in the + // old nodes list). But only those having no children!!! + + /* + * Walk through the zone and remove empty nodes. + * We must walk backwards, so that children are processed before + * their parents. This will allow to remove chain of parent-children + * nodes. + * We cannot remove the nodes right away as it would modify the very + * structure used for walking through the zone. Just put the nodes + * to the list of old nodes to be removed. + * We must also decrease the node's parent's children count now + * and not when deleting the node, so that the chain of parent-child + * nodes may be removed. + */ + knot_zone_tree_t *t = knot_zone_contents_get_nodes(contents); + assert(t != NULL); + + // walk through the zone and select nodes to be removed + knot_zone_tree_reverse_apply_postorder(t, xfrin_check_node_in_tree, + (void *)changes); + + // Do the same with NSEC3 nodes. + t = knot_zone_contents_get_nsec3_nodes(contents); + assert(t != NULL); + + knot_zone_tree_reverse_apply_postorder(t, xfrin_check_node_in_tree, + (void *)changes); + + // remove the nodes one by one + return xfrin_finalize_remove_nodes(contents, changes); +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_fix_refs_in_node(knot_zone_tree_node_t *tnode, void *data) +{ + /*! \todo Passed data is always seto to NULL. */ + assert(tnode != NULL); + //assert(data != NULL); + + //xfrin_changes_t *changes = (xfrin_changes_t *)data; + + // 1) Fix the reference to the node to the new one if there is some + knot_node_t *node = tnode->node; + + knot_node_t *new_node = knot_node_get_new_node(node); + if (new_node != NULL) { + //assert(knot_node_rrset_count(new_node) > 0); + node = new_node; + tnode->node = new_node; + } + + // 2) fix references from the node remaining in the zone + knot_node_update_refs(node); +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_fix_gen_in_node(knot_zone_tree_node_t *tnode, void *data) +{ + /*! \todo Passed data is always seto to NULL. */ + assert(tnode != NULL); + + knot_node_t *node = tnode->node; + + knot_node_set_old(node); +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_fix_hash_refs(ck_hash_table_item_t *item, void *data) +{ + if (item == NULL) { + return; + } + + knot_node_t *new_node = knot_node_get_new_node( + (knot_node_t *)item->value); + if (new_node != NULL) { + assert(item->key_length + == knot_dname_size(knot_node_owner(new_node))); + assert(strncmp(item->key, (const char *)knot_dname_name( + knot_node_owner(new_node)), item->key_length) == 0); + item->value = (void *)new_node; + item->key = (const char *)knot_dname_name( + knot_node_owner(new_node)); + } +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_fix_dname_refs(knot_dname_t *dname, void *data) +{ + UNUSED(data); + knot_dname_update_node(dname); +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_fix_references(knot_zone_contents_t *contents) +{ + /*! \todo This function must not fail!! */ + + /* + * Now the contents are already switched, and we should update all + * references not updated yet, so that the old contents may be removed. + * + * Walk through the zone tree, so that each node will be checked + * and updated. + */ + // fix references in normal nodes + knot_zone_tree_t *tree = knot_zone_contents_get_nodes(contents); + knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_refs_in_node, + NULL); + + // fix refereces in NSEC3 nodes + tree = knot_zone_contents_get_nsec3_nodes(contents); + knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_refs_in_node, + NULL); + + // fix references in hash table + ck_hash_table_t *table = knot_zone_contents_get_hash_table(contents); + ck_apply(table, xfrin_fix_hash_refs, NULL); + + // fix references dname table + int ret = knot_zone_contents_dname_table_apply(contents, + xfrin_fix_dname_refs, NULL); + assert(ret == KNOT_EOK); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int xfrin_fix_generation(knot_zone_contents_t *contents) +{ + assert(contents != NULL); + + knot_zone_tree_t *tree = knot_zone_contents_get_nodes(contents); + knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_gen_in_node, + NULL); + + tree = knot_zone_contents_get_nsec3_nodes(contents); + knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_gen_in_node, + NULL); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static void xfrin_cleanup_update(xfrin_changes_t *changes) +{ + // free old nodes but do not destroy their RRSets + // remove owners also, because of reference counting + for (int i = 0; i < changes->old_nodes_count; ++i) { + dbg_xfrin_detail("Deleting old node: %p\n", changes->old_nodes[i]); + knot_node_dump(changes->old_nodes[i], 0); + knot_node_free(&changes->old_nodes[i], 1, 0); + } + + // free old RRSets, and destroy also domain names in them + // because of reference counting + + // check if there are not some duplicate RRSets +// for (int i = 0; i < changes->old_rrsets_count; ++i) { +// for (int j = i + 1; j < changes->old_rrsets_count; ++j) { +// if (changes->old_rrsets[i] == changes->old_rrsets[j]) { +// assert(0); +// } +// if (changes->old_rrsets[i]->rdata != NULL +// && changes->old_rrsets[i]->rdata +// == changes->old_rrsets[j]->rdata) { +// assert(0); +// } +// } +// } + + for (int i = 0; i < changes->old_rrsets_count; ++i) { +// knot_rrset_deep_free(&changes->old_rrsets[i], 1, 1, 1); + dbg_xfrin_detail("Deleting old RRSet: %p\n", changes->old_rrsets[i]); + knot_rrset_dump(changes->old_rrsets[i], 0); + knot_rrset_free(&changes->old_rrsets[i]); + } + + // delete old RDATA + for (int i = 0; i < changes->old_rdata_count; ++i) { + dbg_xfrin_detail("Deleting old RDATA: %p, type: %s\n", + changes->old_rdata[i], + knot_rrtype_to_string(changes->old_rdata_types[i])); + knot_rdata_dump(changes->old_rdata[i], changes->old_rdata_types[i], 0); + knot_rdata_t *rdata = changes->old_rdata[i]; + assert(rdata != NULL); + do { + knot_rdata_t *tmp = rdata->next; + knot_rdata_deep_free(&rdata, + changes->old_rdata_types[i], 1); + rdata = tmp; + } while (rdata != NULL && rdata != changes->old_rdata[i]); + changes->old_rdata[i] = NULL; + } + + // free old hash table items, but do not touch their contents + for (int i = 0; i < changes->old_hash_items_count; ++i) { + free(changes->old_hash_items[i]); + } + free(changes->old_hash_items); + + // free allocated arrays of nodes and rrsets + free(changes->new_nodes); + free(changes->old_nodes); + free(changes->new_rrsets); + free(changes->old_rrsets); + free(changes->old_rdata); + free(changes->old_rdata_types); +} + +/*----------------------------------------------------------------------------*/ + +int xfrin_apply_changesets_to_zone(knot_zone_t *zone, + knot_changesets_t *chsets) +{ + if (zone == NULL || chsets == NULL || chsets->count == 0) { + return KNOT_EBADARG; + } + + knot_zone_contents_t *old_contents = knot_zone_get_contents(zone); + if (!old_contents) { + return KNOT_EBADARG; + } + +// dbg_xfrin("\nOLD ZONE CONTENTS:\n\n"); +// knot_zone_contents_dump(old_contents, 1); + + /* + * Ensure that the zone generation is set to 0. + */ + if (!knot_zone_contents_gen_is_old(old_contents)) { + // this would mean that a previous update was not completed + // abort + dbg_zone("Trying to apply changesets to zone that is " + "being updated. Aborting.\n"); + return KNOT_EAGAIN; + } + + /* + * Create a shallow copy of the zone, so that the structures may be + * updated. + * + * This will create new zone contents structures (normal nodes' tree, + * NSEC3 tree, hash table, domain name table), but fill them with the + * data from the old contents. + */ + knot_zone_contents_t *contents_copy = NULL; + + int ret = knot_zone_contents_shallow_copy(old_contents, + &contents_copy); + if (ret != KNOT_EOK) { + dbg_xfrin("Failed to create shallow copy of zone: %s\n", + knot_strerror(ret)); + return ret; + } + + /* + * Now, apply one changeset after another until all are applied. + * Changesets may be either from IXFR or from a dynamic update. + * Dynamic updates use special TYPE and CLASS values to distinguish + * requests, such as "remove all RRSets from a node", "remove all RRs + * with the specified type from a node", etc. + * + * When updating anything within some node (removing RR, adding RR), + * the node structure is copied, but the RRSets within are not. + * + * 1) When removing RRs from node, The affected RRSet is copied. This + * it also a 'shallow copy', i.e. the RDATA remain the exact same. + * The specified RRs (i.e. RDATA) are then removed from the copied + * RRSet. + * 2) When adding RRs to node, there are two cases: + * a) If there is a RRSet that should contain these RRs + * this RRSet is copied (shallow copy) and the RRs are added to + * it (rrset_merge()). + * b) If there is not such a RRSet, the whole RRSet from the + * changeset is added to the new node (thus this RRSet must not + * be deleted afterwards). + * + * A special case are RRSIG RRs. These functions assume that they + * are grouped together in knot_rrset_t structures according to + * their header (owner, type, class) AND their 'type covered', i.e. + * there may be more RRSIG RRSets in one changeset (while there + * should not be more RRSets of any other type). + * 3) When removing RRSIG RRs from node, the appropriate RRSet holding + * them must be found (according to the 'type covered' field). This + * RRSet is then copied (shallow copy), Its RRSIGs are also copied + * and the RRSIG RRs are added to the RRSIG copy. + * 4) When adding RRSIG RRs to node, the same process is done - the + * proper RRSet holding them is found, copied, its RRSIGs are + * copied (if there are some) and the RRs are added to the copy. + * + * When a node is copied, reference to the copy is stored within the + * old node (node_t.old_node). This is important, because when the + * zone contents are switched to the new ones, references from old nodes + * that should point to new nodes are not yet set (it would influence + * replying from the old zone contents). While all these references + * (such as node_t.prev, node_t.next, node_t.parent, etc.) are properly + * modified, the search functions use old or new nodes accordingly + * (old nodes while old contents are used, new nodes when new contents + * are used). The 'check_version' parameter turns on this behaviour in + * search functions. + * + * In case of error, we must remove all data created by the update, i.e. + * - new nodes, + * - new RRSets, + * and remove the references to the new nodes from old nodes. + * + * In case of success, the RRSet structures from the changeset + * structures must not be deleted, as they are either already used by + * the server (stored within the new zone contents) or deleted when + * cleaning up the temporary 'changes' structure. + */ + xfrin_changes_t changes; + memset(&changes, 0, sizeof(xfrin_changes_t)); + + for (int i = 0; i < chsets->count; ++i) { + if ((ret = xfrin_apply_changeset(contents_copy, &changes, + &chsets->sets[i])) != KNOT_EOK) { + xfrin_rollback_update(contents_copy, &changes); + dbg_xfrin("Failed to apply changesets to zone: " + "%s\n", knot_strerror(ret)); + return ret; + } + } + + /* + * When all changesets are applied, set generation 1 to the copy of + * the zone so that new nodes are used instead of old ones. + */ +// knot_zone_contents_switch_generation(contents_copy); + //contents_copy->generation = 1; + knot_zone_contents_set_gen_new(contents_copy); + + /* + * Finalize the zone contents. + */ + ret = xfrin_finalize_contents(contents_copy, &changes); + if (ret != KNOT_EOK) { + xfrin_rollback_update(contents_copy, &changes); + dbg_xfrin("Failed to finalize new zone contents: %s\n", + knot_strerror(ret)); + return ret; + } + + /* + * Switch the zone contents + */ + knot_zone_contents_t *old = + knot_zone_switch_contents(zone, contents_copy); + assert(old == old_contents); + + /* + * From now on, the new contents of the zone are being used. + * References to nodes may be updated in the meantime. However, we must + * traverse the zone and fix all references that were not. + */ + /*! \todo This operation must not fail!!! .*/ + ret = xfrin_fix_references(contents_copy); + assert(ret == KNOT_EOK); + + // set generation to finished + knot_zone_contents_set_gen_new_finished(contents_copy); + + // set generation of all nodes to the old one + // now it is safe (no old nodes should be referenced) + ret = xfrin_fix_generation(contents_copy); + assert(ret == KNOT_EOK); + + /* + * Now we may also set the generation back to 0 so that another + * update is possible. + */ + knot_zone_contents_set_gen_old(contents_copy); + + /* + * Wait until all readers finish reading + */ + synchronize_rcu(); + + /* + * Delete all old and unused data. + */ + xfrin_zone_contents_free(&old_contents); + xfrin_cleanup_update(&changes); + + return KNOT_EOK; +} diff --git a/src/libknot/updates/xfr-in.h b/src/libknot/updates/xfr-in.h new file mode 100644 index 0000000..8a7c64b --- /dev/null +++ b/src/libknot/updates/xfr-in.h @@ -0,0 +1,184 @@ +/*! + * \file xfr-in.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief XFR client API. + * + * \addtogroup query_processing + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_XFR_IN_H_ +#define _KNOT_XFR_IN_H_ + +#include <stdint.h> +#include <string.h> + +#include "dname.h" +#include "zone/zone.h" +#include "packet/packet.h" +#include "nameserver/name-server.h" +#include "updates/changesets.h" + +/*----------------------------------------------------------------------------*/ + +typedef struct xfrin_orphan_rrsig { + knot_rrset_t *rrsig; + struct xfrin_orphan_rrsig *next; +} xfrin_orphan_rrsig_t; + +typedef struct xfrin_constructed_zone { + knot_zone_contents_t *contents; + xfrin_orphan_rrsig_t *rrsigs; +} xfrin_constructed_zone_t; + +typedef enum xfrin_transfer_result { + XFRIN_RES_COMPLETE = 1, + XFRIN_RES_SOA_ONLY = 2, + XFRIN_RES_FALLBACK = 3 +} xfrin_transfer_result_t; + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Creates normal query for the given zone name and the SOA type. + * + * \param owner Zone owner. + * \param buffer Buffer to fill the message in. + * \param size In: available space in the buffer. Out: actual size of the + * message in bytes. + * + * \retval KNOT_EOK + * \retval KNOT_ESPACE + * \retval KNOT_ERROR + */ +int xfrin_create_soa_query(knot_dname_t *owner, knot_ns_xfr_t *xfr, + size_t *size); + +/*! + * \brief Checks if a zone transfer is required by comparing the zone's SOA with + * the one received from master server. + * + * \param zone Zone to check. + * \param soa_response Response to SOA query received from master server. + * + * \retval < 0 if an error occured. + * \retval 1 if the transfer is needed. + * \retval 0 if the transfer is not needed. + */ +int xfrin_transfer_needed(const knot_zone_contents_t *zone, + knot_packet_t *soa_response); + +/*! + * \brief Creates normal query for the given zone name and the AXFR type. + * + * \param owner Zone owner. + * \param xfr Data structure holding important data for the query, namely + * pointer to the buffer for wireformat and TSIG data. + * \param size In: available space in the buffer. Out: actual size of the + * message in bytes. + * \param use_tsig If TSIG should be used. + * + * \todo Parameter use_tsig probably not needed. + * + * \retval KNOT_EOK + * \retval KNOT_ESPACE + * \retval KNOT_ERROR + */ +int xfrin_create_axfr_query(knot_dname_t *owner, knot_ns_xfr_t *xfr, + size_t *size, int use_tsig); + +/*! + * \brief Creates normal query for the given zone name and the IXFR type. + * + * \param zone Zone contents. + * \param buffer Buffer to fill the message in. + * \param size In: available space in the buffer. Out: actual size of the + * message in bytes. + * \param use_tsig If TSIG should be used. + * + * \todo Parameter use_tsig probably not needed. + * + * \retval KNOT_EOK + * \retval KNOT_ESPACE + * \retval KNOT_ERROR + */ +int xfrin_create_ixfr_query(const knot_zone_contents_t *zone, + knot_ns_xfr_t *xfr, size_t *size, int use_tsig); + +/*! + * \brief Processes the newly created transferred zone. + * + * \param nameserver Name server to update. + * \param zone Zone build from transfer. + * + * \retval KNOT_ENOTSUP + */ +int xfrin_zone_transferred(knot_nameserver_t *nameserver, + knot_zone_contents_t *zone); + +/*! + * \brief Processes one incoming packet of AXFR transfer by updating the given + * zone. + * + * \param pkt Incoming packet in wire format. + * \param size Size of the packet in bytes. + * \param zone Zone being built. If there is no such zone (i.e. this is the + * first packet, \a *zone may be set to NULL, in which case a new + * zone structure is created). + * + * \retval KNOT_EOK + * + * \todo Refactor!!! + */ +int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, + xfrin_constructed_zone_t **zone*/ + knot_ns_xfr_t *xfr); + +/*! + * \brief Destroys the whole changesets structure. + * + * Frees all RRSets present in the changesets and all their data. Also frees + * the changesets structure and sets the parameter to NULL. + * + * \param changesets Changesets to destroy. + */ +void xfrin_free_changesets(knot_changesets_t **changesets); + +/*! + * \brief Parses IXFR reply packet and fills in the changesets structure. + * + * \param pkt Packet containing the IXFR reply in wire format. + * \param size Size of the packet in bytes. + * \param changesets Changesets to be filled in. + * + * \retval KNOT_EOK + * \retval KNOT_EINVAL + * \retval KNOT_EMALF + * \retval KNOT_ENOMEM + */ +int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr/*const uint8_t *pkt, size_t size, + knot_changesets_t **changesets*/); + +int xfrin_apply_changesets_to_zone(knot_zone_t *zone, + knot_changesets_t *chsets); + +#endif /* _KNOTXFR_IN_H_ */ + +/*! @} */ diff --git a/src/libknot/util/debug.c b/src/libknot/util/debug.c new file mode 100644 index 0000000..0ca67c9 --- /dev/null +++ b/src/libknot/util/debug.c @@ -0,0 +1,233 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdint.h> +#include <assert.h> +#include <stdlib.h> + +#include "util/utils.h" +#include "util/debug.h" +#include "libknot.h" +#include "common/print.h" + +void knot_rdata_dump(knot_rdata_t *rdata, uint32_t type, char loaded_zone) +{ +#if defined(KNOT_ZONE_DEBUG) || defined(KNOT_RDATA_DEBUG) + fprintf(stderr, " ------- RDATA -------\n"); + if (rdata == NULL) { + fprintf(stderr, " There are no rdata in this RRset!\n"); + fprintf(stderr, " ------- RDATA -------\n"); + return; + } + knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(type); + assert(desc != NULL); + char *name; + + for (int i = 0; i < rdata->count; i++) { + if (rdata->items[i].raw_data == NULL) { + continue; + } + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) { + assert(rdata->items[i].dname != NULL); + name = knot_dname_to_str(rdata->items[i].dname); + fprintf(stderr, " DNAME: %d: %s\n", + i, name); + free(name); + if (loaded_zone) { + if (rdata->items[i].dname->node) { + name = + knot_dname_to_str(rdata->items[i].dname->node->owner); + fprintf(stderr, " Has node owner: %s\n", name); + free(name); + } else { + fprintf(stderr, " No node set\n"); + } + } + fprintf(stderr, " labels: "); + hex_print((char *)rdata->items[i].dname->labels, + rdata->items[i].dname->label_count); + + } else { + assert(rdata->items[i].raw_data != NULL); + fprintf(stderr, " %d: raw_data: length: %d\n", i, + *(rdata->items[i].raw_data)); + fprintf(stderr, " "); + hex_print(((char *)( + rdata->items[i].raw_data + 1)), + rdata->items[i].raw_data[0]); + } + } + fprintf(stderr, " ------- RDATA -------\n"); +#endif +} + +void knot_rrset_dump(const knot_rrset_t *rrset, char loaded_zone) +{ +#if defined(KNOT_ZONE_DEBUG) || defined(KNOT_RRSET_DEBUG) + fprintf(stderr, " ------- RRSET -------\n"); + fprintf(stderr, " %p\n", rrset); + if (!rrset) { + return; + } + char *name = knot_dname_to_str(rrset->owner); + fprintf(stderr, " owner: %s\n", name); + free(name); + fprintf(stderr, " type: %s\n", knot_rrtype_to_string(rrset->type)); + fprintf(stderr, " class: %d\n", rrset->rclass); + fprintf(stderr, " ttl: %d\n", rrset->ttl); + + fprintf(stderr, " RRSIGs:\n"); + if (rrset->rrsigs != NULL) { + knot_rrset_dump(rrset->rrsigs, loaded_zone); + } else { + fprintf(stderr, " none\n"); + } + + if (rrset->rdata == NULL) { + fprintf(stderr, " NO RDATA!\n"); + fprintf(stderr, " ------- RRSET -------\n"); + return; + } + + fprintf(stderr, " rdata count: %d\n", rrset->rdata->count); + knot_rdata_t *tmp = rrset->rdata; + + while (tmp->next != rrset->rdata && tmp->next != NULL) { + knot_rdata_dump(tmp, rrset->type, loaded_zone); + tmp = tmp->next; + } + + knot_rdata_dump(tmp, rrset->type, loaded_zone); + + fprintf(stderr, " ------- RRSET -------\n"); +#endif +} + +void knot_node_dump(knot_node_t *node, void *loaded_zone) +{ +#if defined(KNOT_ZONE_DEBUG) || defined(KNOT_NODE_DEBUG) + //char loaded_zone = *((char*) data); + char *name; + + fprintf(stderr, "------- NODE --------\n"); + name = knot_dname_to_str(node->owner); + fprintf(stderr, "owner: %s\n", name); + free(name); + fprintf(stderr, "labels: "); + hex_print((char *)node->owner->labels, node->owner->label_count); + fprintf(stderr, "node: %p\n", node); + fprintf(stderr, "node (in node's owner): %p\n", node->owner->node); + if (loaded_zone && node->prev != NULL) { + name = knot_dname_to_str(node->prev->owner); + fprintf(stderr, "previous node: %s\n", name); + free(name); + } + + if (knot_node_is_deleg_point(node)) { + fprintf(stderr, "delegation point\n"); + } + + if (knot_node_is_non_auth(node)) { + fprintf(stderr, "non-authoritative node\n"); + } + + if (node->parent != NULL) { + /*! \todo This causes segfault when parent was free'd, + * e.g. when applying changesets. + */ + name = knot_dname_to_str(node->parent->owner); + fprintf(stderr, "parent: %s\n", name); + free(name); + } else { + fprintf(stderr, "no parent\n"); + } + + if (node->prev != NULL) { + fprintf(stderr, "previous node: %p\n", node->prev); + /*! \todo This causes segfault when prev was free'd, + * e.g. when applying changesets. + */ + name = knot_dname_to_str(node->prev->owner); + fprintf(stderr, "previous node: %s\n", name); + free(name); + } else { + fprintf(stderr, "previous node: none\n"); + } + + knot_rrset_t **rrsets = knot_node_get_rrsets(node); + + fprintf(stderr, "Wildcard child: "); + + if (node->wildcard_child != NULL) { + /*! \todo This causes segfault when wildcard child was free'd, + * e.g. when applying changesets. + */ + name = knot_dname_to_str(node->wildcard_child->owner); + fprintf(stderr, "%s\n", name); + free(name); + } else { + fprintf(stderr, "none\n"); + } + + fprintf(stderr, "NSEC3 node: "); + + if (node->nsec3_node != NULL) { + /*! \todo This causes segfault when nsec3_node was free'd, + * e.g. when applying changesets. + */ + name = knot_dname_to_str(node->nsec3_node->owner); + fprintf(stderr, "%s\n", name); + free(name); + } else { + fprintf(stderr, "none\n"); + } + + fprintf(stderr, "RRSet count: %d\n", node->rrset_count); + + for (int i = 0; i < node->rrset_count; i++) { + knot_rrset_dump(rrsets[i], (int) loaded_zone); + } + free(rrsets); + //assert(node->owner->node == node); + fprintf(stderr, "------- NODE --------\n"); +#endif +} + +void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone) +{ +#if defined(KNOT_ZONE_DEBUG) + if (!zone) { + fprintf(stderr, "------- STUB ZONE --------\n"); + return; + } + + fprintf(stderr, "------- ZONE --------\n"); + + knot_zone_contents_tree_apply_inorder(zone, knot_node_dump, (void *)&loaded_zone); + + fprintf(stderr, "------- ZONE --------\n"); + + fprintf(stderr, "------- NSEC 3 tree -\n"); + + knot_zone_contents_nsec3_apply_inorder(zone, knot_node_dump, (void *)&loaded_zone); + + fprintf(stderr, "------- NSEC 3 tree -\n"); +#endif +} diff --git a/src/libknot/util/debug.h b/src/libknot/util/debug.h new file mode 100644 index 0000000..2f9f5fd --- /dev/null +++ b/src/libknot/util/debug.h @@ -0,0 +1,755 @@ +/*! + * \file debug.h + * + * \author Jan Kadlec <jan.kadlec.@nic.cz> + * \author Lubos Slovak <lubos.slovak@nic.cz> + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Functions for debug output of structures. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_DEBUG_H_ +#define _KNOT_DEBUG_H_ + +#include <stdint.h> +#include <stdio.h> + +#include "config.h" /* autoconf generated */ + +#include "rdata.h" +#include "rrset.h" +#include "zone/node.h" +#include "zone/zone.h" +#include "util/utils.h" +#include "common/print.h" + +/* + * Debug macros + */ +/*! \todo Set these during configure. */ +//#define KNOT_ZONE_DEBUG +//#define KNOT_RESPONSE_DEBUG +//#define KNOT_ZONEDB_DEBUG +//#define KNOT_DNAME_DEBUG +//#define KNOT_NODE_DEBUG +//#define KNOT_PACKET_DEBUG +//#define KNOT_EDNS_DEBUG +//#define KNOT_RRSET_DEBUG +//#define KNOT_RDATA_DEBUG +//#define KNOT_NSEC3_DEBUG +//#define CUCKOO_DEBUG +//#define CUCKOO_DEBUG_HASH +//#define KNOT_NS_DEBUG +//#define KNOT_XFRIN_DEBUG +//#define KNOT_DDNS_DEBUG +//#define KNOT_TSIG_DEBUG + +/*! + * \brief Dumps RDATA of the given type. + * + * This function is empty if neither KNOT_ZONE_DEBUG nor KNOT_RDATA_DEBUG + * is defined. + * + * \param rdata RDATA to dump. + * \param type Type of the RDATA (needed to properly parse the RDATA). + * \param loaded_zone Set to <> 0 if the RDATA is part of a zone loaded into + * the server. Set to 0 otherwise. + */ +void knot_rdata_dump(knot_rdata_t *rdata, uint32_t type, char loaded_zone); + +/*! + * \brief Dumps RRSet. + * + * This function is empty if neither KNOT_ZONE_DEBUG nor KNOT_RRSET_DEBUG + * is defined. + * + * \param rrset RRSet to dump. + * \param loaded_zone Set to <> 0 if the RRSet is part of a zone loaded into + * the server. Set to 0 otherwise. + */ +void knot_rrset_dump(const knot_rrset_t *rrset, char loaded_zone); + +/*! + * \brief Dumps zone node. + * + * This function is empty if neither KNOT_ZONE_DEBUG nor KNOT_NODE_DEBUG + * is defined. + * + * \param node Node to dump. + * \param loaded_zone Set to <> 0 if the node is part of a zone loaded into + * the server. Set to 0 otherwise. + */ +void knot_node_dump(knot_node_t *node, void *loaded_zone); + +/*! + * \brief Dumps the whole zone. + * + * This function is empty if KNOT_ZONE_DEBUG is not defined. + * + * \param zone Zone to dump. + * \param loaded_zone Set to <> 0 if the node is part of a zone loaded into + * the server. Set to 0 otherwise. + */ +void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); + +/******************************************************************************/ + +#ifdef KNOT_NS_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_ns(msg...) fprintf(stderr, msg) +#define dbg_ns_hex(data, len) hex_print((data), (len)) +#define dbg_ns_exec(cmds) do { cmds } while (0) +#else +#define dbg_ns(msg...) +#define dbg_ns_hex(data, len) +#define dbg_ns_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_ns_verb(msg...) fprintf(stderr, msg) +#define dbg_ns_hex_verb(data, len) hex_print((data), (len)) +#define dbg_ns_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_ns_verb(msg...) +#define dbg_ns_hex_verb(data, len) +#define dbg_ns_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_ns_detail(msg...) fprintf(stderr, msg) +#define dbg_ns_hex_detail(data, len) hex_print((data), (len)) +#define dbg_ns_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_ns_detail(msg...) +#define dbg_ns_hex_detail(data, len) +#define dbg_ns_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_ns(msg...) +#define dbg_ns_hex(data, len) +#define dbg_ns_exec(cmds) +#define dbg_ns_verb(msg...) +#define dbg_ns_hex_verb(data, len) +#define dbg_ns_exec_verb(cmds) +#define dbg_ns_detail(msg...) +#define dbg_ns_hex_detail(data, len) +#define dbg_ns_exec_detail(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOT_DNAME_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_dname(msg...) fprintf(stderr, msg) +#define dbg_dname_hex(data, len) hex_print((data), (len)) +#define dbg_dname_exec(cmds) do { cmds } while (0) +#else +#define dbg_dname(msg...) +#define dbg_dname_hex(data, len) +#define dbg_dname_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_dname_verb(msg...) fprintf(stderr, msg) +#define dbg_dname_hex_verb(data, len) hex_print((data), (len)) +#define dbg_dname_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_dname_verb(msg...) +#define dbg_dname_hex_verb(data, len) +#define dbg_dname_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_dname_detail(msg...) fprintf(stderr, msg) +#define dbg_dname_hex_detail(data, len) hex_print((data), (len)) +#define dbg_dname_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_dname_detail(msg...) +#define dbg_dname_hex_detail(data, len) +#define dbg_dname_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_dname(msg...) +#define dbg_dname_hex(data, len) +#define dbg_dname_exec(cmds) +#define dbg_dname_verb(msg...) +#define dbg_dname_hex_verb(data, len) +#define dbg_dname_exec_verb(cmds) +#define dbg_dname_detail(msg...) +#define dbg_dname_hex_detail(data, len) +#define dbg_dname_exec_detail(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOT_NODE_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_node(msg...) fprintf(stderr, msg) +#define dbg_node_hex(data, len) hex_print((data), (len)) +#else +#define dbg_node(msg...) +#define dbg_node_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_node_verb(msg...) fprintf(stderr, msg) +#define dbg_node_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_node_verb(msg...) +#define dbg_node_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_node_detail(msg...) fprintf(stderr, msg) +#define dbg_node_hex_detail(data, len) hex_print((data), (len)) +#else +#define dbg_node_detail(msg...) +#define dbg_node_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_node(msg...) +#define dbg_node_hex(data, len) +#define dbg_node_verb(msg...) +#define dbg_node_hex_verb(data, len) +#define dbg_node_detail(msg...) +#define dbg_node_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOT_ZONE_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zone(msg...) fprintf(stderr, msg) +#define dbg_zone_hex(data, len) hex_print((data), (len)) +#define dbg_zone_exec(cmds) do { cmds } while (0) +#else +#define dbg_zone(msg...) +#define dbg_zone_hex(data, len) +#define dbg_zone_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zone_verb(msg...) fprintf(stderr, msg) +#define dbg_zone_hex_verb(data, len) hex_print((data), (len)) +#define dbg_zone_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_zone_verb(msg...) +#define dbg_zone_hex_verb(data, len) +#define dbg_zone_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zone_detail(msg...) fprintf(stderr, msg) +#define dbg_zone_hex_detail(data, len) hex_print((data), (len)) +#define dbg_zone_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_zone_detail(msg...) +#define dbg_zone_hex_detail(data, len) +#define dbg_zone_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_zone(msg...) +#define dbg_zone_hex(data, len) +#define dbg_zone_exec(cmds) +#define dbg_zone_verb(msg...) +#define dbg_zone_hex_verb(data, len) +#define dbg_zone_exec_verb(cmds) +#define dbg_zone_detail(msg...) +#define dbg_zone_hex_detail(data, len) +#define dbg_zone_exec_detail(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOT_ZONEDB_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zonedb(msg...) fprintf(stderr, msg) +#define dbg_zonedb_hex(data, len) hex_print((data), (len)) +#define dbg_zonedb_exec(cmds) do { cmds } while (0) +#else +#define dbg_zonedb(msg...) +#define dbg_zonedb_hex(data, len) +#define dbg_zonedb_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zonedb_verb(msg...) fprintf(stderr, msg) +#define dbg_zonedb_hex_verb(data, len) hex_print((data), (len)) +#define dbg_zonedb_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_zonedb_verb(msg...) +#define dbg_zonedb_hex_verb(data, len) +#define dbg_zonedb_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zonedb_detail(msg...) fprintf(stderr, msg) +#define dbg_zonedb_hex_detail(data, len) hex_print((data), (len)) +#define dbg_zonedb_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_zonedb_detail(msg...) +#define dbg_zonedb_hex_detail(data, len) +#define dbg_zonedb_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_zonedb(msg...) +#define dbg_zonedb_hex(data, len) +#define dbg_zonedb_exec(cmds) +#define dbg_zonedb_verb(msg...) +#define dbg_zonedb_hex_verb(data, len) +#define dbg_zonedb_exec_verb(cmds) +#define dbg_zonedb_detail(msg...) +#define dbg_zonedb_hex_detail(data, len) +#define dbg_zonedb_exec_detail(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOT_RESPONSE_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_response(msg...) fprintf(stderr, msg) +#define dbg_response_hex(data, len) hex_print((data), (len)) +#define dbg_response_exec(cmds) do { cmds } while (0) +#else +#define dbg_response(msg...) +#define dbg_response_hex(data, len) +#define dbg_response_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_response_verb(msg...) fprintf(stderr, msg) +#define dbg_response_hex_verb(data, len) hex_print((data), (len)) +#define dbg_response_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_response_verb(msg...) +#define dbg_response_hex_verb(data, len) +#define dbg_response_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_response_detail(msg...) fprintf(stderr, msg) +#define dbg_response_hex_detail(data, len) hex_print((data), (len)) +#define dbg_response_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_response_detail(msg...) +#define dbg_response_hex_detail(data, len) +#define dbg_response_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_response(msg...) +#define dbg_response_hex(data, len) +#define dbg_response_exec(cmds) +#define dbg_response_verb(msg...) +#define dbg_response_hex_verb(data, len) +#define dbg_response_exec_verb(cmds) +#define dbg_response_detail(msg...) +#define dbg_response_hex_detail(data, len) +#define dbg_response_exec_detail(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOT_PACKET_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_packet(msg...) fprintf(stderr, msg) +#define dbg_packet_hex(data, len) hex_print((data), (len)) +#define dbg_packet_exec(cmds) do { cmds } while (0) +#else +#define dbg_packet(msg...) +#define dbg_packet_hex(data, len) +#define dbg_packet_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_packet_verb(msg...) fprintf(stderr, msg) +#define dbg_packet_hex_verb(data, len) hex_print((data), (len)) +#define dbg_packet_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_packet_verb(msg...) +#define dbg_packet_hex_verb(data, len) +#define dbg_packet_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_packet_detail(msg...) fprintf(stderr, msg) +#define dbg_packet_hex_detail(data, len) hex_print((data), (len)) +#define dbg_packet_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_packet_detail(msg...) +#define dbg_packet_hex_detail(data, len) +#define dbg_packet_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_packet(msg...) +#define dbg_packet_hex(data, len) +#define dbg_packet_exec(cmds) +#define dbg_packet_verb(msg...) +#define dbg_packet_hex_verb(data, len) +#define dbg_packet_exec_verb(cmds) +#define dbg_packet_detail(msg...) +#define dbg_packet_hex_detail(data, len) +#define dbg_packet_exec_detail(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOT_EDNS_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_edns(msg...) fprintf(stderr, msg) +#define dbg_edns_hex(data, len) hex_print((data), (len)) +#else +#define dbg_edns(msg...) +#define dbg_edns_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_edns_verb(msg...) fprintf(stderr, msg) +#define dbg_edns_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_edns_verb(msg...) +#define dbg_edns_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_edns_detail(msg...) fprintf(stderr, msg) +#define dbg_edns_hex_detail(data, len) hex_print((data), (len)) +#else +#define dbg_edns_detail(msg...) +#define dbg_edns_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_edns(msg...) +#define dbg_edns_hex(data, len) +#define dbg_edns_verb(msg...) +#define dbg_edns_hex_verb(data, len) +#define dbg_edns_detail(msg...) +#define dbg_edns_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOT_NSEC3_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_nsec3(msg...) fprintf(stderr, msg) +#define dbg_nsec3_hex(data, len) hex_print((data), (len)) +#else +#define dbg_nsec3(msg...) +#define dbg_nsec3_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_nsec3_verb(msg...) fprintf(stderr, msg) +#define dbg_nsec3_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_nsec3_verb(msg...) +#define dbg_nsec3_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_nsec3_detail(msg...) fprintf(stderr, msg) +#define dbg_nsec3_hex_detail(data, len) hex_print((data), (len)) +#else +#define dbg_nsec3_detail(msg...) +#define dbg_nsec3_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_nsec3(msg...) +#define dbg_nsec3_hex(data, len) +#define dbg_nsec3_verb(msg...) +#define dbg_nsec3_hex_verb(data, len) +#define dbg_nsec3_detail(msg...) +#define dbg_nsec3_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef CUCKOO_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_ck(msg...) fprintf(stderr, msg) +#define dbg_ck_hex(data, len) hex_print((data), (len)) +#else +#define dbg_ck(msg...) +#define dbg_ck_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_ck_verb(msg...) fprintf(stderr, msg) +#define dbg_ck_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_ck_verb(msg...) +#define dbg_ck_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_ck_detail(msg...) fprintf(stderr, msg) +#define dbg_ck_hex_detail(data, len) hex_print((data), (len)) +#else +#define dbg_ck_detail(msg...) +#define dbg_ck_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_ck(msg...) +#define dbg_ck_hex(data, len) +#define dbg_ck_verb(msg...) +#define dbg_ck_hex_verb(data, len) +#define dbg_ck_detail(msg...) +#define dbg_ck_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef CUCKOO_DEBUG_HASH + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_ck_hash(msg...) fprintf(stderr, msg) +#define dbg_ck_rehash(msg...) fprintf(stderr, msg) +#define dbg_ck_hash_hex(data, len) hex_print((data), (len)) +#else +#define dbg_ck_hash(msg...) +#define dbg_ck_rehash(msg...) +#define dbg_ck_hash_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_ck_hash_verb(msg...) fprintf(stderr, msg) +#define dbg_ck_hash_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_ck_hash_verb(msg...) +#define dbg_ck_hash_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_ck_hash_detail(msg...) fprintf(stderr, msg) +#define dbg_ck_hash_hex_detail(data, len) hex_print((data), (len)) +#else +#define dbg_ck_hash_detail(msg...) +#define dbg_ck_hash_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_ck_hash(msg...) +#define dbg_ck_rehash(msg...) +#define dbg_ck_hash_hex(data, len) +#define dbg_ck_hash_verb(msg...) +#define dbg_ck_hash_hex_verb(data, len) +#define dbg_ck_hash_detail(msg...) +#define dbg_ck_hash_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#ifdef KNOT_XFRIN_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_xfrin(msg...) fprintf(stderr, msg) +#define dbg_xfrin_hex(data, len) hex_print((data), (len)) +#define dbg_xfrin_exec(cmds) do { cmds } while (0) +#else +#define dbg_xfrin(msg...) +#define dbg_xfrin_hex(data, len) +#define dbg_xfrin_exec(cmds) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_xfrin_verb(msg...) fprintf(stderr, msg) +#define dbg_xfrin_hex_verb(data, len) hex_print((data), (len)) +#define dbg_xfrin_exec_verb(cmds) do { cmds } while (0) +#else +#define dbg_xfrin_verb(msg...) +#define dbg_xfrin_hex_verb(data, len) +#define dbg_xfrin_exec_verb(cmds) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_xfrin_detail(msg...) fprintf(stderr, msg) +#define dbg_xfrin_hex_detail(data, len) hex_print((data), (len)) +#define dbg_xfrin_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_xfrin_detail(msg...) +#define dbg_xfrin_hex_detail(data, len) +#define dbg_xfrin_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_xfrin(msg...) +#define dbg_xfrin_hex(data, len) +#define dbg_xfrin_exec(cmds) +#define dbg_xfrin_verb(msg...) +#define dbg_xfrin_hex_verb(data, len) +#define dbg_xfrin_exec_verb(cmds) +#define dbg_xfrin_detail(msg...) +#define dbg_xfrin_hex_detail(data, len) +#define dbg_xfrin_exec_detail(cmds) +#endif + +/******************************************************************************/ + +#ifdef KNOT_DDNS_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_ddns(msg...) fprintf(stderr, msg) +#define dbg_ddns_hex(data, len) hex_print((data), (len)) +#else +#define dbg_ddns(msg...) +#define dbg_ddns_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_ddns_verb(msg...) fprintf(stderr, msg) +#define dbg_ddns_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_ddns_verb(msg...) +#define dbg_ddns_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_ddns_detail(msg...) fprintf(stderr, msg) +#define dbg_ddns_hex_detail(data, len) hex_print((data), (len)) +#else +#define dbg_ddns_detail(msg...) +#define dbg_ddns_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_ddns(msg...) +#define dbg_ddns_hex(data, len) +#define dbg_ddns_verb(msg...) +#define dbg_ddns_hex_verb(data, len) +#define dbg_ddns_detail(msg...) +#define dbg_ddns_hex_detail(data, len) +#endif + +#ifdef KNOT_TSIG_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_tsig(msg...) fprintf(stderr, msg) +#define dbg_tsig_hex(data, len) hex_print((const char*)(data), (len)) +#else +#define dbg_tsig(msg...) +#define dbg_tsig_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_tsig_verb(msg...) fprintf(stderr, msg) +#define dbg_tsig_hex_verb(data, len) hex_print((const char*)(data), (len)) +#else +#define dbg_tsig_verb(msg...) +#define dbg_tsig_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_tsig_detail(msg...) fprintf(stderr, msg) +#define dbg_tsig_hex_detail(data, len) hex_print((const char*)(data), (len)) +#else +#define dbg_tsig_detail(msg...) +#define dbg_tsig_hex_detail(data, len) +#endif + +/* No messages. */ +#else +#define dbg_tsig(msg...) +#define dbg_tsig_hex(data, len) +#define dbg_tsig_verb(msg...) +#define dbg_tsig_hex_verb(data, len) +#define dbg_tsig_detail(msg...) +#define dbg_tsig_hex_detail(data, len) +#endif + +/******************************************************************************/ + +#endif /* _KNOT_DEBUG_H_ */ + +/*! @} */ diff --git a/src/libknot/util/descriptor.c b/src/libknot/util/descriptor.c new file mode 100644 index 0000000..fa94c24 --- /dev/null +++ b/src/libknot/util/descriptor.c @@ -0,0 +1,501 @@ +/*! + * \file descriptor.c + * + * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>, + * most of the work by NLnet labs. + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \note Most of the constants and functions were taken from NSD's dns.c. + * + * \addtogroup libknot + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <assert.h> +#include <string.h> +#include <sys/types.h> + +#include "libknot.h" + +enum desclen { KNOT_RRTYPE_DESCRIPTORS_LENGTH = 32770 }; // used to be 101 + +/*! + * \brief Table for linking RR class constants to their textual representation. + */ +static knot_lookup_table_t dns_rrclasses[] = { + { KNOT_CLASS_IN, "IN" }, /* the Internet */ + { KNOT_CLASS_CS, "CS" }, /* the CSNET class (Obsolete) */ + { KNOT_CLASS_CH, "CH" }, /* the CHAOS class */ + { KNOT_CLASS_HS, "HS" }, /* Hesiod */ + { 0, NULL } +}; + +/*! \brief RR type descriptors. */ +static knot_rrtype_descriptor_t + knot_rrtype_descriptors[KNOT_RRTYPE_DESCRIPTORS_LENGTH] = { + /* 0 */ + { 0, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 1 */ + { KNOT_RRTYPE_A, "A", 1, { KNOT_RDATA_WF_A }, { KNOT_RDATA_ZF_A }, true }, + /* 2 */ + { KNOT_RRTYPE_NS, "NS", 1, + { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true }, + /* 3 */ + { KNOT_RRTYPE_MD, "MD", 1, + { KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true }, + /* 4 */ + { KNOT_RRTYPE_MF, "MF", 1, + { KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true }, + /* 5 */ + { KNOT_RRTYPE_CNAME, "CNAME", 1, + { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true }, + /* 6 */ + { KNOT_RRTYPE_SOA, "SOA", 7, + { KNOT_RDATA_WF_COMPRESSED_DNAME, KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG, + KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG }, + { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_PERIOD, KNOT_RDATA_ZF_PERIOD, + KNOT_RDATA_ZF_PERIOD, KNOT_RDATA_ZF_PERIOD, KNOT_RDATA_ZF_PERIOD }, + true }, + /* 7 */ + { KNOT_RRTYPE_MB, "MB", 1, + { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true }, + /* 8 */ + { KNOT_RRTYPE_MG, "MG", 1, + { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true }, + /* 9 */ + { KNOT_RRTYPE_MR, "MR", 1, + { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true }, + /* 10 */ + { KNOT_RRTYPE_NULL, NULL, 1, + { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 11 */ + { KNOT_RRTYPE_WKS, "WKS", 2, + { KNOT_RDATA_WF_A, KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_A, KNOT_RDATA_ZF_SERVICES }, true }, + /* 12 */ + { KNOT_RRTYPE_PTR, "PTR", 1, + { KNOT_RDATA_WF_COMPRESSED_DNAME }, + { KNOT_RDATA_ZF_DNAME }, true }, + /* 13 */ + { KNOT_RRTYPE_HINFO, "HINFO", 2, + { KNOT_RDATA_WF_TEXT_SINGLE, KNOT_RDATA_WF_TEXT_SINGLE }, + { KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_TEXT }, true }, + /* 14 */ + { KNOT_RRTYPE_MINFO, "MINFO", 2, + { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_COMPRESSED_DNAME }, + { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME }, true }, + /* 15 */ + { KNOT_RRTYPE_MX, "MX", 2, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_COMPRESSED_DNAME }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true }, + /* 16 */ /* This is obscure, but I guess there's no other way */ + { KNOT_RRTYPE_TXT, "TXT", 1, + { KNOT_RDATA_WF_TEXT }, + { KNOT_RDATA_ZF_TEXT }, + false }, + /* 17 */ + { KNOT_RRTYPE_RP, "RP", 2, + { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_COMPRESSED_DNAME }, + { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME }, true }, + /* 18 */ + { KNOT_RRTYPE_AFSDB, "AFSDB", 2, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_COMPRESSED_DNAME }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true }, + /* 19 */ + { KNOT_RRTYPE_X25, "X25", 1, + { KNOT_RDATA_WF_TEXT_SINGLE }, + { KNOT_RDATA_ZF_TEXT }, true }, + /* 20 */ + { KNOT_RRTYPE_ISDN, "ISDN", 2, + { KNOT_RDATA_WF_TEXT_SINGLE, KNOT_RDATA_WF_TEXT_SINGLE }, + { KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_TEXT }, false }, + /* 21 */ + { KNOT_RRTYPE_RT, "RT", 2, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_COMPRESSED_DNAME }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true }, + /* 22 */ + { KNOT_RRTYPE_NSAP, "NSAP", 1, + { KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_NSAP }, true }, + /* 23 */ + { 23, NULL, 1, { KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 24 */ + { KNOT_RRTYPE_SIG, "SIG", 9, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG, + KNOT_RDATA_WF_SHORT,KNOT_RDATA_WF_UNCOMPRESSED_DNAME, + KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_RRTYPE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_PERIOD, + KNOT_RDATA_ZF_TIME, KNOT_RDATA_ZF_TIME, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME, + KNOT_RDATA_ZF_BASE64 }, + true }, + /* 25 */ + { KNOT_RRTYPE_KEY, "KEY", 4, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_ALGORITHM, + KNOT_RDATA_ZF_BASE64 }, true }, + /* 26 */ + { KNOT_RRTYPE_PX, "PX", 3, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_UNCOMPRESSED_DNAME, + KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME }, true }, + /* 27 */ + { 27, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 28 */ + { KNOT_RRTYPE_AAAA, "AAAA", 1, + { KNOT_RDATA_WF_AAAA }, + { KNOT_RDATA_ZF_AAAA }, true }, + /* 29 */ + { KNOT_RRTYPE_LOC, "LOC", 1, + { KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_LOC }, true }, + /* 30 */ + { KNOT_RRTYPE_NXT, "NXT", 2, + { KNOT_RDATA_WF_UNCOMPRESSED_DNAME, + KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_NXT }, true }, + /* 31 */ + { 31, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 32 */ + { 32, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 33 */ + { KNOT_RRTYPE_SRV, "SRV", 4, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT, + KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, + true }, + /* 34 */ + { 34, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 35 */ + { KNOT_RRTYPE_NAPTR, "NAPTR", 6, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_TEXT_SINGLE, + KNOT_RDATA_WF_TEXT_SINGLE, KNOT_RDATA_WF_TEXT_SINGLE, + KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_TEXT, + KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_DNAME }, true }, + /* 36 */ + { KNOT_RRTYPE_KX, "KX", 2, + { KNOT_RDATA_WF_SHORT, + KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true }, + /* 37 */ + { KNOT_RRTYPE_CERT, "CERT", 4, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT, + KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_CERTIFICATE_TYPE, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_ALGORITHM, + KNOT_RDATA_ZF_BASE64 }, true }, + /* 38 */ + { KNOT_RRTYPE_A6, NULL, 1, { KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 39 */ + { KNOT_RRTYPE_DNAME, "DNAME", 1, + { KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, + { KNOT_RDATA_ZF_DNAME }, true }, + /* 40 */ + { 40, NULL, 1, { KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 41 */ + /* OPT has its parser token, but should never be in zone file... */ + { KNOT_RRTYPE_OPT, "OPT", 1, + { KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_UNKNOWN }, true }, + /* 42 */ + { KNOT_RRTYPE_APL, "APL", 1, + { KNOT_RDATA_WF_APL }, + { KNOT_RDATA_ZF_APL }, false }, + /* 43 */ + { KNOT_RRTYPE_DS, "DS", 4, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_ALGORITHM, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_HEX }, true }, + /* 44 */ + { KNOT_RRTYPE_SSHFP, "SSHFP", 3, + { KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_HEX }, + true }, + /* 45 */ + { KNOT_RRTYPE_IPSECKEY, "IPSECKEY", 5, + { KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_IPSECGATEWAY, + KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_IPSECGATEWAY, + KNOT_RDATA_ZF_BASE64 }, false }, + /* 46 */ + { KNOT_RRTYPE_RRSIG, "RRSIG", 9, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_LONG, + KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG, + KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_LITERAL_DNAME, + KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_RRTYPE, KNOT_RDATA_ZF_ALGORITHM, + KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_PERIOD, + KNOT_RDATA_ZF_TIME, KNOT_RDATA_ZF_TIME, + KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_LITERAL_DNAME, + KNOT_RDATA_ZF_BASE64 }, true }, + /* 47 */ + { KNOT_RRTYPE_NSEC, "NSEC", 2, + { KNOT_RDATA_WF_LITERAL_DNAME, KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_LITERAL_DNAME, KNOT_RDATA_ZF_NSEC }, + true }, + /* 48 */ + { KNOT_RRTYPE_DNSKEY, "DNSKEY", 4, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_BYTE, + KNOT_RDATA_ZF_ALGORITHM, KNOT_RDATA_ZF_BASE64 }, true }, + /* 49 */ + { KNOT_RRTYPE_DHCID, "DHCID", 1, { KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_BASE64 }, true }, + /* 50 */ + { KNOT_RRTYPE_NSEC3, "NSEC3", 6, + { KNOT_RDATA_WF_BYTE, /* hash type */ + KNOT_RDATA_WF_BYTE, /* flags */ + KNOT_RDATA_WF_SHORT, /* iterations */ + KNOT_RDATA_WF_BINARYWITHLENGTH, /* salt */ + KNOT_RDATA_WF_BINARYWITHLENGTH, /* next hashed name */ + KNOT_RDATA_WF_BINARY /* type bitmap */ }, + { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_HEX_LEN, + KNOT_RDATA_ZF_BASE32, KNOT_RDATA_ZF_NSEC }, + true }, + /* 51 */ + { KNOT_RRTYPE_NSEC3PARAM, "NSEC3PARAM", 4, + { KNOT_RDATA_WF_BYTE, /* hash type */ + KNOT_RDATA_WF_BYTE, /* flags */ + KNOT_RDATA_WF_SHORT, /* iterations */ + KNOT_RDATA_WF_BINARYWITHLENGTH /* salt */ }, + { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, + KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_HEX_LEN }, true }, + /* 52 */ + + + /* In NSD they have indices between 52 and 99 filled with + unknown types. TODO add here if it's really needed? */ + /* it is indeed needed, in rrtype_from_string */ + + /* There's a GNU extension that works like this: [first ... last] = value */ + + /* 99 */ + [99] = { KNOT_RRTYPE_SPF, "SPF", 1, + { KNOT_RDATA_WF_TEXT }, + { KNOT_RDATA_ZF_TEXT }, false }, + /* TSIG pseudo RR. */ + [250] = { KNOT_RRTYPE_TSIG, "TSIG", 7, + { KNOT_RDATA_WF_UNCOMPRESSED_DNAME, KNOT_RDATA_WF_UINT48, + KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BINARYWITHSHORT, + KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT, + KNOT_RDATA_WF_BINARYWITHSHORT }, + /* Zoneformat not needed. */ + {0, 0, 0, 0, 0}, true }, + /* 32769 */ + [32769] = { KNOT_RRTYPE_DLV, "DLV", 4, + { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_ALGORITHM, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_HEX }, + true }, +}; + +knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_type(uint16_t type) +{ + if (type < KNOT_RRTYPE_LAST + 1) { + return &knot_rrtype_descriptors[type]; + } else if (type == KNOT_RRTYPE_DLV) { + return &knot_rrtype_descriptors[KNOT_RRTYPE_DLV]; + } + return &knot_rrtype_descriptors[0]; +} + +/* I see a lot of potential here to speed up zone parsing - this is O(n) * + * could be better */ +knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_name(const char *name) +{ + int i; + + for (i = 0; i < KNOT_RRTYPE_DLV + 1; ++i) { + if (knot_rrtype_descriptors[i].name && + strcasecmp(knot_rrtype_descriptors[i].name, name) == 0) { + return &knot_rrtype_descriptors[i]; + } + } + + if (knot_rrtype_descriptors[KNOT_RRTYPE_DLV].name && + strcasecmp(knot_rrtype_descriptors[KNOT_RRTYPE_DLV].name, + name) == 0) { + return &knot_rrtype_descriptors[KNOT_RRTYPE_DLV]; + } + + return NULL; +} + +const char *knot_rrtype_to_string(uint16_t rrtype) +{ + static char buf[20]; + knot_rrtype_descriptor_t *descriptor = + knot_rrtype_descriptor_by_type(rrtype); + if (descriptor->name) { + return descriptor->name; + } else { + snprintf(buf, sizeof(buf), "TYPE%d", (int) rrtype); + return buf; + } +} + +uint16_t knot_rrtype_from_string(const char *name) +{ + char *end; + long rrtype; + knot_rrtype_descriptor_t *entry; + + entry = knot_rrtype_descriptor_by_name(name); + if (entry) { + return entry->type; + } + + if (strlen(name) < 5) { + return 0; + } + + if (strncasecmp(name, "TYPE", 4) != 0) { + return 0; + } + + if (!isdigit((int)name[4])) { + return 0; + } + + /* The rest from the string must be a number. */ + rrtype = strtol(name + 4, &end, 10); + if (*end != '\0') { + return 0; + } + if (rrtype < 0 || rrtype > 65535L) { + return 0; + } + + return (uint16_t) rrtype; +} + +const char *knot_rrclass_to_string(uint16_t rrclass) +{ + static char buf[20]; + knot_lookup_table_t *entry = knot_lookup_by_id(dns_rrclasses, + rrclass); + if (entry) { + assert(strlen(entry->name) < sizeof(buf)); + knot_strlcpy(buf, entry->name, sizeof(buf)); + } else { + snprintf(buf, sizeof(buf), "CLASS%d", (int) rrclass); + } + return buf; +} + +uint16_t knot_rrclass_from_string(const char *name) +{ + char *end; + long rrclass; + knot_lookup_table_t *entry; + + entry = knot_lookup_by_name(dns_rrclasses, name); + if (entry) { + return (uint16_t) entry->id; + } + + if (strlen(name) < 6) { + return 0; + } + + if (strncasecmp(name, "CLASS", 5) != 0) { + return 0; + } + + if (!isdigit((int)name[5])) { + return 0; + } + + // The rest from the string must be a number. + rrclass = strtol(name + 5, &end, 10); + if (*end != '\0') { + return 0; + } + if (rrclass < 0 || rrclass > 65535L) { + return 0; + } + + return (uint16_t) rrclass; +} + +size_t knot_wireformat_size(unsigned int wire_type) +{ + switch(wire_type) { + case KNOT_RDATA_WF_BYTE: + return 1; + break; + case KNOT_RDATA_WF_SHORT: + return 2; + break; + case KNOT_RDATA_WF_LONG: + return 4; + break; + case KNOT_RDATA_WF_A: + return 4; + break; + default: /* unknown size */ + return 0; + break; + } /* switch */ +} + +int knot_rrtype_is_metatype(uint16_t type) +{ + /*! \todo Check if there are some other metatypes. */ + return (type == KNOT_RRTYPE_ANY + || type == KNOT_RRTYPE_AXFR + || type == KNOT_RRTYPE_IXFR + || type == KNOT_RRTYPE_MAILA + || type == KNOT_RRTYPE_MAILB + || type == KNOT_RRTYPE_OPT); +} + diff --git a/src/libknot/util/descriptor.h b/src/libknot/util/descriptor.h new file mode 100644 index 0000000..10d3d20 --- /dev/null +++ b/src/libknot/util/descriptor.h @@ -0,0 +1,332 @@ +/*! + * \file descriptor.h + * + * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>, + * most of the work by NLnet Labs. + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \note Most of the constants and functions were taken from NSD's dns.h. + * + * \addtogroup libknot + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _KNOT_DESCRIPTOR_H_ +#define _KNOT_DESCRIPTOR_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +enum knot_mxrdtln { + /*! \brief Maximum items in RDATA wireformat. */ + KNOT_MAX_RDATA_ITEMS = 64, + /*! \brief Maximum size of one item in RDATA wireformat. */ + KNOT_MAX_RDATA_ITEM_SIZE = 65534, + /*! \brief Maximum wire size of one RDATA. */ + KNOT_MAX_RDATA_WIRE_SIZE = + KNOT_MAX_RDATA_ITEMS * KNOT_MAX_RDATA_ITEM_SIZE +}; + +typedef enum knot_mxrdtln knot_mxrdtln_t; +//#define MAXRDATALEN 64 + +/* 64 is in NSD. Seems a little too much, but I'd say it's not a real issue. */ + +/*! + * \brief Resource record class codes. + */ +enum knot_rr_class { + KNOT_CLASS_IN = 1, + KNOT_CLASS_CS, + KNOT_CLASS_CH, + KNOT_CLASS_HS, + KNOT_CLASS_NONE = 254, + KNOT_CLASS_ANY = 255 +}; + +typedef enum knot_rr_class knot_rr_class_t; + +/*! + * \brief Resource record type constants. + * \todo Not all indices can be used for indexing. + */ +enum knot_rr_type { + KNOT_RRTYPE_UNKNOWN, /*!< 0 - an unknown type */ + KNOT_RRTYPE_A, /*!< 1 - a host address */ + KNOT_RRTYPE_NS, /*!< 2 - an authoritative name server */ + KNOT_RRTYPE_MD, /*!< 3 - a mail destination (Obsolete - use MX) */ + KNOT_RRTYPE_MF, /*!< 4 - a mail forwarder (Obsolete - use MX) */ + KNOT_RRTYPE_CNAME, /*!< 5 - the canonical name for an alias */ + KNOT_RRTYPE_SOA, /*!< 6 - marks the start of a zone of authority */ + KNOT_RRTYPE_MB, /*!< 7 - a mailbox domain name (EXPERIMENTAL) */ + KNOT_RRTYPE_MG, /*!< 8 - a mail group member (EXPERIMENTAL) */ + KNOT_RRTYPE_MR, /*!< 9 - a mail rename domain name (EXPERIMENTAL) */ + KNOT_RRTYPE_NULL, /*!< 10 - a null RR (EXPERIMENTAL) */ + KNOT_RRTYPE_WKS, /*!< 11 - a well known service description */ + KNOT_RRTYPE_PTR, /*!< 12 - a domain name pointer */ + KNOT_RRTYPE_HINFO, /*!< 13 - host information */ + KNOT_RRTYPE_MINFO, /*!< 14 - mailbox or mail list information */ + KNOT_RRTYPE_MX, /*!< 15 - mail exchange */ + KNOT_RRTYPE_TXT, /*!< 16 - text strings */ + KNOT_RRTYPE_RP, /*!< 17 - RFC1183 */ + KNOT_RRTYPE_AFSDB, /*!< 18 - RFC1183 */ + KNOT_RRTYPE_X25, /*!< 19 - RFC1183 */ + KNOT_RRTYPE_ISDN, /*!< 20 - RFC1183 */ + KNOT_RRTYPE_RT, /*!< 21 - RFC1183 */ + KNOT_RRTYPE_NSAP, /*!< 22 - RFC1706 */ + + KNOT_RRTYPE_SIG = 24, /*!< 24 - 2535typecode */ + KNOT_RRTYPE_KEY, /*!< 25 - 2535typecode */ + KNOT_RRTYPE_PX, /*!< 26 - RFC2163 */ + + KNOT_RRTYPE_AAAA = 28, /*!< 28 - ipv6 address */ + KNOT_RRTYPE_LOC, /*!< 29 - LOC record RFC1876 */ + KNOT_RRTYPE_NXT, /*!< 30 - 2535typecode */ + + KNOT_RRTYPE_SRV = 33, /*!< 33 - SRV record RFC2782 */ + + KNOT_RRTYPE_NAPTR = 35, /*!< 35 - RFC2915 */ + KNOT_RRTYPE_KX, /*!< 36 - RFC2230 Key Exchange Delegation Record */ + KNOT_RRTYPE_CERT, /*!< 37 - RFC2538 */ + KNOT_RRTYPE_A6, /*!< 38 - RFC2874 */ + KNOT_RRTYPE_DNAME, /*!< 39 - RFC2672 */ + + KNOT_RRTYPE_OPT = 41, /*!< 41 - Pseudo OPT record... */ + KNOT_RRTYPE_APL, /*!< 42 - RFC3123 */ + KNOT_RRTYPE_DS, /*!< 43 - RFC 4033, 4034, and 4035 */ + KNOT_RRTYPE_SSHFP, /*!< 44 - SSH Key Fingerprint */ + KNOT_RRTYPE_IPSECKEY, /*!< 45 - public key for ipsec use. RFC 4025 */ + KNOT_RRTYPE_RRSIG, /*!< 46 - RFC 4033, 4034, and 4035 */ + KNOT_RRTYPE_NSEC, /*!< 47 - RFC 4033, 4034, and 4035 */ + KNOT_RRTYPE_DNSKEY, /*!< 48 - RFC 4033, 4034, and 4035 */ + KNOT_RRTYPE_DHCID, /*!< 49 - RFC4701 DHCP information */ + /*! + * \brief 50 - NSEC3, secure denial, prevents zonewalking + */ + KNOT_RRTYPE_NSEC3, + /*! + * \brief 51 - NSEC3PARAM at zone apex nsec3 parameters + */ + KNOT_RRTYPE_NSEC3PARAM, + + /* TODO consider some better way of doing this, indices too high */ + + KNOT_RRTYPE_SPF = 99, /*!< RFC 4408 */ + + // not designating any RRs + KNOT_RRTYPE_TSIG = 250, /*!< TSIG - RFC2845. */ + KNOT_RRTYPE_IXFR = 251, /*!< IXFR (not an actual RR). */ + KNOT_RRTYPE_AXFR = 252, /*!< AXFR (not an actual RR). */ + /*! + * \brief A request for mailbox-related records (MB, MG or MR) + */ + KNOT_RRTYPE_MAILB = 253, + /*! + * \brief A request for mail agent RRs (Obsolete - see MX) + */ + KNOT_RRTYPE_MAILA = 254, + KNOT_RRTYPE_ANY = 255, /*!< any type (wildcard) */ + + // totally weird numbers (cannot use for indexing) + KNOT_RRTYPE_TA = 32768, /*!< DNSSEC Trust Authorities */ + KNOT_RRTYPE_DLV = 32769, /*!< RFC 4431 */ + + /*! \brief Last normal RR type. */ + KNOT_RRTYPE_LAST = KNOT_RRTYPE_TSIG + /*! \todo [TSIG] Is it allright to include all <= RR TSIG? + * Because TSIG is normal RR type. */ +}; + +typedef enum knot_rr_type knot_rr_type_t; + +/*! \brief Constants characterising the wire format of RDATA items. */ +enum knot_rdata_wireformat { + /*! + * \brief Possibly compressed domain name. + */ + KNOT_RDATA_WF_COMPRESSED_DNAME = 50, + KNOT_RDATA_WF_UNCOMPRESSED_DNAME = 51, /*!< Uncompressed domain name. */ + KNOT_RDATA_WF_LITERAL_DNAME = 52, /*!< Literal (not downcased) dname. */ + KNOT_RDATA_WF_BYTE = 1, /*!< 8-bit integer. */ + KNOT_RDATA_WF_SHORT = 2, /*!< 16-bit integer. */ + KNOT_RDATA_WF_LONG = 4, /*!< 32-bit integer. */ + KNOT_RDATA_WF_UINT48 = 8, /*!< 48-bit integer. */ + KNOT_RDATA_WF_TEXT = 53, /*!< Text string. */ + KNOT_RDATA_WF_A = 58, /*!< 32-bit IPv4 address. */ + KNOT_RDATA_WF_AAAA = 16, /*!< 128-bit IPv6 address. */ + KNOT_RDATA_WF_BINARY = 54, /*!< Binary data (unknown length). */ + /*! + * \brief Binary data preceded by 1 byte length + */ + KNOT_RDATA_WF_BINARYWITHLENGTH = 55, + KNOT_RDATA_WF_APL = 56, /*!< APL data. */ + KNOT_RDATA_WF_IPSECGATEWAY = 57, /*!< IPSECKEY gateway ip4, ip6 or dname. */ + KNOT_RDATA_WF_BINARYWITHSHORT = 59, + KNOT_RDATA_WF_TEXT_SINGLE = 60 /*!< Text string. */ +}; + +/*! \brief Constants characterising the format of RDATA items in zone file. */ +enum knot_rdata_zoneformat +{ + KNOT_RDATA_ZF_DNAME, /* Domain name. */ + KNOT_RDATA_ZF_LITERAL_DNAME, /* DNS name (not lowercased domain name). */ + KNOT_RDATA_ZF_TEXT, /* Text string. */ + KNOT_RDATA_ZF_BYTE, /* 8-bit integer. */ + KNOT_RDATA_ZF_SHORT, /* 16-bit integer. */ + KNOT_RDATA_ZF_LONG, /* 32-bit integer. */ + KNOT_RDATA_ZF_A, /* 32-bit IPv4 address. */ + KNOT_RDATA_ZF_AAAA, /* 128-bit IPv6 address. */ + KNOT_RDATA_ZF_RRTYPE, /* RR type. */ + KNOT_RDATA_ZF_ALGORITHM, /* Cryptographic algorithm. */ + KNOT_RDATA_ZF_CERTIFICATE_TYPE, + KNOT_RDATA_ZF_PERIOD, /* Time period. */ + KNOT_RDATA_ZF_TIME, + KNOT_RDATA_ZF_BASE64, /* Base-64 binary data. */ + KNOT_RDATA_ZF_BASE32, /* Base-32 binary data. */ + KNOT_RDATA_ZF_HEX, /* Hexadecimal binary data. */ + KNOT_RDATA_ZF_HEX_LEN, /* Hexadecimal binary data. Skip initial length byte. */ + KNOT_RDATA_ZF_NSAP, /* NSAP. */ + KNOT_RDATA_ZF_APL, /* APL. */ + KNOT_RDATA_ZF_IPSECGATEWAY, /* IPSECKEY gateway ip4, ip6 or dname. */ + KNOT_RDATA_ZF_SERVICES, /* Protocol and port number bitmap. */ + KNOT_RDATA_ZF_NXT, /* NXT type bitmap. */ + KNOT_RDATA_ZF_NSEC, /* NSEC type bitmap. */ + KNOT_RDATA_ZF_LOC, /* Location data. */ + KNOT_RDATA_ZF_UNKNOWN /* Unknown data. */ +}; + +/*! \brief Constants characterising the wire format of RDATA items. */ +typedef enum knot_rdata_zoneformat knot_rdata_zoneformat_t; + +/*! \brief Enum containing wireformat codes. */ +typedef enum knot_rdatawireformat knot_rdata_wireformat_t; + +/*! \brief Structure holding RR descriptor. */ +struct knot_rrtype_descriptor { + uint16_t type; /*!< RR type */ + const char *name; /*!< Textual name. */ + uint8_t length; /*!< Maximum number of RDATA items. */ + + /*! \brief Wire format specification for the RDATA. */ + uint8_t wireformat[KNOT_MAX_RDATA_ITEMS]; + + /*! \brief Zone file format specification for the RDATA. */ + uint8_t zoneformat[KNOT_MAX_RDATA_ITEMS]; + + bool fixed_items; /*!< Has fixed number of RDATA items? */ +}; + +/*! \brief Structure holding RR descriptor. */ +typedef struct knot_rrtype_descriptor knot_rrtype_descriptor_t; + +/*! + * \brief Gets RR descriptor for given RR type. + * + * \param type Code of RR type whose descriptor should be returned. + * + * \return RR descriptor for given type code, NULL descriptor if + * unknown type. + * + * \todo Change return value to const. + */ +knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_type(uint16_t type); + +/*! + * \brief Gets RR descriptor for given RR name. + * + * \param name Mnemonic of RR type whose descriptor should be returned. + * + * \return RR descriptor for given name, NULL descriptor if + * unknown type. + * + * \todo Change return value to const. + */ +knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_name(const char *name); + +/*! + * \brief Converts numeric type representation to mnemonic string. + * + * \param rrtype Type RR type code to be converted. + * + * \return Mnemonic string if found, str(TYPE[rrtype]) otherwise. + */ +const char *knot_rrtype_to_string(uint16_t rrtype); + +/*! + * \brief Converts mnemonic string representation of a type to numeric one. + * + * \param name Mnemonic string to be converted. + * + * \return Correct code if found, 0 otherwise. + */ +uint16_t knot_rrtype_from_string(const char *name); + +/*! + * \brief Converts numeric class representation to string one. + * + * \param rrclass Class code to be converted. + * + * \return String represenation of class if found, + * str(CLASS[rrclass]) otherwise. + */ +const char *knot_rrclass_to_string(uint16_t rrclass); + +/*! + * \brief Converts string representation of a class to numeric one. + * + * \param name Class string to be converted. + * + * \return Correct code if found, 0 otherwise. + */ +uint16_t knot_rrclass_from_string(const char *name); + +/*! + * \brief Returns size of wireformat type in bytes. + * + * \param wire_type Wireformat type. + * + * \retval Size of given type on success. + * \retval 0 on unknown type or type that has no length. + */ +size_t knot_wireformat_size(unsigned int wire_type); + +int knot_rrtype_is_metatype(uint16_t type); + +#endif /* _KNOT_DESCRIPTOR_H_ */ + +/*! @} */ + diff --git a/src/libknot/util/error.h b/src/libknot/util/error.h new file mode 100644 index 0000000..da45151 --- /dev/null +++ b/src/libknot/util/error.h @@ -0,0 +1,87 @@ +/*! + * \file error.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Error codes and function for getting error message. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_ERROR_H_ +#define _KNOT_ERROR_H_ + +#include "common/errors.h" + +/*! \brief Error codes used in the library. */ +enum knot_error { + KNOT_EOK = 0, /*!< OK */ + + /* TSIG errors. */ + KNOT_TSIG_EBADSIG = -16, /*!< Failed to verify TSIG MAC. */ + KNOT_TSIG_EBADKEY = -17, /*!< TSIG key not recognized or invalid. */ + KNOT_TSIG_EBADTIME = -18,/*!< TSIG signing time out of range. */ + + /* General errors. */ + KNOT_ERROR = -10000, /*!< General error. */ + KNOT_ENOMEM, /*!< Not enough memory. */ + KNOT_ENOTSUP, /*!< Operation not supported. */ + KNOT_EAGAIN, /*!< OS lacked necessary resources. */ + KNOT_ERANGE, /*!< Value is out of range. */ + KNOT_EBADARG, /*!< Wrong argument supported. */ + KNOT_EFEWDATA, /*!< Not enough data to parse. */ + KNOT_ESPACE, /*!< Not enough space provided. */ + KNOT_EMALF, /*!< Malformed data. */ + KNOT_ECRYPTO, /*!< Error in crypto library. */ + KNOT_ENSEC3PAR, /*!< Missing or wrong NSEC3PARAM record. */ + KNOT_EBADZONE, /*!< Domain name does not belong to the zone. */ + KNOT_EHASH, /*!< Error in hash table. */ + KNOT_EZONEIN, /*!< Error inserting zone. */ + KNOT_ENOZONE, /*!< No such zone found. */ + KNOT_ENONODE, /*!< No such node in zone found. */ + KNOT_ENORRSET, /*!< No such RRSet found. */ + KNOT_EDNAMEPTR, /*!< Domain name pointer larger than allowed. */ + KNOT_EPAYLOAD, /*!< Payload in OPT RR larger than max wire size. */ + KNOT_ECRC, /*!< Wrong dump CRC. */ + KNOT_EPREREQ, /*!< UPDATE prerequisity not met. */ + KNOT_ENOXFR, /*!< Transfer was not sent. */ + KNOT_ENOIXFR, /*!< Transfer is not IXFR (is in AXFR format). */ + KNOT_EXFRREFUSED, /*!< Zone transfer refused by the server. */ + KNOT_ECONN, /*!< Connection reset. */ + KNOT_ERROR_COUNT = 30 +}; + +/*! \brief Table linking error messages to error codes. */ +extern const error_table_t knot_error_msgs[KNOT_ERROR_COUNT]; + +/*! + * \brief Returns error message for the given error code. + * + * \param code Error code. + * + * \return String containing the error message. + */ +static inline const char *knot_strerror(int code) +{ + return error_to_str((const error_table_t*)knot_error_msgs, code); +} + +#endif /* _KNOT_ERROR_H_ */ + +/*! @} */ diff --git a/src/libknot/util/libknot_error.c b/src/libknot/util/libknot_error.c new file mode 100644 index 0000000..bc2bed2 --- /dev/null +++ b/src/libknot/util/libknot_error.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "util/error.h" +#include "util/utils.h" + +#include "common/errors.h" + +const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { + {KNOT_EOK, "OK"}, + {KNOT_ERROR, "General error."}, + {KNOT_ENOMEM, "Not enough memory."}, + {KNOT_ENOTSUP, "Operation not supported."}, + {KNOT_EAGAIN, "OS lacked necessary resources."}, + {KNOT_ERANGE, "Value is out of range."}, + {KNOT_EBADARG, "Wrong argument supported."}, + {KNOT_EFEWDATA, "Not enough data to parse."}, + {KNOT_ESPACE, "Not enough space provided."}, + {KNOT_EMALF, "Malformed data."}, + {KNOT_ECRYPTO, "Error in crypto library."}, + {KNOT_ENSEC3PAR, "Missing or wrong NSEC3PARAM record."}, + {KNOT_EBADZONE, "Domain name does not belong to the given zone."}, + {KNOT_EHASH, "Error in hash table."}, + {KNOT_EZONEIN, "Error inserting zone."}, + {KNOT_ENOZONE, "No such zone found."}, + {KNOT_ENONODE, "No such node in zone found."}, + {KNOT_ENORRSET, "No such RRSet found."}, + {KNOT_EDNAMEPTR, "Domain name pointer larger than allowed."}, + {KNOT_EPAYLOAD, "Payload in OPT RR larger than max wire size."}, + {KNOT_ECRC, "CRC check failed."}, + {KNOT_EPREREQ, "UPDATE prerequisity not met."}, + {KNOT_ENOXFR, "Transfer was not sent."}, + {KNOT_ENOIXFR, "Transfer is not IXFR (is in AXFR format)."}, + {KNOT_EXFRREFUSED, "Zone transfer refused by the server."}, + {KNOT_TSIG_EBADSIG, "Failed to verify TSIG MAC." }, + {KNOT_TSIG_EBADKEY, "TSIG key not recognized or invalid." }, + {KNOT_TSIG_EBADTIME, "TSIG signing time out of range." }, + {KNOT_ECONN, "Connection reset."}, + {KNOT_ERROR, 0} +}; diff --git a/src/libknot/util/tolower.c b/src/libknot/util/tolower.c new file mode 100644 index 0000000..d71c467 --- /dev/null +++ b/src/libknot/util/tolower.c @@ -0,0 +1,276 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "util/tolower.h" + +const uint8_t char_table[CHAR_TABLE_SIZE] = { + '\x00', + '\x01', + '\x02', + '\x03', + '\x04', + '\x05', + '\x06', + '\x07', + '\x08', + '\x09', + '\x0A', + '\x0B', + '\x0C', + '\x0D', + '\x0E', + '\x0F', + '\x10', + '\x11', + '\x12', + '\x13', + '\x14', + '\x15', + '\x16', + '\x17', + '\x18', + '\x19', + '\x1A', + '\x1B', + '\x1C', + '\x1D', + '\x1E', + '\x1F', + '\x20', + '\x21', /* ! */ + '\x22', /* " */ + '\x23', /* # */ + '\x24', /* $ */ + '\x25', /* % */ + '\x26', /* & */ + '\x27', /* ' */ + '\x28', /* ( */ + '\x29', /* ) */ + '\x2A', /* * */ + '\x2B', /* + */ + '\x2C', /* , */ + '\x2D', /* - */ + '\x2E', /* . */ + '\x2F', /* / */ + '\x30', /* 0 */ + '\x31', /* 1 */ + '\x32', /* 2 */ + '\x33', /* 3 */ + '\x34', /* 4 */ + '\x35', /* 5 */ + '\x36', /* 6 */ + '\x37', /* 7 */ + '\x38', /* 8 */ + '\x39', /* 9 */ + '\x3A', /* : */ + '\x3B', /* ; */ + '\x3C', /* < */ + '\x3D', /* = */ + '\x3E', /* > */ + '\x3F', /* ? */ + '\x40', /* @ */ + '\x61', /* A */ + '\x62', /* B */ + '\x63', /* C */ + '\x64', /* D */ + '\x65', /* E */ + '\x66', /* F */ + '\x67', /* G */ + '\x68', /* H */ + '\x69', /* I */ + '\x6A', /* J */ + '\x6B', /* K */ + '\x6C', /* L */ + '\x6D', /* M */ + '\x6E', /* N */ + '\x6F', /* O */ + '\x70', /* P */ + '\x71', /* Q */ + '\x72', /* R */ + '\x73', /* S */ + '\x74', /* T */ + '\x75', /* U */ + '\x76', /* V */ + '\x77', /* W */ + '\x78', /* X */ + '\x79', /* Y */ + '\x7A', /* Z */ + '\x5B', /* [ */ + '\x5C', /* \ */ + '\x5D', /* ] */ + '\x5E', /* ^ */ + '\x5F', /* _ */ + '\x60', /* ` */ + '\x61', /* a */ + '\x62', /* b */ + '\x63', /* c */ + '\x64', /* d */ + '\x65', /* e */ + '\x66', /* f */ + '\x67', /* g */ + '\x68', /* h */ + '\x69', /* i */ + '\x6A', /* j */ + '\x6B', /* k */ + '\x6C', /* l */ + '\x6D', /* m */ + '\x6E', /* n */ + '\x6F', /* o */ + '\x70', /* p */ + '\x71', /* q */ + '\x72', /* r */ + '\x73', /* s */ + '\x74', /* t */ + '\x75', /* u */ + '\x76', /* v */ + '\x77', /* w */ + '\x78', /* x */ + '\x79', /* y */ + '\x7A', /* z */ + '\x7B', /* { */ + '\x7C', /* | */ + '\x7D', /* } */ + '\x7E', /* ~ */ + '\x7F', + '\x80', + '\x81', + '\x82', + '\x83', + '\x84', + '\x85', + '\x86', + '\x87', + '\x88', + '\x89', + '\x8A', + '\x8B', + '\x8C', + '\x8D', + '\x8E', + '\x8F', + '\x90', + '\x91', + '\x92', + '\x93', + '\x94', + '\x95', + '\x96', + '\x97', + '\x98', + '\x99', + '\x9A', + '\x9B', + '\x9C', + '\x9D', + '\x9E', + '\x9F', + '\xA0', + '\xA1', + '\xA2', + '\xA3', + '\xA4', + '\xA5', + '\xA6', + '\xA7', + '\xA8', + '\xA9', + '\xAA', + '\xAB', + '\xAC', + '\xAD', + '\xAE', + '\xAF', + '\xB0', + '\xB1', + '\xB2', + '\xB3', + '\xB4', + '\xB5', + '\xB6', + '\xB7', + '\xB8', + '\xB9', + '\xBA', + '\xBB', + '\xBC', + '\xBD', + '\xBE', + '\xBF', + '\xC0', + '\xC1', + '\xC2', + '\xC3', + '\xC4', + '\xC5', + '\xC6', + '\xC7', + '\xC8', + '\xC9', + '\xCA', + '\xCB', + '\xCC', + '\xCD', + '\xCE', + '\xCF', + '\xD0', + '\xD1', + '\xD2', + '\xD3', + '\xD4', + '\xD5', + '\xD6', + '\xD7', + '\xD8', + '\xD9', + '\xDA', + '\xDB', + '\xDC', + '\xDD', + '\xDE', + '\xDF', + '\xE0', + '\xE1', + '\xE2', + '\xE3', + '\xE4', + '\xE5', + '\xE6', + '\xE7', + '\xE8', + '\xE9', + '\xEA', + '\xEB', + '\xEC', + '\xED', + '\xEE', + '\xEF', + '\xF0', + '\xF1', + '\xF2', + '\xF3', + '\xF4', + '\xF5', + '\xF6', + '\xF7', + '\xF8', + '\xF9', + '\xFA', + '\xFB', + '\xFC', + '\xFD', + '\xFE', + '\xFF', +}; diff --git a/src/libknot/util/tolower.h b/src/libknot/util/tolower.h new file mode 100644 index 0000000..6b9e98c --- /dev/null +++ b/src/libknot/util/tolower.h @@ -0,0 +1,57 @@ +/*! + * \file tolower.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Table for converting ASCII characters to lowercase. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_TOLOWER_H_ +#define _KNOT_TOLOWER_H_ + +#include <stdint.h> + +/*! \brief Size of the character conversion table. */ +#define KNOT_CHAR_TABLE_SIZE 256 + +enum { + /*! \brief Size of the character conversion table. */ + CHAR_TABLE_SIZE = KNOT_CHAR_TABLE_SIZE +}; + +/*! \brief Character table mapping uppercase letters to lowercase. */ +extern const uint8_t char_table[CHAR_TABLE_SIZE]; + +/*! + * \brief Converts ASCII character to lowercase. + * + * \param c ASCII character code. + * + * \return \a c converted to lowercase (or \a c if not applicable). + */ +static inline uint8_t knot_tolower(uint8_t c) { +#if KNOT_CHAR_TABLE_SIZE < 256 + assert(c < CHAR_TABLE_SIZE); +#endif + return char_table[c]; +} + +#endif /* _KNOT_TOLOWER_H_ */ diff --git a/src/libknot/util/utils.c b/src/libknot/util/utils.c new file mode 100644 index 0000000..17b33a7 --- /dev/null +++ b/src/libknot/util/utils.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <unistd.h> + +#include "common.h" +#include "util/utils.h" +#include "common/WELL1024a.h" + +/*----------------------------------------------------------------------------*/ + +knot_lookup_table_t *knot_lookup_by_name(knot_lookup_table_t *table, + const char *name) +{ + while (table->name != NULL) { + if (strcasecmp(name, table->name) == 0) { + return table; + } + table++; + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ + +knot_lookup_table_t *knot_lookup_by_id(knot_lookup_table_t *table, + int id) +{ + while (table->name != NULL) { + if (table->id == id) { + return table; + } + table++; + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ + +size_t knot_strlcpy(char *dst, const char *src, size_t size) +{ + char *d = dst; + const char *s = src; + size_t n = size; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) { + break; + } + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (size != 0) { + *d = '\0'; /* NUL-terminate dst */ + } + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +/*! \brief TLS key for rand seed. */ +static pthread_key_t _qr_key; +static pthread_once_t _qr_once = PTHREAD_ONCE_INIT; + +/*! \brief TLS key initializer. */ +static void _qr_init() +{ + (void) pthread_key_create(&_qr_key, NULL); + (void) pthread_setspecific(_qr_key, (void*)time(0)); +} + +size_t knot_quick_rand() +{ + (void) pthread_once(&_qr_once, _qr_init); + size_t x = (size_t)pthread_getspecific(_qr_key); + + /* Numerical Recipes in C. + * The Art of Scientific Computing, 2nd Edition, + * 1992, ISBN 0-521-43108-5. + * Page 284. + */ + x = 1664525L * x + 1013904223L; + (void) pthread_setspecific(_qr_key, (void*)x); + return x; +} + +uint16_t knot_random_id() +{ + return (uint16_t)(tls_rand() * ((uint16_t)~0)); +} + +struct flock* knot_file_lock(short type, short whence) +{ + static struct flock ret; + ret.l_type = type; + ret.l_start = 0; + ret.l_whence = whence; + ret.l_len = 0; + ret.l_pid = getpid(); + return &ret; +} + diff --git a/src/libknot/util/utils.h b/src/libknot/util/utils.h new file mode 100644 index 0000000..f43b8f0 --- /dev/null +++ b/src/libknot/util/utils.h @@ -0,0 +1,196 @@ +/*! + * \file utils.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Various utilities. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_UTILS_H_ +#define _KNOT_UTILS_H_ + +#include <string.h> +#include <stdint.h> +#include <stdio.h> + +/*! + * \brief A general purpose lookup table. + * + * \note Taken from NSD. + */ +struct knot_lookup_table { + int id; + const char *name; +}; + +typedef struct knot_lookup_table knot_lookup_table_t; + +/*! + * \brief Looks up the given name in the lookup table. + * + * \param table Lookup table. + * \param name Name to look up. + * + * \return Item in the lookup table with the given name or NULL if no such is + * present. + */ +knot_lookup_table_t *knot_lookup_by_name(knot_lookup_table_t *table, + const char *name); + +/*! + * \brief Looks up the given id in the lookup table. + * + * \param table Lookup table. + * \param id ID to look up. + * + * \return Item in the lookup table with the given id or NULL if no such is + * present. + */ +knot_lookup_table_t *knot_lookup_by_id(knot_lookup_table_t *table, + int id); + +/*! + * \brief Strlcpy - safe string copy function, based on FreeBSD implementation. + * + * http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/ + * + * \param dst Destination string. + * \param src Source string. + * \param size How many characters to copy - 1. + * + * \return strlen(src), if retval >= siz, truncation occurred. + */ +size_t knot_strlcpy(char *dst, const char *src, size_t size); + +/* + * Writing / reading arbitrary data to / from wireformat. + */ + +/*! + * \brief Reads 2 bytes from the wireformat data. + * + * \param pos Data to read the 2 bytes from. + * + * \return The 2 bytes read, in inverse endian. + */ +static inline uint16_t knot_wire_read_u16(const uint8_t *pos) +{ + return (pos[0] << 8) | pos[1]; +} + +/*! + * \brief Reads 4 bytes from the wireformat data. + * + * \param pos Data to read the 4 bytes from. + * + * \return The 4 bytes read, in inverse endian. + */ +static inline uint32_t knot_wire_read_u32(const uint8_t *pos) +{ + return (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) | pos[3]; +} + +/*! + * \brief Reads 6 bytes from the wireformat data. + * + * \param pos Data to read the 6 bytes from. + * + * \return The 6 bytes read, in inverse endian. + */ +static inline uint64_t knot_wire_read_u48(const uint8_t *pos) +{ + return ((uint64_t)(pos[0]) << 40) | ((uint64_t)(pos[1]) << 32) | (pos[2] << 24) | + (pos[3] << 16) | (pos[4] << 8) | pos[5]; +} + +/*! + * \brief Writes 2 bytes in wireformat. + * + * The endian of the data is inverted. + * + * \param pos Position where to put the 2 bytes. + * \param data Data to put. + */ +static inline void knot_wire_write_u16(uint8_t *pos, uint16_t data) +{ + pos[0] = (uint8_t)((data >> 8) & 0xff); + pos[1] = (uint8_t)(data & 0xff); +} + +/*! + * \brief Writes 4 bytes in wireformat. + * + * The endian of the data is inverted. + * + * \param pos Position where to put the 4 bytes. + * \param data Data to put. + */ +static inline void knot_wire_write_u32(uint8_t *pos, uint32_t data) +{ + pos[0] = (uint8_t)((data >> 24) & 0xff); + pos[1] = (uint8_t)((data >> 16) & 0xff); + pos[2] = (uint8_t)((data >> 8) & 0xff); + pos[3] = (uint8_t)(data & 0xff); +} + +/*! + * \brief Writes 6 bytes in wireformat. + * + * The endian of the data is inverted. + * + * \param pos Position where to put the 4 bytes. + * \param data Data to put. + */ +static inline void knot_wire_write_u48(uint8_t *pos, uint64_t data) +{ + pos[0] = (uint8_t)((data >> 40) & 0xff); + pos[1] = (uint8_t)((data >> 32) & 0xff); + pos[2] = (uint8_t)((data >> 24) & 0xff); + pos[3] = (uint8_t)((data >> 16) & 0xff); + pos[4] = (uint8_t)((data >> 8) & 0xff); + pos[5] = (uint8_t)(data & 0xff); +} + +/*! + * \brief Linear congruential generator. + * + * Simple pseudorandom generator for general purpose. + * \warning Do not use for cryptography. + * \return Random number <0, (size_t)~0> + */ +size_t knot_quick_rand(); + +uint16_t knot_random_id(); + +/*! + * \brief Helper function for simple locking. + * + * \param type Type of lock. + * \param type Starting position of lock. + * + * \return Locking structure. + */ +struct flock* knot_file_lock(short type, short whence); + +#endif /* _KNOT_UTILS_H_ */ + +/*! @} */ + diff --git a/src/libknot/util/wire.h b/src/libknot/util/wire.h new file mode 100644 index 0000000..0a24ff1 --- /dev/null +++ b/src/libknot/util/wire.h @@ -0,0 +1,926 @@ +/*! + * \file wire.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Functions for manipulating and parsing raw data in DNS packets. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_WIRE_H_ +#define _KNOT_WIRE_H_ + +#include <stdint.h> +#include <assert.h> + +#include "util/utils.h" + +/*! \brief Offset of DNS header fields in wireformat. */ +enum knot_wire_offsets { + KNOT_WIRE_OFFSET_ID = 0, + KNOT_WIRE_OFFSET_FLAGS1 = 2, + KNOT_WIRE_OFFSET_FLAGS2 = 3, + KNOT_WIRE_OFFSET_QDCOUNT = 4, + KNOT_WIRE_OFFSET_ANCOUNT = 6, + KNOT_WIRE_OFFSET_NSCOUNT = 8, + KNOT_WIRE_OFFSET_ARCOUNT = 10 +}; + +/*! \brief Minimum size for some parts of the DNS packet. */ +enum knot_wire_sizes { + KNOT_WIRE_HEADER_SIZE = 12, + KNOT_WIRE_QUESTION_MIN_SIZE = 5, + KNOT_WIRE_RR_MIN_SIZE = 11 +}; + +/* + * Packet header manipulation functions. + */ + +/*! + * \brief Returns the ID from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return DNS packet ID. + */ +static inline uint16_t knot_wire_get_id(const uint8_t *packet) +{ + return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ID); +} + +/*! + * \brief Sets the ID to the wire format of the packet. + * + * \param packet Wire format of the packet. + * \param id DNS packet ID. + */ +static inline void knot_wire_set_id(uint8_t *packet, uint16_t id) +{ + knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ID, id); +} + +/*! + * \brief Returns the first byte of flags from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return First byte of DNS flags. + */ +static inline uint8_t knot_wire_get_flags1(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS1); +} + +/*! + * \brief Sets the first byte of flags to the wire format of the packet. + * + * \param packet Wire format of the packet. + * \param flags1 First byte of the DNS flags. + */ +static inline uint8_t knot_wire_set_flags1(uint8_t *packet, uint8_t flags1) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS1) = flags1; +} + +/*! + * \brief Returns the second byte of flags from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Second byte of DNS flags. + */ +static inline uint8_t knot_wire_get_flags2(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS2); +} + +/*! + * \brief Sets the second byte of flags to the wire format of the packet. + * + * \param packet Wire format of the packet. + * \param flags2 Second byte of the DNS flags. + */ +static inline uint8_t knot_wire_set_flags2(uint8_t *packet, uint8_t flags2) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS2) = flags2; +} + +/*! + * \brief Returns the QDCOUNT (count of Question entries) from wire format of + * the packet. + * + * \param packet Wire format of the packet. + * + * \return QDCOUNT (count of Question entries in the packet). + */ +static inline uint16_t knot_wire_get_qdcount(const uint8_t *packet) +{ + return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT); +} + +/*! + * \brief Sets the QDCOUNT (count of Question entries) to wire format of the + * packet. + * + * \param packet Wire format of the packet. + * \param qdcount QDCOUNT (count of Question entries in the packet). + */ +static inline void knot_wire_set_qdcount(uint8_t *packet, uint16_t qdcount) +{ + knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT, qdcount); +} + +/*! + * \brief Returns the ANCOUNT (count of Answer entries) from wire format of + * the packet. + * + * \param packet Wire format of the packet. + * + * \return ANCOUNT (count of Answer entries in the packet). + */ +static inline uint16_t knot_wire_get_ancount(const uint8_t *packet) +{ + return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT); +} + +/*! + * \brief Sets the ANCOUNT (count of Answer entries) to wire format of the + * packet. + * + * \param packet Wire format of the packet. + * \param ancount ANCOUNT (count of Answer entries in the packet). + */ +static inline void knot_wire_set_ancount(uint8_t *packet, uint16_t ancount) +{ + knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT, ancount); +} + +/*! + * \brief Returns the NSCOUNT (count of Authority entries) from wire format of + * the packet. + * + * \param packet Wire format of the packet. + * + * \return NSCOUNT (count of Authority entries in the packet). + */ +static inline uint16_t knot_wire_get_nscount(const uint8_t *packet) +{ + return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT); +} + +/*! + * \brief Sets the NSCOUNT (count of Authority entries) to wire format of the + * packet. + * + * \param packet Wire format of the packet. + * \param nscount NSCOUNT (count of Authority entries in the packet). + */ +static inline void knot_wire_set_nscount(uint8_t *packet, uint16_t nscount) +{ + knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT, nscount); +} + +/*! + * \brief Returns the ARCOUNT (count of Additional entries) from wire format of + * the packet. + * + * \param packet Wire format of the packet. + * + * \return ARCOUNT (count of Additional entries in the packet). + */ +static inline uint16_t knot_wire_get_arcount(const uint8_t *packet) +{ + return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT); +} + +/*! + * \brief Sets the ARCOUNT (count of Additional entries) to wire format of the + * packet. + * + * \param packet Wire format of the packet. + * \param arcount ARCOUNT (count of Additional entries in the packet). + */ +static inline void knot_wire_set_arcount(uint8_t *packet, uint16_t arcount) +{ + knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT, arcount); +} + +/* + * Packet header flags manipulation functions. + */ +/*! \brief Constants for DNS header flags in the first flags byte. */ +enum knot_wire_flags1_consts { + KNOT_WIRE_RD_MASK = (uint8_t)0x01U, /*!< RD bit mask. */ + KNOT_WIRE_RD_SHIFT = 0, /*!< RD bit shift. */ + KNOT_WIRE_TC_MASK = (uint8_t)0x02U, /*!< TC bit mask. */ + KNOT_WIRE_TC_SHIFT = 1, /*!< TC bit shift. */ + KNOT_WIRE_AA_MASK = (uint8_t)0x04U, /*!< AA bit mask. */ + KNOT_WIRE_AA_SHIFT = 2, /*!< AA bit shift. */ + KNOT_WIRE_OPCODE_MASK = (uint8_t)0x78U, /*!< OPCODE mask. */ + KNOT_WIRE_OPCODE_SHIFT = 3, /*!< OPCODE shift. */ + KNOT_WIRE_QR_MASK = (uint8_t)0x80U, /*!< QR bit mask. */ + KNOT_WIRE_QR_SHIFT = 7 /*!< QR bit shift. */ +}; + +/*! \brief Constants for DNS header flags in the second flags byte. */ +enum knot_wire_flags2_consts { + KNOT_WIRE_RCODE_MASK = (uint8_t)0x0fU, /*!< RCODE mask. */ + KNOT_WIRE_RCODE_SHIFT = 0, /*!< RCODE shift. */ + KNOT_WIRE_CD_MASK = (uint8_t)0x10U, /*!< CD bit mask. */ + KNOT_WIRE_CD_SHIFT = 4, /*!< CD bit shift. */ + KNOT_WIRE_AD_MASK = (uint8_t)0x20U, /*!< AD bit mask. */ + KNOT_WIRE_AD_SHIFT = 5, /*!< AD bit shift. */ + KNOT_WIRE_Z_MASK = (uint8_t)0x40U, /*!< Zero bit mask. */ + KNOT_WIRE_Z_SHIFT = 6, /*!< Zero bit shift. */ + KNOT_WIRE_RA_MASK = (uint8_t)0x80U, /*!< RA bit mask. */ + KNOT_WIRE_RA_SHIFT = 7 /*!< RA bit shift. */ +}; + +/* + * Functions for getting / setting / clearing flags and codes directly in packet + */ + +/*! + * \brief Returns the RD bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the RD bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_rd(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_RD_MASK; +} + +/*! + * \brief Sets the RD bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_rd(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_RD_MASK; +} + +/*! + * \brief Clears the RD bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_flags_clear_rd(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_RD_MASK; +} + +/*! + * \brief Returns the TC bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the TC bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_tc(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_TC_MASK; +} + +/*! + * \brief Sets the TC bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_tc(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_TC_MASK; +} + +/*! + * \brief Clears the TC bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_clear_tc(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_TC_MASK; +} + +/*! + * \brief Returns the AA bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the AA bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_aa(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_AA_MASK; +} + +/*! + * \brief Sets the AA bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_aa(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_AA_MASK; +} + +/*! + * \brief Clears the AA bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_clear_aa(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_AA_MASK; +} + +/*! + * \brief Returns the OPCODE from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return OPCODE of the packet. + */ +static inline uint8_t knot_wire_get_opcode(const uint8_t *packet) +{ + return (*(packet + KNOT_WIRE_OFFSET_FLAGS1) + & KNOT_WIRE_OPCODE_MASK) >> KNOT_WIRE_OPCODE_SHIFT; +} + +/*! + * \brief Sets the OPCODE in the wire format of the packet. + * + * \param packet Wire format of the packet. + * \param opcode OPCODE to set. + */ +static inline void knot_wire_set_opcode(uint8_t *packet, short opcode) +{ + uint8_t *flags1 = packet + KNOT_WIRE_OFFSET_FLAGS1; + *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK) + | ((opcode) << KNOT_WIRE_OPCODE_SHIFT); +} + +/*! + * \brief Returns the QR bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the QR bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_qr(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_QR_MASK; +} + +/*! + * \brief Sets the QR bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_qr(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_QR_MASK; +} + +/*! + * \brief Clears the QR bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_clear_qr(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_QR_MASK; +} + +/*! + * \brief Returns the RCODE from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return RCODE of the packet. + */ +static inline uint8_t knot_wire_get_rcode(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS2) + & KNOT_WIRE_RCODE_MASK; +} + +/*! + * \brief Sets the RCODE in the wire format of the packet. + * + * \param packet Wire format of the packet. + * \param rcode RCODE to set. + */ +static inline void knot_wire_set_rcode(uint8_t *packet, short rcode) +{ + uint8_t *flags2 = packet + KNOT_WIRE_OFFSET_FLAGS2; + *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode); +} + +/*! + * \brief Returns the CD bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the CD bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_cd(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_CD_MASK; +} + +/*! + * \brief Sets the CD bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_cd(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_CD_MASK; +} + +/*! + * \brief Clears the CD bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_clear_cd(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_CD_MASK; +} + +/*! + * \brief Returns the AD bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the AD bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_ad(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_AD_MASK; +} + +/*! + * \brief Sets the AD bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_ad(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_AD_MASK; +} + +/*! + * \brief Clears the AD bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_clear_ad(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_AD_MASK; +} + +/*! + * \brief Returns the Zero bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the Zero bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_z(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_Z_MASK; +} + +/*! + * \brief Sets the Zero bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_z(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_Z_MASK; +} + +/*! + * \brief Clears the Zero bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_clear_z(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_Z_MASK; +} + +/*! + * \brief Returns the RA bit from wire format of the packet. + * + * \param packet Wire format of the packet. + * + * \return Flags with only the RA bit according to its setting in the packet. + */ +static inline uint8_t knot_wire_get_ra(const uint8_t *packet) +{ + return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_RA_MASK; +} + +/*! + * \brief Sets the RA bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_set_ra(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_RA_MASK; +} + +/*! + * \brief Clears the RA bit in the wire format of the packet. + * + * \param packet Wire format of the packet. + */ +static inline void knot_wire_clear_ra(uint8_t *packet) +{ + *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_RA_MASK; +} + +/* + * Functions for getting / setting / clearing flags in flags variable + */ + +/*! + * \brief Returns the RD bit from the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + * + * \return Flags byte with only the RD bit according to its setting in + * \a flags1. + */ +static inline uint8_t knot_wire_flags_get_rd(uint8_t flags1) +{ + return flags1 & KNOT_WIRE_RD_MASK; +} + +/*! + * \brief Sets the RD bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_set_rd(uint8_t *flags1) +{ + *flags1 |= KNOT_WIRE_RD_MASK; +} + +/*! + * \brief Clears the RD bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_flags_clear_rd(uint8_t *flags1) +{ + *flags1 &= ~KNOT_WIRE_RD_MASK; +} + +/*! + * \brief Returns the TC bit from the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + * + * \return Flags byte with only the TC bit according to its setting in + * \a flags1. + */ +static inline uint8_t knot_wire_flags_get_tc(uint8_t flags1) +{ + return flags1 & KNOT_WIRE_TC_MASK; +} + +/*! + * \brief Sets the TC bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_set_tc(uint8_t *flags1) +{ + *flags1 |= KNOT_WIRE_TC_MASK; +} + +/*! + * \brief Clears the TC bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_clear_tc(uint8_t *flags1) +{ + *flags1 &= ~KNOT_WIRE_TC_MASK; +} + +/*! + * \brief Returns the AA bit from the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + * + * \return Flags byte with only the AA bit according to its setting in + * \a flags1. + */ +static inline uint8_t knot_wire_flags_get_aa(uint8_t flags1) +{ + return flags1 & KNOT_WIRE_AA_MASK; +} + +/*! + * \brief Sets the AA bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_set_aa(uint8_t *flags1) +{ + *flags1 |= KNOT_WIRE_AA_MASK; +} + +/*! + * \brief Clears the AA bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_clear_aa(uint8_t *flags1) +{ + *flags1 &= ~KNOT_WIRE_AA_MASK; +} + +/*! + * \brief Returns the OPCODE from the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + * + * \return OPCODE + */ +static inline uint8_t knot_wire_flags_get_opcode(uint8_t flags1) +{ + return (flags1 & KNOT_WIRE_OPCODE_MASK) + >> KNOT_WIRE_OPCODE_SHIFT; +} + +/*! + * \brief Sets the OPCODE in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + * \param opcode OPCODE to set. + */ +static inline void knot_wire_flags_set_opcode(uint8_t *flags1, short opcode) +{ + *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK) + | ((opcode) << KNOT_WIRE_OPCODE_SHIFT); +} + +/*! + * \brief Returns the QR bit from the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + * + * \return Flags byte with only the QR bit according to its setting in + * \a flags1. + */ +static inline uint8_t knot_wire_flags_get_qr(uint8_t flags1) +{ + return flags1 & KNOT_WIRE_QR_MASK; +} + +/*! + * \brief Sets the QR bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_set_qr(uint8_t *flags1) +{ + *flags1 |= KNOT_WIRE_QR_MASK; +} + +/*! + * \brief Clears the QR bit in the first byte of flags. + * + * \param flags1 First byte of DNS header flags. + */ +static inline void knot_wire_flags_clear_qr(uint8_t *flags1) +{ + *flags1 &= ~KNOT_WIRE_QR_MASK; +} + +/*! + * \brief Returns the RCODE from the second byte of flags. + * + * \param flags2 First byte of DNS header flags. + * + * \return RCODE + */ +static inline uint8_t knot_wire_flags_get_rcode(uint8_t flags2) +{ + return flags2 & KNOT_WIRE_RCODE_MASK; +} + +/*! + * \brief Sets the RCODE in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + * \param rcode RCODE to set. + */ +static inline void knot_wire_flags_set_rcode(uint8_t *flags2, short rcode) +{ + *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode); +} + +/*! + * \brief Returns the CD bit from the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + * + * \return Flags byte with only the CD bit according to its setting in + * \a flags2. + */ +static inline uint8_t knot_wire_flags_get_cd(uint8_t flags2) +{ + return flags2 & KNOT_WIRE_CD_MASK; +} + +/*! + * \brief Sets the CD bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_set_cd(uint8_t *flags2) +{ + *flags2 |= KNOT_WIRE_CD_MASK; +} + +/*! + * \brief Clears the CD bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_clear_cd(uint8_t *flags2) +{ + *flags2 &= ~KNOT_WIRE_CD_MASK; +} + +/*! + * \brief Returns the AD bit from the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + * + * \return Flags byte with only the AD bit according to its setting in + * \a flags2. + */ +static inline uint8_t knot_wire_flags_get_ad(uint8_t flags2) +{ + return flags2 & KNOT_WIRE_AD_MASK; +} + +/*! + * \brief Sets the AD bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_set_ad(uint8_t *flags2) +{ + *flags2 |= KNOT_WIRE_AD_MASK; +} + +/*! + * \brief Clears the AD bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_clear_ad(uint8_t *flags2) +{ + *flags2 &= ~KNOT_WIRE_AD_MASK; +} + +/*! + * \brief Returns the Zero bit from the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + * + * \return Flags byte with only the Zero bit according to its setting in + * \a flags2. + */ +static inline uint8_t knot_wire_flags_get_z(uint8_t flags2) +{ + return flags2 & KNOT_WIRE_Z_MASK; +} + +/*! + * \brief Sets the Zero bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_set_z(uint8_t *flags2) +{ + *flags2 |= KNOT_WIRE_Z_MASK; +} + +/*! + * \brief Clears the Zero bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_clear_z(uint8_t *flags2) +{ + *flags2 &= ~KNOT_WIRE_Z_MASK; +} + +/*! + * \brief Returns the RA bit from the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + * + * \return Flags byte with only the RA bit according to its setting in + * \a flags2. + */ +static inline uint8_t knot_wire_flags_get_ra(uint8_t flags2) +{ + return flags2 & KNOT_WIRE_RA_MASK; +} + +/*! + * \brief Sets the RA bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_set_ra(uint8_t *flags2) +{ + *flags2 |= KNOT_WIRE_RA_MASK; +} + +/*! + * \brief Clears the RA bit in the second byte of flags. + * + * \param flags2 Second byte of DNS header flags. + */ +static inline void knot_wire_flags_clear_ra(uint8_t *flags2) +{ + *flags2 &= ~KNOT_WIRE_RA_MASK; +} + +/* + * Pointer manipulation + */ + +enum knot_wire_pointer_consts { + /*! \brief DNS packet pointer designation (first two bits set to 1). */ + KNOT_WIRE_PTR = (uint8_t)0xc0U +}; + +/*! + * \brief Creates a DNS packet pointer and stores it in wire format. + * + * \param pos Position where tu put the pointer. + * \param ptr Relative position of the item to which the pointer should point in + * the wire format of the packet. + */ +static inline void knot_wire_put_pointer(uint8_t *pos, size_t ptr) +{ + uint16_t p = ptr; + knot_wire_write_u16(pos, p); + assert((pos[0] & KNOT_WIRE_PTR) == 0); + pos[0] |= KNOT_WIRE_PTR; +} + +static inline int knot_wire_is_pointer(const uint8_t *pos) +{ + return ((pos[0] & KNOT_WIRE_PTR) != 0); +} + +static inline size_t knot_wire_get_pointer(const uint8_t *pos) +{ + /*! \todo memcpy() is not needed, may be directly assigned. */ + uint16_t p = 0; + memcpy(&p, pos, 2); + p &= ~KNOT_WIRE_PTR; + + uint16_t p2 = knot_wire_read_u16((uint8_t *)&p); + return p2; +} + +#endif /* _KNOT_WIRE_H_ */ + +/*! @} */ diff --git a/src/libknot/zone/dname-table.c b/src/libknot/zone/dname-table.c new file mode 100644 index 0000000..c41b4bd --- /dev/null +++ b/src/libknot/zone/dname-table.c @@ -0,0 +1,310 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> + +#include "zone/dname-table.h" +#include "util/error.h" + +/*!< Tree functions. */ +TREE_DEFINE(dname_table_node, avl); + +struct knot_dname_table_fnc_data { + void (*func)(knot_dname_t *dname, void *data); + void *data; +}; + +static void knot_dname_table_apply(struct dname_table_node *node, void *data) +{ + assert(data != NULL); + assert(node != NULL); + struct knot_dname_table_fnc_data *d = + (struct knot_dname_table_fnc_data *)data; + d->func(node->dname, d->data); +} + +/*! + * \brief Comparison function to be used with tree. + * + * \param n1 First dname to be compared. + * \param n2 Second dname to be compared. + * + * \return strncmp of dname's wireformats. + */ +static int compare_dname_table_nodes(struct dname_table_node *n1, + struct dname_table_node *n2) +{ + assert(n1 && n2); + return (strncmp((char *)n1->dname->name, (char *)n2->dname->name, + (n1->dname->size < n2->dname->size) ? + (n1->dname->size):(n2->dname->size))); +} + +/*! + * \brief Deletes tree node along with its domain name. + * + * \param node Node to be deleted. + * \param data If <> 0, dname in the node will be freed as well. + */ +static void delete_dname_table_node(struct dname_table_node *node, void *data) +{ + if ((ssize_t)data == 1) { + knot_dname_release(node->dname); + } else if ((ssize_t)data == 2) { + knot_dname_free(&node->dname); + } + + /*!< \todo it would be nice to set pointers to NULL. */ + free(node); +} + +static void knot_dname_table_delete_subtree(struct dname_table_node *root) +{ + if (root == NULL) { + return; + } + + knot_dname_table_delete_subtree(root->avl.avl_left); + knot_dname_table_delete_subtree(root->avl.avl_right); + free(root); +} + +static int knot_dname_table_copy_node(const struct dname_table_node *from, + struct dname_table_node **to) +{ + if (from == NULL) { + return KNOT_EOK; + } + + *to = (struct dname_table_node *) + malloc(sizeof(struct dname_table_node)); + if (*to == NULL) { + return KNOT_ENOMEM; + } + memset(*to, 0, sizeof(struct dname_table_node)); + + (*to)->dname = from->dname; + knot_dname_retain((*to)->dname); + (*to)->avl.avl_height = from->avl.avl_height; + + int ret = knot_dname_table_copy_node(from->avl.avl_left, + &(*to)->avl.avl_left); + if (ret != KNOT_EOK) { + return ret; + } + + ret = knot_dname_table_copy_node(from->avl.avl_right, + &(*to)->avl.avl_right); + if (ret != KNOT_EOK) { + knot_dname_table_delete_subtree((*to)->avl.avl_left); + (*to)->avl.avl_left = NULL; + return ret; + } + + return KNOT_EOK; +} + +knot_dname_table_t *knot_dname_table_new() +{ + knot_dname_table_t *ret = malloc(sizeof(knot_dname_table_t)); + CHECK_ALLOC_LOG(ret, NULL); + + ret->tree = malloc(sizeof(table_tree_t)); + if (ret->tree == NULL) { + ERR_ALLOC_FAILED; + free(ret); + return NULL; + } + + TREE_INIT(ret->tree, compare_dname_table_nodes); + + ret->id_counter = 1; + + return ret; +} + +knot_dname_t *knot_dname_table_find_dname(const knot_dname_table_t *table, + knot_dname_t *dname) +{ + if (table == NULL || dname == NULL) { + return NULL; + } + + struct dname_table_node *node = NULL; + struct dname_table_node sought; + sought.dname = dname; + + node = TREE_FIND(table->tree, dname_table_node, avl, &sought); + + if (node == NULL) { + return NULL; + } else { + /* Increase reference counter. */ + knot_dname_retain(node->dname); + + return node->dname; + } +} + +int knot_dname_table_add_dname(knot_dname_table_t *table, + knot_dname_t *dname) +{ + if (dname == NULL || table == NULL) { + return KNOT_EBADARG; + } + + /* Node for insertion has to be created */ + struct dname_table_node *node = + malloc(sizeof(struct dname_table_node)); + CHECK_ALLOC_LOG(node, KNOT_ENOMEM); + + // convert the dname to lowercase + knot_dname_to_lower(dname); + + node->dname = dname; + node->avl.avl_height = 0; + node->avl.avl_left = NULL; + node->avl.avl_right = NULL; + + node->dname->id = table->id_counter++; + assert(node->dname->id != 0); + + /* Increase reference counter. */ + knot_dname_retain(dname); + + TREE_INSERT(table->tree, dname_table_node, avl, node); + return KNOT_EOK; +} + +int knot_dname_table_add_dname_check(knot_dname_table_t *table, + knot_dname_t **dname) +{ + knot_dname_t *found_dname = NULL; + + if (table == NULL || dname == NULL || *dname == NULL) { + return KNOT_EBADARG; + } + + /* Fetch dname, need to release it later. */ + found_dname = knot_dname_table_find_dname(table ,*dname); + + if (!found_dname) { + /* Store reference in table. */ + return knot_dname_table_add_dname(table, *dname); + } else { + /*! \todo Remove the check for equality. */ + if (found_dname != *dname) { + /* Replace dname with found. */ + knot_dname_release(*dname); + *dname = found_dname; + return 1; /*! \todo Error code? */ + + } else { + + /* If the dname is already in the table, there is already + * a reference to it. + */ + knot_dname_release(found_dname); + } + } + + return KNOT_EOK; +} + +int knot_dname_table_shallow_copy(knot_dname_table_t *from, + knot_dname_table_t *to) +{ + to->id_counter = from->id_counter; + + if (to->tree == NULL) { + to->tree = malloc(sizeof(table_tree_t)); + if (to->tree == NULL) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + TREE_INIT(to->tree, compare_dname_table_nodes); + } + + return knot_dname_table_copy_node(from->tree->th_root, + &to->tree->th_root); +} + +void knot_dname_table_free(knot_dname_table_t **table) +{ + if (table == NULL || *table == NULL) { + return; + } + + /* Walk the tree and free each node, but not the dnames. */ + TREE_POST_ORDER_APPLY((*table)->tree, dname_table_node, avl, + delete_dname_table_node, 0); + + free((*table)->tree); + + free(*table); + *table = NULL; +} + +void knot_dname_table_deep_free(knot_dname_table_t **table) +{ + if (table == NULL || *table == NULL) { + return; + } + + /* Walk the tree and free each node, but free the dnames. */ + TREE_POST_ORDER_APPLY((*table)->tree, dname_table_node, avl, + delete_dname_table_node, (void *) 1); + + free((*table)->tree); + + free(*table); + *table = NULL; +} + +void knot_dname_table_destroy(knot_dname_table_t **table) +{ + if (table == NULL || *table == NULL) { + return; + } + + /* Walk the tree and free each node, but free the dnames. */ + TREE_POST_ORDER_APPLY((*table)->tree, dname_table_node, avl, + delete_dname_table_node, (void *) 2); + + free((*table)->tree); + + free(*table); + *table = NULL; +} + +void knot_dname_table_tree_inorder_apply(const knot_dname_table_t *table, + void (*applied_function)(knot_dname_t *node, + void *data), + void *data) +{ + struct knot_dname_table_fnc_data d; + d.data = data; + d.func = applied_function; + + TREE_FORWARD_APPLY(table->tree, dname_table_node, avl, + knot_dname_table_apply, &d); +} + diff --git a/src/libknot/zone/dname-table.h b/src/libknot/zone/dname-table.h new file mode 100644 index 0000000..dd86eaf --- /dev/null +++ b/src/libknot/zone/dname-table.h @@ -0,0 +1,168 @@ +/*! + * \file dname-table.h + * + * \author Jan Kadlec <jan.kadlec.@nic.cz> + * + * \brief Structures representing dname table and functions for + * manipulating these structures. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_DNAME_TABLE_H_ +#define _KNOT_DNAME_TABLE_H_ + +#include <config.h> + +#include "common/tree.h" + +#include "dname.h" +#include "common.h" + + +/*! + * \brief Structure encapsulating + */ +struct dname_table_node { + knot_dname_t *dname; /*!< Dname stored in node. */ + TREE_ENTRY(dname_table_node) avl; /*!< Tree variables. */ +}; + +/*! + * \brief Tree structure. + */ +typedef TREE_HEAD(avl, dname_table_node) table_tree_t; + +/*! + * \brief Structure holding tree together with dname ID counter. + */ +struct knot_dname_table { + unsigned int id_counter; /*!< ID counter (starts from 1) */ + table_tree_t *tree; /*!< AVL tree */ +}; + +typedef struct knot_dname_table knot_dname_table_t; + +/*! + * \brief Creates new empty domain name table. + * + * \retval Created table on success. + * \retval NULL on memory error. + */ +knot_dname_table_t *knot_dname_table_new(); + +/*! + * \brief Finds name in the domain name table. + * + * \note Reference count to dname will be incremented, caller is responsible + * for releasing it. + * + * \param table Domain name table to be searched. + * \param dname Dname to be searched. + * + * \retval Pointer to found dname when dname is present in the table. + * \retval NULL when dname is not present. + */ +knot_dname_t *knot_dname_table_find_dname(const knot_dname_table_t *table, + knot_dname_t *dname); + +/*! + * \brief Adds domain name to domain name table. + * + * \param table Domain name table to be added to. + * \param dname Domain name to be added. + * + * \warning Function does not check for duplicates! + * + * \note This function encapsulates dname in a structure and saves it to a tree. + * + * \retval KNOT_EOK on success. + * \retval KNOT_ENOMEM when memory runs out. + */ +int knot_dname_table_add_dname(knot_dname_table_t *table, + knot_dname_t *dname); + +/*! + * \brief Adds domain name to domain name table and checks for duplicates. + * + * \param table Domain name table to be added to. + * \param dname Domain name to be added. + * + * \note This function encapsulates dname in a structure and saves it to a tree. + * \note If a duplicate is found, \a dname is replaced by the name from table. + * + * \retval KNOT_EOK on success. + * \retval KNOT_ENOMEM when memory runs out. + */ +int knot_dname_table_add_dname_check(knot_dname_table_t *table, + knot_dname_t **dname); + +/*! + * \brief Creates a shallow copy of the domain name table. + * + * Expects an existing knot_dname_table_t structure to be passed via \a to, + * and fills it with the same data (domain names) as the original. Actual + * tree nodes are created, but domain names are not copied (just referenced). + * + * \param from Original domain name table. + * \param to Copy of the domain name table. + */ +int knot_dname_table_shallow_copy(knot_dname_table_t *from, + knot_dname_table_t *to); + +/*! + * \brief Frees dname table without its nodes. Sets pointer to NULL. + * + * \param table Table to be freed. + */ +void knot_dname_table_free(knot_dname_table_t **table); + +/*! + * \brief Frees dname table and all its nodes (and release dnames in the nodes) + * Sets pointer to NULL. + * + * \param table Table to be freed. + */ +void knot_dname_table_deep_free(knot_dname_table_t **table); + +/*! + * \brief Frees dname table and all its nodes (including dnames in the nodes) + * Sets pointer to NULL. + * + * \param table Table to be freed. + */ +void knot_dname_table_destroy(knot_dname_table_t **table); + +/*! + * \brief Encapsulation of domain name table tree traversal function. + * + * \param table Table containing tree to be traversed. + * \param applied_function Function to be used to process nodes. + * \param data Data to be passed to processing function. + */ +void knot_dname_table_tree_inorder_apply(const knot_dname_table_t *table, + void (*applied_function)(knot_dname_t *dname, + void *data), + void *data); + + +#endif // _KNOT_DNAME_TABLE_H_ + +/*! @} */ + diff --git a/src/libknot/zone/node.c b/src/libknot/zone/node.c new file mode 100644 index 0000000..1d2f938 --- /dev/null +++ b/src/libknot/zone/node.c @@ -0,0 +1,906 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> + +#include <urcu.h> + +#include "common.h" +#include "zone/node.h" +#include "rrset.h" +#include "util/error.h" +#include "common/skip-list.h" +#include "common/tree.h" +#include "util/debug.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns the delegation point flag + * + * \param flags Flags to retrieve the flag from. + * + * \return A byte with only the delegation point flag set if it was set in + * \a flags. + */ +static inline uint8_t knot_node_flags_get_deleg(uint8_t flags) +{ + return flags & KNOT_NODE_FLAGS_DELEG; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets the delegation point flag. + * + * \param flags Flags to set the flag in. + */ +static inline void knot_node_flags_set_deleg(uint8_t *flags) +{ + *flags |= KNOT_NODE_FLAGS_DELEG; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns the non-authoritative node flag + * + * \param flags Flags to retrieve the flag from. + * + * \return A byte with only the non-authoritative node flag set if it was set in + * \a flags. + */ +static inline uint8_t knot_node_flags_get_nonauth(uint8_t flags) +{ + return flags & KNOT_NODE_FLAGS_NONAUTH; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets the non-authoritative node flag. + * + * \param flags Flags to set the flag in. + */ +static inline void knot_node_flags_set_nonauth(uint8_t *flags) +{ + *flags |= KNOT_NODE_FLAGS_NONAUTH; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns the old node flag + * + * \param flags Flags to retrieve the flag from. + * + * \return A byte with only the old node flag set if it was set in \a flags. + */ +static inline uint8_t knot_node_flags_get_old(uint8_t flags) +{ + return flags & KNOT_NODE_FLAGS_OLD; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets the old node flag. + * + * \param flags Flags to set the flag in. + */ +static inline void knot_node_flags_set_new(uint8_t *flags) +{ + *flags |= KNOT_NODE_FLAGS_NEW; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns the new node flag + * + * \param flags Flags to retrieve the flag from. + * + * \return A byte with only the new node flag set if it was set in \a flags. + */ +static inline uint8_t knot_node_flags_get_new(uint8_t flags) +{ + return flags & KNOT_NODE_FLAGS_NEW; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets the new node flag. + * + * \param flags Flags to set the flag in. + */ +static inline void knot_node_flags_set_old(uint8_t *flags) +{ + *flags |= KNOT_NODE_FLAGS_OLD; +} + +/*----------------------------------------------------------------------------*/ + +static inline void knot_node_flags_clear_new(uint8_t *flags) +{ + *flags &= ~KNOT_NODE_FLAGS_NEW; +} + +/*----------------------------------------------------------------------------*/ + +static inline void knot_node_flags_clear_old(uint8_t *flags) +{ + *flags &= ~KNOT_NODE_FLAGS_OLD; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Compares the two keys as RR types. + * + * \note This function may be used in data structures requiring generic + * comparation function. + * + * \param key1 First RR type. + * \param key2 Second RR type. + * + * \retval 0 if \a key1 is equal to \a key2. + * \retval < 0 if \a key1 is lower than \a key2. + * \retval > 0 if \a key1 is higher than \a key2. + */ +static int compare_rrset_types(void *rr1, void *rr2) +{ + knot_rrset_t *rrset1 = (knot_rrset_t *)rr1; + knot_rrset_t *rrset2 = (knot_rrset_t *)rr2; + return ((rrset1->type > rrset2->type) ? 1 : + (rrset1->type == rrset2->type) ? 0 : -1); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_node_zone_gen_is_new(const knot_node_t *node) +{ + assert(node->zone != NULL); + knot_zone_contents_t *cont = rcu_dereference(node->zone->contents); + assert(cont != NULL); + return knot_zone_contents_gen_is_new(cont); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_node_zone_gen_is_old(const knot_node_t *node) +{ + assert(node->zone != NULL); + knot_zone_contents_t *cont = rcu_dereference(node->zone->contents); + assert(cont != NULL); + return knot_zone_contents_gen_is_old(cont); +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent, + uint8_t flags) +{ + knot_node_t *ret = (knot_node_t *)calloc(1, sizeof(knot_node_t)); + if (ret == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + /* Store reference to owner. */ + knot_dname_retain(owner); + ret->owner = owner; + knot_node_set_parent(ret, parent); + ret->rrset_tree = gen_tree_new(compare_rrset_types); + ret->flags = flags; + + assert(ret->children == 0); + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, + int merge) +{ + int ret = 0; + + if ((ret = (gen_tree_add(node->rrset_tree, rrset, + (merge) ? knot_rrset_merge : NULL))) < 0) { + dbg_node("Failed to add rrset to node->rrset_tree.\n"); + return KNOT_ERROR; + } + + if (ret >= 0) { + node->rrset_count += (ret > 0 ? 0 : 1); + return ret; + } else { + return KNOT_ERROR; + } +} + +/*----------------------------------------------------------------------------*/ + +const knot_rrset_t *knot_node_rrset(const knot_node_t *node, + uint16_t type) +{ + assert(node != NULL); + assert(node->rrset_tree != NULL); + knot_rrset_t rrset; + rrset.type = type; + return (const knot_rrset_t *)gen_tree_find(node->rrset_tree, &rrset); +} + +/*----------------------------------------------------------------------------*/ + +knot_rrset_t *knot_node_get_rrset(knot_node_t *node, uint16_t type) +{ + knot_rrset_t rrset; + rrset.type = type; + return (knot_rrset_t *)gen_tree_find(node->rrset_tree, &rrset); +} + +/*----------------------------------------------------------------------------*/ + +knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type) +{ + knot_rrset_t dummy_rrset; + dummy_rrset.type = type; + knot_rrset_t *rrset = + (knot_rrset_t *)gen_tree_find(node->rrset_tree, &dummy_rrset); + if (rrset != NULL) { + gen_tree_remove(node->rrset_tree, rrset); + node->rrset_count--; + } + return rrset; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_remove_all_rrsets(knot_node_t *node) +{ + // remove RRSets but do not delete them + gen_tree_clear(node->rrset_tree); + node->rrset_count = 0; + +} + +/*----------------------------------------------------------------------------*/ + +short knot_node_rrset_count(const knot_node_t *node) +{ + return node->rrset_count; +} + +/*----------------------------------------------------------------------------*/ + +struct knot_node_save_rrset_arg { + knot_rrset_t **array; + size_t count; +}; + +static void save_rrset_to_array(void *node, void *data) +{ + knot_rrset_t *rrset = (knot_rrset_t *)node; + struct knot_node_save_rrset_arg *args = + (struct knot_node_save_rrset_arg *)data; + args->array[args->count++] = rrset; +} + +knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node) +{ +// knot_node_dump(node, 1); + if (node->rrset_count == 0) { + return NULL; + } + knot_rrset_t **rrsets = (knot_rrset_t **)malloc( + node->rrset_count * sizeof(knot_rrset_t *)); + CHECK_ALLOC_LOG(rrsets, NULL); + struct knot_node_save_rrset_arg args; + args.array = rrsets; + args.count = 0; + + gen_tree_apply_inorder(node->rrset_tree, save_rrset_to_array, + &args); + + assert(args.count == node->rrset_count); + + return rrsets; +} + +/*----------------------------------------------------------------------------*/ + +const knot_rrset_t **knot_node_rrsets(const knot_node_t *node) +{ + //knot_node_dump((knot_node_t *)node, (void*)1); + if (node->rrset_count == 0) { + return NULL; + } + + knot_rrset_t **rrsets = (knot_rrset_t **)malloc( + node->rrset_count * sizeof(knot_rrset_t *)); + CHECK_ALLOC_LOG(rrsets, NULL); + struct knot_node_save_rrset_arg args; + args.array = rrsets; + args.count = 0; + + gen_tree_apply_inorder(node->rrset_tree, save_rrset_to_array, + &args); + + assert(args.count == node->rrset_count); + assert(args.count); + + return (const knot_rrset_t **)rrsets; + +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_node_parent(const knot_node_t *node, + int check_version) +{ +// assert(!check_version +// || (node->zone != NULL && node->zone->contents != NULL)); + + knot_node_t *parent = node->parent; + + if (check_version && node->zone != NULL) { + int new_gen = knot_node_zone_gen_is_new(node); +// short ver = knot_node_zone_generation(node); + + /*! \todo Remove, this will not be true during the reference + * fixing. + */ +// assert(new_gen || parent == NULL +// || !knot_node_is_new(parent)); + + if (new_gen && parent != NULL) { + // we want the new node + assert(node->parent->new_node != NULL); + parent = parent->new_node; + } + } + + return parent; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_parent(knot_node_t *node, knot_node_t *parent) +{ + // decrease number of children of previous parent + if (node->parent != NULL) { + --parent->children; + } + // set the parent + node->parent = parent; + + // increase the count of children of the new parent + if (parent != NULL) { + ++parent->children; + } +} + +/*----------------------------------------------------------------------------*/ + +unsigned int knot_node_children(const knot_node_t *node) +{ + return node->children; +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_node_previous(const knot_node_t *node, + int check_version) +{ + return knot_node_get_previous(node, check_version); +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_node_get_previous(const knot_node_t *node, + int check_version) +{ + assert(!check_version + || (node->zone != NULL && node->zone->contents != NULL)); + + knot_node_t *prev = node->prev; + + if (check_version && prev != NULL) { + int new_gen = knot_node_zone_gen_is_new(node); + int old_gen = knot_node_zone_gen_is_old(node); +// short ver = knot_node_zone_generation(node); + + if (old_gen) { // we want old node + while (knot_node_is_new(prev)) { + prev = prev->prev; + } + assert(!knot_node_is_new(prev)); + } else if (new_gen) { // we want new node + while (knot_node_is_old(prev)) { + if (prev->new_node) { + prev = prev->new_node; + } else { + prev = prev; + } + } + assert(knot_node_is_new(prev)); + } + } + + return prev; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_previous(knot_node_t *node, knot_node_t *prev) +{ + node->prev = prev; + if (prev != NULL) { + // set the prev pointer of the next node to the given node + if (prev->next != NULL) { + assert(prev->next->prev == prev); + prev->next->prev = node; + } + node->next = prev->next; + prev->next = node; + } +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_node_nsec3_node(const knot_node_t *node, + int check_version) +{ + knot_node_t *nsec3_node = node->nsec3_node; + if (nsec3_node == NULL) { + return NULL; + } + + if (check_version) { + int new_gen = knot_node_zone_gen_is_new(node); + int old_gen = knot_node_zone_gen_is_old(node); +// short ver = knot_node_zone_generation(node); + assert(new_gen || !knot_node_is_new(nsec3_node)); + if (old_gen && knot_node_is_new(nsec3_node)) { + return NULL; + } else if (new_gen && knot_node_is_old(nsec3_node)) { + nsec3_node = nsec3_node->new_node; + } + } + + return nsec3_node; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node) +{ + node->nsec3_node = nsec3_node; + if (nsec3_node != NULL) { + nsec3_node->nsec3_referer = node; + } +} + +/*----------------------------------------------------------------------------*/ + +const knot_dname_t *knot_node_owner(const knot_node_t *node) +{ + return node->owner; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_node_get_owner(const knot_node_t *node) +{ + return node->owner; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_owner(knot_node_t *node, knot_dname_t* owner) +{ + if (node) { + /* Retain new owner and release old owner. */ + knot_dname_retain(owner); + knot_dname_release(node->owner); + node->owner = owner; + } +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_node_wildcard_child(const knot_node_t *node, + int check_version) +{ + knot_node_t *w = node->wildcard_child; + + if (check_version && w != 0) { + int new_gen = knot_node_zone_gen_is_new(node); + int old_gen = knot_node_zone_gen_is_old(node); +// short ver = knot_node_zone_generation(node); + + if (old_gen && knot_node_is_new(w)) { + return NULL; + } else if (new_gen && knot_node_is_old(w)) { + assert(w->new_node != NULL); + w = w->new_node; + } + } + + return w; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_wildcard_child(knot_node_t *node, + knot_node_t *wildcard_child) +{ + node->wildcard_child = wildcard_child; +// assert(wildcard_child->parent == node); +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_node_current(const knot_node_t *node) +{ + if (node == NULL || node->zone == NULL + || knot_zone_contents(node->zone) == NULL) { + return node; + } + + int new_gen = knot_node_zone_gen_is_new(node); + int old_gen = knot_node_zone_gen_is_old(node); +// short ver = knot_node_zone_generation(node); + + if (old_gen && knot_node_is_new(node)) { + return NULL; + } else if (new_gen && knot_node_is_old(node)) { + assert(node->new_node != NULL); + return node->new_node; + } + return node; +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_node_get_current(knot_node_t *node) +{ + if (node == NULL || node->zone == NULL + || knot_zone_contents(node->zone) == NULL) { + return node; + } + + int new_gen = knot_node_zone_gen_is_new(node); + int old_gen = knot_node_zone_gen_is_old(node); +// short ver = knot_node_zone_generation(node); + + if (old_gen && knot_node_is_new(node)) { + return NULL; + } else if (new_gen && knot_node_is_old(node)) { + assert(node->new_node != NULL); + return node->new_node; + } + + assert((old_gen && knot_node_is_old(node)) + || (new_gen && knot_node_is_new(node)) + || (!old_gen && !new_gen)); + + return node; +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_node_new_node(const knot_node_t *node) +{ + return node->new_node; +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_node_get_new_node(const knot_node_t *node) +{ + return node->new_node; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_new_node(knot_node_t *node, + knot_node_t *new_node) +{ + node->new_node = new_node; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone) +{ + node->zone = zone; +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_update_ref(knot_node_t **ref) +{ + if (*ref != NULL && knot_node_is_old(*ref)) { + *ref = (*ref)->new_node; + } +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_update_refs(knot_node_t *node) +{ + /* CLEANUP */ + /* OMG! */ + // reference to previous node + knot_node_update_ref(&node->prev); +// if (node->prev && knot_node_is_old(node->prev)) { +// assert(node->prev->new_node != NULL); +// node->prev = node->prev->new_node; +// } + + // reference to next node + knot_node_update_ref(&node->next); +// if (node->next && knot_node_is_old(node->next)) { +// assert(node->next->new_node != NULL); +// node->next = node->next->new_node; +// } + + // reference to parent +// if (node->parent && knot_node_is_old(node->parent)) { +// assert(node->parent->new_node != NULL); +// // do not use the API function to set parent, so that children count +// // is not changed +// //knot_node_set_parent(node, node->parent->new_node); +// node->parent = node->parent->new_node; +// } + knot_node_update_ref(&node->parent); + + // reference to wildcard child + knot_node_update_ref(&node->wildcard_child); +// if (node->wildcard_child && knot_node_is_old(node->wildcard_child)) { +// assert(node->wildcard_child->new_node != NULL); +// node->wildcard_child = node->wildcard_child->new_node; +// } + + // reference to NSEC3 node + knot_node_update_ref(&node->nsec3_node); +// if (node->nsec3_node && knot_node_is_old(node->nsec3_node)) { +// assert(node->nsec3_node->new_node != NULL); +// node->nsec3_node = node->nsec3_node->new_node; +// } + + // reference to NSEC3 referrer + knot_node_update_ref(&node->nsec3_referer); +// if (node->nsec3_referer && knot_node_is_old(node->nsec3_referer)) { +// assert(node->nsec3_referer->new_node != NULL); +// node->nsec3_referer = node->nsec3_referer->new_node; +// } +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_deleg_point(knot_node_t *node) +{ + knot_node_flags_set_deleg(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_is_deleg_point(const knot_node_t *node) +{ + return knot_node_flags_get_deleg(node->flags); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_non_auth(knot_node_t *node) +{ + knot_node_flags_set_nonauth(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_is_non_auth(const knot_node_t *node) +{ + return knot_node_flags_get_nonauth(node->flags); +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_is_auth(const knot_node_t *node) +{ + return (node->flags == 0); +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_is_new(const knot_node_t *node) +{ + return knot_node_flags_get_new(node->flags); +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_is_old(const knot_node_t *node) +{ + return knot_node_flags_get_old(node->flags); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_new(knot_node_t *node) +{ + knot_node_flags_set_new(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_old(knot_node_t *node) +{ + knot_node_flags_set_old(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_clear_new(knot_node_t *node) +{ + knot_node_flags_clear_new(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_clear_old(knot_node_t *node) +{ + knot_node_flags_clear_old(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + +static void knot_node_free_rrsets_from_tree(void *item, void *data) +{ + if (item == NULL) { + return; + } + + knot_rrset_t *rrset = (knot_rrset_t *)(item); + knot_rrset_deep_free(&rrset, 0, 1, *((int *)data)); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames) +{ + /* CLEANUP */ +// knot_rrset_t **rrsets = knot_node_get_rrsets(node); +// for (int i = 0; i < node->rrset_count; i++) { +// knot_rrset_deep_free(&(rrsets[i]), 0, 1, free_rdata_dnames); +// } + +// free(rrsets); + + char *name = knot_dname_to_str(node->owner); + free(name); + + gen_tree_destroy(&node->rrset_tree, knot_node_free_rrsets_from_tree, + (void *)&free_rdata_dnames); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_free(knot_node_t **node, int free_owner, int fix_refs) +{ + if (node == NULL || *node == NULL) { + return; + } + + dbg_node("Freeing node.\n"); + if ((*node)->rrset_tree != NULL) { + dbg_node("Freeing RRSets.\n"); + gen_tree_destroy(&(*node)->rrset_tree, NULL, NULL); + } + + /*! \todo Always release owner? */ + //if (free_owner) { + dbg_node("Releasing owner.\n"); + knot_dname_release((*node)->owner); + //} + + // check nodes referencing this node and fix the references + + if (fix_refs) { + // previous node + dbg_node("Checking previous.\n"); + if ((*node)->prev && (*node)->prev->next == (*node)) { + (*node)->prev->next = (*node)->next; + } + + dbg_node("Checking next.\n"); + if ((*node)->next && (*node)->next->prev == (*node)) { + (*node)->next->prev = (*node)->prev; + } + + // NSEC3 node + dbg_node("Checking NSEC3.\n"); + if ((*node)->nsec3_node + && (*node)->nsec3_node->nsec3_referer == (*node)) { + (*node)->nsec3_node->nsec3_referer = NULL; + } + + dbg_node("Checking NSEC3 ref.\n"); + if ((*node)->nsec3_referer + && (*node)->nsec3_referer->nsec3_node == (*node)) { + (*node)->nsec3_referer->nsec3_node = NULL; + } + + // wildcard child node + dbg_node("Checking parent's wildcard child.\n"); + if ((*node)->parent + && (*node)->parent->wildcard_child == (*node)) { + (*node)->parent->wildcard_child = NULL; + } + + // fix parent's children count + if ((*node)->parent) { + --(*node)->parent->children; + } + } + + free(*node); + *node = NULL; + + dbg_node("Done.\n"); +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_compare(knot_node_t *node1, knot_node_t *node2) +{ + return knot_dname_compare(node1->owner, node2->owner); +} + +/*----------------------------------------------------------------------------*/ + +int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to) +{ + // create new node + *to = knot_node_new(from->owner, from->parent, from->flags); + if (*to == NULL) { + return KNOT_ENOMEM; + } + + /* Free old rrset_tree, as it will be replaced by shallow copy. */ + gen_tree_destroy(&(*to)->rrset_tree, 0, 0); + + // copy references + // do not use the API function to set parent, so that children count + // is not changed + memcpy(*to, from, sizeof(knot_node_t)); + + // copy RRSets + // copy the skip list with the old references + /* CLEANUP */ + (*to)->rrset_tree = gen_tree_shallow_copy(from->rrset_tree); +// assert((*to)->rrset_tree != from->rrset_tree); +// (*to)->rrsets = skip_copy_list(from->rrsets); + if ((*to)->rrset_tree == NULL) { + free(*to); + *to = NULL; + return KNOT_ENOMEM; + } + + return KNOT_EOK; +} diff --git a/src/libknot/zone/node.h b/src/libknot/zone/node.h new file mode 100644 index 0000000..fcb612d --- /dev/null +++ b/src/libknot/zone/node.h @@ -0,0 +1,436 @@ +/*! + * \file node.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Structure representing one node in domain name tree and API for + * manipulating it. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_NODE_H_ +#define _KNOT_NODE_H_ + +#include "dname.h" +#include "common/skip-list.h" +#include "rrset.h" +#include "common/tree.h" +#include "common/general-tree.h" + +struct knot_zone; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Structure representing one node in a domain name tree, i.e. one domain + * name in a zone. + * + * RRSets are ordered by type and stored in a skip-list to allow fast lookup. + */ +struct knot_node { + knot_dname_t *owner; /*!< Domain name being the owner of this node. */ + struct knot_node *parent; /*!< Parent node in the name hierarchy. */ + + /*! \brief Type-ordered list of RRSets belonging to this node. */ + general_tree_t *rrset_tree; + + unsigned short rrset_count; /*!< Number of RRSets stored in the node. */ + + /*! \brief Wildcard node being the direct descendant of this node. */ + struct knot_node *wildcard_child; + + /*! + * \brief Previous node in canonical order. + * + * Only authoritative nodes or delegation points are referenced by this, + * as only they may contain NSEC records needed for authenticating + * negative answers. + */ + struct knot_node *prev; + + struct knot_node *next; + + /*! + * \brief NSEC3 node corresponding to this node. + * + * Such NSEC3 node has owner in form of the hashed domain name of this + * node prepended as a single label to the zone name. + */ + struct knot_node *nsec3_node; + + struct knot_node *nsec3_referer; + + /*! + * \brief Various flags. + * + * Currently only two: + * 0x01 - node is a delegation point + * 0x02 - node is non-authoritative (under a delegation point) + * 0x80 - node is old and will be removed (during update) + * 0x40 - node is new, should not be used while zone is old + */ + uint8_t flags; + + struct knot_node *new_node; + + unsigned int children; + + /*! + * \brief Generation of node to be used. + * + * If set to 0, the old node will be used. Otherwise new nodes will + * be used. This applies when getting some referenced node. + + */ +// short **generation; + + struct knot_zone *zone; +}; + +typedef struct knot_node knot_node_t; + +/*----------------------------------------------------------------------------*/ +/*! \brief Flags used to mark nodes with some property. */ +typedef enum { + /*! \brief Node is a delegation point (i.e. marking a zone cut). */ + KNOT_NODE_FLAGS_DELEG = (uint8_t)0x01, + /*! \brief Node is not authoritative (i.e. below a zone cut). */ + KNOT_NODE_FLAGS_NONAUTH = (uint8_t)0x02, + /*! \brief Node is old and will be removed (during update). */ + KNOT_NODE_FLAGS_OLD = (uint8_t)0x80, + /*! \brief Node is new and should not be used while zoen is old. */ + KNOT_NODE_FLAGS_NEW = (uint8_t)0x40 +} knot_node_flags_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates and initializes new node structure. + * + * \todo Owner reference counter will be increased. + * + * \param owner Owner of the created node. + * \param parent Parent of the created node. + * \param flags Document me. + * + * \todo Document missing parameters. + * + * \return Newly created node or NULL if an error occured. + */ +knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent, + uint8_t flags); + +/*! + * \brief Adds an RRSet to the node. + * + * \param node Node to add the RRSet to. + * \param rrset RRSet to add. + * + * \retval KNOT_EOK on success. + * \retval KNOT_ERROR if the RRSet could not be inserted. + */ +int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, + int merge); + +/*! + * \brief Returns the RRSet of the given type from the node. + * + * \param node Node to get the RRSet from. + * \param type Type of the RRSet to retrieve. + * + * \return RRSet from node \a node having type \a type, or NULL if no such + * RRSet exists in this node. + */ +const knot_rrset_t *knot_node_rrset(const knot_node_t *node, + uint16_t type); + +/*! + * \brief Returns the RRSet of the given type from the node (non-const version). + * + * \param node Node to get the RRSet from. + * \param type Type of the RRSet to retrieve. + * + * \return RRSet from node \a node having type \a type, or NULL if no such + * RRSet exists in this node. + */ +knot_rrset_t *knot_node_get_rrset(knot_node_t *node, uint16_t type); + +knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type); + +void knot_node_remove_all_rrsets(knot_node_t *node); + +/*! + * \brief Returns number of RRSets in the node. + * + * \param node Node to get the RRSet count from. + * + * \return Number of RRSets in \a node. + */ +short knot_node_rrset_count(const knot_node_t *node); + +/*! + * \brief Returns all RRSets from the node. + * + * \param node Node to get the RRSets from. + * + * \return Newly allocated array of RRSets or NULL if an error occured. + */ +knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node); + +/*! + * \brief Returns all RRSets from the node. + * + * \note This function is identical to knot_node_get_rrsets(), only it returns + * non-modifiable data. + * + * \param node Node to get the RRSets from. + * + * \return Newly allocated array of RRSets or NULL if an error occured. + */ +const knot_rrset_t **knot_node_rrsets(const knot_node_t *node); + +/*! + * \brief Returns the parent of the node. + * + * \param node Node to get the parent of. + * + * \return Parent node of the given node or NULL if no parent has been set (e.g. + * node in a zone apex has no parent). + */ +const knot_node_t *knot_node_parent(const knot_node_t *node, + int check_version); + +/*! + * \brief Sets the parent of the node. + * + * \param node Node to set the parent of. + * \param parent Parent to set to the node. + */ +void knot_node_set_parent(knot_node_t *node, knot_node_t *parent); + +unsigned int knot_node_children(const knot_node_t *node); + +/*! + * \brief Returns the previous authoritative node or delegation point in + * canonical order or the first node in zone. + * + * \param node Node to get the previous node of. + * + * \return Previous authoritative node or delegation point in canonical order or + * the first node in zone if \a node is the last node in zone. + * \retval NULL if previous node is not set. + */ +const knot_node_t *knot_node_previous(const knot_node_t *node, + int check_version); + +/*! + * \brief Returns the previous authoritative node or delegation point in + * canonical order or the first node in zone. + * + * \note This function is identical to knot_node_previous() except that it + * returns non-const node. + * + * \param node Node to get the previous node of. + * + * \return Previous authoritative node or delegation point in canonical order or + * the first node in zone if \a node is the last node in zone. + * \retval NULL if previous node is not set. + */ +knot_node_t *knot_node_get_previous(const knot_node_t *node, + int check_version); + +/*! + * \brief Sets the previous node of the given node. + * + * \param node Node to set the previous node to. + * \param prev Previous node to set. + */ +void knot_node_set_previous(knot_node_t *node, knot_node_t *prev); + +/*! + * \brief Returns the NSEC3 node corresponding to the given node. + * + * \param node Node to get the NSEC3 node for. + * + * \return NSEC3 node corresponding to \a node (i.e. node with owner name + * created by concatenating the hash of owner domain name of \a node + * and the name of the zone \a node belongs to). + * \retval NULL if the NSEC3 node is not set. + */ +const knot_node_t *knot_node_nsec3_node(const knot_node_t *node, + int check_version); + +/*! + * \brief Sets the corresponding NSEC3 node of the given node. + * + * \param node Node to set the NSEC3 node to. + * \param nsec3_node NSEC3 node to set. + */ +void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node); + +/*! + * \brief Returns the owner of the node. + * + * \param node Node to get the owner of. + * + * \return Owner of the given node. + */ +const knot_dname_t *knot_node_owner(const knot_node_t *node); + +/*! + * \todo Document me. + */ +knot_dname_t *knot_node_get_owner(const knot_node_t *node); + +/*! + * \brief Set node owner to specified dname. + * + * Previous owner will be replaced if exist. + * + * \param node Specified node. + * \param owner New owner dname. + */ +void knot_node_set_owner(knot_node_t *node, knot_dname_t* owner); + +/*! + * \brief Returns the wildcard child of the node. + * + * \param node Node to get the owner of. + * + * \return Wildcard child of the given node or NULL if it has none. + */ +const knot_node_t *knot_node_wildcard_child(const knot_node_t *node, + int check_version); + +/*! + * \brief Sets the wildcard child of the node. + * + * \param node Node to set the wildcard child of. + * \param wildcard_child Wildcard child of the node. + */ +void knot_node_set_wildcard_child(knot_node_t *node, + knot_node_t *wildcard_child); + +const knot_node_t *knot_node_current(const knot_node_t *node); + +knot_node_t *knot_node_get_current(knot_node_t *node); + +const knot_node_t *knot_node_new_node(const knot_node_t *node); + +knot_node_t *knot_node_get_new_node(const knot_node_t *node); + +void knot_node_set_new_node(knot_node_t *node, + knot_node_t *new_node); + +void knot_node_set_zone(knot_node_t *node, struct knot_zone *zone); + +void knot_node_update_ref(knot_node_t **ref); + +void knot_node_update_refs(knot_node_t *node); + +/*! + * \brief Mark the node as a delegation point. + * + * \param node Node to mark as a delegation point. + */ +void knot_node_set_deleg_point(knot_node_t *node); + +/*! + * \brief Checks if the node is a delegation point. + * + * \param node Node to check. + * + * \retval <> 0 if \a node is marked as delegation point. + * \retval 0 otherwise. + */ +int knot_node_is_deleg_point(const knot_node_t *node); + +/*! + * \brief Mark the node as non-authoritative. + * + * \param node Node to mark as non-authoritative. + */ +void knot_node_set_non_auth(knot_node_t *node); + +/*! + * \brief Checks if the node is non-authoritative. + * + * \param node Node to check. + * + * \retval <> 0 if \a node is marked as non-authoritative. + * \retval 0 otherwise. + */ +int knot_node_is_non_auth(const knot_node_t *node); + +int knot_node_is_auth(const knot_node_t *node); + +int knot_node_is_new(const knot_node_t *node); + +int knot_node_is_old(const knot_node_t *node); + +void knot_node_set_new(knot_node_t *node); + +void knot_node_set_old(knot_node_t *node); + +void knot_node_clear_new(knot_node_t *node); + +void knot_node_clear_old(knot_node_t *node); + +/*! + * \brief Destroys the RRSets within the node structure. + * + * \param node Node to be destroyed. + * \param free_rdata_dnames Set to <> 0 if you want to delete ALL domain names + * present in RDATA. Set to 0 otherwise. (See + * knot_rdata_deep_free().) + */ +void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames); + +/*! + * \brief Destroys the node structure. + * + * Does not destroy the RRSets within the node. + * Also sets the given pointer to NULL. + * + * \param node Node to be destroyed. + * \param free_owner Set to 0 if you do not want the owner domain name to be + * destroyed also. Set to <> 0 otherwise. + * \param fix_refs + * + * \todo Document missing parameters. + */ +void knot_node_free(knot_node_t **node, int free_owner, int fix_refs); + +/*! + * \brief Compares two nodes according to their owner. + * + * \param node1 First node. + * \param node2 Second node. + * + * \retval < 0 if \a node1 goes before \a node2 according to canonical order + * of their owner names. + * \retval 0 if they are equal. + * \retval > 0 if \a node1 goes after \a node2. + */ +int knot_node_compare(knot_node_t *node1, knot_node_t *node2); + +int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to); + +#endif /* _KNOT_NODE_H_ */ + +/*! @} */ diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c new file mode 100644 index 0000000..d550728 --- /dev/null +++ b/src/libknot/zone/zone-contents.c @@ -0,0 +1,2396 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "zone/zone-contents.h" +#include "util/error.h" +#include "util/debug.h" +#include "common/base32hex.h" +#include "consts.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ + +typedef struct { + void (*func)(knot_node_t *, void *); + void *data; +} knot_zone_tree_func_t; + +typedef struct { + knot_node_t *first_node; + knot_zone_contents_t *zone; + knot_node_t *previous_node; + int check_ver; +} knot_zone_adjust_arg_t; + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_tree_apply(knot_zone_tree_node_t *node, + void *data) +{ + if (node == NULL || data == NULL) { + return; + } + + knot_zone_tree_func_t *f = (knot_zone_tree_func_t *)data; + f->func(node->node, f->data); +} + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Checks if the given node can be inserted into the given zone. + * + * Checks if both the arguments are non-NULL and if the owner of the node + * belongs to the zone (i.e. is a subdomain of the zone apex). + * + * \param zone Zone to which the node is going to be inserted. + * \param node Node to check. + * + * \retval KNOT_EOK if both arguments are non-NULL and the node belongs to the + * zone. + * \retval KNOT_EBADARG if either of the arguments is NULL. + * \retval KNOT_EBADZONE if the node does not belong to the zone. + */ +static int knot_zone_contents_check_node( + const knot_zone_contents_t *contents, const knot_node_t *node) +{ + if (contents == NULL || node == NULL) { + return KNOT_EBADARG; + } + + // assert or just check?? + assert(contents->apex != NULL); + + if (!knot_dname_is_subdomain(node->owner, + knot_node_owner(contents->apex))) { +dbg_zone_exec( + char *node_owner = knot_dname_to_str(knot_node_owner(node)); + char *apex_owner = knot_dname_to_str(contents->apex->owner); + dbg_zone("zone: Trying to insert foreign node to a " + "zone. Node owner: %s, zone apex: %s\n", + node_owner, apex_owner); + free(node_owner); + free(apex_owner); +); + return KNOT_EBADZONE; + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Destroys all RRSets in a node. + * + * This function is designed to be used in the tree-iterating functions. + * + * \param node Node to destroy RRSets from. + * \param data Unused parameter. + */ +static void knot_zone_contents_destroy_node_rrsets_from_tree( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(tnode != NULL); + assert(tnode->node != NULL); + + int free_rdata_dnames = (int)((intptr_t)data); + knot_node_free_rrsets(tnode->node, free_rdata_dnames); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Destroys node owner. + * + * This function is designed to be used in the tree-iterating functions. + * + * \param node Node to destroy the owner of. + * \param data Unused parameter. + */ +static void knot_zone_contents_destroy_node_owner_from_tree( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(tnode != NULL); + assert(tnode->node != NULL); + + UNUSED(data); + /*!< \todo change completely! */ + knot_node_free(&tnode->node, 0, 0); +} + +/*! + * \brief Finds and sets wildcard child for given node's owner. + * + * \param zone Current zone. + * \param node Node to be used. + */ +static void find_and_set_wildcard_child(knot_zone_contents_t *zone, + knot_node_t *node) +{ + knot_dname_t *chopped = knot_dname_left_chop(node->owner); + assert(chopped); + knot_node_t *wildcard_parent; + wildcard_parent = + knot_zone_contents_get_node(zone, chopped); + + knot_dname_free(&chopped); + + assert(wildcard_parent); /* it *has* to be there */ + + knot_node_set_wildcard_child(wildcard_parent, node); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts one RDATA item by replacing domain name by one present in the + * zone. + * + * This function tries to find the domain name in the zone. If the name is not + * in the zone, it does nothing. If it is there, it destroys the domain name + * stored in the RDATA item and replaces it by pointer to the domain name from + * the zone. + * + * \warning Call this function only with RDATA items which store domain names, + * otherwise the behaviour is undefined. + * + * \param rdata RDATA where the item is located. + * \param zone Zone to which the RDATA belongs. + * \param pos Position of the RDATA item in the RDATA. + */ +static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, + knot_zone_contents_t *zone, + knot_node_t *node, + int pos) +{ + return; + const knot_rdata_item_t *dname_item + = knot_rdata_item(rdata, pos); + + assert(dname_item); + + if (dname_item != NULL) { + knot_dname_t *dname = dname_item->dname; + const knot_node_t *n = NULL; + const knot_node_t *closest_encloser = NULL; + const knot_node_t *prev = NULL; + + if (knot_dname_is_wildcard(dname)) { + find_and_set_wildcard_child(zone, node); + } + + int ret = knot_zone_contents_find_dname(zone, dname, &n, + &closest_encloser, &prev); + + // n = knot_zone_find_node(zone, dname); + + if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) { + // TODO: do some cleanup if needed + return; + } + + assert(ret != KNOT_ZONE_NAME_FOUND + || n == closest_encloser); + + if (ret != KNOT_ZONE_NAME_FOUND + && (closest_encloser != NULL)) { + dbg_zone("Saving closest encloser to RDATA.\n"); + // save pointer to the closest encloser + knot_rdata_item_t *item = + knot_rdata_get_item(rdata, pos); + assert(item->dname != NULL); + assert(item->dname->node == NULL); + //skip_insert(list, (void *)item->dname, + // (void *)closest_encloser->owner, NULL); + item->dname->node = closest_encloser->owner->node; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts all RDATA in the given RRSet by replacing domain names by ones + * present in the zone. + * + * This function selects the RDATA items containing a domain name (according to + * RR type descriptor of the RRSet's type and adjusts the item using + * knot_zone_adjust_rdata_item(). + * + * \param rrset RRSet to adjust RDATA in. + * \param zone Zone to which the RRSet belongs. + */ +static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, + knot_zone_contents_t *zone, + knot_node_t *node) +{ + uint16_t type = knot_rrset_type(rrset); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + assert(desc); + + knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset); + knot_rdata_t *rdata = rdata_first; + + if (rdata == NULL) { + return; + } + + while (rdata->next != rdata_first) { + for (int i = 0; i < rdata->count; ++i) { + if (desc->wireformat[i] + == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_LITERAL_DNAME) { + dbg_zone("Adjusting domain name at " + "position %d of RDATA of record with owner " + "%s and type %s.\n", + i, rrset->owner->name, + knot_rrtype_to_string(type)); + + knot_zone_contents_adjust_rdata_item(rdata, + zone, + node, + i); + } + } + rdata = rdata->next; + } + + for (int i = 0; i < rdata->count; ++i) { + if (desc->wireformat[i] + == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_LITERAL_DNAME) { + dbg_zone("Adjusting domain name at " + "position %d of RDATA of record with owner " + "%s and type %s.\n", + i, rrset->owner->name, + knot_rrtype_to_string(type)); + + knot_zone_contents_adjust_rdata_item(rdata, zone, + node, i); + } + } + +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts all RRSets in the given node by replacing domain names in + * RDATA by ones present in the zone. + * + * This function just calls knot_zone_adjust_rdata_in_rrset() for all RRSets + * in the node (including all RRSIG RRSets). + * + * \param node Zone node to adjust the RRSets in. + * \param zone Zone to which the node belongs. + */ +static void knot_zone_contents_adjust_rrsets(knot_node_t *node, + knot_zone_contents_t *zone) +{ + //return; + knot_rrset_t **rrsets = knot_node_get_rrsets(node); + short count = knot_node_rrset_count(node); + + assert(count == 0 || rrsets != NULL); + + for (int r = 0; r < count; ++r) { + assert(rrsets[r] != NULL); + dbg_zone("Adjusting next RRSet.\n"); + knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone, + node); + knot_rrset_t *rrsigs = rrsets[r]->rrsigs; + if (rrsigs != NULL) { + dbg_zone("Adjusting next RRSIGs.\n"); + knot_zone_contents_adjust_rdata_in_rrset(rrsigs, + zone, + node); + } + } + + free(rrsets); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts zone node for faster query processing. + * + * - Adjusts RRSets in the node (see knot_zone_adjust_rrsets()). + * - Marks the node as delegation point or non-authoritative (below a zone cut) + * if applicable. + * - Stores reference to corresponding NSEC3 node if applicable. + * + * \param node Zone node to adjust. + * \param zone Zone the node belongs to. + */ +static void knot_zone_contents_adjust_node(knot_node_t *node, + knot_zone_contents_t *zone, + int check_ver) +{ + +dbg_zone_exec( + char *name = knot_dname_to_str(node->owner); + dbg_zone("----- Adjusting node %s -----\n", name); + free(name); +); + + // adjust domain names in RDATA + knot_zone_contents_adjust_rrsets(node, zone); + +dbg_zone_exec( + if (knot_node_parent(node, 1)) { + char *name = knot_dname_to_str(knot_node_owner( + knot_node_parent(node, check_ver))); + dbg_zone("Parent: %s\n", name); + dbg_zone("Parent is delegation point: %s\n", + knot_node_is_deleg_point(knot_node_parent(node, check_ver)) + ? "yes" : "no"); + dbg_zone("Parent is non-authoritative: %s\n", + knot_node_is_non_auth(knot_node_parent(node, check_ver)) + ? "yes" : "no"); + free(name); + } else { + dbg_zone("No parent!\n"); + } +); + // delegation point / non-authoritative node + if (knot_node_parent(node, check_ver) + && (knot_node_is_deleg_point(knot_node_parent(node, check_ver)) + || knot_node_is_non_auth(knot_node_parent(node, check_ver)))) { + knot_node_set_non_auth(node); + } else if (knot_node_rrset(node, KNOT_RRTYPE_NS) != NULL + && node != zone->apex) { + knot_node_set_deleg_point(node); + } + + // authorative node? +// if (!knot_node_is_non_auth(node)) { + zone->node_count++; +// } + + // assure that owner has proper node + if (knot_dname_node(knot_node_owner(node), 0) == NULL) { + knot_dname_set_node(knot_node_get_owner(node), node); + knot_dname_set_node(knot_node_get_owner(node), node); + } + + // NSEC3 node (only if NSEC3 tree is not empty) + const knot_node_t *prev; + const knot_node_t *nsec3; + int match = knot_zone_contents_find_nsec3_for_name(zone, + knot_node_owner(node), + &nsec3, &prev, check_ver); + if (match != KNOT_ZONE_NAME_FOUND) { + nsec3 = NULL; + } + + knot_node_set_nsec3_node(node, (knot_node_t *)nsec3); + + dbg_zone("Set flags to the node: \n"); + dbg_zone("Delegation point: %s\n", + knot_node_is_deleg_point(node) ? "yes" : "no"); + dbg_zone("Non-authoritative: %s\n", + knot_node_is_non_auth(node) ? "yes" : "no"); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts zone node for faster query processing. + * + * This function is just a wrapper over knot_zone_adjust_node() to be used + * in tree-traversing functions. + * + * \param node Zone node to adjust. + * \param data Zone the node belongs to. + */ +static void knot_zone_contents_adjust_node_in_tree( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(data != NULL); + assert(tnode != NULL); + assert(tnode->node != NULL); + + knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; + knot_node_t *node = tnode->node; + knot_node_set_previous(node, args->previous_node); + args->previous_node = node; + if (args->first_node == NULL) { + args->first_node = node; + } + knot_zone_contents_t *zone = args->zone; + + knot_zone_contents_adjust_node(node, zone, args->check_ver); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts NSEC3 node for faster query processing. + * + * This function is just a wrapper over knot_zone_adjust_nsec3_node() to be + * used in tree-traversing functions. + * + * \param node Zone node to adjust. + * \param data Zone the node belongs to. + */ +static void knot_zone_contents_adjust_nsec3_node_in_tree( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(data != NULL); + assert(tnode != NULL); + assert(tnode->node != NULL); + + knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; + knot_node_t *node = tnode->node; + knot_node_set_previous(node, args->previous_node); + args->previous_node = node; + if (args->first_node == NULL) { + args->first_node = node; + } + + /* Not needed anymore. */ +// knot_zone_contents_t *zone = args->zone; +// knot_zone_contents_adjust_nsec3_node(node, zone, 1); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Creates a NSEC3 hashed name for the given domain name. + * + * \note The zone's NSEC3PARAM record must be parsed prior to calling this + * function (see knot_zone_load_nsec3param()). + * + * \param zone Zone from which to take the NSEC3 parameters. + * \param name Domain name to hash. + * \param nsec3_name Hashed name. + * + * \retval KNOT_EOK + * \retval KNOT_ENSEC3PAR + * \retval KNOT_ECRYPTO + * \retval KNOT_ERROR if an error occured while creating a new domain name + * from the hash or concatenating it with the zone name. + */ +static int knot_zone_contents_nsec3_name(const knot_zone_contents_t *zone, + const knot_dname_t *name, + knot_dname_t **nsec3_name) +{ + assert(nsec3_name != NULL); + + *nsec3_name = NULL; + + const knot_nsec3_params_t *nsec3_params = + knot_zone_contents_nsec3params(zone); + + if (nsec3_params == NULL) { +dbg_zone_exec( + char *n = knot_dname_to_str(zone->apex->owner); + dbg_zone("No NSEC3PARAM for zone %s.\n", n); + free(n); +); + return KNOT_ENSEC3PAR; + } + + uint8_t *hashed_name = NULL; + size_t hash_size = 0; + +dbg_zone_exec( + char *n = knot_dname_to_str(name); + dbg_zone("Hashing name %s.\n", n); + free(n); +); + + int res = knot_nsec3_sha1(nsec3_params, knot_dname_name(name), + knot_dname_size(name), &hashed_name, + &hash_size); + + if (res != 0) { + char *n = knot_dname_to_str(name); + dbg_zone("Error while hashing name %s.\n", n); + free(n); + return KNOT_ECRYPTO; + } + + dbg_zone("Hash: "); + dbg_zone_hex((char *)hashed_name, hash_size); + dbg_zone("\n"); + + char *name_b32 = NULL; + size_t size = base32hex_encode_alloc((char *)hashed_name, hash_size, + &name_b32); + + if (size == 0) { + char *n = knot_dname_to_str(name); + dbg_zone("Error while encoding hashed name %s to " + "base32.\n", n); + free(n); + if (name_b32 != NULL) { + free(name_b32); + } + return KNOT_ECRYPTO; + } + + assert(name_b32 != NULL); + free(hashed_name); + + dbg_zone("Base32-encoded hash: %s\n", name_b32); + + /* Will be returned to caller, make sure it is released after use. */ + *nsec3_name = knot_dname_new_from_str(name_b32, size, NULL); + + free(name_b32); + + if (*nsec3_name == NULL) { + dbg_zone("Error while creating domain name for hashed" + " name.\n"); + return KNOT_ERROR; + } + + assert(zone->apex->owner != NULL); + knot_dname_t *ret = knot_dname_cat(*nsec3_name, zone->apex->owner); + + if (ret == NULL) { + dbg_zone("Error while creating NSEC3 domain name for " + "hashed name.\n"); + knot_dname_release(*nsec3_name); + return KNOT_ERROR; + } + + assert(ret == *nsec3_name); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tries to find the given domain name in the zone tree. + * + * \param zone Zone to search in. + * \param name Domain name to find. + * \param node Found node. + * \param previous Previous node in canonical order (i.e. the one directly + * preceding \a name in canonical order, regardless if the name + * is in the zone or not). + * + * \retval <> 0 if the domain name was found. In such case \a node holds the + * zone node with \a name as its owner. \a previous is set + * properly. + * \retval 0 if the domain name was not found. \a node may hold any (or none) + * node. \a previous is set properly. + */ +static int knot_zone_contents_find_in_tree(knot_zone_tree_t *tree, + const knot_dname_t *name, + knot_node_t **node, + knot_node_t **previous) +{ + assert(tree != NULL); + assert(name != NULL); + assert(node != NULL); + assert(previous != NULL); + + knot_node_t *found = NULL, *prev = NULL; +// knot_node_t *found2 = NULL, *prev2 = NULL; + + int exact_match = knot_zone_tree_get_less_or_equal( + tree, name, &found, &prev, 1); + +// assert(prev != NULL); + assert(exact_match >= 0); + *node = found; + *previous = prev; + +// if (prev == NULL) { +// // either the returned node is the root of the tree, or it is +// // the leftmost node in the tree; in both cases node was found +// // set the previous node of the found node +// assert(exact_match); +// assert(found != NULL); +// *previous = knot_node_get_previous(found, 1); +// } else { +// // otherwise check if the previous node is not an empty +// // non-terminal +// *previous = (knot_node_rrset_count(prev) == 0) +// ? knot_node_get_previous(prev, 1) +// : prev; +// } + + return exact_match; +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_contents_node_to_hash(knot_zone_tree_node_t *tnode, + void *data) +{ + assert(tnode != NULL && tnode->node != NULL + && tnode->node->owner != NULL && data != NULL); + + knot_node_t *node = tnode->node; + + knot_zone_contents_t *zone = (knot_zone_contents_t *)data; + /* + * By the original approach, only authoritative nodes and delegation + * points should be added to the hash table, but currently, all nodes + * are being added when the zone is created (don't know why actually:), + * so we will do no distinction here neither. + */ + +#ifdef USE_HASH_TABLE +//dbg_zone_exec( +// char *name = knot_dname_to_str(node->owner); +// dbg_zone("Adding node with owner %s to hash table.\n", name); +// free(name); +//); + //assert(zone->table != NULL); + // add the node also to the hash table if authoritative, or deleg. point + if (zone->table != NULL + && ck_insert_item(zone->table, + (const char *)node->owner->name, + node->owner->size, (void *)node) != 0) { + dbg_zone("Error inserting node into hash table!\n"); + } +#endif +} + +/*----------------------------------------------------------------------------*/ + +static int knot_zone_contents_dnames_from_rdata_to_table( + knot_dname_table_t *table, knot_rdata_t *rdata, + knot_rrtype_descriptor_t *d) +{ + unsigned int count = knot_rdata_item_count(rdata); + int rc = 0; + assert(count <= d->length); + // for each RDATA item + for (unsigned int j = 0; j < count; ++j) { + if (d->wireformat[j] + == KNOT_RDATA_WF_COMPRESSED_DNAME + || d->wireformat[j] + == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || d->wireformat[j] + == KNOT_RDATA_WF_LITERAL_DNAME) { + dbg_zone("Saving dname from " + "rdata to dname table" + ".\n"); + rc = knot_dname_table_add_dname_check(table, + &knot_rdata_get_item(rdata, j)->dname); + if (rc < 0) { + dbg_zone("Error: %s\n", + knot_strerror(rc)); + return rc; + } + } + } + + dbg_zone("RDATA OK.\n"); + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_zone_contents_dnames_from_rrset_to_table( + knot_dname_table_t *table, knot_rrset_t *rrset, int replace_owner, + knot_dname_t *owner) +{ + assert(table != NULL && rrset != NULL && owner != NULL); + + if (replace_owner) { + // discard the old owner and replace it with the new + knot_rrset_set_owner(rrset, owner); + } + dbg_zone("RRSet owner: %p\n", rrset->owner); + + knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type( + knot_rrset_type(rrset)); + if (desc == NULL) { + // not recognized RR type, ignore + dbg_zone("RRSet type not recognized.\n"); + return KNOT_EOK; + } + // for each RDATA in RRSet + knot_rdata_t *rdata = knot_rrset_get_rdata(rrset); + while (rdata != NULL) { + int rc = knot_zone_contents_dnames_from_rdata_to_table(table, + rdata, desc); + if (rc != KNOT_EOK) { + return rc; + } + + rdata = knot_rrset_rdata_get_next(rrset, rdata); + } + + dbg_zone("RRSet OK.\n"); + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_zone_contents_dnames_from_node_to_table( + knot_dname_table_t *table, knot_node_t *node) +{ + /* + * Assuming that all the RRSets have the same owner as the node. + */ + + // insert owner + char *name = knot_dname_to_str(node->owner); + dbg_zone("Node owner before inserting to dname table: %p.\n", + node->owner); + dbg_zone("Node owner before inserting to dname table: %s.\n", + name); + free(name); + //knot_dname_t *old_owner = node->owner; + int rc = knot_dname_table_add_dname_check(table, &node->owner); + if (rc < 0) { + dbg_zone("Failed to add dname to dname table.\n"); + return rc; + } + int replace_owner = (rc > 0); + dbg_zone("Node owner after inserting to dname table: %p.\n", + node->owner); + name = knot_dname_to_str(node->owner); + dbg_zone("Node owner after inserting to dname table: %s.\n", + name); + free(name); + + knot_rrset_t **rrsets = knot_node_get_rrsets(node); + // for each RRSet + for (int i = 0; i < knot_node_rrset_count(node); ++i) { + dbg_zone("Inserting RRSets from node to table.\n"); + rc = knot_zone_contents_dnames_from_rrset_to_table(table, + rrsets[i], replace_owner, node->owner); + if (rc != KNOT_EOK) { + return rc; + } + } + + free(rrsets); + + dbg_zone("Node OK\n"); + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, + uint node_count, + int use_domain_table, + struct knot_zone *zone) +{ + knot_zone_contents_t *contents = (knot_zone_contents_t *) + calloc(1, sizeof(knot_zone_contents_t)); + if (contents == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + +// printf("created cont: %p (%s)\n", +// contents, knot_dname_to_str(apex->owner)); + + contents->apex = apex; + contents->zone = zone; + knot_node_set_zone(apex, zone); + + dbg_zone("Creating tree for normal nodes.\n"); + contents->nodes = malloc(sizeof(knot_zone_tree_t)); + if (contents->nodes == NULL) { + ERR_ALLOC_FAILED; + goto cleanup; + } + + dbg_zone("Creating tree for NSEC3 nodes.\n"); + contents->nsec3_nodes = malloc(sizeof(knot_zone_tree_t)); + if (contents->nsec3_nodes == NULL) { + ERR_ALLOC_FAILED; + goto cleanup; + } + + if (use_domain_table) { + dbg_zone("Creating domain name table.\n"); + contents->dname_table = knot_dname_table_new(); + if (contents->dname_table == NULL) { + ERR_ALLOC_FAILED; + goto cleanup; + } + } else { + contents->dname_table = NULL; + } + + contents->node_count = node_count; + + /* Initialize NSEC3 params */ + dbg_zone("Initializing NSEC3 parameters.\n"); + contents->nsec3_params.algorithm = 0; + contents->nsec3_params.flags = 0; + contents->nsec3_params.iterations = 0; + contents->nsec3_params.salt_length = 0; + contents->nsec3_params.salt = NULL; + + dbg_zone("Initializing zone trees.\n"); + if (knot_zone_tree_init(contents->nodes) != KNOT_EOK + || knot_zone_tree_init(contents->nsec3_nodes) != KNOT_EOK) { + goto cleanup; + } + + dbg_zone("Inserting apex into the zone tree.\n"); + if (knot_zone_tree_insert(contents->nodes, apex) != KNOT_EOK) { + dbg_zone("Failed to insert apex to the zone tree.\n"); + goto cleanup; + } + +#ifdef USE_HASH_TABLE + if (contents->node_count > 0) { + dbg_zone("Creating hash table.\n"); + contents->table = ck_create_table(contents->node_count); + if (contents->table == NULL) { + goto cleanup; + } + + // insert the apex into the hash table + dbg_zone("Inserting apex into the hash table.\n"); + if (ck_insert_item(contents->table, + (const char *)knot_dname_name( + knot_node_owner(apex)), + knot_dname_size(knot_node_owner(apex)), + (void *)apex) != 0) { + ck_destroy_table(&contents->table, NULL, 0); + goto cleanup; + } + } else { + contents->table = NULL; + } +#endif + + // insert names from the apex to the domain table + if (use_domain_table) { + dbg_zone("Inserting names from apex to table.\n"); + int rc = knot_zone_contents_dnames_from_node_to_table( + contents->dname_table, apex); + if (rc != KNOT_EOK) { + ck_destroy_table(&contents->table, NULL, 0); + goto cleanup; + } + } + + return contents; + +cleanup: + dbg_zone("Cleaning up.\n"); + free(contents->dname_table); + free(contents->nodes); + free(contents->nsec3_nodes); + free(contents); + return NULL; +} + +/*----------------------------------------------------------------------------*/ + +//short knot_zone_contents_generation(const knot_zone_contents_t *zone) +//{ +// return zone->generation; +//} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents) +{ + return (contents->generation == 0); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents) +{ + return (contents->generation == 1); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_gen_is_finished(const knot_zone_contents_t *contents) +{ + return (contents->generation == -1); +} + +/*----------------------------------------------------------------------------*/ + +//void knot_zone_contents_switch_generation(knot_zone_contents_t *zone) +//{ +// zone->generation = 1 - zone->generation; +//} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents) +{ + contents->generation = 0; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents) +{ + contents->generation = 1; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_contents_set_gen_new_finished(knot_zone_contents_t *contents) +{ + contents->generation = -1; +} + +/*----------------------------------------------------------------------------*/ + +uint16_t knot_zone_contents_class(const knot_zone_contents_t *contents) +{ + if (contents == NULL || contents->apex == NULL + || knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA) == NULL) { + return KNOT_EBADARG; + } + + return knot_rrset_class(knot_node_rrset(contents->apex, + KNOT_RRTYPE_SOA)); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_add_node(knot_zone_contents_t *zone, + knot_node_t *node, int create_parents, + uint8_t flags, int use_domain_table) +{ + if (zone == NULL || node == NULL) { + return KNOT_EBADARG; + } + + int ret = 0; + if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { + return ret; + } + + ret = knot_zone_tree_insert(zone->nodes, node); + if (ret != KNOT_EOK) { + dbg_zone("Failed to insert node into zone tree.\n"); + return ret; + } + +#ifdef USE_HASH_TABLE + char *name = knot_dname_to_str(node->owner); +// dbg_zone("Adding node with owner %s to hash table.\n", name); + free(name); + //assert(zone->table != NULL); + // add the node also to the hash table if authoritative, or deleg. point + if (zone->table != NULL + && ck_insert_item(zone->table, + (const char *)node->owner->name, + node->owner->size, (void *)node) != 0) { + dbg_zone("Error inserting node into hash table!\n"); + /*! \todo Remove the node from the tree. */ + return KNOT_EHASH; + } +#endif + assert(knot_zone_contents_find_node(zone, node->owner)); + + if (use_domain_table) { + ret = knot_zone_contents_dnames_from_node_to_table( + zone->dname_table, node); + if (ret != KNOT_EOK) { + /*! \todo Remove node from the tree and hash table.*/ + dbg_zone("Failed to add dnames into table.\n"); + return ret; + } + } + + knot_node_set_zone(node, zone->zone); + + if (!create_parents) { + return KNOT_EOK; + } + + dbg_zone("Creating parents of the node.\n"); + + knot_dname_t *chopped = + knot_dname_left_chop(knot_node_owner(node)); + if (knot_dname_compare(knot_node_owner(zone->apex), chopped) == 0) { + dbg_zone("Zone apex is the parent.\n"); + knot_node_set_parent(node, zone->apex); + } else { + knot_node_t *next_node; + while ((next_node + = knot_zone_contents_get_node(zone, chopped)) == NULL) { + /* Adding new dname to zone + add to table. */ + dbg_zone("Creating new node.\n"); + next_node = knot_node_new(chopped, NULL, flags); + if (next_node == NULL) { + /* Directly discard. */ + knot_dname_free(&chopped); + return KNOT_ENOMEM; + } + if (use_domain_table) { + ret = + knot_zone_contents_dnames_from_node_to_table( + zone->dname_table, next_node); + if (ret != KNOT_EOK) { + /*! \todo Will next_node leak? */ + knot_dname_release(chopped); + return ret; + } + } + + if (next_node->owner != chopped) { + /* Node owner was in RDATA */ + chopped = next_node->owner; + } + + assert(knot_zone_contents_find_node(zone, chopped) + == NULL); + assert(knot_node_owner(next_node) == chopped); + + dbg_zone("Inserting new node to zone tree.\n"); +// TREE_INSERT(zone->tree, knot_node, avl, next_node); + + ret = knot_zone_tree_insert(zone->nodes, + next_node); + if (ret != KNOT_EOK) { + dbg_zone("Failed to insert new node " + "to zone tree.\n"); + /*! \todo Delete the node?? */ + /* Directly discard. */ + knot_dname_release(chopped); + return ret; + } + +#ifdef USE_HASH_TABLE +dbg_zone_exec( + char *name = knot_dname_to_str( + knot_node_owner(next_node)); + dbg_zone("Adding new node with owner %s to " + "hash table.\n", name); + free(name); +); + + if (zone->table != NULL + && ck_insert_item(zone->table, + (const char *)knot_dname_name( + knot_node_owner(next_node)), + knot_dname_size(knot_node_owner(next_node)), + (void *)next_node) != 0) { + dbg_zone("Error inserting node into " + "hash table!\n"); + /*! \todo Delete the node?? */ + /* Directly discard. */ + knot_dname_release(chopped); + return KNOT_EHASH; + } + + // set parent + knot_node_set_parent(node, next_node); + + // set zone + knot_node_set_zone(next_node, zone->zone); + + // check if the node is not wildcard child of the parent + if (knot_dname_is_wildcard( + knot_node_owner(node))) { + knot_node_set_wildcard_child(next_node, node); + } +#endif + dbg_zone("Next parent.\n"); + node = next_node; + knot_dname_t *chopped_last = chopped; + chopped = knot_dname_left_chop(chopped); + + /* Release last chop, reference is already stored + * in next_node. + */ + knot_dname_release(chopped_last); + + } + // set the found parent (in the zone) as the parent of the last + // inserted node + assert(knot_node_parent(node, 0) == NULL); + knot_node_set_parent(node, next_node); + + dbg_zone("Created all parents.\n"); + } + + /* Directly discard. */ + /*! \todo This may be double-release. */ + knot_dname_release(chopped); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, + knot_rrset_t *rrset, knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table) +{ + if (zone == NULL || rrset == NULL || zone->apex == NULL + || zone->apex->owner == NULL || node == NULL) { + return KNOT_EBADARG; + } + + // check if the RRSet belongs to the zone + if (knot_dname_compare(knot_rrset_owner(rrset), + zone->apex->owner) != 0 + && !knot_dname_is_subdomain(knot_rrset_owner(rrset), + zone->apex->owner)) { + return KNOT_EBADZONE; + } + + if ((*node) == NULL + && (*node = knot_zone_contents_get_node(zone, + knot_rrset_owner(rrset))) == NULL) { + return KNOT_ENONODE; + } + + assert(*node != NULL); + + // add all domain names from the RRSet to domain name table + int rc; + + /*! \todo REMOVE RRSET */ + rc = knot_node_add_rrset(*node, rrset, + dupl == KNOT_RRSET_DUPL_MERGE); + if (rc < 0) { + dbg_zone("Failed to add RRSet to node.\n"); + return rc; + } + + int ret = rc; + + if (use_domain_table) { + dbg_zone("Saving RRSet to table.\n"); + rc = knot_zone_contents_dnames_from_rrset_to_table( + zone->dname_table, rrset, 0, (*node)->owner); + if (rc != KNOT_EOK) { + dbg_zone("Error saving domain names from " + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent " + "state.\n"); + // WARNING: the zone is not in consistent state now - + // there may be domain names in it that are not inserted + // into the domain table + return rc; + } + } + + // replace RRSet's owner with the node's owner (that is already in the + // table) + /*! \todo Do even if domain table is not used?? */ + if (ret == KNOT_EOK && rrset->owner != (*node)->owner) { + knot_rrset_set_owner(rrset, (*node)->owner); + } + + dbg_zone("RRSet OK.\n"); + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_add_rrsigs(knot_zone_contents_t *zone, + knot_rrset_t *rrsigs, + knot_rrset_t **rrset, + knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table) +{ + if (zone == NULL || rrsigs == NULL || rrset == NULL || node == NULL + || zone->apex == NULL || zone->apex->owner == NULL) { +dbg_zone_exec( + dbg_zone("Parameters: zone=%p, rrsigs=%p, rrset=%p, " + "node=%p\n", zone, rrsigs, rrset, node); + if (zone != NULL) { + dbg_zone("zone->apex=%p\n", zone->apex); + if (zone->apex != NULL) { + dbg_zone("zone->apex->owner=%p\n", + zone->apex->owner); + } + } +); + return KNOT_EBADARG; + } + + // check if the RRSet belongs to the zone + if (*rrset != NULL + && knot_dname_compare(knot_rrset_owner(*rrset), + zone->apex->owner) != 0 + && !knot_dname_is_subdomain(knot_rrset_owner(*rrset), + zone->apex->owner)) { + return KNOT_EBADZONE; + } + + // check if the RRSIGs belong to the RRSet + if (*rrset != NULL + && (knot_dname_compare(knot_rrset_owner(rrsigs), + knot_rrset_owner(*rrset)) != 0)) { + dbg_zone("RRSIGs does not belong to the given RRSet.\n"); + return KNOT_EBADARG; + } + + // if no RRSet given, try to find the right RRSet + if (*rrset == NULL) { + // even no node given + // find proper node + knot_node_t *(*get_node)(const knot_zone_contents_t *, + const knot_dname_t *) + = (knot_rdata_rrsig_type_covered( + knot_rrset_rdata(rrsigs)) == KNOT_RRTYPE_NSEC3) + ? knot_zone_contents_get_nsec3_node + : knot_zone_contents_get_node; + + if (*node == NULL + && (*node = get_node( + zone, knot_rrset_owner(rrsigs))) == NULL) { + dbg_zone("Failed to find node for RRSIGs.\n"); + return KNOT_ENONODE; + } + + assert(*node != NULL); + + // find the RRSet in the node + // take only the first RDATA from the RRSIGs + dbg_zone("Finding RRSet for type %s\n", + knot_rrtype_to_string( + knot_rdata_rrsig_type_covered( + knot_rrset_rdata(rrsigs)))); + *rrset = knot_node_get_rrset( + *node, knot_rdata_rrsig_type_covered( + knot_rrset_rdata(rrsigs))); + if (*rrset == NULL) { + dbg_zone("Failed to find RRSet for RRSIGs.\n"); + return KNOT_ENORRSET; + } + } + + assert(*rrset != NULL); + + // add all domain names from the RRSet to domain name table + int rc; + int ret = KNOT_EOK; + + rc = knot_rrset_add_rrsigs(*rrset, rrsigs, dupl); + if (rc < 0) { + dbg_dname("Failed to add RRSIGs to RRSet.\n"); + return rc; + } else if (rc > 0) { + assert(dupl == KNOT_RRSET_DUPL_MERGE); + ret = 1; + } + + if (use_domain_table) { + dbg_zone("Saving RRSIG RRSet to table.\n"); + rc = knot_zone_contents_dnames_from_rrset_to_table( + zone->dname_table, rrsigs, 0, (*rrset)->owner); + if (rc != KNOT_EOK) { + dbg_zone("Error saving domain names from " + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent " + "state.\n"); + // WARNING: the zone is not in consistent state now - + // there may be domain names in it that are not inserted + // into the domain table + return rc; + } + } + + // replace RRSet's owner with the node's owner (that is already in the + // table) + if ((*rrset)->owner != (*rrset)->rrsigs->owner) { + knot_rrset_set_owner((*rrset)->rrsigs, (*rrset)->owner); + } + + dbg_zone("RRSIGs OK\n"); + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, + knot_node_t *node, int create_parents, + uint8_t flags, int use_domain_table) +{ + UNUSED(create_parents); + UNUSED(flags); + + if (zone == NULL || node == NULL) { + return KNOT_EBADARG; + } + + int ret = 0; + if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { + return ret; + } + + // how to know if this is successfull?? +// TREE_INSERT(zone->nsec3_nodes, knot_node, avl, node); + knot_zone_tree_insert(zone->nsec3_nodes, node); + + if (use_domain_table) { + ret = knot_zone_contents_dnames_from_node_to_table( + zone->dname_table, node); + if (ret != KNOT_EOK) { + /*! \todo Remove the node from the tree. */ + dbg_zone("Failed to add dnames into table.\n"); + return ret; + } + } + + // no parents to be created, the only parent is the zone apex + // set the apex as the parent of the node + knot_node_set_parent(node, zone->apex); + + // set the zone to the node + knot_node_set_zone(node, zone->zone); + + // cannot be wildcard child, so nothing to be done + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone, + knot_rrset_t *rrset, + knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table) +{ + if (zone == NULL || rrset == NULL || zone->apex == NULL + || zone->apex->owner == NULL || node == NULL) { + return KNOT_EBADARG; + } + + // check if the RRSet belongs to the zone + if (knot_dname_compare(knot_rrset_owner(rrset), + zone->apex->owner) != 0 + && !knot_dname_is_subdomain(knot_rrset_owner(rrset), + zone->apex->owner)) { + return KNOT_EBADZONE; + } + + if ((*node) == NULL + && (*node = knot_zone_contents_get_nsec3_node( + zone, knot_rrset_owner(rrset))) == NULL) { + return KNOT_ENONODE; + } + + assert(*node != NULL); + + // add all domain names from the RRSet to domain name table + int rc; + + /*! \todo REMOVE RRSET */ + rc = knot_node_add_rrset(*node, rrset, + dupl == KNOT_RRSET_DUPL_MERGE); + if (rc < 0) { + return rc; + } + + int ret = rc; + + if (use_domain_table) { + dbg_zone("Saving NSEC3 RRSet to table.\n"); + rc = knot_zone_contents_dnames_from_rrset_to_table( + zone->dname_table, rrset, 0, (*node)->owner); + if (rc != KNOT_EOK) { + dbg_zone("Error saving domain names from " + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent " + "state.\n"); + // WARNING: the zone is not in consistent state now - + // there may be domain names in it that are not inserted + // into the domain table + return rc; + } + } + + // replace RRSet's owner with the node's owner (that is already in the + // table) + /*! \todo Do even if domain table is not used? */ + if (rrset->owner != (*node)->owner) { + knot_rrset_set_owner(rrset, (*node)->owner); + } + + dbg_zone("NSEC3 OK\n"); + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_remove_node(knot_zone_contents_t *contents, + const knot_node_t *node, knot_zone_tree_node_t **removed_tree, + ck_hash_table_item_t **removed_hash) +{ + if (contents == NULL || node == NULL) { + return KNOT_EBADARG; + } + + const knot_dname_t *owner = knot_node_owner(node); + + // 1) remove the node from hash table + *removed_hash = NULL; + *removed_hash = ck_remove_item(contents->table, + (const char *)knot_dname_name(owner), + knot_dname_size(owner)); +// int ret = ck_detete_item(contents->table, +// (const char *)knot_dname_name(owner), +// knot_dname_size(owner), NULL, 0); + if (*removed_hash == NULL) { + return KNOT_ENONODE; + } + + // 2) remove the node from the zone tree + *removed_tree = NULL; + int ret = knot_zone_tree_remove(contents->nodes, owner, removed_tree); + if (ret != KNOT_EOK) { + return KNOT_ENONODE; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents, + const knot_node_t *node, knot_zone_tree_node_t **removed) +{ + if (contents == NULL || node == NULL) { + return KNOT_EBADARG; + } + + const knot_dname_t *owner = knot_node_owner(node); + + // remove the node from the zone tree + *removed = NULL; + int ret = knot_zone_tree_remove(contents->nsec3_nodes, owner, removed); + if (ret != KNOT_EOK) { + return KNOT_ENONODE; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_create_and_fill_hash_table( + knot_zone_contents_t *zone) +{ + if (zone == NULL || zone->apex == NULL || zone->apex->owner == NULL) { + return KNOT_EBADARG; + } + /* + * 1) Create hash table. + */ +#ifdef USE_HASH_TABLE + if (zone->node_count > 0) { + zone->table = ck_create_table(zone->node_count); + if (zone->table == NULL) { + return KNOT_ENOMEM; + } + + // insert the apex into the hash table + if (ck_insert_item(zone->table, + (const char *)zone->apex->owner->name, + zone->apex->owner->size, + (void *)zone->apex) != 0) { + return KNOT_EHASH; + } + } else { + zone->table = NULL; + return KNOT_EOK; // OK? + } + + /* + * 2) Fill in the hash table. + * + * In this point, the nodes in the zone must be adjusted, so that only + * relevant nodes (authoritative and delegation points are inserted. + * + * TODO: how to know if this was successful?? + */ + /*! \todo Replace by zone tree. */ + int ret = knot_zone_tree_forward_apply_inorder(zone->nodes, + knot_zone_contents_node_to_hash, zone); + if (ret != KNOT_EOK) { + dbg_zone("Failed to insert nodes to hash table.\n"); + return ret; + } + +#endif + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_zone_contents_get_node(const knot_zone_contents_t *zone, + const knot_dname_t *name) +{ + if (zone == NULL || name == NULL) { + return NULL; + } + + // create dummy node to use for lookup +// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL); +// knot_node_t *n = TREE_FIND(zone->tree, knot_node, avl, tmp); +// knot_node_free(&tmp, 0); + + knot_node_t *n; + int ret = knot_zone_tree_get(zone->nodes, name, &n); + if (ret != KNOT_EOK) { + dbg_zone("Failed to find name in the zone tree.\n"); + return NULL; + } + + return n; +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_zone_contents_get_nsec3_node( + const knot_zone_contents_t *zone, const knot_dname_t *name) +{ + if (zone == NULL || name == NULL) { + return NULL; + } + + // create dummy node to use for lookup +// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL); +// knot_node_t *n = TREE_FIND(zone->nsec3_nodes, knot_node, avl, tmp); +// knot_node_free(&tmp, 0); + knot_node_t *n; + int ret = knot_zone_tree_get(zone->nsec3_nodes, name, &n); + + if (ret != KNOT_EOK) { + dbg_zone("Failed to find NSEC3 name in the zone tree." + "\n"); + return NULL; + } + + return n; +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_zone_contents_find_node( + const knot_zone_contents_t *zone,const knot_dname_t *name) +{ + return knot_zone_contents_get_node(zone, name); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_find_dname(const knot_zone_contents_t *zone, + const knot_dname_t *name, + const knot_node_t **node, + const knot_node_t **closest_encloser, + const knot_node_t **previous) +{ + if (zone == NULL || name == NULL || node == NULL + || closest_encloser == NULL || previous == NULL + || zone->apex == NULL || zone->apex->owner == NULL) { + return KNOT_EBADARG; + } + +dbg_zone_exec( + char *name_str = knot_dname_to_str(name); + char *zone_str = knot_dname_to_str(zone->apex->owner); + dbg_zone("Searching for name %s in zone %s...\n", + name_str, zone_str); + free(name_str); + free(zone_str); +); + + if (knot_dname_compare(name, zone->apex->owner) == 0) { + *node = zone->apex; + *closest_encloser = *node; + return KNOT_ZONE_NAME_FOUND; + } + + if (!knot_dname_is_subdomain(name, zone->apex->owner)) { + *node = NULL; + *closest_encloser = NULL; + return KNOT_EBADZONE; + } + + knot_node_t *found = NULL, *prev = NULL; + + int exact_match = knot_zone_contents_find_in_tree(zone->nodes, name, + &found, &prev); + assert(exact_match >= 0); + *node = found; + *previous = prev; + +dbg_zone_exec( + char *name_str = (*node) ? knot_dname_to_str((*node)->owner) + : "(nil)"; + char *name_str2 = (*previous != NULL) + ? knot_dname_to_str((*previous)->owner) + : "(nil)"; + dbg_zone("Search function returned %d, node %s and prev: %s\n", + exact_match, name_str, name_str2); + + if (*node) { + free(name_str); + } + if (*previous != NULL) { + free(name_str2); + } +); + + *closest_encloser = *node; + + // there must be at least one node with domain name less or equal to + // the searched name if the name belongs to the zone (the root) + if (*node == NULL) { + return KNOT_EBADZONE; + } + + // TODO: this could be replaced by saving pointer to closest encloser + // in node + + if (!exact_match) { + int matched_labels = knot_dname_matched_labels( + knot_node_owner((*closest_encloser)), name); + while (matched_labels < knot_dname_label_count( + knot_node_owner((*closest_encloser)))) { + (*closest_encloser) = + knot_node_parent((*closest_encloser), 1); + assert(*closest_encloser); + } + } +dbg_zone_exec( + char *n = knot_dname_to_str(knot_node_owner((*closest_encloser))); + dbg_zone("Closest encloser: %s\n", n); + free(n); +); + + dbg_zone("find_dname() returning %d\n", exact_match); + + return (exact_match) + ? KNOT_ZONE_NAME_FOUND + : KNOT_ZONE_NAME_NOT_FOUND; +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_zone_contents_get_previous( + const knot_zone_contents_t *zone, const knot_dname_t *name) +{ + if (zone == NULL || name == NULL) { + return NULL; + } + + knot_node_t *found = NULL, *prev = NULL; + + int exact_match = knot_zone_contents_find_in_tree(zone->nodes, name, + &found, &prev); + assert(exact_match >= 0); + assert(prev != NULL); + + return prev; +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_zone_contents_find_previous( + const knot_zone_contents_t *zone, const knot_dname_t *name) +{ + return knot_zone_contents_get_previous(zone, name); +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_zone_contents_get_previous_nsec3( + const knot_zone_contents_t *zone, const knot_dname_t *name) +{ + if (zone == NULL || name == NULL) { + return NULL; + } + + knot_node_t *found = NULL, *prev = NULL; + + int exact_match = knot_zone_contents_find_in_tree(zone->nsec3_nodes, + name, &found, &prev); + assert(exact_match >= 0); + assert(prev != NULL); + + return prev; +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_zone_contents_find_previous_nsec3( + const knot_zone_contents_t *zone, const knot_dname_t *name) +{ + return knot_zone_contents_get_previous(zone, name); +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_contents_left_chop(char *name, size_t *size) +{ + short label_size = name[0]; + + memmove(name, name + label_size + 1, *size -label_size - 1); + *size = *size - label_size - 1; +} + +/*----------------------------------------------------------------------------*/ +#ifdef USE_HASH_TABLE +int knot_zone_contents_find_dname_hash(const knot_zone_contents_t *zone, + const knot_dname_t *name, + const knot_node_t **node, + const knot_node_t **closest_encloser) +{ + if (zone == NULL || name == NULL || node == NULL + || closest_encloser == NULL) { + return KNOT_EBADARG; + } + +dbg_zone_exec( + char *name_str = knot_dname_to_str(name); + char *zone_str = knot_dname_to_str(zone->apex->owner); + dbg_zone("Searching for name %s in zone %s...\n", + name_str, zone_str); + free(name_str); + free(zone_str); +); + + if (knot_dname_compare(name, zone->apex->owner) == 0) { + *node = zone->apex; + *closest_encloser = *node; + return KNOT_ZONE_NAME_FOUND; + } + + if (!knot_dname_is_subdomain(name, zone->apex->owner)) { + *node = NULL; + *closest_encloser = NULL; + return KNOT_EBADZONE; + } + + // temporary name used for hashing + char name_tmp[KNOT_MAX_DNAME_LENGTH]; + size_t name_size = name->size; + if (knot_dname_to_lower_copy(name, name_tmp, KNOT_MAX_DNAME_LENGTH) + != KNOT_EOK) { + return KNOT_ERROR; + } + + const ck_hash_table_item_t *item = ck_find_item(zone->table, + name_tmp, name_size); + + if (item != NULL) { + *node = (const knot_node_t *)item->value; + *closest_encloser = *node; + + dbg_zone("Found node in hash table: %p (owner %p, " + "labels: %d)\n", *node, (*node)->owner, + knot_dname_label_count((*node)->owner)); + assert(*node != NULL); + assert(*closest_encloser != NULL); + return KNOT_ZONE_NAME_FOUND; + } + + *node = NULL; + + // chop leftmost labels until some node is found + // copy the name for chopping + /* Local allocation, will be discarded. */ + //knot_dname_t *name_copy = knot_dname_deep_copy(name); +dbg_zone_exec( + //char *n = knot_dname_to_str(name_copy); + dbg_zone("Finding closest encloser..\nStarting with: %.*s\n", + (int)name_size, name_tmp); + //free(n); +); + + while (item == NULL) { + //knot_dname_left_chop_no_copy(name_copy); + knot_zone_contents_left_chop(name_tmp, &name_size); +dbg_zone_exec( + //char *n = knot_dname_to_str(name_copy); + dbg_zone("Chopped leftmost label: %.*s\n", + (int)name_size, name_tmp); + //free(n); +); + // not satisfied in root zone!! + //assert(name_copy->label_count > 0); + assert(name_size > 0); + + item = ck_find_item(zone->table, name_tmp, name_size); + } + + /* Directly discard. */ + //knot_dname_free(&name_copy); + + assert(item != NULL); + *closest_encloser = (const knot_node_t *)item->value; + + return KNOT_ZONE_NAME_NOT_FOUND; +} +#endif +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_zone_contents_find_nsec3_node( + const knot_zone_contents_t *zone, const knot_dname_t *name) +{ + return knot_zone_contents_get_nsec3_node(zone, name); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_find_nsec3_for_name(const knot_zone_contents_t *zone, + const knot_dname_t *name, + const knot_node_t **nsec3_node, + const knot_node_t **nsec3_previous, + int check_ver) +{ + if (zone == NULL || name == NULL + || nsec3_node == NULL || nsec3_previous == NULL) { + return KNOT_EBADARG; + } + + knot_dname_t *nsec3_name = NULL; + int ret = knot_zone_contents_nsec3_name(zone, name, &nsec3_name); + + if (ret != KNOT_EOK) { + return ret; + } + +dbg_zone_exec( + char *n = knot_dname_to_str(nsec3_name); + dbg_zone("NSEC3 node name: %s.\n", n); + free(n); +); + + const knot_node_t *found = NULL, *prev = NULL; + + // create dummy node to use for lookup + int exact_match = knot_zone_tree_find_less_or_equal( + zone->nsec3_nodes, nsec3_name, &found, &prev, check_ver); + assert(exact_match >= 0); + + knot_dname_release(nsec3_name); + +dbg_zone_exec( + if (found) { + char *n = knot_dname_to_str(found->owner); + dbg_zone("Found NSEC3 node: %s.\n", n); + free(n); + } else { + dbg_zone("Found no NSEC3 node.\n"); + } + + if (prev) { + assert(prev->owner); + char *n = knot_dname_to_str(prev->owner); + dbg_zone("Found previous NSEC3 node: %s.\n", n); + free(n); + } else { + dbg_zone("Found no previous NSEC3 node.\n"); + } +); + *nsec3_node = found; + + if (prev == NULL) { + // either the returned node is the root of the tree, or it is + // the leftmost node in the tree; in both cases node was found + // set the previous node of the found node + assert(exact_match); + assert(*nsec3_node != NULL); + *nsec3_previous = knot_node_previous(*nsec3_node, check_ver); + } else { + *nsec3_previous = prev; + } + + dbg_zone("find_nsec3_for_name() returning %d\n", exact_match); + + return (exact_match) + ? KNOT_ZONE_NAME_FOUND + : KNOT_ZONE_NAME_NOT_FOUND; +} + +/*----------------------------------------------------------------------------*/ + +const knot_node_t *knot_zone_contents_apex( + const knot_zone_contents_t *zone) +{ + if (zone == NULL) { + return NULL; + } + + return zone->apex; +} + +/*----------------------------------------------------------------------------*/ + +knot_node_t *knot_zone_contents_get_apex(const knot_zone_contents_t *zone) +{ + if (zone == NULL) { + return NULL; + } + + return zone->apex; +} + +/*----------------------------------------------------------------------------*/ + +//knot_dname_t *knot_zone_contents_name(const knot_zone_contents_t *zone) +//{ +// if (zone == NULL) { +// return NULL; +// } + +// return zone->name; +//} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_adjust(knot_zone_contents_t *zone, int check_ver) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + // load NSEC3PARAM (needed on adjusting function) + knot_zone_contents_load_nsec3param(zone); + + knot_zone_adjust_arg_t adjust_arg; + adjust_arg.zone = zone; + adjust_arg.first_node = NULL; + adjust_arg.previous_node = NULL; + adjust_arg.check_ver = check_ver; + + dbg_zone("Adjusting normal nodes.\n"); + int ret = knot_zone_tree_forward_apply_inorder(zone->nodes, + knot_zone_contents_adjust_node_in_tree, + &adjust_arg); + if (ret != KNOT_EOK) { + return ret; + } + dbg_zone("Done.\n"); + + assert(zone->apex == adjust_arg.first_node); + knot_node_set_previous(zone->apex, adjust_arg.previous_node); + + adjust_arg.first_node = NULL; + adjust_arg.previous_node = NULL; + + dbg_zone("Adjusting NSEC3 nodes.\n"); + ret = knot_zone_tree_forward_apply_inorder( + zone->nsec3_nodes, + knot_zone_contents_adjust_nsec3_node_in_tree, + &adjust_arg); + + dbg_zone("Done.\n"); + if (adjust_arg.first_node) { + knot_node_set_previous(adjust_arg.first_node, + adjust_arg.previous_node); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_load_nsec3param(knot_zone_contents_t *zone) +{ + if (zone == NULL || zone->apex == NULL) { + return KNOT_EBADARG; + } + + const knot_rrset_t *rrset = knot_node_rrset(zone->apex, + KNOT_RRTYPE_NSEC3PARAM); + + if (rrset != NULL) { + knot_nsec3_params_from_wire(&zone->nsec3_params, rrset); + } else { + memset(&zone->nsec3_params, 0, sizeof(knot_nsec3_params_t)); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_nsec3_enabled(const knot_zone_contents_t *zone) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + //return (zone->nsec3_params.algorithm != 0); + return (zone->nsec3_nodes->th_root != NULL); +} + +/*----------------------------------------------------------------------------*/ + +const knot_nsec3_params_t *knot_zone_contents_nsec3params( + const knot_zone_contents_t *zone) +{ + if (zone == NULL) { + return NULL; + } + + if (knot_zone_contents_nsec3_enabled(zone)) { + return &zone->nsec3_params; + } else { + return NULL; + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_tree_apply_postorder(knot_zone_contents_t *zone, + void (*function)(knot_node_t *node, void *data), + void *data) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_func_t f; + f.func = function; + f.data = data; + + return knot_zone_tree_forward_apply_postorder(zone->nodes, + knot_zone_tree_apply, &f); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_tree_apply_inorder(knot_zone_contents_t *zone, + void (*function)(knot_node_t *node, void *data), + void *data) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_func_t f; + f.func = function; + f.data = data; + + return knot_zone_tree_forward_apply_inorder(zone->nodes, + knot_zone_tree_apply, &f); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_tree_apply_inorder_reverse( + knot_zone_contents_t *zone, + void (*function)(knot_node_t *node, void *data), void *data) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_func_t f; + f.func = function; + f.data = data; + + return knot_zone_tree_reverse_apply_inorder(zone->nodes, + knot_zone_tree_apply, &f); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_nsec3_apply_postorder(knot_zone_contents_t *zone, + void (*function)(knot_node_t *node, void *data), + void *data) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_func_t f; + f.func = function; + f.data = data; + + return knot_zone_tree_forward_apply_postorder( + zone->nsec3_nodes, knot_zone_tree_apply, &f); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_nsec3_apply_inorder(knot_zone_contents_t *zone, + void (*function)(knot_node_t *node, void *data), + void *data) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_func_t f; + f.func = function; + f.data = data; + + return knot_zone_tree_forward_apply_inorder( + zone->nsec3_nodes, knot_zone_tree_apply, &f); +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_nsec3_apply_inorder_reverse( + knot_zone_contents_t *zone, + void (*function)(knot_node_t *node, void *data), void *data) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_func_t f; + f.func = function; + f.data = data; + + return knot_zone_tree_reverse_apply_inorder( + zone->nsec3_nodes, knot_zone_tree_apply, &f); +} + +/*----------------------------------------------------------------------------*/ + +knot_zone_tree_t *knot_zone_contents_get_nodes( + knot_zone_contents_t *contents) +{ + return contents->nodes; +} + +/*----------------------------------------------------------------------------*/ + +knot_zone_tree_t *knot_zone_contents_get_nsec3_nodes( + knot_zone_contents_t *contents) +{ + return contents->nsec3_nodes; +} + +/*----------------------------------------------------------------------------*/ + +ck_hash_table_t *knot_zone_contents_get_hash_table( + knot_zone_contents_t *contents) +{ + return contents->table; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_dname_table_apply(knot_zone_contents_t *contents, + void (*function)(knot_dname_t *, + void *), + void *data) +{ + if (contents == NULL || function == NULL) { + return KNOT_EBADARG; + } + + knot_dname_table_tree_inorder_apply(contents->dname_table, + function, data); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, + knot_zone_contents_t **to) +{ + if (from == NULL || to == NULL) { + return KNOT_EBADARG; + } + + /* Copy to same destination as source. */ + if (from == *to) { + return KNOT_EBADARG; + } + + int ret = KNOT_EOK; + + knot_zone_contents_t *contents = (knot_zone_contents_t *)calloc( + 1, sizeof(knot_zone_contents_t)); + if (contents == NULL) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + contents->apex = from->apex; + + contents->nodes = malloc(sizeof(knot_zone_tree_t)); + if (contents->nodes == NULL) { + ERR_ALLOC_FAILED; + ret = KNOT_ENOMEM; + goto cleanup; + } + + contents->nsec3_nodes = malloc(sizeof(knot_zone_tree_t)); + if (contents->nsec3_nodes == NULL) { + ERR_ALLOC_FAILED; + ret = KNOT_ENOMEM; + goto cleanup; + } + + if (from->dname_table != NULL) { + contents->dname_table = knot_dname_table_new(); + if (contents->dname_table == NULL) { + ERR_ALLOC_FAILED; + ret = KNOT_ENOMEM; + goto cleanup; + } + if ((ret = knot_dname_table_shallow_copy(from->dname_table, + contents->dname_table)) != KNOT_EOK) { + goto cleanup; + } + } else { + contents->dname_table = NULL; + } + + contents->node_count = from->node_count; + contents->generation = from->generation; + + contents->zone = from->zone; + + /* Initialize NSEC3 params */ + memcpy(&contents->nsec3_params, &from->nsec3_params, + sizeof(knot_nsec3_params_t)); + + if ((ret = knot_zone_tree_shallow_copy(from->nodes, + contents->nodes)) != KNOT_EOK + || (ret = knot_zone_tree_shallow_copy(from->nsec3_nodes, + contents->nsec3_nodes)) != KNOT_EOK) { + goto cleanup; + } + +#ifdef USE_HASH_TABLE + if (from->table != NULL) { +// ret = ck_copy_table(from->table, &contents->table); + ret = ck_shallow_copy(from->table, &contents->table); + if (ret != 0) { + dbg_zone("knot_zone_contents_shallow_copy: " + "hash table copied\n"); + ret = KNOT_ERROR; + goto cleanup; + } + } +#endif + + dbg_zone("knot_zone_contents_shallow_copy: " + "finished OK\n"); + + *to = contents; + return KNOT_EOK; + +cleanup: + knot_zone_tree_free(&contents->nodes); + knot_zone_tree_free(&contents->nsec3_nodes); + free(contents->dname_table); + free(contents); + return ret; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_contents_free(knot_zone_contents_t **contents) +{ + if (contents == NULL || *contents == NULL) { + return; + } + + // free the zone tree, but only the structure + knot_zone_tree_free(&(*contents)->nodes); + knot_zone_tree_free(&(*contents)->nsec3_nodes); + +#ifdef USE_HASH_TABLE + if ((*contents)->table != NULL) { + ck_destroy_table(&(*contents)->table, NULL, 0); + } +#endif + knot_nsec3_params_free(&(*contents)->nsec3_params); + + knot_dname_table_free(&(*contents)->dname_table); + + free(*contents); + *contents = NULL; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_contents_deep_free(knot_zone_contents_t **contents, + int destroy_dname_table) +{ + if (contents == NULL || *contents == NULL) { + return; + } + + if ((*contents) != NULL) { + +#ifdef USE_HASH_TABLE + if ((*contents)->table != NULL) { + ck_destroy_table(&(*contents)->table, NULL, 0); + } +#endif + /* has to go through zone twice, rdata may contain references to + node owners earlier in the zone which may be already freed */ + /* NSEC3 tree is deleted first as it may contain references to + the normal tree. */ + + knot_zone_tree_reverse_apply_postorder( + (*contents)->nsec3_nodes, + knot_zone_contents_destroy_node_rrsets_from_tree, + (void*)1); + + knot_zone_tree_reverse_apply_postorder( + (*contents)->nsec3_nodes, + knot_zone_contents_destroy_node_owner_from_tree, 0); + + knot_zone_tree_reverse_apply_postorder( + (*contents)->nodes, + knot_zone_contents_destroy_node_rrsets_from_tree, + (void*)1); + + knot_zone_tree_reverse_apply_postorder( + (*contents)->nodes, + knot_zone_contents_destroy_node_owner_from_tree, 0); + + // free the zone tree, but only the structure + // (nodes are already destroyed) + dbg_zone("Destroying zone tree.\n"); + knot_zone_tree_free(&(*contents)->nodes); + dbg_zone("Destroying NSEC3 zone tree.\n"); + knot_zone_tree_free(&(*contents)->nsec3_nodes); + + knot_nsec3_params_free(&(*contents)->nsec3_params); + + if (destroy_dname_table) { + /* + * Hack, used in zcompile - destroys the table using + * dname_free() instead of dname_retain(). + */ + knot_dname_table_destroy(&(*contents)->dname_table); + } else { + knot_dname_table_deep_free(&(*contents)->dname_table); + } + } + + free((*contents)); + *contents = NULL; +} + diff --git a/src/libknot/zone/zone-contents.h b/src/libknot/zone/zone-contents.h new file mode 100644 index 0000000..2856f76 --- /dev/null +++ b/src/libknot/zone/zone-contents.h @@ -0,0 +1,556 @@ +/*! + * \file zone-contents.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Zone contents structure and API for manipulating it. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_ZONE_CONTENTS_H_ +#define _KNOT_ZONE_CONTENTS_H_ + +//#include <time.h> + +#include "zone/node.h" +#include "dname.h" +#include "nsec3.h" +#include "zone/dname-table.h" +#include "common/tree.h" +#include "hash/cuckoo-hash-table.h" + +#include "zone-tree.h" + +struct knot_zone; + +/*----------------------------------------------------------------------------*/ + +typedef struct knot_zone_contents_t { + knot_node_t *apex; /*!< Apex node of the zone (holding SOA) */ + + ck_hash_table_t *table; /*!< Hash table for holding zone nodes. */ + knot_zone_tree_t *nodes; + knot_zone_tree_t *nsec3_nodes; + + /*! + * \todo Unify the use of this field - authoritative nodes vs. all. + */ + uint node_count; + + knot_dname_table_t *dname_table; + + knot_nsec3_params_t nsec3_params; + + /*! \brief Generation of the zone during update. + * + * Possible values: + * - 0 - Original version of the zone. Old nodes should be used. + * - 1 - New (updated) zone. New nodes should be used. + * - -1 - New (updated) zone, but exactly the stored nodes should be + * used, no matter their generation. + */ + short generation; + + struct knot_zone *zone; +} knot_zone_contents_t; + +/*----------------------------------------------------------------------------*/ + +knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, + uint node_count, + int use_domain_table, + struct knot_zone *zone); + +time_t knot_zone_contents_version(const knot_zone_contents_t *contents); + +void knot_zone_contents_set_version(knot_zone_contents_t *contents, + time_t version); + +//short knot_zone_contents_generation(const knot_zone_contents_t *contents); + +int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents); +int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents); +int knot_zone_contents_gen_is_finished(const knot_zone_contents_t *contents); + +//void knot_zone_contents_switch_generation(knot_zone_contents_t *contents); + +void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents); +void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents); +void knot_zone_contents_set_gen_new_finished(knot_zone_contents_t *contents); + +uint16_t knot_zone_contents_class(const knot_zone_contents_t *contents); + +/*! + * \brief Adds a node to the given zone. + * + * Checks if the node belongs to the zone, i.e. if its owner is a subdomain of + * the zone's apex. It thus also forbids adding node with the same name as the + * zone apex. + * + * \warning This function may destroy domain names saved in the node, that + * are already present in the zone. + * + * \param zone Zone to add the node into. + * \param node Node to add into the zone. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_EBADZONE + * \retval KNOT_EHASH + */ +int knot_zone_contents_add_node(knot_zone_contents_t *contents, + knot_node_t *node, int create_parents, + uint8_t flags, int use_domain_table); + +/*! + * \brief Adds a RRSet to the given zone. + * + * Checks if the RRSet belongs to the zone, i.e. if its owner is a subdomain of + * the zone's apex. The RRSet is inserted only if the node is given, or if + * a node where the RRSet should belong is found in the zone. + * + * \warning The function does not check if the node is already inserted in the + * zone, just assumes that it is. + * \warning This function may destroy domain names saved in the RRSet, that + * are already present in the zone. + * + * \param zone Zone to add the node into. + * \param rrset RRSet to add into the zone. + * \param node Node the RRSet should be inserted into. (Should be a node of the + * given zone.) If set to NULL, the function will find proper node + * and set it to this parameter. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_EBADZONE + */ +int knot_zone_contents_add_rrset(knot_zone_contents_t *contents, + knot_rrset_t *rrset, + knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table); + +int knot_zone_contents_add_rrsigs(knot_zone_contents_t *contents, + knot_rrset_t *rrsigs, + knot_rrset_t **rrset, knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table); + +/*! + * \brief Adds a node holding NSEC3 records to the given zone. + * + * Checks if the node belongs to the zone, i.e. if its owner is a subdomain of + * the zone's apex. It does not check if the node really contains any NSEC3 + * records, nor if the name is a hash (as there is actually no way of + * determining this). + * + * \param zone Zone to add the node into. + * \param node Node to add into the zone. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_EBADZONE + */ +int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *contents, + knot_node_t *node, int create_parents, + uint8_t flags, int use_domain_table); + +int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *contents, + knot_rrset_t *rrset, + knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table); + +int knot_zone_contents_remove_node(knot_zone_contents_t *contents, + const knot_node_t *node, knot_zone_tree_node_t **removed_tree, + ck_hash_table_item_t **removed_hash); + +//knot_zone_tree_node_t *knot_zone_contents_remove_node( +// knot_zone_contents_t *contents, const knot_node_t *node); + +int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents, + const knot_node_t *node, knot_zone_tree_node_t **removed); + +/*! + * \warning Always call knot_zone_adjust_dnames() prior to calling this + * function. Otherwise the node count would not be set. + * + * \note Currently, all nodes (even non-authoritative) are inserted into the + * hash table. + */ +int knot_zone_contents_create_and_fill_hash_table( + knot_zone_contents_t *contents); + +/*! + * \brief Tries to find a node with the specified name in the zone. + * + * \param zone Zone where the name should be searched for. + * \param name Name to find. + * + * \return Corresponding node if found, NULL otherwise. + */ +knot_node_t *knot_zone_contents_get_node( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +/*! + * \brief Tries to find a node with the specified name among the NSEC3 nodes + * of the zone. + * + * \param zone Zone where the name should be searched for. + * \param name Name to find. + * + * \return Corresponding node if found, NULL otherwise. + */ +knot_node_t *knot_zone_contents_get_nsec3_node( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +/*! + * \brief Tries to find a node with the specified name in the zone. + * + * \note This function is identical to knot_zone_contents_get_node(), only it returns + * constant reference. + * + * \param zone Zone where the name should be searched for. + * \param name Name to find. + * + * \return Corresponding node if found, NULL otherwise. + */ +const knot_node_t *knot_zone_contents_find_node( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +/*! + * \brief Tries to find domain name in the given zone using AVL tree. + * + * \param[in] zone Zone to search for the name. + * \param[in] name Domain name to search for. + * \param[out] node The found node (if it was found, otherwise it may contain + * arbitrary node). + * \param[out] closest_encloser Closest encloser of the given name in the zone. + * \param[out] previous Previous domain name in canonical order. + * + * \retval KNOT_ZONE_NAME_FOUND if node with owner \a name was found. + * \retval KNOT_ZONE_NAME_NOT_FOUND if it was not found. + * \retval KNOT_EBADARG + * \retval KNOT_EBADZONE + */ +int knot_zone_contents_find_dname(const knot_zone_contents_t *contents, + const knot_dname_t *name, + const knot_node_t **node, + const knot_node_t **closest_encloser, + const knot_node_t **previous); + +/*! + * \brief Finds previous name in canonical order to the given name in the zone. + * + * \param zone Zone to search for the name. + * \param name Domain name to find the previous domain name of. + * + * \return Previous node in canonical order, or NULL if some parameter is wrong. + */ +const knot_node_t *knot_zone_contents_find_previous( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +knot_node_t *knot_zone_contents_get_previous( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +const knot_node_t *knot_zone_contents_find_previous_nsec3( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +knot_node_t *knot_zone_contents_get_previous_nsec3( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +#ifdef USE_HASH_TABLE +/*! + * \brief Tries to find domain name in the given zone using the hash table. + * + * \param[in] zone Zone to search for the name. + * \param[in] name Domain name to search for. + * \param[out] node The found node (if it was found, otherwise it may contain + * arbitrary node). + * \param[out] closest_encloser Closest encloser of the given name in the zone. + * \param[out] previous Previous domain name in canonical order. + * + * \retval KNOT_ZONE_NAME_FOUND if node with owner \a name was found. + * \retval KNOT_ZONE_NAME_NOT_FOUND if it was not found. + * \retval KNOT_EBADARG + * \retval KNOT_EBADZONE + */ +int knot_zone_contents_find_dname_hash(const knot_zone_contents_t *contents, + const knot_dname_t *name, + const knot_node_t **node, + const knot_node_t **closest_encloser); +#endif + +/*! + * \brief Tries to find a node with the specified name among the NSEC3 nodes + * of the zone. + * + * \note This function is identical to knot_zone_contents_get_nsec3_node(), only it + * returns constant reference. + * + * \param zone Zone where the name should be searched for. + * \param name Name to find. + * + * \return Corresponding node if found, NULL otherwise. + */ +const knot_node_t *knot_zone_contents_find_nsec3_node( + const knot_zone_contents_t *contents, const knot_dname_t *name); + +/*! + * \brief Finds NSEC3 node and previous NSEC3 node in canonical order, + * corresponding to the given domain name. + * + * This functions creates a NSEC3 hash of \a name and tries to find NSEC3 node + * with the hashed domain name as owner. + * + * \param[in] zone Zone to search in. + * \param[in] name Domain name to get the corresponding NSEC3 nodes for. + * \param[out] nsec3_node NSEC3 node corresponding to \a name (if found, + * otherwise this may be an arbitrary NSEC3 node). + * \param[out] nsec3_previous The NSEC3 node immediately preceding hashed domain + * name corresponding to \a name in canonical order. + * + * \retval KNOT_ZONE_NAME_FOUND if the corresponding NSEC3 node was found. + * \retval KNOT_ZONE_NAME_NOT_FOUND if it was not found. + * \retval KNOT_EBADARG + * \retval KNOT_ENSEC3PAR + * \retval KNOT_ECRYPTO + * \retval KNOT_ERROR + */ +int knot_zone_contents_find_nsec3_for_name( + const knot_zone_contents_t *contents, + const knot_dname_t *name, + const knot_node_t **nsec3_node, + const knot_node_t **nsec3_previous, + int check_ver); +/*! + * \brief Returns the apex node of the zone. + * + * \param zone Zone to get the apex of. + * + * \return Zone apex node. + */ +const knot_node_t *knot_zone_contents_apex( + const knot_zone_contents_t *contents); + +knot_node_t *knot_zone_contents_get_apex( + const knot_zone_contents_t *contents); + +//knot_dname_t *knot_zone_contents_name( +// const knot_zone_contents_t *contents); + +/*! + * \brief Optimizes zone by replacing domain names in RDATA with references to + * domain names present in zone (as node owners). + * + * \param zone Zone to adjust domain names in. + */ +int knot_zone_contents_adjust(knot_zone_contents_t *contents, int check_ver); + +/*! + * \brief Parses the NSEC3PARAM record stored in the zone. + * + * This function properly fills in the nsec3_params field of the zone structure + * according to data stored in the NSEC3PARAM record. This is necessary to do + * before any NSEC3 operations on the zone are requested, otherwise they will + * fail (error KNOT_ENSEC3PAR). + * + * \note If there is no NSEC3PARAM record in the zone, this function clears + * the nsec3_params field of the zone structure (fills it with zeros). + * + * \param zone Zone to get the NSEC3PARAM record from. + */ +int knot_zone_contents_load_nsec3param(knot_zone_contents_t *contents); + +/*! + * \brief Checks if the zone uses NSEC3. + * + * This function will return 0 if the NSEC3PARAM record was not parse prior to + * calling it. + * + * \param zone Zone to check. + * + * \retval <> 0 if the zone uses NSEC3. + * \retval 0 if it does not. + * + * \see knot_zone_contents_load_nsec3param() + */ +int knot_zone_contents_nsec3_enabled(const knot_zone_contents_t *contents); + +/*! + * \brief Returns the parsed NSEC3PARAM record of the zone. + * + * \note You must parse the NSEC3PARAM record prior to calling this function + * (knot_zone_contents_load_nsec3param()). + * + * \param zone Zone to get the NSEC3PARAM record from. + * + * \return Parsed NSEC3PARAM from the zone or NULL if the zone does not use + * NSEC3 or the record was not parsed before. + * + * \see knot_zone_contents_load_nsec3param() + */ +const knot_nsec3_params_t *knot_zone_contents_nsec3params( + const knot_zone_contents_t *contents); + +/*! + * \brief Applies the given function to each regular node in the zone. + * + * This function uses post-order depth-first forward traversal, i.e. the + * function is first recursively applied to subtrees and then to the root. + * + * \param zone Nodes of this zone will be used as parameters for the function. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + */ +int knot_zone_contents_tree_apply_postorder(knot_zone_contents_t *contents, + void (*function)(knot_node_t *node, void *data), + void *data); + +/*! + * \brief Applies the given function to each regular node in the zone. + * + * This function uses in-order depth-first forward traversal, i.e. the function + * is first recursively applied to left subtree, then to the root and then to + * the right subtree. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param zone Nodes of this zone will be used as parameters for the function. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + */ +int knot_zone_contents_tree_apply_inorder(knot_zone_contents_t *contents, + void (*function)(knot_node_t *node, void *data), + void *data); + +/*! + * \brief Applies the given function to each regular node in the zone. + * + * This function uses in-order depth-first reverse traversal, i.e. the function + * is first recursively applied to right subtree, then to the root and then to + * the left subtree. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param zone Nodes of this zone will be used as parameters for the function. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + */ +int knot_zone_contents_tree_apply_inorder_reverse( + knot_zone_contents_t *contents, + void (*function)(knot_node_t *node, void *data), void *data); + +/*! + * \brief Applies the given function to each NSEC3 node in the zone. + * + * This function uses post-order depth-first forward traversal, i.e. the + * function is first recursively applied to subtrees and then to the root. + * + * \param zone NSEC3 nodes of this zone will be used as parameters for the + * function. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + */ +int knot_zone_contents_nsec3_apply_postorder(knot_zone_contents_t *contents, + void (*function)(knot_node_t *node, void *data), + void *data); + +/*! + * \brief Applies the given function to each NSEC3 node in the zone. + * + * This function uses in-order depth-first forward traversal, i.e. the function + * is first recursively applied to left subtree, then to the root and then to + * the right subtree. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param zone NSEC3 nodes of this zone will be used as parameters for the + * function. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + */ +int knot_zone_contents_nsec3_apply_inorder(knot_zone_contents_t *contents, + void (*function)(knot_node_t *node, void *data), + void *data); + +/*! + * \brief Applies the given function to each NSEC3 node in the zone. + * + * This function uses in-order depth-first reverse traversal, i.e. the function + * is first recursively applied to right subtree, then to the root and then to + * the left subtree. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param zone NSEC3 nodes of this zone will be used as parameters for the + * function. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + */ +int knot_zone_contents_nsec3_apply_inorder_reverse( + knot_zone_contents_t *contents, + void (*function)(knot_node_t *node, void *data), void *data); + +knot_zone_tree_t *knot_zone_contents_get_nodes( + knot_zone_contents_t *contents); + +knot_zone_tree_t *knot_zone_contents_get_nsec3_nodes( + knot_zone_contents_t *contents); + +ck_hash_table_t *knot_zone_contents_get_hash_table( + knot_zone_contents_t *contents); + +int knot_zone_contents_dname_table_apply(knot_zone_contents_t *contents, + void (*function)(knot_dname_t *, + void *), + void *data); + +/*! + * \brief Creates a shallow copy of the zone (no stored data are copied). + * + * This function creates a new zone structure in \a to, creates new trees for + * regular nodes and for NSEC3 nodes, creates new hash table and a new domain + * table. It also fills these structures with the exact same data as the + * original zone is - no copying of stored data is done, just pointers are + * copied. + * + * \param from Original zone. + * \param to Copy of the zone. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + */ +int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, + knot_zone_contents_t **to); + +void knot_zone_contents_free(knot_zone_contents_t **contents); + +void knot_zone_contents_deep_free(knot_zone_contents_t **contents, + int destroy_dname_table); + +#endif + +/*! @} */ diff --git a/src/libknot/zone/zone-tree.c b/src/libknot/zone/zone-tree.c new file mode 100644 index 0000000..cdf128e --- /dev/null +++ b/src/libknot/zone/zone-tree.c @@ -0,0 +1,470 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#include "zone-tree.h" +#include "zone/node.h" +#include "util/error.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ + +// AVL tree functions +TREE_DEFINE(knot_zone_tree_node, avl); + +/*----------------------------------------------------------------------------*/ + +static int knot_zone_tree_node_compare(knot_zone_tree_node_t *node1, + knot_zone_tree_node_t *node2) +{ + assert(node1 != NULL); + assert(node2 != NULL); + assert(node1->node != NULL); + assert(node2->node != NULL); + assert(knot_node_owner(node1->node) != NULL); + assert(knot_node_owner(node2->node) != NULL); + + return knot_node_compare(node1->node, node2->node); +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_tree_delete_subtree(knot_zone_tree_node_t *root) +{ + if (root == NULL) { + return; + } + + knot_zone_tree_delete_subtree(root->avl.avl_left); + knot_zone_tree_delete_subtree(root->avl.avl_right); + free(root); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_zone_tree_copy_node(knot_zone_tree_node_t *from, + knot_zone_tree_node_t **to) +{ + if (from == NULL) { + *to = NULL; + return KNOT_EOK; + } + + *to = (knot_zone_tree_node_t *) + malloc(sizeof(knot_zone_tree_node_t)); + if (*to == NULL) { + return KNOT_ENOMEM; + } + + (*to)->node = from->node; + (*to)->avl.avl_height = from->avl.avl_height; + + int ret = knot_zone_tree_copy_node(from->avl.avl_left, + &(*to)->avl.avl_left); + if (ret != KNOT_EOK) { + return ret; + } + + ret = knot_zone_tree_copy_node(from->avl.avl_right, + &(*to)->avl.avl_right); + if (ret != KNOT_EOK) { + knot_zone_tree_delete_subtree((*to)->avl.avl_left); + (*to)->avl.avl_left = NULL; + return ret; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_tree_free_node(knot_zone_tree_node_t *node, + int free_data, int free_owner) +{ + if (node == NULL) { + return; + } + + knot_zone_tree_free_node(node->avl.avl_left, free_data, free_owner); + + knot_zone_tree_free_node(node->avl.avl_right, free_data, free_owner); + + if (free_data) { + knot_node_free(&node->node, free_owner, 0); + } + + free(node); +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_init(knot_zone_tree_t *tree) +{ + if (tree == NULL) { + return KNOT_EBADARG; + } + + TREE_INIT(tree, knot_zone_tree_node_compare); + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_insert(knot_zone_tree_t *tree, knot_node_t *node) +{ + if (tree == NULL || node == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_node_t *znode = (knot_zone_tree_node_t *)malloc( + sizeof(knot_zone_tree_node_t)); + if (znode == NULL) { + return KNOT_ENOMEM; + } + + znode->node = node; + znode->avl.avl_left = NULL; + znode->avl.avl_right = NULL; + znode->avl.avl_height = 0; + + /*! \todo How to know if this was successful? */ + TREE_INSERT(tree, knot_zone_tree_node, avl, znode); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_find(knot_zone_tree_t *tree, const knot_dname_t *owner, + const knot_node_t **found) +{ + if (tree == NULL || owner == NULL || found == NULL) { + return KNOT_EBADARG; + } + + knot_node_t *f = NULL; + int ret = knot_zone_tree_get(tree, owner, &f); + *found = f; + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_get(knot_zone_tree_t *tree, const knot_dname_t *owner, + knot_node_t **found) +{ + if (tree == NULL || owner == NULL) { + return KNOT_EBADARG; + } + + *found = NULL; + + // create dummy node to use for lookup + knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc( + sizeof(knot_zone_tree_node_t)); + if (tmp == NULL) { + return KNOT_ENOMEM; + } + + // create dummy data node to use for lookup + knot_node_t *tmp_data = knot_node_new( + (knot_dname_t *)owner, NULL, 0); + if (tmp_data == NULL) { + free(tmp); + return KNOT_ENOMEM; + } + tmp->node = tmp_data; + + knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl, + tmp); + + knot_node_free(&tmp_data, 0, 0); + free(tmp); + + if (n != NULL) { + *found = n->node; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_find_less_or_equal(knot_zone_tree_t *tree, + const knot_dname_t *owner, + const knot_node_t **found, + const knot_node_t **previous, + int check_version) +{ + if (tree == NULL || owner == NULL || found == NULL || previous == NULL) { + return KNOT_EBADARG; + } + + knot_node_t *f, *p; + int ret = knot_zone_tree_get_less_or_equal(tree, owner, &f, &p, check_version); + + *found = f; + *previous = p; + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree, + const knot_dname_t *owner, + knot_node_t **found, + knot_node_t **previous, + int check_version) +{ + if (tree == NULL || owner == NULL || found == NULL + || previous == NULL) { + return KNOT_EBADARG; + } + + knot_zone_tree_node_t *f = NULL, *prev = NULL; + + // create dummy node to use for lookup + knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc( + sizeof(knot_zone_tree_node_t)); + if (tmp == NULL) { + return KNOT_ENOMEM; + } + + // create dummy data node to use for lookup + knot_node_t *tmp_data = knot_node_new( + (knot_dname_t *)owner, NULL, 0); + if (tmp_data == NULL) { + free(tmp); + return KNOT_ENOMEM; + } + tmp->node = tmp_data; + + int exact_match = TREE_FIND_LESS_EQUAL( + tree, knot_zone_tree_node, avl, tmp, &f, &prev); + + knot_node_free(&tmp_data, 0, 0); + free(tmp); + + *found = (exact_match > 0) ? f->node : NULL; + + if (exact_match < 0) { + // previous is not really previous but should be the leftmost + // node in the tree; take it's previous + assert(prev != NULL); + *previous = knot_node_get_previous(prev->node, check_version); + exact_match = 0; + } else if (prev == NULL) { + if (!exact_match) { + printf("Searched for owner %s in zone tree.\n", + knot_dname_to_str(owner)); + printf("Exact match: %d\n", exact_match); + printf("Found node: %p: %s.\n", f, (f) + ? knot_dname_to_str(knot_node_owner(f->node)) + : "none"); + printf("Previous node: %p: %s.\n", prev, (prev) + ? knot_dname_to_str(knot_node_owner(prev->node)) + : "none"); + } + + // either the returned node is the root of the tree, or + // it is the leftmost node in the tree; in both cases + // node was found set the previous node of the found + // node + assert(exact_match > 0); + assert(f != NULL); + *previous = knot_node_get_previous(f->node, check_version); + } else { + // otherwise check if the previous node is not an empty + // non-terminal + /*! \todo Here we assume that the 'prev' pointer always points + * to an empty non-terminal. + */ + *previous = (knot_node_rrset_count(prev->node) == 0) + ? knot_node_get_previous(prev->node, check_version) + : prev->node; + } + + assert(exact_match >= 0); + + return exact_match; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_remove(knot_zone_tree_t *tree, + const knot_dname_t *owner, + knot_zone_tree_node_t **removed) +{ + if (tree == NULL || owner == NULL || removed == NULL) { + return KNOT_EBADARG; + } + + // create dummy node to use for lookup + knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc( + sizeof(knot_zone_tree_node_t)); + if (tmp == NULL) { + return KNOT_ENOMEM; + } + + // create dummy data node to use for lookup + knot_node_t *tmp_data = knot_node_new( + (knot_dname_t *)owner, NULL, 0); + if (tmp_data == NULL) { + free(tmp); + return KNOT_ENOMEM; + } + tmp->node = tmp_data; + + // we must first find the node, so that it may be destroyed + knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl, + tmp); + + /*! \todo How to know if this was successful? */ + TREE_REMOVE(tree, knot_zone_tree_node, avl, tmp); + + knot_node_free(&tmp_data, 0, 0); + free(tmp); + +// *removed = (n) ? n->node : NULL; +// free(n); + *removed = n; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_forward_apply_inorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data) +{ + if (tree == NULL || function == NULL) { + return KNOT_EBADARG; + } + + TREE_FORWARD_APPLY(tree, knot_zone_tree_node, avl, + function, data); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_forward_apply_postorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data) +{ + if (tree == NULL || function == NULL) { + return KNOT_EBADARG; + } + + TREE_POST_ORDER_APPLY(tree, knot_zone_tree_node, avl, + function, data); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_reverse_apply_inorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data) +{ + if (tree == NULL || function == NULL) { + return KNOT_EBADARG; + } + + TREE_REVERSE_APPLY(tree, knot_zone_tree_node, avl, + function, data); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_reverse_apply_postorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data) +{ + if (tree == NULL || function == NULL) { + return KNOT_EBADARG; + } + + TREE_REVERSE_APPLY_POST(tree, knot_zone_tree_node, avl, + function, data); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_tree_shallow_copy(knot_zone_tree_t *from, + knot_zone_tree_t *to) +{ + if (to == NULL || from == NULL) { + return KNOT_EBADARG; + } + /* + * This function will copy the tree by hand, so that the nodes + * do not have to be inserted the normal way. It should be substantially + * faster. + */ + + to->th_cmp = from->th_cmp; + + return knot_zone_tree_copy_node(from->th_root, &to->th_root); +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_tree_free(knot_zone_tree_t **tree) +{ + if (tree == NULL || *tree == NULL) { + return; + } + knot_zone_tree_free_node((*tree)->th_root, 0, 0); + free(*tree); + *tree = NULL; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_tree_deep_free(knot_zone_tree_t **tree, int free_owners) +{ + if (tree == NULL || *tree == NULL) { + return; + } + knot_zone_tree_free_node((*tree)->th_root, 1, free_owners); + free(*tree); + *tree = NULL; +} + +/*----------------------------------------------------------------------------*/ diff --git a/src/libknot/zone/zone-tree.h b/src/libknot/zone/zone-tree.h new file mode 100644 index 0000000..0971749 --- /dev/null +++ b/src/libknot/zone/zone-tree.h @@ -0,0 +1,300 @@ +/*! + * \file zone-tree.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Zone tree structure and API for manipulating it. + * + * Implemented as AVL tree. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_ZONE_TREE_H_ +#define _KNOT_ZONE_TREE_H_ + +#include "common/tree.h" +#include "zone/node.h" + +/*----------------------------------------------------------------------------*/ + +typedef struct knot_zone_tree_node { + /*! \brief Structure for connecting this node to an AVL tree. */ + TREE_ENTRY(knot_zone_tree_node) avl; + /*! \brief Zone tree data. */ + knot_node_t *node; + /*! \brief Owner of the node. */ +// knot_dname_t *owner; +} knot_zone_tree_node_t; + +/*----------------------------------------------------------------------------*/ + +typedef TREE_HEAD(knot_zone_tree, knot_zone_tree_node) knot_zone_tree_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Initializes the zone tree. + * + * Does not allocate the structure. Must be called before any use of the tree. + * + * \param tree Zone tree structure to initialize. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + */ +int knot_zone_tree_init(knot_zone_tree_t *tree); + +/*! + * \brief Inserts the given node into the zone tree. + * + * \param tree Zone tree to insert the node into. + * \param node Node to insert. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + */ +int knot_zone_tree_insert(knot_zone_tree_t *tree, knot_node_t *node); + +/*! + * \brief Finds node with the given owner in the zone tree. + * + * \param tree Zone tree to search in. + * \param owner Owner of the node to find. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + */ +int knot_zone_tree_find(knot_zone_tree_t *tree, + const knot_dname_t *owner, + const knot_node_t **found); + +/*! + * \brief Finds node with the given owner in the zone tree. + * + * \note This function is identical to knot_zone_tree_find() except that it + * returns non-const node. + * + * \param tree Zone tree to search in. + * \param owner Owner of the node to find. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + */ +int knot_zone_tree_get(knot_zone_tree_t *tree, + const knot_dname_t *owner, + knot_node_t **found); + +/*! + * \brief Tries to find the given domain name in the zone tree and returns the + * associated node and previous node in canonical order. + * + * \param zone Zone to search in. + * \param owner Owner of the node to find. + * \param found Found node. + * \param previous Previous node in canonical order (i.e. the one directly + * preceding \a owner in canonical order, regardless if the name + * is in the zone or not). + * + * \retval > 0 if the domain name was found. In such case \a found holds the + * zone node with \a owner as its owner. + * \a previous is set properly. + * \retval 0 if the domain name was not found. \a found may hold any (or none) + * node. \a previous is set properly. + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + */ +int knot_zone_tree_find_less_or_equal(knot_zone_tree_t *tree, + const knot_dname_t *owner, + const knot_node_t **found, + const knot_node_t **previous, + int check_version); + +/*! + * \brief Tries to find the given domain name in the zone tree and returns the + * associated node and previous node in canonical order. + * + * \note This function is identical to knot_zone_tree_find_less_or_equal() + * except that it returns non-const nodes. + * + * \param zone Zone to search in. + * \param owner Owner of the node to find. + * \param found Found node. + * \param previous Previous node in canonical order (i.e. the one directly + * preceding \a owner in canonical order, regardless if the name + * is in the zone or not). + * + * \retval > 0 if the domain name was found. In such case \a found holds the + * zone node with \a owner as its owner. + * \a previous is set properly. + * \retval 0 if the domain name was not found. \a found may hold any (or none) + * node. \a previous is set properly. + * \retval KNOT_EBADARG + * \retval KNOT_ENOMEM + */ +int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree, + const knot_dname_t *owner, + knot_node_t **found, + knot_node_t **previous, + int check_version); + +/*! + * \brief Removes node with the given owner from the zone tree and returns it. + * + * \param tree Zone tree to remove the node from. + * \param owner Owner of the node to find. + * \param removed The removed node. + * + * \retval The removed node. + */ +int knot_zone_tree_remove(knot_zone_tree_t *tree, + const knot_dname_t *owner, + knot_zone_tree_node_t **removed); + +/*! + * \brief Applies the given function to each node in the zone. + * + * This function uses in-order depth-first forward traversal, i.e. the function + * is first recursively applied to left subtree, then to the root and then to + * the right subtree. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param tree Zone tree to apply the function to. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + */ +int knot_zone_tree_forward_apply_inorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data); + +/*! + * \brief Applies the given function to each node in the zone. + * + * This function uses post-order depth-first forward traversal, i.e. the + * function is first recursively applied to subtrees and then to the root. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param tree Zone tree to apply the function to. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + */ +int knot_zone_tree_forward_apply_postorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data); + +/*! + * \brief Applies the given function to each node in the zone. + * + * This function uses in-order depth-first reverse traversal, i.e. the function + * is first recursively applied to right subtree, then to the root and then to + * the left subtree. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param tree Zone tree to apply the function to. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + */ +int knot_zone_tree_reverse_apply_inorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data); + +/*! + * \brief Applies the given function to each node in the zone. + * + * This function uses post-order depth-first reverse traversal, i.e. the + * function is first recursively applied to right subtree, then to the + * left subtree and then to the root. + * + * \note This implies that the zone is stored in a binary tree. Is there a way + * to make this traversal independent on the underlying structure? + * + * \param tree Zone tree to apply the function to. + * \param function Function to be applied to each node of the zone. + * \param data Arbitrary data to be passed to the function. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + */ +int knot_zone_tree_reverse_apply_postorder(knot_zone_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data); + +/*! + * \brief Copies the whole zone tree structure (but not the data contained + * within). + * + * \warning This function does not check if the target zone tree is empty, + * it just replaces the root pointer. + * + * \param from Original zone tree. + * \param to Zone tree to copy the original one into. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +int knot_zone_tree_shallow_copy(knot_zone_tree_t *from, + knot_zone_tree_t *to); + +/*! + * \brief Destroys the zone tree, not touching the saved data. + * + * \param tree Zone tree to be destroyed. + */ +void knot_zone_tree_free(knot_zone_tree_t **tree); + +/*! + * \brief Destroys the zone tree, together with the saved data. + * + * \param tree Zone tree to be destroyed. + * \param free_owners Set to <> 0 if owners of the nodes should be destroyed + * as well. Set to 0 otherwise. + */ +void knot_zone_tree_deep_free(knot_zone_tree_t **tree, int free_owners); + +/*----------------------------------------------------------------------------*/ + +#endif // _KNOT_ZONE_TREE_H_ + +/*! @} */ + diff --git a/src/libknot/zone/zone.c b/src/libknot/zone/zone.c new file mode 100644 index 0000000..9de1a53 --- /dev/null +++ b/src/libknot/zone/zone.c @@ -0,0 +1,246 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include <urcu.h> + +#include "common.h" +#include "zone/zone.h" +#include "zone/node.h" +#include "dname.h" +#include "consts.h" +#include "util/descriptor.h" +#include "nsec3.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/utils.h" +#include "common/tree.h" +#include "common/base32hex.h" +#include "hash/cuckoo-hash-table.h" +#include "zone/zone-contents.h" + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_zone_t *knot_zone_new_empty(knot_dname_t *name) +{ + if (!name) { + return 0; + } + + dbg_zone("Creating new zone!\n"); + + knot_zone_t *zone = malloc(sizeof(knot_zone_t)); + if (zone == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + memset(zone, 0, sizeof(knot_zone_t)); + + // save the zone name + dbg_zone("Setting zone name.\n"); + zone->name = name; + return zone; +} + +/*----------------------------------------------------------------------------*/ + +knot_zone_t *knot_zone_new(knot_node_t *apex, uint node_count, + int use_domain_table) +{ + knot_zone_t *zone = knot_zone_new_empty( + knot_dname_deep_copy(knot_node_owner(apex))); + if (zone == NULL) { + return NULL; + } + + dbg_zone("Creating zone contents.\n"); + zone->contents = knot_zone_contents_new(apex, node_count, + use_domain_table, zone); + if (zone->contents == NULL) { + knot_dname_release(zone->name); + free(zone); + return NULL; + } + + zone->contents->zone = zone; + + return zone; +} + +/*----------------------------------------------------------------------------*/ + +knot_zone_contents_t *knot_zone_get_contents( + const knot_zone_t *zone) +{ + if (zone == NULL) { + return NULL; + } + + return rcu_dereference(zone->contents); +} + +/*----------------------------------------------------------------------------*/ + +const knot_zone_contents_t *knot_zone_contents( + const knot_zone_t *zone) +{ + if (zone == NULL) { + return NULL; + } + + return rcu_dereference(zone->contents); +} + +/*----------------------------------------------------------------------------*/ + +time_t knot_zone_version(const knot_zone_t *zone) +{ + if (zone == NULL) { + return KNOT_EBADARG; + } + + return zone->version; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_set_version(knot_zone_t *zone, time_t version) +{ + if (zone == NULL) { + return; + } + + zone->version = version; +} + +/*----------------------------------------------------------------------------*/ + +short knot_zone_is_master(const knot_zone_t *zone) +{ + return zone->master; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_set_master(knot_zone_t *zone, short master) +{ + zone->master = master; +} + +/*----------------------------------------------------------------------------*/ + +const void *knot_zone_data(const knot_zone_t *zone) +{ + return zone->data; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_set_data(knot_zone_t *zone, void *data) +{ + zone->data = data; +} + +/*----------------------------------------------------------------------------*/ + +const knot_dname_t *knot_zone_name(const knot_zone_t *zone) +{ + return zone->name; +} + +/*----------------------------------------------------------------------------*/ + +knot_zone_contents_t *knot_zone_switch_contents(knot_zone_t *zone, + knot_zone_contents_t *new_contents) +{ + if (zone == NULL) { + return NULL; + } + + knot_zone_contents_t *old_contents = + rcu_xchg_pointer(&zone->contents, new_contents); + return old_contents; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_free(knot_zone_t **zone) +{ + if (zone == NULL || *zone == NULL) { + return; + } + + dbg_zone("zone_free().\n"); + + if ((*zone)->contents + && !knot_zone_contents_gen_is_old((*zone)->contents)) { + // zone is in the middle of an update, report + dbg_zone("Destroying zone that is in the middle of an " + "update.\n"); + } + + knot_dname_release((*zone)->name); + + /* Call zone data destructor if exists. */ + if ((*zone)->dtor) { + (*zone)->dtor(*zone); + } + + knot_zone_contents_free(&(*zone)->contents); + free(*zone); + *zone = NULL; + + dbg_zone("Done.\n"); +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table) +{ + if (zone == NULL || *zone == NULL) { + return; + } + + if ((*zone)->contents + && !knot_zone_contents_gen_is_old((*zone)->contents)) { + // zone is in the middle of an update, report + dbg_zone("Destroying zone that is in the middle of an " + "update.\n"); + } + +dbg_zone_exec( + char *name = knot_dname_to_str((*zone)->name); + dbg_zone("Destroying zone %p, name: %s.\n", *zone, name); + free(name); +); + + knot_dname_release((*zone)->name); + + /* Call zone data destructor if exists. */ + if ((*zone)->dtor) { + (*zone)->dtor(*zone); + } + + knot_zone_contents_deep_free(&(*zone)->contents, destroy_dname_table); + free(*zone); + *zone = NULL; +} diff --git a/src/libknot/zone/zone.h b/src/libknot/zone/zone.h new file mode 100644 index 0000000..331ef1f --- /dev/null +++ b/src/libknot/zone/zone.h @@ -0,0 +1,157 @@ +/*! + * \file zone.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Zone structure and API for manipulating it. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_ZONE_H_ +#define _KNOT_ZONE_H_ + +#include <time.h> + +#include "zone/node.h" +#include "dname.h" +#include "nsec3.h" +#include "zone/dname-table.h" +#include "common/tree.h" +#include "hash/cuckoo-hash-table.h" + +#include "zone-tree.h" + +#include "zone/zone-contents.h" + +/*----------------------------------------------------------------------------*/ + +//typedef TREE_HEAD(avl_tree, knot_node) avl_tree_t; +//struct event_t; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Return values for search functions. + * + * Used in knot_zone_find_dname() and knot_zone_find_dname_hash(). + */ +enum knot_zone_retvals { + KNOT_ZONE_NAME_FOUND = 1, + KNOT_ZONE_NAME_NOT_FOUND = 0 +}; + +typedef enum knot_zone_retvals knot_zone_retvals_t; + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Structure for holding DNS zone. + * + * \warning Make sure not to insert the same nodes using both the normal and + * NSEC3 functions. Although this will be successfull, it will produce + * double-free errors when destroying the zone. + */ +struct knot_zone { + knot_dname_t *name; + + knot_zone_contents_t *contents; + + time_t version; + + /*! \todo Set when loading zone. */ + short master; + + void *data; /*!< Pointer to generic zone-related data. */ + int (*dtor)(struct knot_zone *); /*!< Data destructor. */ +}; + +typedef struct knot_zone knot_zone_t; + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Creates new empty DNS zone. + * + * \notice Zone will be created without contents. + * + * \param name Zone owner. + * + * \return The initialized zone structure or NULL if an error occured. + */ +knot_zone_t *knot_zone_new_empty(knot_dname_t *name); + +/*! + * \brief Creates new DNS zone. + * + * \param apex Node representing the zone apex. + * \param node_count Number of authorative nodes in the zone. + * + * \return The initialized zone structure or NULL if an error occured. + */ +knot_zone_t *knot_zone_new(knot_node_t *apex, uint node_count, + int use_domain_table); + +knot_zone_contents_t *knot_zone_get_contents( + const knot_zone_t *zone); + +const knot_zone_contents_t *knot_zone_contents( + const knot_zone_t *zone); + + +time_t knot_zone_version(const knot_zone_t *zone); + +void knot_zone_set_version(knot_zone_t *zone, time_t version); + +short knot_zone_is_master(const knot_zone_t *zone); + +void knot_zone_set_master(knot_zone_t *zone, short master); + +const void *knot_zone_data(const knot_zone_t *zone); + +void knot_zone_set_data(knot_zone_t *zone, void *data); + +const knot_dname_t *knot_zone_name(const knot_zone_t *zone); + +knot_zone_contents_t *knot_zone_switch_contents(knot_zone_t *zone, + knot_zone_contents_t *new_contents); + +/*! + * \brief Correctly deallocates the zone structure, without deleting its nodes. + * + * Also sets the given pointer to NULL. + * + * \param zone Zone to be freed. + */ +void knot_zone_free(knot_zone_t **zone); + +/*! + * \brief Correctly deallocates the zone structure and all nodes within. + * + * Also sets the given pointer to NULL. + * + * \param zone Zone to be freed. + * \param free_rdata_dnames Set to <> 0 if you want to delete ALL domain names + * present in RDATA. Set to 0 otherwise. (See + * knot_rdata_deep_free().) + */ +void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table); + +#endif + +/*! @} */ diff --git a/src/libknot/zone/zonedb.c b/src/libknot/zone/zonedb.c new file mode 100644 index 0000000..8f07d45 --- /dev/null +++ b/src/libknot/zone/zonedb.c @@ -0,0 +1,389 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdlib.h> +#include <assert.h> + +#include <urcu.h> + +#include "common.h" +#include "zone/zone.h" +#include "zone/zonedb.h" +#include "dname.h" +#include "zone/node.h" +#include "util/error.h" +#include "util/debug.h" +#include "common/general-tree.h" + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Compares the two arguments interpreted as zone names (domain names). + * + * Use this function with generic data structures (such as the skip list). + * + * \param d1 First zone name. + * \param d2 Second zone name. + * + * \retval 0 if the two zone names are equal. + * \retval < 0 if \a d1 is before \a d2 in canonical order. + * \retval > 0 if \a d1 is after \a d2 in canonical order. + */ +static int knot_zonedb_compare_zone_names(void *p1, void *p2) +{ + const knot_zone_t *zone1 = (const knot_zone_t *)p1; + const knot_zone_t *zone2 = (const knot_zone_t *)p2; + + int ret = knot_dname_compare(zone1->name, zone2->name); + +dbg_zonedb_exec( + char *name1 = knot_dname_to_str(zone1->name); + char *name2 = knot_dname_to_str(zone2->name); + dbg_zonedb("Compared names %s and %s, result: %d.\n", + name1, name2, ret); + free(name1); + free(name2); +); + + return (ret); +} + +/*----------------------------------------------------------------------------*/ + +//static int knot_zonedb_replace_zone_in_list(void **list_item, void **new_zone) +//{ +// assert(list_item != NULL); +// assert(*list_item != NULL); +// assert(new_zone != NULL); +// assert(*new_zone != NULL); + +// dbg_zonedb("Replacing list item %p with new zone %p\n", +// *list_item, *new_zone); + +// *list_item = *new_zone; + +// return 0; +//} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_zonedb_t *knot_zonedb_new() +{ + knot_zonedb_t *db = + (knot_zonedb_t *)malloc(sizeof(knot_zonedb_t)); + CHECK_ALLOC_LOG(db, NULL); + + db->zone_tree = gen_tree_new(knot_zonedb_compare_zone_names); + if (db->zone_tree == NULL) { + free(db); + return NULL; + } + + db->zone_count = 0; + + return db; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone) +{ + if (db == NULL || zone == NULL) { + return KNOT_EBADARG; + } +dbg_zonedb_exec( + char *name = knot_dname_to_str(zone->name); + dbg_zonedb("Inserting zone %s into zone db.\n", name); + free(name); +); + + int ret = KNOT_EOK; + if (knot_zone_contents(zone)) { + ret = knot_zone_contents_load_nsec3param( + knot_zone_get_contents(zone)); + if (ret != KNOT_EOK) { + return ret; + } + } + + ret = gen_tree_add(db->zone_tree, zone, NULL); + + if (ret == 0) { + db->zone_count++; + } + + return (ret != 0) ? KNOT_EZONEIN : KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +knot_zone_t *knot_zonedb_remove_zone(knot_zonedb_t *db, + const knot_dname_t *zone_name) +{ + knot_zone_t dummy_zone; + memset(&dummy_zone, 0, sizeof(knot_zone_t)); + dummy_zone.name = (knot_dname_t *)zone_name; + + // add some lock to avoid multiple removals + knot_zone_t *z = (knot_zone_t *)gen_tree_find(db->zone_tree, + &dummy_zone); + + if (z == NULL) { + return NULL; + } + + // remove the zone from the skip list, but do not destroy it + gen_tree_remove(db->zone_tree, &dummy_zone); + +// if (destroy_zone) { +// // properly destroy the zone and all its contents +// knot_zone_deep_free(&z, 0); +// } + + db->zone_count--; + + //return KNOT_EOK; + return z; +} + +/*----------------------------------------------------------------------------*/ + +//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db, +// knot_zone_t *zone) +//{ +// knot_zone_t *z = knot_zonedb_find_zone(db, +// knot_node_owner(knot_zone_apex(zone))); +// if (z == NULL) { +// return NULL; +// } + +// /*! \todo The replace should be atomic!!! */ + +// dbg_zonedb("Found zone: %p\n", z); + +// int ret = skip_remove(db->zones, +// (void *)knot_node_owner(knot_zone_apex(zone)), +// NULL, NULL); +// if (ret != 0) { +// return NULL; +// } + +// dbg_zonedb("Removed zone, return value: %d\n", ret); +// dbg_zonedb("Old zone: %p\n", z); + +// ret = skip_insert(db->zones, +// (void *)knot_node_owner(knot_zone_apex(zone)), +// (void *)zone, NULL); + +// dbg_zonedb("Inserted zone, return value: %d\n", ret); + +// if (ret != 0) { +// // return the removed zone back +// skip_insert(db->zones, +// (void *)knot_node_owner(knot_zone_apex(z)), +// (void *)z, NULL); +// /*! \todo There may be problems and the zone may remain +// removed. */ +// return NULL; +// } + +// return z; +//} + +/*----------------------------------------------------------------------------*/ + +knot_zone_t *knot_zonedb_find_zone(const knot_zonedb_t *db, + const knot_dname_t *zone_name) +{ + knot_zone_t dummy_zone; + dummy_zone.name = (knot_dname_t *)zone_name; + return (knot_zone_t *)gen_tree_find(db->zone_tree, &dummy_zone); +} + +/*----------------------------------------------------------------------------*/ + +const knot_zone_t *knot_zonedb_find_zone_for_name(knot_zonedb_t *db, + const knot_dname_t *dname) +{ + if (db == NULL || dname == NULL) { + return NULL; + } + + knot_zone_t dummy_zone; + dummy_zone.name = (knot_dname_t *)dname; + void *found = NULL; + int exact_match = gen_tree_find_less_or_equal(db->zone_tree, + &dummy_zone, + &found); + UNUSED(exact_match); + + knot_zone_t *zone = (found) ? (knot_zone_t *)found : NULL; + +dbg_zonedb_exec( + char *name = knot_dname_to_str(dname); + dbg_zonedb("Found zone for name %s: %p\n", name, zone); + free(name); +); + if (zone != NULL && zone->contents != NULL + && knot_dname_compare(zone->contents->apex->owner, dname) != 0 + && !knot_dname_is_subdomain(dname, zone->contents->apex->owner)) { + zone = NULL; + } + + return zone; +} + +/*----------------------------------------------------------------------------*/ + +knot_zone_contents_t *knot_zonedb_expire_zone(knot_zonedb_t *db, + const knot_dname_t *zone_name) +{ + if (db == NULL || zone_name == NULL) { + return NULL; + } + + // Remove the contents from the zone, but keep the zone in the zonedb. + + knot_zone_t *zone = knot_zonedb_find_zone(db, zone_name); + if (zone == NULL) { + return NULL; + } + + return knot_zone_switch_contents(zone, NULL); +} + +/*----------------------------------------------------------------------------*/ + +knot_zonedb_t *knot_zonedb_copy(const knot_zonedb_t *db) +{ + knot_zonedb_t *db_new = + (knot_zonedb_t *)malloc(sizeof(knot_zonedb_t)); + CHECK_ALLOC_LOG(db_new, NULL); + + db_new->zone_tree = gen_tree_shallow_copy(db->zone_tree); + if (db_new->zone_tree == NULL) { + free(db_new); + return NULL; + } + + return db_new; +} + +size_t knot_zonedb_zone_count(const knot_zonedb_t *db) +{ + return db->zone_count; +} + +struct knot_zone_db_tree_arg { + const knot_zone_t **zones; + size_t count; +}; + +static void save_zone_to_array(void *node, void *data) +{ + knot_zone_t *zone = (knot_zone_t *)node; + struct knot_zone_db_tree_arg *args = + (struct knot_zone_db_tree_arg *)data; + assert(data); + args->zones[args->count++] = zone; +} + +const knot_zone_t **knot_zonedb_zones(const knot_zonedb_t *db) +{ + struct knot_zone_db_tree_arg args; + args.zones = malloc(sizeof(knot_zone_t) * db->zone_count); + args.count = 0; + CHECK_ALLOC_LOG(args.zones, NULL); + + gen_tree_apply_inorder(db->zone_tree, save_zone_to_array, + &args); + assert(db->zone_count == args.count); + + return args.zones; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zonedb_free(knot_zonedb_t **db) +{ + gen_tree_destroy(&((*db)->zone_tree), NULL ,NULL); + free(*db); + *db = NULL; +} + +/*----------------------------------------------------------------------------*/ + +static void delete_zone_from_db(void *node, void *data) +{ + UNUSED(data); + knot_zone_t *zone = (knot_zone_t *)node; + assert(zone); + synchronize_rcu(); + knot_zone_deep_free(&zone, 0); +} + +void knot_zonedb_deep_free(knot_zonedb_t **db) +{ + dbg_zonedb("Deleting zone db (%p).\n", *db); +// dbg_zonedb("Is it empty (%p)? %s\n", +// (*db)->zones, skip_is_empty((*db)->zones) ? "yes" : "no"); + +//dbg_zonedb_exec( +// int i = 1; +// char *name = NULL; +// while (zn != NULL) { +// dbg_zonedb("%d. zone: %p, key: %p\n", i, zn->value, +// zn->key); +// assert(zn->key == ((knot_zone_t *)zn->value)->apex->owner); +// name = knot_dname_to_str((knot_dname_t *)zn->key); +// dbg_zonedb(" zone name: %s\n", name); +// free(name); + +// zn = skip_next(zn); +// } + +// zn = skip_first((*db)->zones); +//); + +// while (zn != NULL) { +// zone = (knot_zone_t *)zn->value; +// assert(zone != NULL); + +// // remove the zone from the database +// skip_remove((*db)->zones, zn->key, NULL, NULL); +// // wait for all readers to finish +// synchronize_rcu; +// // destroy the zone +// knot_zone_deep_free(&zone, 0); + +// zn = skip_first((*db)->zones); +// } + +// assert(skip_is_empty((*db)->zones)); + +// skip_destroy_list(&(*db)->zones, NULL, NULL); + gen_tree_destroy(&((*db)->zone_tree), delete_zone_from_db, NULL); + assert((*db)->zone_tree == NULL); + free(*db); + *db = NULL; +} + +/*----------------------------------------------------------------------------*/ + diff --git a/src/libknot/zone/zonedb.h b/src/libknot/zone/zonedb.h new file mode 100644 index 0000000..d5a4992 --- /dev/null +++ b/src/libknot/zone/zonedb.h @@ -0,0 +1,145 @@ +/*! + * \file zonedb.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Zone database structure and API for manipulating it. + * + * Zone database groups several zones and provides functions for finding + * suitable zone for a domain name, for searching in a particular zone, etc. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_ZONEDB_H_ +#define _KNOT_ZONEDB_H_ + +#include "common/general-tree.h" +#include "zone/zone.h" +#include "zone/node.h" +#include "dname.h" + +/*! + * \brief Zone database structure. Contains all zones managed by the server. + */ +struct knot_zonedb { + general_tree_t *zone_tree; /*!< AVL tree of zones. */ + size_t zone_count; +}; + +typedef struct knot_zonedb knot_zonedb_t; + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Allocates and initializes the zone database structure. + * + * \return Pointer to the created zone database structure or NULL if an error + * occured. + */ +knot_zonedb_t *knot_zonedb_new(); + +/*! + * \brief Adds new zone to the database. + * + * \param db Zone database to store the zone. + * \param zone Parsed zone. + * + * \retval KNOT_EOK + * \retval KNOT_EZONEIN + */ +int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone); + +/*! + * \brief Removes the given zone from the database if it exists. + * + * \note Assumes that the zone was adjusted using knot_zone_adjust_dnames(). + * If it was not, it may leak some memory due to checks used in + * knot_rdata_deep_free(). + * + * \param db Zone database to remove from. + * \param zone_name Name of the zone to be removed. + * \param destroy_zone Set to <> 0 if you do want the function to destroy the + * zone after removing from zone database. Set to 0 + * otherwise. + * + * \retval KNOT_EOK + * \retval KNOT_ENOZONE + */ +knot_zone_t * knot_zonedb_remove_zone(knot_zonedb_t *db, + const knot_dname_t *zone_name); + +//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db, +// knot_zone_t *zone); + +/*! + * \brief Finds zone exactly matching the given zone name. + * + * \param db Zone database to search in. + * \param zone_name Domain name representing the zone name. + * + * \return Zone with \a zone_name being the owner of the zone apex or NULL if + * not found. + */ +knot_zone_t *knot_zonedb_find_zone(const knot_zonedb_t *db, + const knot_dname_t *zone_name); + + +/*! + * \brief Finds zone the given domain name should belong to. + * + * \param db Zone database to search in. + * \param dname Domain name to find zone for. + * + * \retval Zone in which the domain name should be present or NULL if no such + * zone is found. + */ +const knot_zone_t *knot_zonedb_find_zone_for_name(knot_zonedb_t *db, + const knot_dname_t *dname); + +knot_zone_contents_t *knot_zonedb_expire_zone(knot_zonedb_t *db, + const knot_dname_t *zone_name); + +size_t knot_zonedb_zone_count(const knot_zonedb_t *db); +const knot_zone_t **knot_zonedb_zones(const knot_zonedb_t *db); + +/*! + * \brief Destroys and deallocates the zone database structure (but not the + * zones within). + * + * \param db Zone database to be destroyed. + */ +void knot_zonedb_free(knot_zonedb_t **db); + +/*! + * \brief Destroys and deallocates the whole zone database including the zones. + * + * \note Assumes that the zone was adjusted using knot_zone_adjust_dnames(). + * If it was not, it may leak some memory due to checks used in + * knot_rdata_deep_free(). + * + * \param db Zone database to be destroyed. + */ +void knot_zonedb_deep_free(knot_zonedb_t **db); + +/*----------------------------------------------------------------------------*/ + +#endif /* _KNOT_ZONEDB_H_ */ + +/*! @} */ diff --git a/src/tests/README b/src/tests/README new file mode 100644 index 0000000..2f299ad --- /dev/null +++ b/src/tests/README @@ -0,0 +1,10 @@ +Unit testing +------------ + +Make assembles "unittest" binary with all of the planned tests included. +So far it is accepting the same parameters as the "cutedns", +but an own parameter format is being developed. + +Example: +bin/unittest samples/example.com.zone + diff --git a/src/tests/common/acl_tests.c b/src/tests/common/acl_tests.c new file mode 100644 index 0000000..b4232ac --- /dev/null +++ b/src/tests/common/acl_tests.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> + +#include "tests/common/acl_tests.h" +#include "common/sockaddr.h" +#include "common/acl.h" + +static int acl_tests_count(int argc, char *argv[]); +static int acl_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api acl_tests_api = { + "ACL", //! Unit name + &acl_tests_count, //! Count scheduled tests + &acl_tests_run //! Run scheduled tests +}; + +static int acl_tests_count(int argc, char *argv[]) +{ + return 13; +} + +static int acl_tests_run(int argc, char *argv[]) +{ + // 1. Create an ACL + acl_t *acl = acl_new(ACL_DENY, "simple ACL"); + ok(acl != 0, "acl: new"); + + // 2. Create IPv4 address + sockaddr_t test_v4; + int ret = sockaddr_set(&test_v4, AF_INET, "127.0.0.1", 12345); + ok(ret > 0, "acl: new IPv4 address"); + + // 3. Create IPv6 address + sockaddr_t test_v6; + ret = sockaddr_set(&test_v6, AF_INET6, "::1", 54321); + ok(ret > 0, "acl: new IPv6 address"); + + // 4. Create simple IPv4 rule + ret = acl_create(acl, &test_v4, ACL_ACCEPT); + ok(ret == ACL_ACCEPT, "acl: inserted IPv4 rule"); + + // 5. Create simple IPv6 rule + ret = acl_create(acl, &test_v6, ACL_ACCEPT); + ok(ret == ACL_ACCEPT, "acl: inserted IPv6 rule"); + + // 6. Create simple IPv4 'any port' rule + sockaddr_t test_v4a; + sockaddr_set(&test_v4a, AF_INET, "20.20.20.20", 0); + ret = acl_create(acl, &test_v4a, ACL_ACCEPT); + ok(ret == ACL_ACCEPT, "acl: inserted IPv4 'any port' rule"); + + // 7. Attempt to match unmatching address + sockaddr_t unmatch_v4; + sockaddr_set(&unmatch_v4, AF_INET, "10.10.10.10", 24424); + ret = acl_match(acl, &unmatch_v4); + ok(ret == ACL_DENY, "acl: matching non-existing address"); + + // 8. Attempt to match unmatching IPv6 address + sockaddr_t unmatch_v6; + sockaddr_set(&unmatch_v6, AF_INET6, "2001:db8::1428:57ab", 24424); + ret = acl_match(acl, &unmatch_v6); + ok(ret == ACL_DENY, "acl: matching non-existing IPv6 address"); + + // 9. Attempt to match matching address + ret = acl_match(acl, &test_v4); + ok(ret == ACL_ACCEPT, "acl: matching existing address"); + + // 10. Attempt to match matching address + ret = acl_match(acl, &test_v6); + ok(ret == ACL_ACCEPT, "acl: matching existing IPv6 address"); + + // 11. Attempt to match matching 'any port' address + sockaddr_t match_v4a; + sockaddr_set(&match_v4a, AF_INET, "20.20.20.20", 24424); + ret = acl_match(acl, &match_v4a); + ok(ret == ACL_ACCEPT, "acl: matching existing IPv4 'any port' address"); + + // 12. Attempt to match matching address without matching port + sockaddr_set(&unmatch_v4, AF_INET, "127.0.0.1", 54321); + ret = acl_match(acl, &unmatch_v4); + ok(ret == ACL_DENY, "acl: matching address without matching port"); + + // 13. Invalid parameters + lives_ok({ + acl_delete(0); + acl_create(0, 0, ACL_ERROR); + acl_match(0, 0); + acl_truncate(0); + acl_name(0); + }, "acl: won't crash with NULL parameters"); + + // Return + return 0; +} diff --git a/src/tests/common/acl_tests.h b/src/tests/common/acl_tests.h new file mode 100644 index 0000000..a928e2d --- /dev/null +++ b/src/tests/common/acl_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_ACL_TESTS_H_ +#define _KNOTD_ACL_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api acl_tests_api; + +#endif /* _KNOTD_ACL_TESTS_H_ */ diff --git a/src/tests/common/da_tests.c b/src/tests/common/da_tests.c new file mode 100644 index 0000000..627e8aa --- /dev/null +++ b/src/tests/common/da_tests.c @@ -0,0 +1,330 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "tests/common/da_tests.h" +#include "common/dynamic-array.h" +#include <unistd.h> +#include <urcu.h> + +static int da_tests_count(int argc, char *argv[]); +static int da_tests_run(int argc, char *argv[]); + +/* + * Unit API. + */ +unit_api da_tests_api = { + "Dynamic array", + &da_tests_count, + &da_tests_run +}; + +/* + * Unit implementation. + */ + +static const int DA_TEST_COUNT = 5; +static const int RCU_THREADS = 3; +static const int DA_FRAGMENT = 10; +static const int DA_DEF_SIZE = 1000; +static const int DA_OPERATIONS = 1000; +enum Operations { + DA_RESERVE = 0, + DA_OCCUPY = 1, + DA_RELEASE = 2, + DA_OPCOUNT = 3 +}; + +static int da_tests_count(int argc, char *argv[]) +{ + return DA_TEST_COUNT; +} + +static void do_something(int loops) +{ + int i; + int res = 1; + + static const int LOOPS = 10000; + + for (int j = 1; j <= LOOPS; ++j) { + for (i = 1; i <= loops; ++i) { + res *= i; + } + } +} + +static void *test_rcu_routine(void *obj) +{ + rcu_register_thread(); + rcu_read_lock(); + + do_something(1000); + + rcu_read_unlock(); + rcu_unregister_thread(); + + return NULL; +} + +static int test_rcu_threads() +{ + // Create threads + pthread_t *threads = malloc(RCU_THREADS * sizeof(pthread_t)); + for (int i = 0; i < RCU_THREADS; ++i) { + if (pthread_create(&threads[i], NULL, test_rcu_routine, NULL)) { + diag("rcu: failed to create thread %d", i); + free(threads); + return 0; + } + } + + // Join threads + void *pret = NULL; + for (int i = 0; i < RCU_THREADS; ++i) { + if (pthread_join(threads[i], &pret)) { + diag("rcu: failed to join thread %d", i); + free(threads); + return 0; + } + } + + synchronize_rcu(); + free(threads); + + return 1; +} + +static int test_da_init(da_array_t *arr) +{ + return da_initialize(arr, DA_DEF_SIZE, sizeof(uint)) == 0; +} + +static int test_da_random_op(da_array_t *arr) +{ + unsigned seed = (unsigned)time(0); + uint allocated = DA_DEF_SIZE; + uint size = 0; + + for (int i = 0; i < DA_OPERATIONS; ++i) { + int r = rand_r(&seed) % DA_OPCOUNT; + int count = rand_r(&seed) % DA_FRAGMENT + 1; + + switch (r) { + + // Perform reserve operation + case DA_RESERVE: + if (da_reserve(arr, count) >= 0 && + size <= allocated) { + if ((allocated - size) < count) { + allocated *= 2; + } + } else { + diag("dynamic-array: da_reserve(%p, %d) failed" + " (size %d, alloc'd %d)", + arr, count, size, allocated); + return 0; + } + break; + + // Perform occupy operation + case DA_OCCUPY: + if (da_occupy(arr, count) == 0) { + uint *items = (uint *) da_get_items(arr); + for (int j = 0; j < da_get_count(arr); ++j) { + items[j] = rand_r(&seed); + } + if (size <= allocated && + (allocated - size) >= count) { + size += count; + } else { + return 0; + } + } else { + diag("dynamic-array: da_occupy(%p, %d) failed" + " (size %d, alloc'd %d)", + arr, count, size, allocated); + return 0; + } + break; + + // Perform release operation + case DA_RELEASE: + if (arr->count > 0) { + count = (rand_r(&seed) % DA_FRAGMENT) % arr->count; + da_release(arr, count); + + if (size <= allocated && size >= count) { + size -= count; + } else { + return 0; + } + } + break; + + default: + break; + } + + // Check allocated / size + if (allocated != arr->allocated || size != arr->count) { + diag("dynamic-array: allocated memory %d (expected %d)" + " size %d (expected %d) mismatch", + arr->allocated, allocated, arr->count, size); + return 0; + } + } + + return 1; +} + +void *test_da_read(void *obj) +{ + rcu_register_thread(); + rcu_read_lock(); + + unsigned seed = (unsigned)time(0); + da_array_t *arr = (da_array_t *) obj; + int index = rand_r(&seed) % da_get_count(arr); + + note(" dynamic-array: read thread"); + note(" read thread: saving pointer to %d. item", index); + uint *item = &((uint *) da_get_items(arr))[index]; + note(" read thread: before: pointer: %p item: %u", item, *item); + + do_something(100000); + + note(" read thread after: pointer: %p item: %u", item, *item); + rcu_read_unlock(); + note(" read thread unlocked: pointer: %p item: %u", item, *item); + + do_something(10000); + + note(" read thread: now the item should be deallocated"); + //note(" read thread: pointer: %p item: %u", item, *item); + + rcu_unregister_thread(); + + return NULL; +} + +static int test_da_resize_holding(da_array_t *arr) +{ + int ret = 1; + rcu_register_thread(); + pthread_t reader; + + // Create thread for reading + note("dynamic-array: creating read threads"); + if (pthread_create(&reader, NULL, test_da_read, (void *)arr)) { + diag("dynamic-array: failed to create reading thread", + __func__); + rcu_unregister_thread(); + return 0; + } + + // Wait some time, so the other thread gets the item for reading + do_something(5000); + + // Force resize + note(" dynamic-array: array resized"); + if (da_reserve(arr, arr->allocated - arr->count + 1) == -1) { + diag("dynamic-array: da_reserve(%p, %d) failed", arr, + arr->allocated - arr->count + 1); + ret = 0; + } + + //Wait for the thread to finish + void *pret = NULL; + if (pthread_join(reader, &pret)) { + diag("dynamic-array: failed to join reading thread", + __func__); + ret = 0; + } + + rcu_unregister_thread(); + return ret; +} + +static int test_da_resize(da_array_t *arr) +{ + unsigned seed = (unsigned)time(0); + int orig_count = da_get_count(arr); + note("dynamic-array: allocated: %d, items: %d", arr->allocated, + orig_count); + // store the items currently in the array + int *items = (int *)malloc(orig_count * sizeof(int)); + for (int i = 0; i < orig_count; ++i) { + items[i] = ((int *)da_get_items(arr))[i]; + } + + // force resize + int res = 0; + while ((res = da_reserve(arr, 10)) == 0) { + int i = da_get_count(arr); + da_occupy(arr, 10); + for (; i < da_get_count(arr); ++i) { + ((int *)da_get_items(arr))[i] = rand_r(&seed); + } + } + + if (res < 0) { + diag("dynamic-array: failed to reserve space"); + return 0; + } + + int errors = 0; + for (int i = 0; i < orig_count; ++i) { + if (items[i] != ((int *)da_get_items(arr))[i]) { + diag("dynamic-array: Wrong item on position %d." + "Should be: %d, " + "present value: %d", i, items[i], + ((int *)da_get_items(arr))[i]); + ++errors; + } + } + + free(items); + + return errors == 0; +} + +static int da_tests_run(int argc, char *argv[]) +{ + // Init + rcu_init(); + da_array_t array; + + // Test 1: test rcu + ok(test_rcu_threads(), "dynamic-array: rcu tests"); + + // Test 2: init + ok(test_da_init(&array), "dynamic-array: init"); + + // Test 3: reserve/occupy random operations + ok(test_da_random_op(&array), + "dynamic-array: randomized reserve/occupy/release"); + + // Test 4: resizing array while holding an item + ok(test_da_resize_holding(&array), + "dynamic-array: resize array while holding an item"); + + // Test 5: resize + ok(test_da_resize(&array), "dynamic-array: resize array"); + + // Cleanup + da_destroy(&array); + return 0; +} diff --git a/src/tests/common/da_tests.h b/src/tests/common/da_tests.h new file mode 100644 index 0000000..d51b7be --- /dev/null +++ b/src/tests/common/da_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_DA_TESTS_H_ +#define _KNOTD_DA_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api da_tests_api; + +#endif /* _KNOTD_DA_TESTS_H_ */ diff --git a/src/tests/common/events_tests.c b/src/tests/common/events_tests.c new file mode 100644 index 0000000..d7702fe --- /dev/null +++ b/src/tests/common/events_tests.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <sys/time.h> + +#include "tests/common/events_tests.h" +#include "common/evqueue.h" +#include "common/evsched.h" + +static int events_tests_count(int argc, char *argv[]); +static int events_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api events_tests_api = { + "Event queue and scheduler", //! Unit name + &events_tests_count, //! Count scheduled tests + &events_tests_run //! Run scheduled tests +}; + +void* term_thr(void *arg) +{ + evsched_t *s = (evsched_t *)arg; + + /* Sleep for 100ms. */ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; // 100ms + select(0, 0, 0, 0, &tv); + + /* Issue termination event. */ + evsched_schedule_term(s, 0); + return 0; +} + +static int events_tests_count(int argc, char *argv[]) +{ + return 9 + 11; +} + +static int events_tests_run(int argc, char *argv[]) +{ + /* + * Event queue tests. + */ + + // 1. Construct an event queue + evqueue_t *q = evqueue_new(); + ok(q != 0, "evqueue: new"); + + // 2. Send integer through event queue + int ret = 0; + uint8_t sent = 0xaf, rcvd = 0; + ret = evqueue_write(q, &sent, sizeof(uint8_t)); + ok(ret == sizeof(uint8_t), "evqueue: send byte through"); + + // 3. Receive byte from event queue + ret = evqueue_read(q, &rcvd, sizeof(uint8_t)); + ok(ret == sizeof(uint8_t), "evqueue: received byte"); + + // 4. Received match + ok(sent == rcvd, "evqueue: received byte match"); + + // 5. Sending event + event_t ev, rev; + memset(&ev, 0, sizeof(event_t)); + memset(&rev, 0, sizeof(event_t)); + ev.type = 0xfa11; + ev.data = (void*)0xceed; + ret = evqueue_add(q, &ev); + ok(ret == 0, "evqueue: sent event to queue"); + + // 6. Poll for new events + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 100 * 1000 * 1000; // 100ms + ret = evqueue_poll(q, &ts, 0); + ok(ret > 0, "evqueue: polling queue for events"); + + // 7. Compare received event + ret = evqueue_get(q, &rev); + /* Compare useful data, as event owner was changed in evqueue_get(). */ + if (ev.type == rev.type && ev.data == rev.data) { + ret = 0; + } + ok(ret == 0, "evqueue: received event matches sent"); + + // 8. Invalid parameters + lives_ok({ + evqueue_free(0); + evqueue_poll(0,0,0); + evqueue_read(0, 0, 0); + evqueue_write(0, 0, 0); + evqueue_read(0, 0, 0); + evqueue_get(0, 0); + evqueue_add(0, 0); + }, "evqueue: won't crash with NULL parameters"); + + // 9. Free event queue + lives_ok({evqueue_free(&q);}, "evqueue: delete"); + + /* + * Event scheduler tests. + */ + + // 1. Construct event scheduler + event_t *e = 0; + evsched_t *s = evsched_new(); + ok(s != 0, "evsched: new"); + + // 2. Schedule event to happen after N ms + int msecs = 50; + struct timeval st, rt; + gettimeofday(&st, 0); + e = evsched_schedule_cb(s, 0, (void*)0xcafe, msecs); + ok(e != 0, "evsched: scheduled empty event after %dms", msecs); + + // 3. Wait for next event + e = evsched_next(s); + evsched_event_finished(s); + gettimeofday(&rt, 0); + ok(e != 0, "evsched: received valid event"); + + // 4. Check receive time + double passed = (rt.tv_sec - st.tv_sec) * 1000; + passed += (rt.tv_usec - st.tv_usec) / 1000; + double margin = msecs * 0.2; + double lb = msecs - margin, ub = msecs + margin; + int in_bounds = (passed >= lb) && (passed <= ub); + ok(in_bounds, "evsched: receive time %.1lfms is in <%.1lf,%.1lf>", + passed, lb, ub); + + // 5. Check data + ok(e->data == (void*)0xcafe, "evsched: received data is valid"); + + // 6. Delete event + lives_ok({evsched_event_free(s, e);}, "evsched: deleted event"); + + // 7. Insert and immediately cancel an event + e = evsched_schedule_cb(s, 0, (void*)0xdead, 1000); + ret = evsched_cancel(s, e); + ok(ret == 0, "evsched: inserted and cancelled an event"); + if (e) { + evsched_event_free(s, e); + } + + // 8. Start listener thread and block + pthread_t t; + pthread_create(&t, 0, term_thr, s); + e = evsched_next(s); + evsched_event_finished(s); + ok(e != 0, "evsched: received termination event"); + + // 9. Termination event is valid + ok(e->type == EVSCHED_TERM, "evsched: termination event is valid"); + evsched_event_free(s, e); + pthread_join(t, 0); + + // 10. Invalid parameters + lives_ok({ + evsched_delete(0); + evsched_event_new(0, 0); + evsched_event_free(0, 0); + evsched_next(0); + evsched_schedule(0, 0, 0); + evsched_schedule_cb(0, 0, 0, 0); + evsched_schedule_term(0, 0); + evsched_cancel(0, 0); + + }, "evsched: won't crash with NULL parameters"); + + // 11. Delete event scheduler + lives_ok({evsched_delete(&s);}, "evsched: delete"); + + + return 0; +} diff --git a/src/tests/common/events_tests.h b/src/tests/common/events_tests.h new file mode 100644 index 0000000..b54b6da --- /dev/null +++ b/src/tests/common/events_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD__EVENTS_TESTS_H_ +#define _KNOTD__EVENTS_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api events_tests_api; + +#endif /* _KNOTD__EVENTS_TESTS_H_ */ diff --git a/src/tests/common/fdset_tests.c b/src/tests/common/fdset_tests.c new file mode 100644 index 0000000..7dd95a1 --- /dev/null +++ b/src/tests/common/fdset_tests.c @@ -0,0 +1,177 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <sys/time.h> +#include <pthread.h> + +#include "tests/common/fdset_tests.h" +#include "common/fdset.h" + +#define WRITE_PATTERN ((char) 0xde) +#define WRITE_PATTERN_LEN sizeof(char) + + +/* Subtract the `struct timeval' values X and Y, + storing the result in RESULT. + Return 1 if the difference is negative, otherwise 0. + Copyright http://www.delorie.com/gnu/docs/glibc/libc_428.html +*/ +static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval* y) +{ + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_usec < y->tv_usec) { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* Compute the time remaining to wait. + tv_usec is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} + +static size_t timeval_diff(struct timeval *from, struct timeval *to) { + struct timeval res; + timeval_subtract(&res, to, from); + return res.tv_sec*1000 + res.tv_usec/1000; +} + +static int fdset_tests_count(int argc, char *argv[]); +static int fdset_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api fdset_tests_api = { + "Native fdset poll wrapper", //! Unit name + &fdset_tests_count, //! Count scheduled tests + &fdset_tests_run //! Run scheduled tests +}; + +void* thr_action(void *arg) +{ + int *fd = (int *)arg; + + /* Sleep for 100ms. */ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; // 100ms + select(0, 0, 0, 0, &tv); + + /* Write pattern. */ + char pattern = WRITE_PATTERN; + int ret = write(*fd, &pattern, WRITE_PATTERN_LEN); + ret = ret; /* Use variable. */ + + return 0; +} + +static int fdset_tests_count(int argc, char *argv[]) +{ + return 11; +} + +static int fdset_tests_run(int argc, char *argv[]) +{ + diag("fdset: implements '%s'", fdset_method()); + + /* 1. Create fdset. */ + fdset_t *set = fdset_new(); + ok(set != 0, "fdset: new"); + + /* 2. Create pipe. */ + int fds[2], tmpfds[2]; + int ret = pipe(fds); + ok(ret >= 0, "fdset: pipe() works"); + ret = pipe(tmpfds); + + /* 3. Add fd to set. */ + ret = fdset_add(set, fds[0], OS_EV_READ); + ok(ret == 0, "fdset: add to set works"); + fdset_add(set, tmpfds[0], OS_EV_READ); + + /* Schedule write. */ + struct timeval ts, te; + gettimeofday(&ts, 0); + pthread_t t; + pthread_create(&t, 0, thr_action, &fds[1]); + + /* 4. Watch fdset. */ + ret = fdset_wait(set); + gettimeofday(&te, 0); + size_t diff = timeval_diff(&ts, &te); + + ok(ret > 0 && diff > 99 && diff < 10000, + "fdset: poll returned events in %zu ms", diff); + + /* 5. Prepare event set. */ + fdset_it_t it; + ret = fdset_begin(set, &it); + ok(ret == 0 && it.fd == fds[0], "fdset: begin is valid, ret=%d", ret); + + /* 6. Receive data. */ + char buf = 0x00; + ret = read(it.fd, &buf, WRITE_PATTERN_LEN); + ok(ret >= 0 && buf == WRITE_PATTERN, "fdset: contains valid data, fd=%d", it.fd); + + /* 7. Iterate event set. */ + ret = fdset_next(set, &it); + ok(ret < 0, "fdset: boundary check works"); + + /* 8. Remove from event set. */ + ret = fdset_remove(set, fds[0]); + ok(ret == 0, "fdset: remove from fdset works"); + close(fds[0]); + close(fds[1]); + ret = fdset_remove(set, tmpfds[0]); + close(tmpfds[1]); + close(tmpfds[1]); + + /* 9. Poll empty fdset. */ + ret = fdset_wait(set); + ok(ret <= 0, "fdset: polling empty fdset returns -1 (ret=%d)", ret); + + /* 10. Crash test. */ + lives_ok({ + fdset_destroy(0); + fdset_add(0, -1, 0); + fdset_remove(0, -1); + fdset_wait(0); + fdset_begin(0, 0); + fdset_end(0, 0); + fdset_next(0, 0); + fdset_method(); + }, "fdset: crash test successful"); + + /* 11. Destroy fdset. */ + ret = fdset_destroy(set); + ok(ret == 0, "fdset: destroyed"); + + /* Cleanup. */ + pthread_join(t, 0); + + return 0; +} diff --git a/src/tests/common/fdset_tests.h b/src/tests/common/fdset_tests.h new file mode 100644 index 0000000..d29e1a9 --- /dev/null +++ b/src/tests/common/fdset_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_FDSET_TESTS_H_ +#define _KNOTD_FDSET_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api fdset_tests_api; + +#endif /* _KNOTD_FDSET_TESTS_H_ */ diff --git a/src/tests/common/skiplist_tests.c b/src/tests/common/skiplist_tests.c new file mode 100644 index 0000000..4fe99ec --- /dev/null +++ b/src/tests/common/skiplist_tests.c @@ -0,0 +1,198 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <time.h> + +#include "tests/common/skiplist_tests.h" +#include "common/skip-list.h" + +static int skiplist_tests_count(int argc, char *argv[]); +static int skiplist_tests_run(int argc, char *argv[]); + +/* + * Unit API. + */ +unit_api skiplist_tests_api = { + "Skip list", + &skiplist_tests_count, + &skiplist_tests_run +}; + +/* + * Unit implementation. + */ + +static const int SKIPLIST_TEST_COUNT = 5; + +static int skiplist_tests_count(int argc, char *argv[]) +{ + return SKIPLIST_TEST_COUNT; +} + +/* Comparing and merging limited to int keys used in test. + */ +int test_skip_compare_keys(void *key1, void *key2) +{ + return ((long)key1 < (long)key2) ? + -1 : (((long)key1 > (long)key2) ? 1 : 0); +} + +int test_skip_merge_values(void **lvalue, void **rvalue) +{ + (*lvalue) = (void *)((long)(*lvalue) + (long)(*rvalue)); + return 0; +} + +int test_skiplist_create(skip_list_t **list) +{ + *list = skip_create_list(test_skip_compare_keys); + return *list != NULL; +} + +int test_skiplist_fill(skip_list_t *list, long *uitems, int loops) +{ + int uitem_count = 0; + for (int i = 0; i < loops; ++i) { + long key = rand() % 100 + 1; + long value = rand() % 100 + 1; + int res = skip_insert(list, (void *)key, (void *)value, + test_skip_merge_values); + switch (res) { + case -2: + diag("skiplist: merging failed"); + return 0; + break; + case -1: + diag("skiplist: insert failed"); + return 0; + break; + case 0: + uitems[uitem_count++] = key; + break; + default: + break; + } + } + + return uitem_count; +} + +int test_skiplist_lookup_seq(skip_list_t *list, long *uitems, int uitems_count) +{ + int errors = 0; + + // Sequential lookup + for (int i = 0; i < uitems_count; ++i) { + void *found = skip_find(list, (void *) uitems[i]); + if (found == NULL) { + diag("skiplist: sequential " + "lookup failed, key: %d", uitems[i]); + ++errors; + } + } + + if (errors) { + diag("skiplist: sequential lookup: %d found %d missed," + " %.2f%% success rate", + uitems_count - errors, errors, + (uitems_count - errors) / (float) uitems_count * 100.0); + } + + return errors == 0; +} + +int test_skiplist_lookup_rand(skip_list_t *list, long *uitems, int uitems_count) +{ + int errors = 0; + srand((unsigned)time(NULL)); + + // Random lookup + for (int i = 0; i < uitems_count; ++i) { + long key = rand() % uitems_count + 1; + void *found = skip_find(list, (void *) key); + if (found == NULL) { + diag("skiplist: random lookup" + "failed, key: %d", uitems[i]); + ++errors; + } + } + + if (errors) { + diag("skiplist: sequential lookup: " + "%d found %d missed, %.2f%% success rate", + uitems_count - errors, errors, + (uitems_count - errors) / (float) uitems_count * 100.0); + } + return errors == 0; +} + + +int test_skiplist_remove(skip_list_t *list, long *uitems, int uitems_count) +{ + int errors = 0; + + // delete items + for (int i = 0; i < uitems_count; ++i) { + int res = skip_remove(list, (void *) uitems[i], NULL, NULL); + switch (res) { + case 0: + break; + default: + ++errors; + break; + } + } + + if (errors) { + diag("skiplist: sequential lookup: %d found %d missed, " + "%.2f%% success rate", + uitems_count - errors, errors, + (uitems_count - errors) / (float) uitems_count * 100.0); + } + return errors == 0; +} + +static int skiplist_tests_run(int argc, char *argv[]) +{ + const int loops = 100; + int uitems_count = 0; + long *uitems = malloc(loops * sizeof(long)); + skip_list_t *list = 0; + + // Test 1: create + ok(test_skiplist_create(&list), "skiplist: create"); + + // Test 2: fill + ok(uitems_count = test_skiplist_fill(list, uitems, loops), + "skiplist: fill"); + + // Test 3: sequential lookup + ok(test_skiplist_lookup_seq(list, uitems, uitems_count), + "skiplist: sequential lookup"); + + // Test 4: sequential lookup + ok(test_skiplist_lookup_seq(list, uitems, uitems_count), + "skiplist: random lookup lookup"); + + // Test 5: remove items + ok(test_skiplist_remove(list, uitems, uitems_count), + "skiplist: random lookup lookup"); + + // Cleanup + skip_destroy_list(&list, NULL, NULL); + free(uitems); + return 0; +} diff --git a/src/tests/common/skiplist_tests.h b/src/tests/common/skiplist_tests.h new file mode 100644 index 0000000..ff91706 --- /dev/null +++ b/src/tests/common/skiplist_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_SKIPLIST_TESTS_H_ +#define _KNOTD_SKIPLIST_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api skiplist_tests_api; + +#endif /* _KNOTD_SKIPLIST_TESTS_H_ */ diff --git a/src/tests/common/slab_tests.c b/src/tests/common/slab_tests.c new file mode 100644 index 0000000..f362ca0 --- /dev/null +++ b/src/tests/common/slab_tests.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <time.h> +#include <stdbool.h> + +#include "tests/common/slab_tests.h" +#include "common/slab/slab.h" +#include "knot/common.h" + +/* Explicitly ask for symbols, + * as the constructor and destructor + * aren't created for test modules. + */ +extern void slab_init(); +extern void slab_deinit(); + +static int slab_tests_count(int argc, char *argv[]); +static int slab_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api slab_tests_api = { + "SLAB allocator", //! Unit name + &slab_tests_count, //! Count scheduled tests + &slab_tests_run //! Run scheduled tests +}; + +static int slab_tests_count(int argc, char *argv[]) +{ + return 7; +} + +static int slab_tests_run(int argc, char *argv[]) +{ + // 1. Create slab cache + srand(time(0)); + const unsigned pattern = 0xdeadbeef; + slab_cache_t cache; + int ret = slab_cache_init(&cache, sizeof(int)); + ok(ret == 0, "slab: created empty cache"); + + // 2. Couple alloc/free + bool valid_free = true; + lives_ok({ + for(int i = 0; i < 100; ++i) { + int* data = (int*)slab_cache_alloc(&cache); + *data = pattern; + slab_free(data); + if (*data == pattern) + valid_free = false; + } + }, "slab: couple alloc/free"); + + // 5. Verify freed block + ok(valid_free, "slab: freed memory is correctly invalidated"); + + // 4. Reap memory + slab_t* slab = cache.slabs_free; + int free_count = 0; + while (slab) { + slab_t* next = slab->next; + if (slab_isempty(slab)) { + ++free_count; + } + slab = next; + } + + int reaped = slab_cache_reap(&cache); + cmp_ok(reaped, "==", free_count, "slab: cache reaping works"); + + // Stress cache + int alloc_count = 73521; + void** ptrs = alloca(alloc_count * sizeof(void*)); + int ptrs_i = 0; + for(int i = 0; i < alloc_count; ++i) { + double roll = rand() / (double) RAND_MAX; + if ((ptrs_i == 0) || (roll < 0.6)) { + int id = ptrs_i++; + ptrs[id] = slab_cache_alloc(&cache); + if (ptrs[id] == 0) { + ptrs_i--; + } else { + int* data = (int*)ptrs[id]; + *data = pattern; + } + } else { + slab_free(ptrs[--ptrs_i]); + } + } + + // 5. Delete cache + slab_cache_destroy(&cache); + ok(cache.bufsize == 0, "slab: freed cache"); + + // 6. Greate GP allocator + slab_alloc_t alloc; + ret = slab_alloc_init(&alloc); + ok(ret == 0, "slab: created GP allocator"); + + // 7. Stress allocator + unsigned ncount = 0; + ptrs_i = 0; + for(int i = 0; i < alloc_count; ++i) { + double roll = rand() / (double) RAND_MAX; + size_t bsize = roll * 2048; + bsize = MAX(bsize, 8); + if ((ptrs_i == 0) || (roll < 0.6)) { + void* m = slab_alloc_alloc(&alloc, bsize); + if (m == 0) { + ++ncount; + } else { + ptrs[ptrs_i++] = m; + } + } else { + slab_free(ptrs[--ptrs_i]); + } + } + + cmp_ok(ncount, "==", 0, "slab: GP allocator alloc/free working"); + + // 7. Destroy allocator + slab_alloc_destroy(&alloc); + + return 0; +} diff --git a/src/tests/common/slab_tests.h b/src/tests/common/slab_tests.h new file mode 100644 index 0000000..4d45fb8 --- /dev/null +++ b/src/tests/common/slab_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_SLAB_TESTS_H_ +#define _KNOTD_SLAB_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api slab_tests_api; + +#endif /* _KNOTD_SLAB_TESTS_H_ */ diff --git a/src/tests/files/sample_conf b/src/tests/files/sample_conf new file mode 100644 index 0000000..6cd9e50 --- /dev/null +++ b/src/tests/files/sample_conf @@ -0,0 +1,59 @@ +# configuration file will follow bird (and juniper) type of configuration file +# i.e. curly brackets will be used; + +# what to do with }; +# a) ignore ; if it follows } + +system { + + identity "I have no mouth and must scream"; + version "Infinitesimal"; + storage "/var/run/knot/"; +} + +keys { + key0.example.net hmac-md5 "Wg=="; # key special for one remote + key1.example.net hmac-md5 "==gW"; # implicit key for whole zone +} + +remotes { + remote0 { address 1.2.3.4; } +} + +zones { + example.net { + file "/var/lib/knot/example.net"; + xfr-out remote0; + } +} + +interfaces { + interface0 { + address 10.10.1.1; + port 53531; + } + + interface1 { + address ::0; + # port 53; + } +} + +log { + syslog { + any notice, warning, error; + zone all; + } + + file "/var/log/knot/server.err" { + server error; + } + + stderr { + any warning, error; + } + + stdout { + any info; + } +} diff --git a/src/tests/knot/conf_tests.c b/src/tests/knot/conf_tests.c new file mode 100644 index 0000000..61520ea --- /dev/null +++ b/src/tests/knot/conf_tests.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> + +#include "tests/knot/conf_tests.h" +#include "knot/conf/conf.h" + +/* Resources. */ +#include "tests/sample_conf.rc" + +static int conf_tests_count(int argc, char *argv[]); +static int conf_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api conf_tests_api = { + "Configuration parser", //! Unit name + &conf_tests_count, //! Count scheduled tests + &conf_tests_run //! Run scheduled tests +}; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int conf_tests_count(int argc, char *argv[]) +{ + return 21; +} + +/*! Run all scheduled tests for given parameters. + */ +static int conf_tests_run(int argc, char *argv[]) +{ + + // Test 1: Allocate new config + const char *config_fn = "rc:/sample_conf"; + conf_t *conf = conf_new(config_fn); + ok(conf != 0, "config_new()"); + + // Test 2: Parse config + int ret = conf_parse_str(conf, sample_conf_rc); + ok(ret == 0, "parsing configuration file %s", config_fn); + skip(ret != 0, conf_tests_count(argc, argv) - 2); + { + + // Test 3: Test server version (0-level depth) + is(conf->version, "Infinitesimal", "server version loaded ok"); + + // Test 4: Test interfaces (1-level depth) + ok(!EMPTY_LIST(conf->ifaces), "configured interfaces exist"); + + // Test 5,6,7,8: Interfaces content (2-level depth) + struct node *n = HEAD(conf->ifaces); + conf_iface_t *iface = (conf_iface_t*)n; + is(iface->address, "10.10.1.1", "interface0 address check"); + cmp_ok(iface->port, "==", 53531, "interface0 port check"); + n = n->next; + iface = (conf_iface_t*)n; + is(iface->address, "::0", "interface1 address check"); + cmp_ok(iface->port, "==", 53, "interface1 default port check"); + + // Test 9,10: Check server key + if(conf->key_count <= 0) { + ok(0, "TSIG key algorithm check - NO KEY FOUND"); + ok(0, "TSIG key secret check - NO KEY FOUND"); + } else { + knot_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k; + cmp_ok(k->algorithm, "==", KNOT_TSIG_ALG_HMAC_MD5, + "TSIG key algorithm check"); + is(k->secret, "Wg==", "TSIG key secret check"); + } + + // Test 11,12,13,14,15,16,17,18: Check logging facilities + cmp_ok(conf->logs_count, "==", 4, "log facilites count check"); + n = HEAD(conf->logs); + ok(!EMPTY_LIST(conf->logs), "log facilities not empty"); + + conf_log_t *log = (conf_log_t*)n; + node *nm = HEAD(log->map); + conf_log_map_t *m = (conf_log_map_t*)nm; + cmp_ok(log->type, "==", LOGT_SYSLOG, "log0 is syslog"); + + skip(EMPTY_LIST(log->map), 5); + { + cmp_ok(m->source, "==", LOG_ANY, "syslog first rule is ANY"); + int mask = LOG_MASK(LOG_NOTICE)|LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR); + cmp_ok(m->prios, "==", mask, "syslog mask is equal"); + nm = nm->next; + m = (conf_log_map_t*)nm; + ok(m != 0, "syslog has more than 1 rule"); + skip(!m, 2); + { + cmp_ok(m->source, "==", LOG_ZONE, "syslog next rule is for zone"); + cmp_ok(m->prios, "==", 0xff, "rule for zone is: any level"); + } + endskip; + } endskip; + + // Test 19,20: File facility checks + n = n->next; + log = (conf_log_t*)n; + ok(n != 0, "log has next facility"); + skip(!n, 1); + { + is(log->file, "/var/log/knot/server.err", "log file matches"); + } endskip; + + // Test 21: Load key dname + const char *sample_str = "key0.example.net"; + knot_dname_t *sample = knot_dname_new_from_str(sample_str, + strlen(sample_str), 0); + if (conf->key_count > 0) { + knot_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k; + ok(knot_dname_compare(sample, k->name) == 0, + "TSIG key dname check"); + } else { + ok(0, "TSIG key dname check - NO KEY FOUND"); + } + knot_dname_free(&sample); + + } endskip; + + // Deallocating config + conf_free(conf); + + return 0; +} diff --git a/src/tests/knot/conf_tests.h b/src/tests/knot/conf_tests.h new file mode 100644 index 0000000..dfd2fd7 --- /dev/null +++ b/src/tests/knot/conf_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_CONF_TESTS_H_ +#define _KNOTD_CONF_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api conf_tests_api; + +#endif /* _KNOTD_CONF_TESTS_H_ */ diff --git a/src/tests/knot/dthreads_tests.c b/src/tests/knot/dthreads_tests.c new file mode 100644 index 0000000..d95fbed --- /dev/null +++ b/src/tests/knot/dthreads_tests.c @@ -0,0 +1,392 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <pthread.h> +#include <sched.h> +#include <sys/select.h> +#include <signal.h> + +#include "tests/knot/dthreads_tests.h" +#include "knot/server/dthreads.h" + +static int dt_tests_count(int argc, char *argv[]); +static int dt_tests_run(int argc, char *argv[]); + +/* + * Unit API. + */ +unit_api dthreads_tests_api = { + "DThreads", + &dt_tests_count, + &dt_tests_run +}; + +/* + * Unit implementation. + */ +static const int DT_TEST_COUNT = 23; + +/* Unit runnable data. */ +static pthread_mutex_t _runnable_mx; +static volatile int _runnable_i = 0; +static const int _runnable_cycles = 10000; + +/*! \brief Unit runnable. */ +int runnable(struct dthread_t *thread) +{ + for (int i = 0; i < _runnable_cycles; ++i) { + + // Increase counter + pthread_mutex_lock(&_runnable_mx); + ++_runnable_i; + pthread_mutex_unlock(&_runnable_mx); + + // Cancellation point + if (dt_is_cancelled(thread)) { + break; + } + + // Yield + sched_yield(); + } + + return 0; +} + +/*! \brief Unit blocking runnable. */ +int runnable_simio(struct dthread_t *thread) +{ + // Infinite blocking, must be interrupted + select(0, 0, 0, 0, 0); + return 0; +} + +/*! \brief Create unit. */ +static inline dt_unit_t *dt_test_create(int size) +{ + return dt_create(size); +} + +/*! \brief Assign a task. */ +static inline int dt_test_single(dt_unit_t *unit) +{ + return dt_repurpose(unit->threads[0], &runnable, NULL) == 0; +} + +/*! \brief Assign task to all unit threads. */ +static inline int dt_test_coherent(dt_unit_t *unit) +{ + int ret = 0; + for (int i = 0; i < unit->size; ++i) { + ret += dt_repurpose(unit->threads[i], &runnable, NULL); + } + + return ret == 0; +} + +/*! \brief Repurpose single thread. */ +static inline int dt_test_repurpose(dt_unit_t *unit, int id) +{ + return dt_repurpose(unit->threads[id], &runnable_simio, NULL) == 0; +} + +/*! \brief Cancel single thread. */ +static inline int dt_test_cancel(dt_unit_t *unit, int id) +{ + return dt_cancel(unit->threads[id]) == 0; +} + +/*! \brief Reanimate dead threads. */ +static inline int dt_test_reanimate(dt_unit_t *unit) +{ + // Compact all threads + int ret = 0; + ret += dt_compact(unit); + + // Remove purpose from all + for (int i = 0; i < unit->size; ++i) { + ret += dt_repurpose(unit->threads[i], 0, 0); + } + + // Set single thread to purpose + ret += dt_repurpose(unit->threads[0], &runnable, 0); + + // Restart + _runnable_i = 0; + ret += dt_start(unit); + + // Wait for finish + ret += dt_join(unit); + + // Verify + int expected = 1 * _runnable_cycles; + if (_runnable_i != expected) { + return 0; + } + + // Check return codes + return ret == 0; +} + +/*! \brief Resize unit. */ +static inline int dt_test_resize(dt_unit_t *unit, int size) +{ + // Resize + int ret = 0; + ret = dt_resize(unit, size); + if (ret < 0) { + return 0; + } + + // Check outcome + if (unit->size != size) { + return 0; + } + + // Repurpose all + _runnable_i = 0; + for (int i = 0; i < size; ++i) { + ret += dt_repurpose(unit->threads[i], &runnable, 0); + ret += dt_start_id(unit->threads[i]); + } + + // Wait for finish + ret += dt_join(unit); + + // Verify + int expected = size * _runnable_cycles; + note("resize test: %d threads, %d ticks, %d expected", + size, _runnable_i, expected); + if (_runnable_i != expected) { + return 0; + } + + // Check return codes + return ret == 0; +} + +/*! \brief Resize unit while threads are active. */ +static inline int dt_test_liveresize(dt_unit_t *unit) +{ + // Size + int size = unit->size; + int size_hi = size + 2; + int size_lo = size - 1; + + // Expand + int ret = 0; + ret = dt_resize(unit, size_hi); + if (ret < 0) { + return 0; + } + + // Repurpose all + for (int i = 0; i < unit->size; ++i) { + ret += dt_repurpose(unit->threads[i], &runnable, 0); + } + + // Restart + _runnable_i = 0; + ret += dt_start(unit); + + // Shrink + ret += dt_resize(unit, size_lo); + + // Wait for finish + ret += dt_join(unit); + + // Verify + int expected_hi = size_hi * _runnable_cycles; + int expected_lo = size_lo * _runnable_cycles; + note("resize test: %d->%d->%d threads, %d ticks, <%d,%d> expected", + size, size_hi, size_lo, _runnable_i, expected_lo, expected_hi); + + if (_runnable_i > expected_hi || _runnable_i < expected_lo) { + return 0; + } + + // Check return codes + return ret == 0; +} + +/*! \brief Start unit. */ +static inline int dt_test_start(dt_unit_t *unit) +{ + return dt_start(unit) == 0; +} + +/*! \brief Stop unit. */ +static inline int dt_test_stop(dt_unit_t *unit) +{ + return dt_stop(unit); +} + +/*! \brief Join unit. */ +static inline int dt_test_join(dt_unit_t *unit) +{ + return dt_join(unit) == 0; +} + +/*! API: return number of tests. */ +static int dt_tests_count(int argc, char *argv[]) +{ + return DT_TEST_COUNT; +} + +// Signal handler +static void interrupt_handle(int s) +{ +} + +/*! API: run tests. */ +static int dt_tests_run(int argc, char *argv[]) +{ + // Register service and signal handler + struct sigaction sa; + sa.sa_handler = interrupt_handle; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGALRM, &sa, NULL); // Interrupt + + /* Initialize */ + srand(time(NULL)); + struct timeval tv; + pthread_mutex_init(&_runnable_mx, NULL); + + /* Test 1: Create unit */ + dt_unit_t *unit = dt_test_create(dt_optimal_size()); + ok(unit != 0, "dthreads: create unit (optimal size %d)", unit->size); + skip(unit == 0, DT_TEST_COUNT - 1); + + /* Test 2: Assign a single task. */ + ok(dt_test_single(unit), "dthreads: assign single task"); + + /* Test 3: Start tasks. */ + _runnable_i = 0; + ok(dt_test_start(unit), "dthreads: start single task"); + + /* Test 4: Wait for tasks. */ + ok(dt_test_join(unit), "dthreads: join threads"); + + /* Test 5: Compare counter. */ + int expected = _runnable_cycles * 1; + cmp_ok(_runnable_i, "==", expected, "dthreads: result ok"); + + /* Test 6: Repurpose threads. */ + _runnable_i = 0; + ok(dt_test_coherent(unit), "dthreads: repurpose to coherent"); + + /* Test 7: Restart threads. */ + ok(dt_test_start(unit), "dthreads: start coherent unit"); + + /* Test 8: Repurpose single thread. */ + tv.tv_sec = 0; + tv.tv_usec = 4000 + rand() % 1000; // 4-5ms + note("waiting for %dus to let thread do some work ...", + tv.tv_usec); + select(0, 0, 0, 0, &tv); + ok(dt_test_repurpose(unit, 0), "dthreads: repurpose on-the-fly"); + + /* Test 9: Cancel blocking thread. */ + tv.tv_sec = 0; + tv.tv_usec = (250 + rand() % 500) * 1000; // 250-750ms + note("waiting for %dms to let thread pretend blocking I/O ...", + tv.tv_usec / 1000); + select(0, 0, 0, 0, &tv); + ok(dt_test_cancel(unit, 0), "dthreads: cancel blocking thread"); + + /* Test 10: Wait for tasks. */ + ok(dt_test_join(unit), "dthreads: join threads"); + + /* Test 11: Compare counter. */ + int expected_lo = _runnable_cycles * (unit->size - 1); + cmp_ok(_runnable_i, ">=", expected_lo, + "dthreads: result %d is => %d", _runnable_i, expected_lo); + + /* Test 12: Compare counter #2. */ + int expected_hi = _runnable_cycles * unit->size; + cmp_ok(_runnable_i, "<=", expected_hi, + "dthreads: result %d is <= %d", _runnable_i, expected_hi); + + /* Test 13: Reanimate dead threads. */ + ok(dt_test_reanimate(unit), "dthreads: reanimate dead threads"); + + /* Test 14: Expand unit by 100%. */ + int size = unit->size * 2; + ok(dt_test_resize(unit, size), + "dthreads: expanding unit to size * 2 (%d threads)", size); + + /* Test 15: Shrink unit to half. */ + size = unit->size / 2; + ok(dt_test_resize(unit, size), + "dthreads: shrinking unit to size / 2 (%d threads)", size); + + /* Test 16: Resize while threads are active. */ + ok(dt_test_liveresize(unit), "dthreads: resizing unit while active"); + + /* Test 17: Deinitialize */ + dt_delete(&unit); + ok(unit == 0, "dthreads: delete unit"); + endskip; + + /* Test 18: Wrong values. */ + unit = dt_create(-1); + ok(unit == 0, "dthreads: create with negative count"); + unit = dt_create_coherent(dt_optimal_size(), 0, 0); + + /* Test 19: NULL runnable. */ + cmp_ok(dt_start(unit), "==", 0, "dthreads: start with NULL runnable"); + + /* Test 20: resize to negative value. */ + cmp_ok(dt_resize(unit, -19), + "<", 0, "dthreads: resize to negative size"); + + /* Test 21: resize to zero value. */ + cmp_ok(dt_resize(unit, 0), "<", 0, "dthreads: resize to NULL size"); + dt_join(unit); + dt_delete(&unit); + + /* Test 22: NULL operations crashing. */ + int op_count = 14; + int expected_min = op_count * -1; + // All functions must return -1 at least + int ret = 0; + lives_ok( { + ret += dt_activate(0); // -1 + ret += dt_cancel(0); // -1 + ret += dt_compact(0); // -1 + dt_delete(0); // + ret += dt_is_cancelled(0); // 0 + ret += dt_join(0); // -1 + ret += dt_repurpose(0, 0, 0); // -1 + ret += dt_resize(0, 0); // -1 + ret += dt_setprio(0, 0); // -1 + ret += dt_signalize(0, SIGALRM); // -1 + ret += dt_start(0); // -1 + ret += dt_start_id(0); // -1 + ret += dt_stop(0); // -1 + ret += dt_stop_id(0); // -1 + ret += dt_unit_lock(0); // -1 + ret += dt_unit_unlock(0); // -1 + }, "dthreads: not crashed while executing functions on NULL context"); + + /* Test 23: expected results. */ + cmp_ok(ret, "<=", expected_min, + "dthreads: correct values when passed NULL context " + "(%d, min: %d)", ret, expected_min); + + pthread_mutex_destroy(&_runnable_mx); + return 0; +} diff --git a/src/tests/knot/dthreads_tests.h b/src/tests/knot/dthreads_tests.h new file mode 100644 index 0000000..e41bdc5 --- /dev/null +++ b/src/tests/knot/dthreads_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_DTHREADS_TESTS_H_ +#define _KNOTD_DTHREADS_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api dthreads_tests_api; + +#endif /* _KNOTD_DTHREADS_TESTS_H_ */ diff --git a/src/tests/knot/journal_tests.c b/src/tests/knot/journal_tests.c new file mode 100644 index 0000000..21c92fe --- /dev/null +++ b/src/tests/knot/journal_tests.c @@ -0,0 +1,184 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <string.h> + +#include "tests/knot/journal_tests.h" +#include "knot/server/journal.h" +#include "knot/other/error.h" + +static int journal_tests_count(int argc, char *argv[]); +static int journal_tests_run(int argc, char *argv[]); + +/* + * Unit API. + */ +unit_api journal_tests_api = { + "Journal", + &journal_tests_count, + &journal_tests_run +}; + +/* + * Unit implementation. + */ +static const int JOURNAL_TEST_COUNT = 11; + +/*! \brief Generate random string with given length. */ +static int randstr(char* dst, size_t len) +{ + for (int i = 0; i < len - 1; ++i) { + dst[i] = '0' + (int) (('Z'-'0') * (rand() / (RAND_MAX + 1.0))); + } + dst[len - 1] = '\0'; + + return 0; +} + +/*! \brief Walk journal of chars into buffer. */ +static int _wbi = 0; +static char _walkbuf[7]; +static int walkchars_cmp(uint64_t k1, uint64_t k2) { + return k1 - k2; +} + +static int walkchars(journal_t *j, journal_node_t *n) { + journal_read(j, n->id, walkchars_cmp, _walkbuf + _wbi); + ++_wbi; + return 0; +} + +/*! API: return number of tests. */ +static int journal_tests_count(int argc, char *argv[]) +{ + return JOURNAL_TEST_COUNT; +} + +/*! API: run tests. */ +static int journal_tests_run(int argc, char *argv[]) +{ + /* Test 1: Create tmpfile. */ + int fsize = 8092; + int jsize = 6; + char jfn_buf[] = "/tmp/journal.XXXXXX"; + int tmp_fd = mkstemp(jfn_buf); + ok(tmp_fd >= 0, "journal: create temporary file"); + skip(tmp_fd < 0, JOURNAL_TEST_COUNT - 1); + + /* Test 2: Create journal. */ + const char *jfilename = jfn_buf; + int ret = journal_create(jfilename, jsize); + ok(ret == KNOTD_EOK, "journal: create journal '%s'", jfilename); + + /* Test 3: Open journal. */ + journal_t *j = journal_open(jfilename, fsize, 0); + ok(j != 0, "journal: open"); + + /* Test 4: Write entry to log. */ + const char *sample = "deadbeef"; + ret = journal_write(j, 0x0a, sample, strlen(sample)); + ok(ret == KNOTD_EOK, "journal: write"); + + /* Test 5: Read entry from log. */ + char tmpbuf[64] = {'\0'}; + ret = journal_read(j, 0x0a, 0, tmpbuf); + ok(ret == KNOTD_EOK, "journal: read entry"); + + /* Test 6: Compare read data. */ + ret = strncmp(sample, tmpbuf, strlen(sample)); + ok(ret == 0, "journal: read data integrity check"); + + /* Append several characters. */ + journal_write(j, 0, "X", 1); /* Dummy */ + char word[7] = { 'w', 'o', 'r', 'd', '0', '\0', '\0' }; + for (int i = 0; i < strlen(word); ++i) { + journal_write(j, i, word+i, 1); + } + + /* Test 7: Compare journal_walk() result. */ + _wbi = 0; + journal_walk(j, walkchars); + _walkbuf[_wbi] = '\0'; + ret = strcmp(word, _walkbuf); + ok(ret == 0, "journal: read data integrity check 2 '%s'", _walkbuf); + _wbi = 0; + + /* Test 8: Change single letter and compare. */ + word[5] = 'X'; + journal_write(j, 5, word+5, 1); /* append 'X', shifts out 'w' */ + journal_walk(j, walkchars); + _walkbuf[_wbi] = '\0'; + ret = strcmp(word + 1, _walkbuf); + ok(ret == 0, "journal: read data integrity check 3 '%s'", _walkbuf); + _wbi = 0; + + /* Close journal. */ + journal_close(j); + + /* Recreate journal. */ + remove(jfilename); + fsize = 8092; + jsize = 512; + ret = journal_create(jfilename, jsize); + j = journal_open(jfilename, fsize, 0); + + /* Test 9: Write random data. */ + int chk_key = 0; + char chk_buf[64] = {'\0'}; + ret = 0; + const int itcount = 1;//jsize * 5 + 5; + for (int i = 0; i < itcount; ++i) { + int key = rand() % 65535; + randstr(tmpbuf, sizeof(tmpbuf)); + if (journal_write(j, key, tmpbuf, sizeof(tmpbuf)) != KNOTD_EOK) { + ret = -1; + break; + } + + /* Store some key on the end. */ + if (i == itcount - 2) { + chk_key = key; + memcpy(chk_buf, tmpbuf, sizeof(chk_buf)); + } + } + ok(ret == 0, "journal: sustained looped writes"); + + /* Test 10: Check data integrity. */ + memset(tmpbuf, 0, sizeof(tmpbuf)); + journal_read(j, chk_key, 0, tmpbuf); + ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); + ok(ret == 0, "journal: read data integrity check"); + + /* Test 11: Reopen log and re-read value. */ + memset(tmpbuf, 0, sizeof(tmpbuf)); + journal_close(j); + j = journal_open(jfilename, fsize, 0); + journal_read(j, chk_key, 0, tmpbuf); + ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); + ok(ret == 0, "journal: read data integrity check after close/open"); + + /* Close journal. */ + journal_close(j); + + /* Close temporary file fd. */ + close(tmp_fd); + + /* Delete journal. */ + remove(jfilename); + + endskip; + + return 0; +} diff --git a/src/tests/knot/journal_tests.h b/src/tests/knot/journal_tests.h new file mode 100644 index 0000000..beec8ca --- /dev/null +++ b/src/tests/knot/journal_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_JOURNAL_TESTS_H_ +#define _KNOTD_JOURNAL_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api journal_tests_api; + +#endif /* _KNOTD_JOURNAL_TESTS_H_ */ diff --git a/src/tests/knot/server_tests.c b/src/tests/knot/server_tests.c new file mode 100644 index 0000000..5ae04d8 --- /dev/null +++ b/src/tests/knot/server_tests.c @@ -0,0 +1,113 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "tests/knot/server_tests.h" +#include "knot/server/server.h" + +static int server_tests_count(int argc, char *argv[]); +static int server_tests_run(int argc, char *argv[]); + +/* + * Unit API. + */ +unit_api server_tests_api = { + "Server", + &server_tests_count, + &server_tests_run +}; + +/* + * Unit implementation. + */ + +static const int SERVER_TEST_COUNT = 4; + +/*! Test: create server. */ +server_t *test_server_create() +{ + return server_create(); +} + +/*! Test: start server. */ +int test_server_start(server_t *s) +{ + return server_start(s) == 0; +} + +/*! Test: finish server. */ +int test_server_finish(server_t *s) +{ + return server_wait(s) == 0; +} + +/*! Test: stop server. */ +int test_server_destroy(server_t *s) +{ + server_destroy(&s); + return s == 0; +} + +/*! API: return number of tests. */ +static int server_tests_count(int argc, char *argv[]) +{ + return SERVER_TEST_COUNT + 1; +} + +// Signal handler +static void interrupt_handle(int s) +{ +} + +/*! API: run tests. */ +static int server_tests_run(int argc, char *argv[]) +{ + server_t *server = 0; + int ret = 0; + + // Register service and signal handler + struct sigaction sa; + sa.sa_handler = interrupt_handle; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGALRM, &sa, NULL); // Interrupt + + //! Test server for correct initialization + server = test_server_create(); + ok(server != 0, "server: initialized"); + + //! Test server startup + ret = 0; + lives_ok( { + ret = test_server_start(server); + }, "server: not crashing on runtime"); + + //! Test server exit code + ok(ret, "server: started ok"); + if (ret) { + server_stop(server); + } else { + diag("server crashed, skipping deinit and destroy tests"); + } + + //! Test server waiting for finish + skip(!ret, 2); + ok(test_server_finish(server), "server: waiting for finish"); + + //! Test server for correct deinitialization + ok(test_server_destroy(server), "server: deinit"); + endskip; + + return 0; +} diff --git a/src/tests/knot/server_tests.h b/src/tests/knot/server_tests.h new file mode 100644 index 0000000..43ad0c1 --- /dev/null +++ b/src/tests/knot/server_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_SERVER_TESTS_H_ +#define _KNOTD_SERVER_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api server_tests_api; + +#endif /* _KNOTD_SERVER_TESTS_H_ */ diff --git a/src/tests/libknot/files/parsed_data b/src/tests/libknot/files/parsed_data Binary files differnew file mode 100644 index 0000000..4027c92 --- /dev/null +++ b/src/tests/libknot/files/parsed_data diff --git a/src/tests/libknot/files/parsed_data_queries b/src/tests/libknot/files/parsed_data_queries Binary files differnew file mode 100644 index 0000000..5857c87 --- /dev/null +++ b/src/tests/libknot/files/parsed_data_queries diff --git a/src/tests/libknot/files/raw_data b/src/tests/libknot/files/raw_data Binary files differnew file mode 100644 index 0000000..f94236b --- /dev/null +++ b/src/tests/libknot/files/raw_data diff --git a/src/tests/libknot/files/raw_data_queries b/src/tests/libknot/files/raw_data_queries Binary files differnew file mode 100644 index 0000000..9062d5a --- /dev/null +++ b/src/tests/libknot/files/raw_data_queries diff --git a/src/tests/libknot/libknot/cuckoo_tests.c b/src/tests/libknot/libknot/cuckoo_tests.c new file mode 100644 index 0000000..c1306a3 --- /dev/null +++ b/src/tests/libknot/libknot/cuckoo_tests.c @@ -0,0 +1,382 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <time.h> +#include <assert.h> + +#include "tests/libknot/libknot/cuckoo_tests.h" + +#include "libknot/hash/cuckoo-hash-table.h" + +//#define CK_TEST_DEBUG +//#define CK_TEST_LOOKUP +//#define CK_TEST_OUTPUT +//#define CK_TEST_REMOVE +//#define CK_TEST_COMPARE + +#ifdef CK_TEST_DEBUG +#define CK_TEST_LOOKUP +#define CK_TEST_OUTPUT +#define CK_TEST_REMOVE +#define CK_TEST_COMPARE +#endif + +/*----------------------------------------------------------------------------*/ + +static int cuckoo_tests_count(int argc, char *argv[]); +static int cuckoo_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api cuckoo_tests_api = { + "Cuckoo hashing", //! Unit name + &cuckoo_tests_count, //! Count scheduled tests + &cuckoo_tests_run //! Run scheduled tests +}; + +/*----------------------------------------------------------------------------*/ + +/* + * Unit implementation + */ +static const int CUCKOO_TESTS_COUNT = 13; +static const int CUCKOO_MAX_ITEMS = 1000; +static const int CUCKOO_TEST_MAX_KEY_SIZE = 10; + +typedef struct test_cuckoo_items { + char **keys; + size_t *key_sizes; + size_t *values; + size_t *deleted; + int count; + int total_count; +} test_cuckoo_items; + +/*----------------------------------------------------------------------------*/ + +static inline char rand_char() +{ + return (char)((rand() % 26) + 97); +} + +/*----------------------------------------------------------------------------*/ + +static inline void rand_str(char *str, int size) +{ + for (int i = 0; i < size; ++i) { + str[i] = rand_char(); + } +} + +/*----------------------------------------------------------------------------*/ + +static int cuckoo_tests_count(int argc, char *argv[]) +{ + return CUCKOO_TESTS_COUNT; +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_create(ck_hash_table_t **table, uint items) +{ + *table = ck_create_table(items); + return (*table != NULL); +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_insert(ck_hash_table_t *table, + const test_cuckoo_items *items) +{ + assert(table != NULL); + int errors = 0; + for (int i = 0; i < items->count; ++i) { + assert(items->values[i] != 0); + if (ck_insert_item(table, items->keys[i], items->key_sizes[i], + (void *)items->values[i]) != 0) { + ++errors; + } + } + return errors == 0; +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_lookup(ck_hash_table_t *table, + const test_cuckoo_items *items) +{ + int errors = 0; + for (int i = 0; i < items->count; ++i) { + const ck_hash_table_item_t *found = ck_find_item( + table, items->keys[i], items->key_sizes[i]); + if (!found) { + if (items->deleted[i] == 0) { + diag("Not found item with key %.*s\n", + items->key_sizes[i], items->keys[i]); + ++errors; + } + } else { + if (items->deleted[i] != 0 + || found->key != items->keys[i] + || (size_t)(found->value) != items->values[i]) { + diag("Found item with key %.*s (size %u) " + "(should be %.*s (size %u)) and value %zu " + "(should be %d).\n", + found->key_length, found->key, + found->key_length, items->key_sizes[i], + items->keys[i], items->key_sizes[i], + (size_t)found->value, items->values[i]); + ++errors; + } + } + } + + if (errors > 0) { + diag("Not found %d of %d items.\n", errors, items->count); + } else { + note("Found %d items.\n", items->count); + } + + return errors == 0; +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_delete(ck_hash_table_t *table, test_cuckoo_items *items) +{ + int errors = 0; + // delete approx. 1/10 items from the table + int count = rand() % (CUCKOO_MAX_ITEMS / 10) + 1; + + for (int i = 0; i < count; ++i) { + int item = rand() % items->count; + if (items->deleted[item] == 0 + && ck_delete_item(table, items->keys[item], + items->key_sizes[item], NULL, 0) != 0) { + ++errors; + } else { + items->deleted[item] = 1; + } + } + + return errors == 0; +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_modify(ck_hash_table_t *table, test_cuckoo_items *items) +{ + int errors = 0; + // modify approx. 1/10 items from the table + int count = rand() % (CUCKOO_MAX_ITEMS / 10) + 1; + + for (int i = 0; i < count; ++i) { + int item = rand() % items->count; + int old_value = items->values[item]; + items->values[item] = rand() + 1; + if (ck_update_item(table, items->keys[item], + items->key_sizes[item], + (void *)items->values[item], NULL) != 0 + && items->deleted[item] == 1) { + ++errors; + items->values[item] = old_value; + } + } + + return 1; +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_rehash(ck_hash_table_t *table) +{ + return (ck_rehash(table) == 0); +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_resize(ck_hash_table_t *table) +{ + // test the resize explicitly + return (ck_resize_table(table) == 0); +} + +/*----------------------------------------------------------------------------*/ + +static int test_cuckoo_full(ck_hash_table_t *table, test_cuckoo_items *items) +{ + // invoke the resize by inserting so much items that thay cannot + // fit into the table + int new_count = table->items; + + while (new_count < hashsize(table->table_size_exp) * table->table_count) { + new_count += table->items; + } + + note("Old item count: %d, new count: %d, capacity of the table: %d\n", + table->items, new_count, + hashsize(table->table_size_exp) * table->table_count); + + assert(new_count <= items->total_count); + + int errors = 0; + + for (int i = items->count; i < new_count; ++i) { + assert(items->values[i] != 0); + if (ck_insert_item(table, items->keys[i], items->key_sizes[i], + (void *)items->values[i]) != 0) { + ++errors; + } + } + + items->count = new_count; + + return (errors == 0); +} + +/*----------------------------------------------------------------------------*/ + +static void create_random_items(test_cuckoo_items *items, int item_count) +{ + assert(items != NULL); + + items->count = item_count; + items->total_count = item_count * 10; + items->values = (size_t *)malloc(items->total_count * sizeof(size_t)); + items->key_sizes = (size_t *)malloc(items->total_count * sizeof(size_t)); + items->deleted = (size_t *)malloc(items->total_count * sizeof(size_t)); + items->keys = (char **)malloc(items->total_count * sizeof(char *)); + + for (int i = 0; i < items->total_count; ++i) { + int value = rand() + 1; + int key_size = rand() % CUCKOO_TEST_MAX_KEY_SIZE + 1; + char *key = malloc(key_size * sizeof(char)); + assert(key != NULL); + rand_str(key, key_size); + + // check if the key is not already in the table + int found = 0; + for (int j = 0; j < i; ++j) { + if (items->key_sizes[j] == key_size + && strncmp(items->keys[j], key, key_size) == 0) { + found = 1; + break; + } + } + + if (!found) { + assert(value != 0); + items->values[i] = value; + items->key_sizes[i] = key_size; + items->keys[i] = key; + items->deleted[i] = 0; + } else { + free(key); + --i; + } + } +} + +/*----------------------------------------------------------------------------*/ + +static void delete_items(test_cuckoo_items *items) +{ + free(items->deleted); + free(items->key_sizes); + free(items->values); + for (int i = 0; i < items->total_count; ++i) { + free(items->keys[i]); + } + free(items->keys); +} + +/*----------------------------------------------------------------------------*/ + +/*! Run all scheduled tests for given parameters. + */ +static int cuckoo_tests_run(int argc, char *argv[]) +{ + srand(time(NULL)); + int res; + + const int item_count = rand() % CUCKOO_MAX_ITEMS + 1; + test_cuckoo_items *items = (test_cuckoo_items *) + malloc(sizeof(test_cuckoo_items)); + + ck_hash_table_t *table = NULL; + + // Test 1: create + ok(res = test_cuckoo_create(&table, item_count), + "cuckoo hashing: create"); + + create_random_items(items, item_count); + + skip(!res, 10); + // Test 2: insert + ok(test_cuckoo_insert(table, items), "cuckoo hashing: insert"); + + // Test 3: lookup + ok(test_cuckoo_lookup(table, items), "cuckoo hashing: lookup"); + + // Test 4: delete + ok(test_cuckoo_delete(table, items), "cuckoo hashing: delete"); + + // Test 5: lookup 2 + ok(test_cuckoo_lookup(table, items), + "cuckoo hashing: lookup after delete"); + + // Test 6: modify + ok(test_cuckoo_modify(table, items), "cuckoo hashing: modify"); + + // Test 7: lookup 3 + ok(test_cuckoo_lookup(table, items), + "cuckoo hashing: lookup after modify"); + + // Test 8: rehash + ok(test_cuckoo_rehash(table), "cuckoo hashing: rehash"); + + // Test 9: lookup 4 + ok(test_cuckoo_lookup(table, items), + "cuckoo hashing: lookup after rehash"); + + // Test 10: resize + ok(test_cuckoo_resize(table), "cuckoo hashing: resize"); + + // Test 11: lookup 5 + ok(test_cuckoo_lookup(table, items), + "cuckoo hashing: lookup after resize"); + + // Test 12: owerflow the table + ok(test_cuckoo_full(table, items), "cuckoo hashing: overflow"); + + // Test 13: lookup 5 + ok(test_cuckoo_lookup(table, items), + "cuckoo hashing: lookup after overflow"); + + endskip; + + /** + * \note These last 2 tests found some major bug in the cuckoo hash + * table, so running them results in abort upon assertion. + * Disabled for now. + */ + + // Cleanup + ck_destroy_table(&table, NULL, 0); + delete_items(items); + free(items); + + return 0; +} diff --git a/src/tests/libknot/libknot/cuckoo_tests.h b/src/tests/libknot/libknot/cuckoo_tests.h new file mode 100644 index 0000000..b6b0db8 --- /dev/null +++ b/src/tests/libknot/libknot/cuckoo_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_CUCKOO_TESTS_H_ +#define _KNOTD_CUCKOO_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api cuckoo_tests_api; + +#endif /* _KNOTD_CUCKOO_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/dname_table_tests.c b/src/tests/libknot/libknot/dname_table_tests.c new file mode 100644 index 0000000..0d00a44 --- /dev/null +++ b/src/tests/libknot/libknot/dname_table_tests.c @@ -0,0 +1,393 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* blame: jan.kadlec@nic.cz */ + +#include <assert.h> + +#include "dname_table_tests.h" +#include "libknot/util/error.h" +#include "libknot/zone/dname-table.h" +/* *test_t structures */ +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" + +static int knot_dname_table_tests_count(int argc, char *argv[]); +static int knot_dname_table_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api dname_table_tests_api = { + "Dname table", //! Unit name + &knot_dname_table_tests_count, //! Count scheduled tests + &knot_dname_table_tests_run //! Run scheduled tests +}; + +/* Helper functions. */ +static knot_dname_t *dname_from_test_dname_str(const test_dname_t *test_dname) +{ + assert(test_dname != NULL); + knot_dname_t *ret = knot_dname_new_from_str (test_dname->str, + strlen(test_dname->str), + NULL); + CHECK_ALLOC(ret, NULL); + + return ret; +} + +static int dname_compare_sort_wrapper(const void *ptr1, const void *ptr2) +{ + const knot_dname_t *dname1 = + dname_from_test_dname_str((const test_dname_t *)ptr1); + const knot_dname_t *dname2 = + dname_from_test_dname_str((const test_dname_t *)ptr2); + assert(dname1 && dname2); + return knot_dname_compare(dname1, dname2); +} + +/* Unit implementation. */ +enum {DNAME_TABLE_DNAME_COUNT = 3}; + +/* Strings are enough, we're not testing dname here ... */ +static test_dname_t DNAME_TABLE_DNAMES[DNAME_TABLE_DNAME_COUNT] = { + /* list ptr, string, wire, length, labels, label_count */ + {NULL, NULL, ".", NULL, 1, NULL, 0}, + {NULL, NULL, "a.ns.nic.cz.", NULL, 13, NULL, 0}, + {NULL, NULL, "b.ns.nic.cz.", NULL, 13, NULL, 0} +}; + +static int test_dname_table_new() +{ + knot_dname_table_t *table = knot_dname_table_new(); + if (table == NULL) { + return 0; + } + + knot_dname_table_free(&table); + return 1; +} + +struct test_dname_table_arg { + /* Times two - safety measure. */ + knot_dname_t *array[DNAME_TABLE_DNAME_COUNT * 2]; + uint count; +}; + +static void save_dname_to_array(knot_dname_t *node, void *data) +{ + assert(data); + struct test_dname_table_arg *arg = (struct test_dname_table_arg *)data; + arg->array[arg->count] = node; + arg->count++; +} + +static int test_dname_table_adding() +{ + int errors = 0; + knot_dname_table_t *table = knot_dname_table_new(); + CHECK_ALLOC(table, 0); + + /* Add NULL */ + if (knot_dname_table_add_dname(table, NULL) != KNOT_EBADARG) { + diag("Adding NULL dname did not result in an error!"); + errors++; + } + + /* Add to NULL table*/ + if (knot_dname_table_add_dname(NULL, NULL) != KNOT_EBADARG) { + diag("Adding to NULL table did not result in an error!"); + errors++; + } + + /* Add NULL */ + if (knot_dname_table_add_dname_check(table, NULL) != KNOT_EBADARG) { + diag("Adding NULL dname did not result in an error!"); + errors++; + } + + /* Add to NULL table*/ + if (knot_dname_table_add_dname_check(NULL, NULL) != KNOT_EBADARG) { + diag("Adding to NULL table did not result in an error!"); + errors++; + } + + + /* Add valid dnames. */ + for (int i = 0; i < DNAME_TABLE_DNAME_COUNT; i++) { + knot_dname_t *dname = + dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]); + if (!dname) { + diag("Could not create dname from test dname!"); + errors++; + continue; + } + if (knot_dname_table_add_dname(table, dname) != KNOT_EOK) { + diag("Could not add dname! (%s)", + DNAME_TABLE_DNAMES[i].str); + errors++; + } + } + + /* + * Using inorder traversal of the table, + * create array containing dnames. + */ + + struct test_dname_table_arg arg; + arg.count = 0; + + knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg); + + if (arg.count != DNAME_TABLE_DNAME_COUNT) { + diag("Table contains too many dnames!"); + /* No sense in continuing. */ + knot_dname_table_deep_free(&table); + return 0; + } + + /* + * Check that inordered array is really sorted + * and contains valid dnames. + */ + for (int i = 0; i < DNAME_TABLE_DNAME_COUNT; i++) { + assert(arg.array[i]); + const char *str = knot_dname_to_str(arg.array[i]); + if (str == NULL) { + diag("Wrong dname in table!"); + errors++; + continue; + } + + if (arg.array[i]->size != + DNAME_TABLE_DNAMES[i].size) { + diag("Wrong dname size in table!"); + diag("Is: %u should be %u.", + arg.array[i]->size, + DNAME_TABLE_DNAMES[i].size); + errors++; + continue; + } + + if (strncmp(str, DNAME_TABLE_DNAMES[i].str, + DNAME_TABLE_DNAMES[i].size) != 0) { + diag("Wrong dname wire in table!"); + errors++; + } + } + + /* Now add one dname once again. It has to be the first item! */ + + if (knot_dname_table_add_dname(table, + dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0])) != + KNOT_EOK) { + diag("Could not add dname to table once it's already there!"); + /* Next test would not make sense. */ + knot_dname_table_deep_free(&table); + return 0; + } + + /* + * After walking the table, there should now be + * DNAME_TABLE_DNAME_COUNT + 1 items, with 2 identical + * items at the beginning. + */ + + memset(arg.array, 0, + sizeof(knot_dname_t *) * DNAME_TABLE_DNAME_COUNT * 2); + arg.count = 0; + knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg); + + if (arg.count != DNAME_TABLE_DNAME_COUNT + 1) { + diag("Identical dname was not added!"); + /* Again, next test would not make any sense. */ + knot_dname_table_deep_free(&table); + return 0; + } + + if (knot_dname_compare(arg.array[0], arg.array[1]) != 0) { + diag("First two dnames in table are not identical!"); + errors++; + } + + /* Delete table, wipe out array. */ + knot_dname_table_deep_free(&table); + memset(arg.array, 0, + sizeof(knot_dname_t *) * DNAME_TABLE_DNAME_COUNT * 2); + arg.count = 0; + + table = knot_dname_table_new(); + assert(table); + + /* + * Add dname with same content twice using knot_dname_table_add2 - + * table should now only contain one item. + */ + + knot_dname_t *tmp_dname = + dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0]); + assert(tmp_dname); + + if (knot_dname_table_add_dname_check(table, &tmp_dname) != KNOT_EOK) { + diag("Could not add dname using dname_table_add_dname2!"); + knot_dname_table_deep_free(&table); + knot_dname_free(&tmp_dname); + return 0; + } + + tmp_dname = dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0]); + assert(tmp_dname); + + knot_dname_t *dname_before_add = tmp_dname; + + if (knot_dname_table_add_dname_check(table, &tmp_dname) != 1) { + diag("Could not add dname again using dname_table_add_dname2!"); + knot_dname_table_deep_free(&table); + return 0; + } + + if (tmp_dname == dname_before_add) { + diag("Dname was not freed after insertion!"); + errors++; + } + + knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg); + + if (arg.count != 1) { + diag("Add_dname2 has added dname when it shouldn't!"); + errors++; + } + + if (knot_dname_compare(tmp_dname, arg.array[0]) != 0) { + diag("Add_dname2 has added wrong dname!"); + errors++; + } + + knot_dname_table_deep_free(&table); + return (errors == 0); +} + +static int test_dname_table_find() +{ + int errors = 0; + knot_dname_table_t *table = knot_dname_table_new(); + assert(table); + + if (knot_dname_table_find_dname(table, NULL) != NULL) { + diag("Dname table did not return NULL when searching NULL!"); + errors++; + } + + if (knot_dname_table_find_dname(NULL, NULL) != NULL) { + diag("Passing NULL instead of dname table did not " + "return NULL!"); + errors++; + } + + /* Add all dnames but the last one. */ + for (int i = 0; i < DNAME_TABLE_DNAME_COUNT - 1; i++) { + knot_dname_t *dname = + dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]); + if (!dname) { + diag("Could not create dname from test dname!"); + errors++; + continue; + } + if (knot_dname_table_add_dname(table, dname) != KNOT_EOK) { + diag("Could not add dname! (%s)", + DNAME_TABLE_DNAMES[i].str); + errors++; + } + } + + /* Search for added dnames. */ + for (int i = 0; i < DNAME_TABLE_DNAME_COUNT - 1; i++) { + knot_dname_t *dname = + dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]); + if (!dname) { + diag("Could not create dname from test dname!"); + errors++; + continue; + } + + knot_dname_t *found_dname = + knot_dname_table_find_dname(table, dname); + + if (found_dname == NULL) { + diag("Dname table did not return " + "dname when it should!"); + errors++; + continue; + } + + if (knot_dname_compare(found_dname, dname) != 0) { + diag("Returned dname did not match!"); + errors++; + continue; + } + } + + /* Search for last dname, it should return NULL. */ + knot_dname_t *dname = + dname_from_test_dname_str( + &DNAME_TABLE_DNAMES[DNAME_TABLE_DNAME_COUNT]); + assert(dname); + + if (knot_dname_table_find_dname(table, dname) != NULL) { + diag("Dname table returned dname when it " + "should not be there!"); + errors++; + } + + knot_dname_free(&dname); + knot_dname_table_deep_free(&table); + + return (errors == 0); +} + +static const int KNOT_DNAME_TABLE_TEST_COUNT = 3; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_dname_table_tests_count(int argc, char *argv[]) +{ + return KNOT_DNAME_TABLE_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_dname_table_tests_run(int argc, char *argv[]) +{ + int final_res = 1; + int res = 0; + + /* Sort array containing test dnames. */ + qsort(DNAME_TABLE_DNAMES, DNAME_TABLE_DNAME_COUNT, + sizeof(test_dname_t), dname_compare_sort_wrapper); + + ok((res = test_dname_table_new()), "dname table: new"); + final_res *= res; + + skip(!res, 2); + + ok((res = test_dname_table_adding()), "dname table: adding"); + final_res *= res; + + ok((res = test_dname_table_find()), "dname table: searching"); + final_res *= res; + + endskip; + + return final_res; +} diff --git a/src/tests/libknot/libknot/dname_table_tests.h b/src/tests/libknot/libknot/dname_table_tests.h new file mode 100644 index 0000000..f3088e9 --- /dev/null +++ b/src/tests/libknot/libknot/dname_table_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_DNAME_TABLE_TESTS_H_ +#define _KNOTD_DNAME_TABLE_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api dname_table_tests_api; + +#endif /* _KNOTD_DNAME_TABLE_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/dname_tests.c b/src/tests/libknot/libknot/dname_tests.c new file mode 100644 index 0000000..9730756 --- /dev/null +++ b/src/tests/libknot/libknot/dname_tests.c @@ -0,0 +1,877 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <assert.h> + +#include "tests/libknot/libknot/dname_tests.h" +#include "libknot/dname.h" +#include "libknot/zone/node.h" + +static int knot_dname_tests_count(int argc, char *argv[]); +static int knot_dname_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api dname_tests_api = { + "DNS library - dname", //! Unit name + &knot_dname_tests_count, //! Count scheduled tests + &knot_dname_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +// C will not accept const int in other const definition +enum { TEST_DOMAINS_OK = 8 }; + +enum { TEST_DOMAINS_BAD = 4 }; + +enum { TEST_DOMAINS_NON_FQDN = 6 }; + +static knot_node_t *NODE_ADDRESS = (knot_node_t *)0xDEADBEEF; + +struct test_domain { + char *str; + char *wire; + uint size; + char *labels; + short label_count; +}; + +/*! \warning Do not change the order in those, if you want to test some other + * feature with new dname, add it at the end of these arrays. + */ +static const struct test_domain + test_domains_ok[TEST_DOMAINS_OK] = { + { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21, + "\x0\x4\x9\x10", 4 }, + { "some.test.domain.com.", "\4some\4test\6domain\3com", 22, + "\x0\x5\xA\x11", 4 }, + { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21, + "\x0\x4\x9\x10", 4 }, + { "some.test.domain.com.", "\4some\4test\6domain\3com", 22, + "\x0\x5\xA\x11", 4 }, + { "test.domain.com.", "\4test\6domain\3com", 17, + "\x0\x5\xC", 3 }, + { ".", "\0", 1, + "", 0 }, + { "foo.bar.net.", "\3foo\3bar\3net", 13, + "\x0\x4\x8", 3}, + { "bar.net.", "\3bar\3net", 9, + "\x0\x4", 2} +}; + +static const struct test_domain // sizes are strlen()s here + test_domains_non_fqdn[TEST_DOMAINS_NON_FQDN] = { + { "www", "\3www", 4, "\x0", 1 }, + { "example", "\7example", 8, "\x0", 1 }, + { "com", "\3com", 4, "\x0", 1 }, + { "www.example.com", "\3www\7example\3com", 16, "\x0\x4\xC", + 3 }, + { "some", "\4some", 5, "\x0", 1 }, + { "example.com", "\7example\3com", 12, "\x0\x8", 2 } + }; + +static const struct test_domain + test_domains_bad[TEST_DOMAINS_BAD] = { + { NULL, "\2ex\3com", 0, "", 0 }, + { "ex.com.", NULL, 0, "", 0 }, + { "ex.com.\5", "\3ex\3com\0\5", 10, "", 0 }, + { "example.com", "\3example\3com", 12, "\x0\x8", 2 } +}; + +static int test_dname_create() +{ + knot_dname_t *dname = knot_dname_new(); + if (dname == NULL + || knot_dname_name(dname) != NULL + || knot_dname_size(dname) != 0 + || knot_dname_node(dname, 0) != NULL) { + diag("New domain name not initialized properly!"); + return 0; + } + knot_dname_free(&dname); + if (dname != NULL) { + diag("Pointer to the structure not set to" + "NULL when deallocating!"); + return 0; + } + return 1; +} + +static int test_dname_delete() +{ + // how to test this?? + return 0; +} + +static int check_domain_name(const knot_dname_t *dname, + const struct test_domain *test_domains, int i, + int check_node) +{ + int errors = 0; + + if (dname == NULL) { + diag("Domain name #%d not created!", i); + return 1; + } + + // check size + if (knot_dname_size(dname) != test_domains[i].size) { + diag("Bad size of the created domain name: %u (should be %u).", + knot_dname_size(dname), test_domains[i].size); + ++errors; + } + // check wire format + uint size = knot_dname_size(dname); + if (strncmp((char *)knot_dname_name(dname), + test_domains[i].wire, size) != 0) { + diag("The wire format of the created domain name is wrong:" + " '%.*s' (should be '%.*s').", + size, knot_dname_name(dname), + size, test_domains[i].wire); + ++errors; + } + // check labels + if (test_domains[i].label_count != dname->label_count) { + diag("Label count of the created domain name is wrong:" + " %d (should be %d)\n", dname->label_count, + test_domains[i].label_count); + ++errors; + } + if (strncmp((char *)dname->labels, test_domains[i].labels, + test_domains[i].label_count) != 0) { + diag("Label offsets of the created domain name are wrong.\n"); + ++errors; + } + + if (check_node) { + if (knot_dname_node(dname, 0) != NODE_ADDRESS) { + diag("Node pointer in the created domain name is wrong:" + "%p (should be %p)", + knot_dname_node(dname, 0), NODE_ADDRESS); + ++errors; + } + } + + return errors; +} + +static int test_dname_create_from_str() +{ + int errors = 0; + knot_dname_t *dname = NULL; + + for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) { + //note("testing domain: %s", test_domains_ok[i].str); + dname = knot_dname_new_from_str(test_domains_ok[i].str, + strlen(test_domains_ok[i].str), NODE_ADDRESS); + errors += check_domain_name(dname, test_domains_ok, i, 1); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +static int test_dname_create_from_str_non_fqdn() +{ + int errors = 0; + knot_dname_t *dname = NULL; + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) { + //note("testing domain: %s", test_domains_non_fqdn[i].str); + dname = knot_dname_new_from_str(test_domains_non_fqdn[i].str, + strlen(test_domains_non_fqdn[i].str), NULL); + errors += check_domain_name(dname, test_domains_non_fqdn, i, 0); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +static int test_dname_cat() +{ + int errors = 0; + + /* + * This uses three particular dnames from test_domains structure + * where the third dname is a concatenation of the first two dnames. + */ + + knot_dname_t *d1, *d2, *d3; + + d1 = knot_dname_new_from_str(test_domains_non_fqdn[0].str, + strlen(test_domains_non_fqdn[0].str), NULL); + d2 = knot_dname_new_from_str(test_domains_non_fqdn[1].str, + strlen(test_domains_non_fqdn[1].str), NULL); + d3 = knot_dname_new_from_str(test_domains_non_fqdn[2].str, + strlen(test_domains_non_fqdn[2].str), NULL); + + knot_dname_cat(d1, d2); + knot_dname_cat(d1, d3); + + errors += check_domain_name(d1, test_domains_non_fqdn, 3, 0); + + knot_dname_free(&d1); + knot_dname_free(&d2); + knot_dname_free(&d3); + + /* + * Same thing as above, only different case. + */ + + d1 = knot_dname_new_from_str(test_domains_non_fqdn[4].str, + strlen(test_domains_non_fqdn[4].str), + NODE_ADDRESS); + + d2 = knot_dname_new_from_str(test_domains_ok[4].str, + strlen(test_domains_ok[4].str), + NODE_ADDRESS); + + knot_dname_cat(d1, d2); + + errors += check_domain_name(d1, test_domains_ok, 1, 1); + + knot_dname_free(&d1); + knot_dname_free(&d2); + + return (errors == 0); +} + +static int test_dname_left_chop() +{ + int errors = 0; + + /* Uses same principle as test_dname_cat(), only reversed */ + + /* TODO this would maybe deserver separate structure */ + + knot_dname_t *d1; + + d1 = knot_dname_new_from_str(test_domains_ok[1].str, + strlen(test_domains_ok[1].str), + NODE_ADDRESS); + + knot_dname_t *chopped; + + chopped = knot_dname_left_chop(d1); + + errors += check_domain_name(chopped, test_domains_ok, 4, 0); + + knot_dname_free(&d1); + knot_dname_free(&chopped); + + d1 = knot_dname_new_from_str(test_domains_non_fqdn[3].str, + strlen(test_domains_non_fqdn[3].str), + NODE_ADDRESS); + + chopped = knot_dname_left_chop(d1); + + errors += check_domain_name(chopped, test_domains_non_fqdn, 5, 0); + + knot_dname_free(&d1); + knot_dname_free(&chopped); + + return (errors == 0); +} + +static int test_dname_create_from_wire() +{ + int errors = 0; + knot_dname_t *dname = NULL; + + for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) { + assert(strlen(test_domains_ok[i].wire) + 1 == + test_domains_ok[i].size); + dname = knot_dname_new_from_wire( + (uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size, NODE_ADDRESS); + errors += check_domain_name(dname, test_domains_ok, i, 1); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +static int test_dname_to_str() +{ + int errors = 0; + + /* + * Converts dname wireformat to string represenation, which is compared + * with entries in test_domains structure. + */ + + knot_dname_t *dname = NULL; + + for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) { + dname = knot_dname_new_from_wire( + (uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size, NODE_ADDRESS); + char *name_str = knot_dname_to_str(dname); + if (strcmp(name_str, test_domains_ok[i].str) != 0) { + diag("Presentation format of domain name wrong:" + " %s (should be %s)", + name_str, test_domains_ok[i].str); + ++errors; + } + free(name_str); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +/* called by lives_ok */ +static int test_faulty_data() +{ + knot_dname_t *dname = NULL; + + /* + * This takes dnames from test_domains_bad array, which contains + * malformed dnames. TODO add something like: 2www3foo - it's gonna fail + */ + + for (int i = 0; i < TEST_DOMAINS_BAD; i++) { + + if (test_domains_bad[i].str != NULL) { + dname = knot_dname_new_from_str( + test_domains_bad[i].str, + strlen(test_domains_bad[i].str), + NODE_ADDRESS); + } else { + dname = knot_dname_new_from_str( + test_domains_bad[i].str, 0, NODE_ADDRESS); + } + + knot_dname_free(&dname); + + dname = knot_dname_new_from_wire( + (uint8_t *)test_domains_bad[i].wire, + test_domains_bad[i].size, NODE_ADDRESS); + + knot_dname_free(&dname); + } + + return 1; //did it get here? success +} + +static int test_dname_compare() +{ + knot_dname_t *dnames[TEST_DOMAINS_OK]; + + /* This uses particular dnames from TEST_DOMAINS_OK array */ + + for (int i = 0; i < TEST_DOMAINS_OK; ++i) { + dnames[i] = knot_dname_new_from_wire( + (uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size, NODE_ADDRESS); + } + + int errors = 0; + /* abc < some */ + if (knot_dname_compare(dnames[0], dnames[1]) >= 0) { + diag("Dname comparison error"); + errors++; + } + + /* abc.test.domain.com. < foo.bar.net. */ + if (knot_dname_compare(dnames[0], dnames[6]) >= 0) { + diag("Dname comparison error"); + errors++; + } + + /* foo.bar.net. < . */ + if (knot_dname_compare(dnames[5], dnames[0]) >= 0) { + diag("Dname comparison error"); + errors++; + } + + /* bar.net. < foo.bar.net. */ + if (knot_dname_compare(dnames[7], dnames[6]) >= 0) { + diag("Dname comparison error"); + errors++; + } + + /* some == some */ + if (knot_dname_compare(dnames[1], dnames[3]) != 0) { + diag("Dname comparison error"); + errors++; + } + + /*xyz > some */ + if (knot_dname_compare(dnames[2], dnames[1]) <= 0) { + diag("Dname comparison error"); + errors++; + } + + /*foo.bar.net. > xyz.test.domain.com. */ + if (knot_dname_compare(dnames[6], dnames[3]) <= 0) { + diag("Dname comparison error"); + errors++; + } + +// /* xyz.test.domain.com. > . */ +// if (knot_dname_compare(dnames[3], dnames[5]) <= 0) { +// diag("Dname comparison error"); +// errors++; +// } + + /* bar.net. < foo.bar.net. */ + if (knot_dname_compare(dnames[6], dnames[7]) <= 0) { + diag("Dname comparison error"); + errors++; + } + + for (int i = 0; i < TEST_DOMAINS_OK; i++) { + knot_dname_free(&dnames[i]); + } + + return (errors == 0); +} + +static int test_dname_is_fqdn() +{ + int errors = 0; + + knot_dname_t *dname; + + /* All dnames in TEST_DOMAINS_OK are fqdn */ + + for (int i = 0; i < TEST_DOMAINS_OK && !errors; ++i) { + dname = knot_dname_new_from_wire( + (uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size, NODE_ADDRESS); + errors += !knot_dname_is_fqdn(dname); + knot_dname_free(&dname); + } + + /* None of the following dnames should be fqdn */ + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN && !errors; ++i) { + dname = knot_dname_new_from_str(test_domains_non_fqdn[i].str, + strlen(test_domains_non_fqdn[i].str), NULL); + errors += knot_dname_is_fqdn(dname); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +static int test_dname_is_subdomain() +{ + int errors = 0; + + knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK]; + knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN]; + + for (int i = 0; i < TEST_DOMAINS_OK; ++i) { + dnames_fqdn[i] = knot_dname_new_from_wire( + (const uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size, NULL); + assert(dnames_fqdn[i] != NULL); + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) { + dnames_non_fqdn[i] = knot_dname_new_from_str( + test_domains_non_fqdn[i].str, + test_domains_non_fqdn[i].size, NULL); + assert(dnames_non_fqdn[i] != NULL); + } + + // fqdn names 0 - 3 should be subdomains of name 4 + knot_dname_t *parent = dnames_fqdn[4]; + for (int i = 0; i < 3; ++i) { + if (!knot_dname_is_subdomain(dnames_fqdn[i], parent)) { + diag("(fqdn 1-%d) " + "Name %s was not considered subdomain of %s", i, + knot_dname_name(dnames_fqdn[i]), + knot_dname_name(parent)); + ++errors; + } + } + + // fqdn names 0 - 4 should be subdomains of name 5 (root) + parent = dnames_fqdn[5]; + for (int i = 0; i < 4; ++i) { + if (!knot_dname_is_subdomain(dnames_fqdn[i], parent)) { + diag("(fqdn 2-%d) " + "Name %s was not considered subdomain of %s", i, + knot_dname_name(dnames_fqdn[i]), + knot_dname_name(parent)); + ++errors; + } + } + + // non-fqdn names 3 and 5 should be subdomains of non-fqdn name 2 + parent = dnames_non_fqdn[2]; + if (!knot_dname_is_subdomain(dnames_non_fqdn[3], parent)) { + diag("(non-fqdn 1) " + "Name %.*s was not considered subdomain of %.*s", + knot_dname_size(dnames_non_fqdn[3]), + knot_dname_name(dnames_non_fqdn[3]), + knot_dname_size(parent), + knot_dname_name(parent)); + ++errors; + } + if (!knot_dname_is_subdomain(dnames_non_fqdn[5], parent)) { + diag("(non-fqdn 2) " + "Name %.*s was not considered subdomain of %.*s", + knot_dname_size(dnames_non_fqdn[5]), + knot_dname_name(dnames_non_fqdn[5]), + knot_dname_size(parent), + knot_dname_name(parent)); + ++errors; + } + + // non-fqdn name 3 should be subdomain of non-fqdn name 5 + parent = dnames_non_fqdn[5]; + if (!knot_dname_is_subdomain(dnames_non_fqdn[3], parent)) { + diag("(non-fqdn 3) " + "Name %.*s was not considered subdomain of %.*s", + knot_dname_size(dnames_non_fqdn[3]), + knot_dname_name(dnames_non_fqdn[3]), + knot_dname_size(parent), + knot_dname_name(parent)); + ++errors; + } + + // identical names should not be considered subdomains + if (knot_dname_is_subdomain(dnames_fqdn[0], dnames_fqdn[0])) { + diag("(identical names) " + "Name %s was considered subdomain of itself", + knot_dname_name(dnames_fqdn[0])); + ++errors; + } + if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_fqdn[3])) { + diag("(identical names) " + "Name %s was considered subdomain of %s", + knot_dname_name(dnames_fqdn[1]), + knot_dname_name(dnames_fqdn[3])); + ++errors; + } + + // fqdn name should not be considered subdomain of non-fqdn name + if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_non_fqdn[2])) { + diag("(fqdn subdomain of non-fqdn) " + "Name %s was considered subdomain of %.*s", + knot_dname_name(dnames_fqdn[1]), + knot_dname_size(dnames_non_fqdn[2]), + knot_dname_name(dnames_non_fqdn[2])); + ++errors; + } + + // non-fqdn name should not be considered subdomain of fqdn name + if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_non_fqdn[2])) { + diag("(non-fqdn subdomain of fqdn) " + "Name %s was considered subdomain of %.*s", + knot_dname_name(dnames_fqdn[1]), + knot_dname_size(dnames_non_fqdn[2]), + knot_dname_name(dnames_non_fqdn[2])); + ++errors; + } + + // parent name should not be considered subdomain of its subdomain + if (knot_dname_is_subdomain(dnames_fqdn[4], dnames_fqdn[0])) { + diag("(ancestor subdomain of name) " + "Name %s was considered subdomain of %s", + knot_dname_name(dnames_fqdn[4]), + knot_dname_name(dnames_fqdn[0])); + ++errors; + } + + for (int i = 0; i < TEST_DOMAINS_OK; ++i) { + knot_dname_free(&dnames_fqdn[i]); + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) { + knot_dname_free(&dnames_non_fqdn[i]); + } + + return (errors == 0); +} + +static int check_wires(const uint8_t *wire1, uint size1, + uint8_t *wire2, uint size2) +{ + if (size1 != size2) { + return 0; + } + + int i; + + for (i = 0; (i < size1); i++) { + if (wire1[i] != wire2[i]) { + return 0; + } + } + + return 1; +} + +/*!< \note not to be run separately */ +static int test_dname_name(knot_dname_t **dnames_fqdn, + knot_dname_t **dnames_non_fqdn) +{ + assert(dnames_fqdn); + assert(dnames_non_fqdn); + + int errors = 0; + + for (int i = 0; i < TEST_DOMAINS_OK; i++) { + const uint8_t *tmp_name; + + tmp_name = knot_dname_name(dnames_fqdn[i]); + if (!check_wires(tmp_name, dnames_fqdn[i]->size, + (uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size)) { + diag("Got bad name value from structure: " + "%s, should be: %s. Sizes: %d and: %d", + tmp_name, test_domains_ok[i].wire, + dnames_fqdn[i]->size, + test_domains_ok[i].size); + errors++; + } + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { + const uint8_t *tmp_name; + tmp_name = knot_dname_name(dnames_non_fqdn[i]); + if (!check_wires(tmp_name, dnames_non_fqdn[i]->size - 1, + (uint8_t *)test_domains_non_fqdn[i].wire, + test_domains_non_fqdn[i].size)) { + diag("Got bad name value from structure: " + "%s, should be: %s. Sizes: %d and %d\n", + tmp_name, test_domains_non_fqdn[i].wire, + dnames_non_fqdn[i]->size, + test_domains_non_fqdn[i].size); +// hex_print(dnames_non_fqdn[i]->name, +// dnames_non_fqdn[i]->size); +// hex_print(test_domains_non_fqdn[i].wire, +// test_domains_non_fqdn[i].size); +// diag("%s and %s\n", +// knot_dname_to_str(dnames_non_fqdn[i]), +// test_domains_non_fqdn[i]); + errors++; + } + } + + return errors; +} + +/* \note not to be run separately */ +static int test_dname_size(knot_dname_t **dnames_fqdn, + knot_dname_t **dnames_non_fqdn) +{ + assert(dnames_fqdn); + assert(dnames_non_fqdn); + + int errors = 0; + + for (int i = 0; i < TEST_DOMAINS_OK; i++) { + uint8_t tmp_size; + if ((tmp_size = knot_dname_size(dnames_fqdn[i])) != + test_domains_ok[i].size) { + diag("Got bad size value from structure: " + "%u, should be: %u", + tmp_size, test_domains_ok[i].size); + errors++; + } + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { + uint8_t tmp_size; + if ((tmp_size = knot_dname_size(dnames_non_fqdn[i])) != + test_domains_non_fqdn[i].size) { + diag("Got bad size value from structure: " + "%u, should be: %u", + tmp_size, test_domains_non_fqdn[i].size); + errors++; + } + } + + return errors; +} + +/* \note not to be run separately */ +static int test_dname_node(knot_dname_t **dnames_fqdn, + knot_dname_t **dnames_non_fqdn) +{ + assert(dnames_fqdn); + assert(dnames_non_fqdn); + + int errors = 0; + + for (int i = 0; i < TEST_DOMAINS_OK; i++) { + const knot_node_t *tmp_node; + if ((tmp_node = knot_dname_node(dnames_fqdn[i], 0)) != + NODE_ADDRESS) { + diag("Got bad node value from structure: " + "%p, should be: %p", + tmp_node, NODE_ADDRESS); + errors++; + } + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { + const knot_node_t *tmp_node; + if ((tmp_node = knot_dname_node(dnames_non_fqdn[i], 0)) != + NODE_ADDRESS) { + diag("Got bad node value from structure: " + "%s, should be: %s", + tmp_node, NODE_ADDRESS); + errors++; + } + } + + return errors; +} + +static int test_dname_getters(uint type) +{ + int errors = 0; + + knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK]; + knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN]; + + for (int i = 0; i < TEST_DOMAINS_OK; i++) { + dnames_fqdn[i] = knot_dname_new_from_wire( + (uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size, NODE_ADDRESS); + assert(dnames_fqdn[i] != NULL); + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { + printf("Creating dname: %s size: %d\n", test_domains_non_fqdn[i].wire, test_domains_non_fqdn[i].size); + dnames_non_fqdn[i] = knot_dname_new_from_str( + test_domains_non_fqdn[i].str, + test_domains_non_fqdn[i].size, NODE_ADDRESS); + assert(dnames_non_fqdn[i] != NULL); + } + + switch (type) { + case 0: { + errors += test_dname_name(dnames_fqdn, dnames_non_fqdn); + break; + } + + case 1: { + errors += test_dname_size(dnames_fqdn, dnames_non_fqdn); + break; + } + + case 2: { + errors += test_dname_node(dnames_fqdn, dnames_non_fqdn); + break; + } + } /* switch */ + + for (int i = 0; i < TEST_DOMAINS_OK; i++) { + knot_dname_free(&dnames_fqdn[i]); + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { + knot_dname_free(&dnames_non_fqdn[i]); + } + + return (errors == 0); +} + +static const int KNOT_DNAME_TEST_COUNT = 15; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_dname_tests_count(int argc, char *argv[]) +{ + return KNOT_DNAME_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_dname_tests_run(int argc, char *argv[]) +{ + int res = 0, + res_str = 0, + res_wire = 0, + res_str_non_fqdn = 0, + res_final = 1; + + res = test_dname_create(); + ok(res, "dname: create empty"); + res_final *= res; + + skip(!res, 12); + + todo(); + + ok((res = test_dname_delete()), "dname: delete"); + //res_final *= res; + + endtodo; + + ok((res_str = test_dname_create_from_str()), "dname: create from str"); + ok((res_wire = test_dname_create_from_wire()), + "dname: create from wire"); + ok((res_str_non_fqdn = test_dname_create_from_str_non_fqdn()), + "dname: create from str non fqdn"); + res_final *= res_str; + res_final *= res_wire; + res_final *= res_str_non_fqdn; + + todo(); + res = test_dname_getters(0); + ok(res, "dname: name"); + endtodo; + + todo(); + res = test_dname_getters(1); + ok(res, "dname: size"); + endtodo; + + res = test_dname_getters(2); + ok(res, "dname: node"); + + skip(!res_str || !res_wire || !res_str_non_fqdn, 2); + + ok((res = test_dname_to_str()), "dname: convert to str"); + res_final *= res; + + lives_ok(test_faulty_data(); , "dname: faulty data test"); + + endskip; /* !res_str || !res_wire */ + + ok((res = test_dname_compare()), "dname: compare"); + res_final *= res; + + ok((res = test_dname_cat()), "dname: cat"); + res_final *= res; + + ok((res = test_dname_is_fqdn()), "dname: fqdn"); + res_final *= res; + + ok((res = test_dname_left_chop()), "dname: left chop"); + res_final *= res; + + ok((res = test_dname_is_subdomain()), "dname: is subdomain"); + res_final *= res; + + endskip; /* create failed */ + + return res_final; +} diff --git a/src/tests/libknot/libknot/dname_tests.h b/src/tests/libknot/libknot/dname_tests.h new file mode 100644 index 0000000..a7d75aa --- /dev/null +++ b/src/tests/libknot/libknot/dname_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_DNAME_TESTS_H_ +#define _KNOTD_DNAME_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api dname_tests_api; + +#endif /* _KNOTD_DNAME_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/edns_tests.c b/src/tests/libknot/libknot/edns_tests.c new file mode 100644 index 0000000..ac5d130 --- /dev/null +++ b/src/tests/libknot/libknot/edns_tests.c @@ -0,0 +1,596 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "tests/libknot/libknot/edns_tests.h" +#include "libknot/common.h" +#include "libknot/edns.h" + +static int knot_edns_tests_count(int argc, char *argv[]); +static int knot_edns_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api edns_tests_api = { + "DNS library - EDNS", //! Unit name + &knot_edns_tests_count, //! Count scheduled tests + &knot_edns_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +enum { TEST_EDNS = 1, OPTION_COUNT = 3 }; + +struct test_edns_options { + uint16_t code; + uint16_t length; + uint8_t *data; +}; + +struct test_edns { + struct test_edns_options *options; + uint16_t payload; + uint8_t ext_rcode; + uint8_t version; + uint16_t flags; + short option_count; + short options_max; + short size; +}; + +typedef struct test_edns test_edns_t; + +struct test_edns_options test_options_data[OPTION_COUNT] = { + {5, 7, (uint8_t *)"123456"}, + {4, 3, (uint8_t *)"12"}, + {1, 5, (uint8_t *)"13333"} +}; + +test_edns_t test_edns_data[TEST_EDNS] = { +{ NULL, 4096, 2, 0, 0, 0, 10, 11} +}; + +enum edns_mask { + KNOT_EDNS_DO_MASK = (uint16_t)0x8000 +}; + +/* Creates actual knot_opt_rr_t variable from test_edns_t variable */ +static knot_opt_rr_t *opt_rr_from_test_edns(test_edns_t *test_edns) +{ + knot_opt_rr_t *ret = knot_edns_new(); + + CHECK_ALLOC_LOG(ret, NULL); + + ret->flags = test_edns->flags; + ret->ext_rcode = test_edns->ext_rcode; + ret->payload = test_edns->payload; + ret->version = test_edns->version; + + for (int i = 0; i < test_edns->option_count; i++) { + if (knot_edns_add_option(ret, test_edns->options[i].code, + test_edns->options[i].length, + test_edns->options[i].data) != 0) { + knot_edns_free(&ret); + return NULL; + } + } + + return ret; +} + +/* simple wire compare - 0 if same, 1 otherwise */ +static int edns_compare_wires(uint8_t *wire1, + uint8_t *wire2, + uint16_t length) +{ + for (uint i = 0; i < length; i++) { + if (wire1[i] != wire2[i]) { + return 1; + } + } + + return 0; +} + +static int check_edns(const knot_opt_rr_t *edns, + const test_edns_t *test_edns) +{ + if (edns->option_count != test_edns->option_count) { + diag("Option count is wrong"); + return -1; + } + + for (int i = 0; i < edns->option_count; i++) { + /* check options */ + if (edns->options[i].code != test_edns->options[i].code) { + diag("Code in options is wrong"); + return -1; + } + + if (edns->options[i].length != test_edns->options[i].length) { + diag("Length in options is wrong"); + return -1; + } + + if (edns_compare_wires(edns->options[i].data, + test_edns->options[i].data, + edns->options[i].length) != 0) { + diag("Data in options are wrong"); + return -1; + } + } + + if (edns->version != test_edns->version) { + diag("Version is wrong"); + return -1; + } + + if (edns->flags != test_edns->flags) { + diag("Flags are wrong"); + return -1; + } + + if (edns->size != test_edns->size) { + diag("Size is wrong"); + return -1; + } + + return 0; +} + +static int test_edns_get_payload(const knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + if (knot_edns_get_payload(edns) != + test_edns->payload) { + return 0; + } else { + return 1; + } +} + +static int test_edns_get_ext_rcode(const knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + if (knot_edns_get_ext_rcode(edns) != + test_edns->ext_rcode) { + return 0; + } else { + return 1; + } +} + +static int test_edns_get_flags(const knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + if (knot_edns_get_flags(edns) != + test_edns->flags) { + return 0; + } else { + return 1; + } +} + +static int test_edns_get_version(const knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + if (knot_edns_get_version(edns) != + test_edns->version) { + return 0; + } else { + return 1; + } +} + +static int test_edns_do(const knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + if (knot_edns_do(edns) != + (test_edns->flags & KNOT_EDNS_DO_MASK)) { + return 0; + } else { + return 1; + } +} + +static int test_edns_size(knot_opt_rr_t *edns, test_edns_t *test_edns) +{ + if (knot_edns_size(edns) != + test_edns->size) { + return 0; + } else { + return 1; + } +} + +static int test_edns_set_payload(knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + knot_edns_set_payload(edns, test_edns->payload); + + if (edns->payload != + test_edns->payload) { + return 0; + } else { + return 1; + } +} + +static int test_edns_set_ext_rcode(knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + knot_edns_set_ext_rcode(edns, test_edns->ext_rcode); + if (edns->ext_rcode != + test_edns->ext_rcode) { + return 0; + } else { + return 1; + } +} + +static int test_edns_set_version(knot_opt_rr_t *edns, + test_edns_t *test_edns) +{ + knot_edns_set_version(edns, + test_edns->version); + + if (edns->version != + test_edns->version) { + return 0; + } else { + return 1; + } +} + +static int test_edns_set_do(knot_opt_rr_t *edns) +{ + knot_edns_set_do(edns); + + if (!knot_edns_do(edns)) { + return 0; + } else { + return 1; + } +} + +static int test_edns_getters(uint type) +{ + int errors = 0; + for (int i = 0; i < TEST_EDNS; i++) { + knot_opt_rr_t *edns = + opt_rr_from_test_edns(&(test_edns_data[i])); + if (edns == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + switch(type) { + case 0: + if (test_edns_get_payload(edns, + &test_edns_data[i]) != 1) { + diag("Got wrong payload!"); + errors++; + } + break; + case 1: + if (test_edns_get_ext_rcode(edns, + &test_edns_data[i]) != 1) { + diag("Got wrong extended RCODE!"); + errors++; + } + break; + case 2: + if (test_edns_get_flags(edns, + &test_edns_data[i]) != 1) { + diag("Got wrong flags!"); + + errors++; + } + break; + case 3: + if (test_edns_get_version(edns, + &test_edns_data[i]) != 1) { + diag("Got wrong version!"); + errors++; + } + break; + case 4: + if (test_edns_do(edns, + &test_edns_data[i]) != 1) { + diag("Got wrong DO bit!"); + errors++; + } + break; + case 5: + if (test_edns_size(edns, + &test_edns_data[i]) != 1) { + diag("Got wrong size!"); + errors++; + } + break; + default: + diag("Unknown option"); + errors++; + } /* switch */ + + knot_edns_free(&edns); + } + + return (errors == 0); +} + +static int test_edns_setters(uint type) +{ + int errors = 0; + for (int i = 0; i < TEST_EDNS; i++) { + knot_opt_rr_t *edns = + opt_rr_from_test_edns(&(test_edns_data[i])); + if (edns == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + switch(type) { + case 0: + if (test_edns_set_payload(edns, + &test_edns_data[i]) != 1) { + diag("Set wrong payload!"); + errors++; + } + break; + case 1: + if (test_edns_set_ext_rcode(edns, + &test_edns_data[i]) != 1) { + diag("Set wrong ext_rcode"); + errors++; + } + break; + case 2: + if (test_edns_set_version(edns, + &test_edns_data[i]) != 1) { + diag("Set wrong version!"); + errors++; + } + break; + case 3: + if (test_edns_set_do(edns) != 1) { + diag("Set wrong DO bit!"); + errors++; + } + break; + default: + diag("Unknown option"); + errors++; + } /* switch */ + + knot_edns_free(&edns); + } + + return (errors == 0); +} + +static int test_edns_wire() +{ + /* + * Tests to_wire and from_wire in one test. + */ + for (int i = 0; i < TEST_EDNS; i++) { + /* Creates instance from test_edns_t. */ + knot_opt_rr_t *edns = + opt_rr_from_test_edns(&(test_edns_data[i])); + if (edns == NULL) { + ERR_ALLOC_FAILED; + return -1; + } + + uint8_t *wire = NULL; + wire = malloc(sizeof(uint8_t) * edns->size); + CHECK_ALLOC_LOG(wire, 0); + + /* Converts EDNS to wire. */ + short wire_size = knot_edns_to_wire(edns, wire, 100); + + if (wire_size == -1) { + diag("Could not create EDNS wire"); + return 0; + } + + knot_opt_rr_t *edns_from_wire = knot_edns_new(); + if (edns == NULL) { + return 0; + } + + /* TODO use some constant */ + /* Creates new EDNS from wire */ + if (knot_edns_new_from_wire(edns_from_wire, + wire, + 100) <= 0) { + diag("Could not create from wire"); + return 0; + } + + /* Checks whether EDNS created from wire is the same */ + if (check_edns(edns_from_wire, + &(test_edns_data[i])) != 0) { + diag("EDNS created from wire is different from the " + "original one"); + } + + free(wire); + knot_edns_free(&edns_from_wire); + knot_edns_free(&edns); + } + return 1; +} + +static int test_edns_add_option() +{ + /* + * Create empty EDNS and add options one by one, testing their presence. + */ + for (int i = 0; i < TEST_EDNS; i++) { + knot_opt_rr_t *edns = knot_edns_new(); + assert(edns->option_count == 0); + + if (edns == NULL) { + ERR_ALLOC_FAILED; + return 0; + } + + for (int j = 0; j < test_edns_data[i].option_count; j++) { + if (knot_edns_add_option(edns, + test_edns_data[i].options[j].code, + test_edns_data[i].options[j].length, + test_edns_data[i].options[j]. + data) != 0) { + diag("Could not add option"); + return 0; + } + + if (edns->options[j].code != + test_edns_data[i].options[j].code) { + diag("Option code wrongly added!"); + return 0; + } + + if (edns->options[j].length != + test_edns_data[i].options[j].length) { + diag("Option length wrongly added!"); + return 0; + } + + if (edns_compare_wires(edns->options[j].data, + test_edns_data[i]. + options[j].data, + edns->options[j].length) != 0) { + diag("Option wire wrongly added!"); + return 0; + } + } + knot_edns_free(&edns); + } + return 1; +} + +static int test_edns_has_option() +{ + /* + * Create empty EDNS and add options one by one, testing their presence + */ + for (int i = 0; i < TEST_EDNS; i++) { + knot_opt_rr_t *edns = knot_edns_new(); + assert(edns->option_count == 0); + + if (edns == NULL) { + ERR_ALLOC_FAILED; + return 0; + } + + for (int j = 0; j < test_edns_data[i].option_count; j++) { + if (knot_edns_add_option(edns, + test_edns_data[i].options[j].code, + test_edns_data[i].options[j].length, + test_edns_data[i].options[j]. + data) != 0) { + diag("Could not add option"); + return 0; + } + + if (knot_edns_has_option(edns, + test_edns_data[i].options[j].code) != 1) { + diag("Option not found!"); + return 0; + } + } + knot_edns_free(&edns); + } + return 1; +} + +static const int KNOT_EDNS_TESTS_COUNT = 12; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_edns_tests_count(int argc, char *argv[]) +{ + return KNOT_EDNS_TESTS_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_edns_tests_run(int argc, char *argv[]) +{ + int res = 0; + int res_final = 1; + + res = test_edns_getters(0); + ok(res, "ends: get payload"); + res_final *= res; + + res = test_edns_getters(1); + ok(res, "ends: get extenden RCODE"); + res_final *= res; + + res = test_edns_getters(2); + ok(res, "ends: get flags"); + res_final *= res; + + res = test_edns_getters(3); + ok(res, "ends: get version"); + res_final *= res; + + res = test_edns_getters(4); + ok(res, "ends: do"); + res_final *= res; + + res = test_edns_getters(5); + ok(res, "ends: size"); + res_final *= res; + + res = test_edns_setters(0); + ok(res, "ends: set payload"); + res_final *= res; + + res = test_edns_setters(1); + ok(res, "ends: set extended RCODE"); + res_final *= res; + + res = test_edns_setters(2); + ok(res, "ends: set version"); + res_final *= res; + + res = test_edns_setters(3); + ok(res, "ends: set DO"); + res_final *= res; + + res = test_edns_add_option(); + ok(res, "ends: add option"); + res_final *= res; + + res = test_edns_has_option(); + ok(res, "ends: has option"); + res_final *= res; + + res = test_edns_wire(); + ok(res, "ends: to_wire and from_wire"); + res_final *= res; + + return res_final; +} diff --git a/src/tests/libknot/libknot/edns_tests.h b/src/tests/libknot/libknot/edns_tests.h new file mode 100644 index 0000000..4553234 --- /dev/null +++ b/src/tests/libknot/libknot/edns_tests.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file edns_tests.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * Contains unit tests for ENDS API + * + * Contains tests for: + * - ENDS API + */ +#ifndef _KNOTD__EDNS_TESTS_H_ +#define _KNOTD__EDNS_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api edns_tests_api; + +#endif /* _KNOTD__EDNS_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/node_tests.c b/src/tests/libknot/libknot/node_tests.c new file mode 100644 index 0000000..f04a202 --- /dev/null +++ b/src/tests/libknot/libknot/node_tests.c @@ -0,0 +1,344 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "tests/libknot/libknot/node_tests.h" +#include "libknot/dname.h" +#include "libknot/zone/node.h" +#include "libknot/util/descriptor.h" + +static int knot_node_tests_count(int argc, char *argv[]); +static int knot_node_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api node_tests_api = { + "DNS library - node", //! Unit name + &knot_node_tests_count, //! Count scheduled tests + &knot_node_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +// C will not accept const int in other const definition +enum { TEST_NODES = 2, RRSETS = 5}; + +struct test_node { + knot_dname_t owner; + knot_node_t *parent; + uint size; +}; + +static knot_dname_t test_dnames[TEST_NODES] = { + {{}, (uint8_t *)"\3www\7example\3com", 17}, + {{}, (uint8_t *)"\3www\7example\3com", 17} +}; + +static struct test_node test_nodes[TEST_NODES] = { + {{{}, (uint8_t *)"\3com", 4}, (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\3www\7example\3com", 17}, (knot_node_t *)NULL} +}; + +static knot_rrset_t rrsets[RRSETS] = { + {&test_dnames[0], 1, 1, 3600, NULL, NULL}, + {&test_dnames[1], 2, 1, 3600, NULL, NULL}, + {&test_dnames[1], 7, 1, 3600, NULL, NULL}, + {&test_dnames[1], 3, 1, 3600, NULL, NULL}, + {&test_dnames[1], 9, 1, 3600, NULL, NULL} +}; + +static int test_node_create() +{ + /* Tests creation of node by comparing with test_node struct */ + knot_node_t *tmp; + int errors = 0; + for (int i = 0; i < TEST_NODES && !errors; i++) { + tmp = knot_node_new(&test_nodes[i].owner, + test_nodes[i].parent, 0); + if (tmp == NULL || + tmp->owner != &test_nodes[i].owner || + tmp->parent != test_nodes[i].parent || + tmp->rrset_tree == NULL) { + errors++; + diag("Failed to create node structure"); + } + knot_node_free(&tmp, 0, 0); + } + return (errors == 0); +} + +static int test_node_add_rrset() +{ + knot_node_t *tmp; + knot_rrset_t *rrset; + int errors = 0; + for (int i = 0; i < TEST_NODES && !errors; i++) { + /* create node from test_node structure */ + tmp = knot_node_new(&test_nodes[i].owner, + test_nodes[i].parent, 0); + rrset = &rrsets[i]; + if (knot_node_add_rrset(tmp, rrset, 0) < 0) { + errors++; + diag("Failed to insert rrset into node"); + } + + /* check if rrset is really there */ + + const knot_rrset_t *rrset_from_node = NULL; + if ((rrset_from_node = + knot_node_rrset(tmp, rrset->type)) == NULL) { + errors++; + diag("Inserted rrset could not be found"); + continue; + } + + /* compare rrset from node with original rrset */ + + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + + int cmp = 0; + + if ((rrset_from_node->rdata == NULL) && + (rrset->rdata == NULL)) { + cmp = 0; + } else if ((rrset_from_node->rdata != NULL) && + (rrset->rdata != NULL)) { + cmp = knot_rdata_compare(rrset_from_node->rdata, + rrset->rdata, + desc->wireformat); + } else { /* one is not NULL and other is -> error */ + cmp = 1; + } + + if (!((rrset_from_node->type == rrset->type) && + (rrset_from_node->rclass == rrset->rclass) && + (rrset_from_node->ttl == rrset->ttl) && + (rrset_from_node->rrsigs == rrset->rrsigs) && + (cmp == 0))) { + errors++; + diag("Values in found rrset are wrong"); + } + + knot_node_free(&tmp, 0, 0); + } + + return (errors == 0); +} + +static int test_node_get_rrset() +{ + knot_node_t *tmp; + knot_rrset_t *rrset; + int errors = 0; + + knot_node_t *nodes[TEST_NODES]; + + for (int i = 0; i < TEST_NODES && !errors; i++) { + tmp = knot_node_new(&test_nodes[i].owner, + test_nodes[i].parent, 0); + nodes[i] = tmp; + for (int j = 0; j < RRSETS; j++) { + knot_node_add_rrset(tmp, &rrsets[j], 0); + } + } + + for (int i = 0; i < TEST_NODES && !errors; i++) { + for (int j = 0; j < RRSETS; j++) { + rrset = &rrsets[j]; + if (knot_node_rrset(nodes[i], rrset->type) + != rrset) { + errors++; + diag("Failed to get proper rrset from node"); + } + } + knot_node_free(&nodes[i], 0, 0); + } + + return (errors == 0); +} + +static int test_node_get_parent() +{ + knot_node_t *tmp; + knot_rrset_t *rrset; + int errors = 0; + + knot_node_t *nodes[TEST_NODES]; + + for (int i = 0; i < TEST_NODES && !errors; i++) { + tmp = knot_node_new(&test_nodes[i].owner, + test_nodes[i].parent, 0); + nodes[i] = tmp; + rrset = &rrsets[i]; + knot_node_add_rrset(tmp, rrset, 0); + } + + for (int i = 0; i < TEST_NODES && !errors; i++) { + rrset = &rrsets[i]; + if (knot_node_parent(nodes[i], 0) != test_nodes[i].parent) { + errors++; + diag("Failed to get proper parent from node"); + } + knot_node_free(&nodes[i], 0, 0); + } + return (errors == 0); +} + +static int test_node_sorting() +{ + knot_node_t *tmp; + knot_rrset_t *rrset; + int errors = 0; + + tmp = knot_node_new(&test_nodes[0].owner, test_nodes[0].parent, 0); + + /* Will add rrsets to node. */ + + for (int i = 0; i < RRSETS && !errors; i++) { + rrset = &rrsets[i]; + knot_node_add_rrset(tmp, rrset, 0); + } + +// const skip_node_t *node = skip_first(tmp->rrsets); + +// int last = *((uint16_t *)node->key); + +// /* TODO there is now an API function knot_node_rrsets ... */ + +// /* Iterates through skip list and checks, whether it is sorted. */ + +// while ((node = skip_next(node)) != NULL) { +// if (last > *((uint16_t *)node->key)) { +// errors++; +// diag("RRset sorting error"); +// } +// last = *((uint16_t *)node->key); +// } + + knot_node_free(&tmp, 0, 0); + return (errors == 0); +} + +static int test_node_delete() +{ + int errors = 0; + + knot_node_t *tmp_node; + + for (int i = 0; i < TEST_NODES; i++) { + tmp_node = knot_node_new(&test_nodes[i].owner, + test_nodes[i].parent, 0); + + knot_node_free(&tmp_node, 0, 0); + + errors += (tmp_node != NULL); + } + + return (errors == 0); +} + +static int test_node_set_parent() +{ + knot_node_t *tmp_parent = knot_node_new(NULL, NULL, 0); + int errors = 0; + + knot_node_t *tmp_node; + + for (int i = 0; i < TEST_NODES; i++) { + tmp_node = knot_node_new(&test_nodes[i].owner, + test_nodes[i].parent, 0); + + knot_node_set_parent(tmp_node, tmp_parent); + + if (tmp_node->parent != tmp_node->parent) { + diag("Parent node is wrongly set."); + errors++; + } + knot_node_free(&tmp_node, 0, 0); + } + knot_node_free(&tmp_parent, 0, 0); + return (errors == 0); +} + +static int test_node_free_rrsets() +{ + int errors = 0; + + knot_node_t *tmp_node; + + for (int i = 0; i < TEST_NODES; i++) { + tmp_node = knot_node_new(&test_nodes[i].owner, + test_nodes[i].parent, 0); + + knot_node_free_rrsets(tmp_node, 0); + +// errors += (tmp_node->rrsets != NULL); + + knot_node_free(&tmp_node, 0, 0); + } + return (errors == 0); +} + +static const int KNOT_NODE_TEST_COUNT = 8; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_node_tests_count(int argc, char *argv[]) +{ + return KNOT_NODE_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_node_tests_run(int argc, char *argv[]) +{ + int res = 0, + res_final = 1; + + res = test_node_create(); + ok(res, "node: create"); + res_final *= res; + + skip(!res, 6) + + ok((res = test_node_add_rrset()), "node: add"); + res_final *= res; + + ok((res = test_node_get_rrset()), "node: get"); + res_final *= res; + + ok((res = test_node_get_parent()), "node: get parent"); + res_final *= res; + + ok((res = test_node_set_parent()), "node: set parent"); + res_final *= res; + + ok((res = test_node_sorting()), "node: sort"); + res_final *= res; + + ok((res = test_node_free_rrsets()), "node: free rrsets"); + res_final *= res; + + endskip; + + ok((res = test_node_delete()), "node: delete"); + //res_final *= res; + + return res_final; +} diff --git a/src/tests/libknot/libknot/node_tests.h b/src/tests/libknot/libknot/node_tests.h new file mode 100644 index 0000000..a90179f --- /dev/null +++ b/src/tests/libknot/libknot/node_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_NODE_TESTS_H_ +#define _KNOTD_NODE_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api node_tests_api; + +#endif /* _KNOTD_NODE_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/nsec3_tests.c b/src/tests/libknot/libknot/nsec3_tests.c new file mode 100644 index 0000000..7b95549 --- /dev/null +++ b/src/tests/libknot/libknot/nsec3_tests.c @@ -0,0 +1,252 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* blame: jan.kadlec@nic.cz */ + +#include <assert.h> + +#include "libknot/common.h" +#include "libknot/util/error.h" +#include "libknot/nsec3.h" +#include "libknot/util/utils.h" +#include "common/base32hex.h" +#include "nsec3_tests.h" + +#ifdef TEST_WITH_LDNS +#include "ldns/ldns.h" +#endif + +static int knot_nsec3_tests_count(int argc, char *argv[]); +static int knot_nsec3_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api nsec3_tests_api = { + "NSEC3", //! Unit name + &knot_nsec3_tests_count, //! Count scheduled tests + &knot_nsec3_tests_run //! Run scheduled tests +}; + +extern int compare_wires_simple(uint8_t *w1, uint8_t *w2, uint count); + +static int test_nsec3_params_from_wire() +{ + /* Create sample NSEC3PARAM rdata */ + knot_rdata_item_t items[4]; + knot_rdata_t *rdata = knot_rdata_new(); + rdata->items = items; + rdata->count = 4; + knot_rdata_item_set_raw_data(rdata, 0, (uint16_t *)"\x1\x0\x1"); + knot_rdata_item_set_raw_data(rdata, 1, (uint16_t *)"\x1\x0\x0"); + knot_rdata_item_set_raw_data(rdata, 2, (uint16_t *)"\x2\x0\x0\x64"); + knot_rdata_item_set_raw_data(rdata, 3, + (uint16_t *)"\xF\x0\xE\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF"); + + knot_rrset_t *rrset = + knot_rrset_new(knot_dname_new_from_str("cz.", + strlen("cz."), NULL), + KNOT_RRTYPE_NSEC3PARAM, + KNOT_CLASS_IN, + 3600); + assert(rrset); + int ret = knot_rrset_add_rdata(rrset, rdata); + assert(ret == KNOT_EOK); + + knot_nsec3_params_t nsec3_test_params; + + int errors = 0; + int lived = 0; + lives_ok({ + /* Create special variable for this block. */ + if (knot_nsec3_params_from_wire(NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + + lived = 0; + if (knot_nsec3_params_from_wire(&nsec3_test_params, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + + lived = 0; + if (knot_nsec3_params_from_wire(NULL, rrset) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + + }, "nsec3 params from wire NULL tests"); + errors += lived != 1; + + if (knot_nsec3_params_from_wire(&nsec3_test_params, + rrset) != KNOT_EOK) { + diag("Could not convert nsec3 params to wire!"); + return 0; + } + + if (nsec3_test_params.algorithm != 1) { + diag("Algorithm error"); + errors++; + } + + if (nsec3_test_params.flags != 0) { + diag("Flags error %d", nsec3_test_params.flags); + errors++; + } + + if (nsec3_test_params.iterations != 100) { + diag("Iterations error %d", nsec3_test_params.iterations); + errors++; + } + printf("salt length: %d\n", nsec3_test_params.salt_length); + + if (nsec3_test_params.salt_length != 14) { + diag("Salt length error %d", nsec3_test_params.salt_length); + return 0; + } + + if (compare_wires_simple((uint8_t *)nsec3_test_params.salt, + (uint8_t *)"\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF", + 14) != 0) { + diag("Salt wire error"); + errors++; + } + + knot_rrset_free(&rrset); + return (errors == 0); +} + +static int test_nsec3_sha1() +{ + int errors = 0; + int lived = 0; + + knot_nsec3_params_t nsec3_test_params; + + lives_ok({ + if (knot_nsec3_sha1(NULL, NULL, 1, NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_nsec3_sha1(&nsec3_test_params, + NULL, 1, NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + uint8_t data[20]; + lived = 1; + lived = 0; + if (knot_nsec3_sha1(&nsec3_test_params, + data, 20, NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + uint8_t *digest = NULL; + lived = 1; + lived = 0; + if (knot_nsec3_sha1(&nsec3_test_params, + data, 20, &digest, NULL) != + KNOT_EBADARG) { + errors++; + } +// size_t size = 0; +// lived = 1; +// lived = 0; +// if (knot_nsec3_sha1(&nsec3_test_params, +// data, 20, &digest, &size) != +// KNOT_EBADARG) { +// errors++; +// } + lived = 1; + }, "NSEC3: nsec3 sha1 NULL tests"); + if (errors) { + diag("Does not return KNOT_EBADARG after " + "execution with wrong arguments!"); + } + + errors += lived != 1; + + uint8_t *digest = NULL; + size_t digest_size = 0; + if (knot_nsec3_sha1(&nsec3_test_params, + (uint8_t *)"\2ns\3nic\2cz", + strlen("\2ns\3nic\2cz"), &digest, + &digest_size) != KNOT_EOK) { + diag("Could not hash name!"); + return 0; + } + +#ifdef TEST_WITH_LDNS + ldns_rdf *name = ldns_dname_new_frm_str("ns.nic.cz."); + assert(name); + ldns_rdf *hashed_name = ldns_nsec3_hash_name(name, + nsec3_test_params.algorithm, + nsec3_test_params.iterations, + nsec3_test_params.salt_length, + nsec3_test_params.salt); + assert(hashed_name); +// knot_dname_t *dname_from_ldns = +// knot_dname_new_from_wire(ldns_rdf_data(hashed_name), +// ldns_rdf_size(hashed_name), +// NULL); + + char *name_b32 = NULL; + size_t size_b32 = base32hex_encode_alloc((char *)digest, digest_size, + &name_b32); + +// hex_print(name_b32, size_b32); +// hex_print(ldns_rdf_data(hashed_name), ldns_rdf_size(hashed_name)); + if (ldns_rdf_size(hashed_name) != size_b32) { + diag("Wrong hashed name length! Should be: %d is: %d", + ldns_rdf_size(hashed_name), size_b32); + return 0; + } + + if (compare_wires_simple(ldns_rdf_data(hashed_name), + (uint8_t *)name_b32, size_b32) != 0) { + diag("Wrong hashed name wire!"); + errors++; + } +#endif + +#ifndef TEST_WITH_LDNS + diag("Warning: without ldns this test is only partial!"); +#endif + return (errors == 0); +} + +static const int KNOT_NSEC3_TESTS_COUNT = 2; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_nsec3_tests_count(int argc, char *argv[]) +{ + return KNOT_NSEC3_TESTS_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_nsec3_tests_run(int argc, char *argv[]) +{ + ok(test_nsec3_params_from_wire(), "nsec3: params from wire"); + ok(test_nsec3_sha1(), "nsec3: sha1"); + return 1; +} diff --git a/src/tests/libknot/libknot/nsec3_tests.h b/src/tests/libknot/libknot/nsec3_tests.h new file mode 100644 index 0000000..10e7ed9 --- /dev/null +++ b/src/tests/libknot/libknot/nsec3_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_NSEC3_TESTS_H_ +#define _KNOTD_NSEC3_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api nsec3_tests_api; + +#endif /* _KNOTD_NSEC3_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/packet_tests.c b/src/tests/libknot/libknot/packet_tests.c new file mode 100644 index 0000000..185504f --- /dev/null +++ b/src/tests/libknot/libknot/packet_tests.c @@ -0,0 +1,430 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* blame: jan.kadlec@nic.cz */ + +#include <assert.h> +#include <stdint.h> + +#include "packet_tests.h" +#include "libknot/util/error.h" +#include "libknot/packet/packet.h" +#include "libknot/util/wire.h" +/* *test_t structures */ +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" + +static int packet_tests_count(int argc, char *argv[]); +static int packet_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api packet_tests_api = { + "packet", //! Unit name + &packet_tests_count, //! Count scheduled tests + &packet_tests_run //! Run scheduled tests +}; + +static int test_packet_new() +{ + int errors = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_NONE); + if (packet == NULL) { + diag("Could not create packet using prealloc_node constant!"); + errors++; + } + knot_packet_free(&packet); + + packet = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + if (packet == NULL) { + diag("Could not create packet using prealloc_query constant!"); + errors++; + } + knot_packet_free(&packet); + + packet = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + if (packet == NULL) { + diag("Could not create packet using prealloc_resp constant!"); + errors++; + } + knot_packet_free(&packet); + + /*!< \todo Should it create packet using any size? */ + + return (errors == 0); +} + +static int test_packet_parse_from_wire() +{ + int errors = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + + int tmp = 0; + lives_ok({ + if (knot_packet_parse_from_wire(NULL, NULL, 0, 0) != + KNOT_EBADARG) { + diag("Trying to parse NULL packet with NULL wire " + "did not return KNOT_EBADARG!"); + errors++; + } + tmp = 1; + tmp = 0; + if (knot_packet_parse_from_wire(packet, NULL, 0, 0) != + KNOT_EBADARG) { + diag("Trying to parse with NULL wire " + "did not return KNOT_EBADARG!"); + errors++; + } + tmp = 1; + tmp = 0; + if (knot_packet_parse_from_wire(packet, (uint8_t *)0xbeef, + 0, 0) != + KNOT_EFEWDATA) { + diag("Trying to parse 0 lengt" + "did not return KNOT_EOK!"); + errors++; + } + tmp = 1; + }, "packet: parse from wire NULL tests."); + errors += tmp != 1; + + knot_packet_free(&packet); + + return (errors == 0); +} + +static int test_packet_parse_next_rr_answer() +{ + int errors = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + + int tmp = 0; + lives_ok({ + int ret = 0; + if (knot_packet_parse_next_rr_answer(NULL, NULL) != + KNOT_EBADARG) { + diag("Trying to parse next RR answer with " + "NULL packet with and NULL RRSet " + "did not return KNOT_EBADARG!"); + errors++; + } + tmp = 1; + tmp = 0; + if ((ret = knot_packet_parse_next_rr_answer(packet, + NULL)) != + KNOT_EBADARG) { + diag("Trying to parse next RR with NULL RRSet pointer " + "did not return KNOT_EBADARG! Got %d.", + ret); + errors++; + } + tmp = 1; +// knot_rrset_t *rrset = (knot_rrset_t *)0xaaaa; +// tmp = 0; +// if (knot_packet_parse_next_rr_answer(packet, +// &rrset) != +// KNOT_EBADARG) { +// diag("Trying to parse next RR answer with rrset pointer" +// " not pointing to NULL did not " +// "return KNOT_EBADARG!"); +// errors++; +// } +// tmp = 1; + }, "packet: parse next rr answer NULL tests."); + errors += tmp != 1; + + knot_packet_free(&packet); + + return (errors == 0); +} + +static int test_packet_parse_rest() +{ + int res = 0; + lives_ok({res = knot_packet_parse_rest(NULL);}, + "packet: parse rest NULL test"); + + if (res != KNOT_EBADARG) { + diag("parse rest NULL did not return KNOT_EBADARG.\n"); + return 1; + } + + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_NONE); + assert(packet); + + todo(); + lives_ok({res = knot_packet_parse_rest(packet);}, + "packet: parser rest empty packet"); + endtodo; + + knot_packet_free(&packet); + + return 1; +} + + +static int test_packet_set_max_size() +{ + int errors = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_NONE); + assert(packet); + + int lived = 0; + + lives_ok({ + lived = 0; + if (knot_packet_set_max_size(NULL, 1) != KNOT_EBADARG) { + diag("Calling packet_set_max() with NULL packet " + "did not return KNOT_EBADARG"); + errors++; + } + lived = 1; + }, "packet: set max size NULL test"); + + errors += lived != 1; + + if (knot_packet_set_max_size(packet, 0) != KNOT_EBADARG) { + diag("Calling packet_set_max() with size eqeal to 0 did not " + "return KNOT_EBADARG"); + errors++; + } + + if (knot_packet_set_max_size(packet, 10) != KNOT_EOK) { + diag("Calling packet_set_max() with valid arguments did not " + "return KNOT_EOK"); + errors++; + } + + knot_packet_free(&packet); + + return (errors == 0); +} + +static int test_packet_add_tmp_rrset() +{ + int errors = 0; + int lived = 0; + + /* knot_packet_add_tmp_rrset only works with pointers. */ + knot_rrset_t *rrset = (knot_rrset_t *)0xabcdef; + + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + + lives_ok({ + if (knot_packet_add_tmp_rrset(NULL, rrset) != + KNOT_EBADARG) { + diag("Trying to add to NULL packet did not return " + "KNOT_EBADARG!"); + errors++; + } + lived = 1; + + lived = 0; + if (knot_packet_add_tmp_rrset(packet, NULL) != + KNOT_EBADARG) { + diag("Trying to add NULL rrset did not return " + "KNOT_EBADARG!"); + errors++; + } + lived = 1; + + lived = 0; + if (knot_packet_add_tmp_rrset(NULL, NULL) != + KNOT_EBADARG) { + diag("Trying to add NULL rrset to NULL packet " + "did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + }, "packet: add tmp rrset NULL test"); + errors += lived != 1; + + if (knot_packet_add_tmp_rrset(packet, rrset) != KNOT_EOK) { + diag("Could not add valid RRSet to packet!"); + errors++; + } + + /* Not freeing because RRSet is fake. */ +// knot_packet_free(&packet); + + free(packet->wireformat); + free(packet); + + return (errors == 0); +} + +//static int test_packet_contains() +//{ +// int errors = 0; +// int lives = 0; + +// knot_packet_t *packet = +// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); +// assert(packet); + +// lives_ok({ +// if (knot_packet_contains(packet, NULL, +// KNOT_RRSET_COMPARE_PTR) != +// KNOT_EBADARG{ +// diag(); +// } +// }, "packet: contains NULL tests); + +// knot_packet_contains() + +//} + +static int test_packet_header_to_wire() +{ + int errors = 0; + int lived = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + size_t size; + + lives_ok({ + knot_packet_header_to_wire(NULL, NULL, NULL); + lived = 1; + lived = 0; + knot_packet_header_to_wire(&packet->header, NULL, &size); + lived = 1; + }, "packet: header to wire NULL tests"); + errors += lived != 1; + + knot_packet_free(&packet); + return (errors == 0); +} + +static int test_packet_question_to_wire() +{ + int errors = 0 ; + int lived = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + + lives_ok({ + if (knot_packet_question_to_wire(NULL) != KNOT_EBADARG) { + diag("Calling packet_question_to_wire with " + "NULL pointer did not result to KNOT_EBADARG!"); + errors++; + } + lived = 1; + }, "packet: question to wire NULL tests"); + errors += lived != 1; + + packet->size = KNOT_WIRE_HEADER_SIZE + 1; + if (knot_packet_question_to_wire(packet) != KNOT_ERROR) { + diag("Calling packet_question_to_wire with oversized packet " + "did not return KNOT_ERROR!"); + errors++; + } + + knot_packet_free(&packet); + return (errors == 0); +} + +static int test_packet_edns_to_wire() +{ + int errors = 0 ; + int lived = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + + lives_ok({ + knot_packet_edns_to_wire(NULL); + lived = 1; + }, "packet: question to wire NULL tests"); + errors += lived != 1; + + knot_packet_free(&packet); + return (errors == 0); +} + +static int test_packet_to_wire() +{ + int errors = 0 ; + int lived = 0; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + + lives_ok({ + if (knot_packet_to_wire(NULL, NULL, NULL) != KNOT_EBADARG) { + diag("Calling packet_to_wire with " + "NULL pointers did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + size_t size; + lived = 0; + if (knot_packet_to_wire(packet, NULL, &size) != + KNOT_EBADARG) { + diag("Calling packet_to_wire with " + "NULL wire did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + uint8_t *wire = (uint8_t *)0xabcdef; + lived = 0; + if (knot_packet_to_wire(packet, &wire, &size) != + KNOT_EBADARG) { + diag("Calling packet_to_wire with " + "wire not pointing to NULL did not return" + " KNOT_EBADARG!"); + errors++; + } + lived = 1; + }, "packet: to wire NULL tests"); + errors += lived != 1; + + knot_packet_free(&packet); + return (errors == 0); +} + +static const uint KNOT_PACKET_TEST_COUNT = 21; + +static int packet_tests_count(int argc, char *argv[]) +{ + return KNOT_PACKET_TEST_COUNT; +} + +static int packet_tests_run(int argc, char *argv[]) +{ + int res = 0; + ok(res = test_packet_new(), "packet: new"); + skip(!res, 20); + ok(test_packet_parse_rest(), "packet: parse rest"); + ok(test_packet_parse_from_wire(), "packet: parse from wire"); + ok(test_packet_parse_next_rr_answer(), "packet: parse next rr answer"); + ok(test_packet_set_max_size(), "packet: set max size"); + ok(test_packet_add_tmp_rrset(), "packet: add tmp rrset"); + ok(test_packet_header_to_wire(), "packet: header to wire"); + ok(test_packet_question_to_wire(), "packet: header to wire"); + ok(test_packet_edns_to_wire(), "packet: header to wire"); + ok(test_packet_to_wire(), "packet: to wire"); +// ok(res = test_packet_contains(), "Packet: contains"); + endskip; + return 1; +} diff --git a/src/tests/libknot/libknot/packet_tests.h b/src/tests/libknot/libknot/packet_tests.h new file mode 100644 index 0000000..5a8ce03 --- /dev/null +++ b/src/tests/libknot/libknot/packet_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_PACKET_TESTS_H_ +#define _KNOTD_PACKET_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api packet_tests_api; + +#endif /* _KNOTD_PACKET_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/query_tests.c b/src/tests/libknot/libknot/query_tests.c new file mode 100644 index 0000000..1e4e081 --- /dev/null +++ b/src/tests/libknot/libknot/query_tests.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* blame: jan.kadlec@nic.cz */ + +#include <assert.h> +#include <stdint.h> + +#include "packet_tests.h" +#include "libknot/util/error.h" +#include "libknot/packet/packet.h" +#include "libknot/util/wire.h" +#include "libknot/packet/query.h" +/* *test_t structures */ +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" + +static int query_tests_count(int argc, char *argv[]); +static int query_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api query_tests_api = { + "query", //! Unit name + &query_tests_count, //! Count scheduled tests + &query_tests_run //! Run scheduled tests +}; + +static const uint KNOT_QUERY_TEST_COUNT = 1; + +static int query_tests_count(int argc, char *argv[]) +{ + return KNOT_QUERY_TEST_COUNT; +} + +static int test_query_init() +{ + int errors = 0; + int lived = 0; + knot_packet_t *query = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + assert(query); + lives_ok({ + if (knot_query_init(NULL) != KNOT_EBADARG) { + diag("Calling query_init with NULL query did " + "not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + }, "query: init NULL tests"); + errors += lived != 1; + + assert(knot_packet_set_max_size(query, 1024 * 10) == KNOT_EOK); + if (knot_query_init(query) != KNOT_EOK) { + diag("Calling query_init with valid query did not return " + "KNOT_EOK!"); + errors++; + } + + if (!knot_packet_is_query(query)) { + diag("QR flag was not set!"); + errors++; + } + + return (errors == 0); +} + +static int test_query_set_question() +{ + int errors = 0; + int lived = 0; + + knot_packet_t *query = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + assert(query); + assert(knot_packet_set_max_size(query, 1024 * 10) == KNOT_EOK); + knot_query_init(query); + + knot_rrset_t *rrset = + knot_rrset_new(knot_dname_new_from_str("a.ns.cz.", + strlen("a.ns.cz."), + NULL), + KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600); + assert(rrset); + + knot_question_t *question = malloc(sizeof(knot_question_t)); + assert(question); + question->qname = rrset->owner; + question->qtype = rrset->type; + question->qclass = rrset->rclass; + + lives_ok({ + if (knot_query_set_question(NULL, NULL) != KNOT_EBADARG) { + diag("Calling query_set_question with NULL"); + errors++; + } + lived = 1; + lived = 0; + if (knot_query_set_question(query, NULL) != KNOT_EBADARG) { + diag("Calling query_set_question with NULL"); + errors++; + } + lived = 1; + lived = 0; + if (knot_query_set_question(NULL, question) != KNOT_EBADARG) { + diag("Calling query_set_question with NULL"); + errors++; + } + lived = 1; + }, "query: set question NULL tests"); + errors += lived != 1; + + if (knot_query_set_question(query, question) != KNOT_EOK) { + diag("Calling query_set_question with valid arguments "); + errors++; + } + + if (query->question.qname != rrset->owner) { + diag("Qname was not set right!"); + errors++; + } + + if (query->question.qtype != rrset->type) { + diag("Qtype was not set right!"); + errors++; + } + + if (query->question.qclass != rrset->rclass) { + diag("Qclass was not set right!"); + errors++; + } + + if (query->header.qdcount != 1) { + diag("Qdcount was not set right!"); + errors++; + } + + knot_packet_free(&query); + knot_rrset_deep_free(&rrset, 1, 0, 0); + + return (errors == 0); +} + +static int query_tests_run(int argc, char *argv[]) +{ + ok(test_query_init(), "query: init"); + ok(test_query_set_question(), "query: set question"); + return 1; +} diff --git a/src/tests/libknot/libknot/query_tests.h b/src/tests/libknot/libknot/query_tests.h new file mode 100644 index 0000000..037ecab --- /dev/null +++ b/src/tests/libknot/libknot/query_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_QUERY_TESTS_H_ +#define _KNOTD_QUERY_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api query_tests_api; + +#endif /* _KNOTD_QUERY_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/rdata_tests.c b/src/tests/libknot/libknot/rdata_tests.c new file mode 100644 index 0000000..561686a --- /dev/null +++ b/src/tests/libknot/libknot/rdata_tests.c @@ -0,0 +1,954 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <assert.h> + +#include "tests/libknot/libknot/rdata_tests.h" +#include "libknot/common.h" +#include "libknot/rdata.h" +#include "libknot/dname.h" +#include "libknot/util/descriptor.h" +#include "libknot/util/utils.h" +#include "libknot/util/error.h" + +enum { TEST_DOMAINS_OK = 8 }; + +struct test_domain { + char *str; + char *wire; + uint size; + char *labels; + short label_count; +}; + +/*! \warning Do not change the order in those, if you want to test some other + * feature with new dname, add it at the end of these arrays. + */ +static const struct test_domain + test_domains_ok[TEST_DOMAINS_OK] = { + { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21, + "\x0\x4\x9\x10", 4 }, + { "some.test.domain.com.", "\4some\4test\6domain\3com", 22, + "\x0\x5\xA\x11", 4 }, + { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21, + "\x0\x4\x9\x10", 4 }, + { "some.test.domain.com.", "\4some\4test\6domain\3com", 22, + "\x0\x5\xA\x11", 4 }, + { "test.domain.com.", "\4test\6domain\3com", 17, + "\x0\x5\xC", 3 }, + { ".", "\0", 1, + "", 0 }, + { "foo.bar.net.", "\3foo\3bar\3net", 13, + "\x0\x4\x8", 3}, + { "bar.net.", "\3bar\3net", 9, + "\x0\x4", 2} +}; + + +static int knot_rdata_tests_count(int argc, char *argv[]); +static int knot_rdata_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api rdata_tests_api = { + "DNS library - rdata", //! Unit name + &knot_rdata_tests_count, //! Count scheduled tests + &knot_rdata_tests_run //! Run scheduled tests +}; + +/*----------------------------------------------------------------------------*/ +/* + * Unit implementation. + */ + +static uint16_t *RDATA_ITEM_PTR = (uint16_t *)0xDEADBEEF; + +enum { RDATA_ITEMS_COUNT = 7, TEST_RDATA_COUNT = 4 , RDATA_DNAMES_COUNT = 2 }; + +static knot_dname_t RDATA_DNAMES[RDATA_DNAMES_COUNT] = { + {{}, (uint8_t *)"\6abcdef\7example\3com", 20, + (uint8_t *)"\x0\x7\xF", 3}, + {{}, (uint8_t *)"\6abcdef\3foo\3com", 16, + (uint8_t *)"\x0\x7\xB", 3} +}; + +static knot_rdata_item_t TEST_RDATA_ITEMS[RDATA_ITEMS_COUNT] = { + {.dname = (knot_dname_t *)0xF00}, + {.raw_data = (uint16_t *)"some data"}, + {.raw_data = (uint16_t *)"other data"}, + {.raw_data = (uint16_t *)"123456"}, + {.raw_data = (uint16_t *)"654321"}, + {.dname = &RDATA_DNAMES[0]}, + {.dname = &RDATA_DNAMES[1]} +}; + +/* \note indices 0 to 3 should not be changed - used in (and only in) + * test_rdata_compare() - better than creating new struct just for this + */ +static knot_rdata_t test_rdata[TEST_RDATA_COUNT] = { + {&TEST_RDATA_ITEMS[3], 1, &test_rdata[1]}, + {&TEST_RDATA_ITEMS[4], 1, &test_rdata[2]}, + {&TEST_RDATA_ITEMS[5], 1, &test_rdata[3]}, + {&TEST_RDATA_ITEMS[6], 1, &test_rdata[4]}, +}; + +static knot_rdata_t TEST_RDATA = { + &TEST_RDATA_ITEMS[0], + 3, + &TEST_RDATA +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tests knot_rdata_new(). + * + * Creates new RDATA structure with no items and tests if there really are no + * items in it. + * + * \retval > 0 on success. + * \retval 0 otherwise. + */ +static int test_rdata_create() +{ + knot_rdata_t *rdata = knot_rdata_new(); + if (rdata == NULL) { + diag("RDATA structure not created!"); + return 0; + } + + if (knot_rdata_item(rdata, 0) != NULL) { + diag("Get item returned something else than NULL!"); + knot_rdata_free(&rdata); + return 0; + } + + knot_rdata_free(&rdata); + return 1; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tests knot_rdata_free(). + * + * \retval > 0 on success. + * \retval 0 otherwise. + */ +static int test_rdata_delete() +{ + // how to test this?? + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static void generate_rdata(uint8_t *data, int size) +{ + for (int i = 0; i < size; ++i) { + data[i] = rand() % 256; + } +} + +/*----------------------------------------------------------------------------*/ + +static int fill_rdata(uint8_t *data, int max_size, uint16_t rrtype, + knot_rdata_t *rdata) +{ + assert(rdata != NULL); + assert(data != NULL); + assert(max_size > 0); + + uint8_t *pos = data; + int used = 0; + int wire_size = 0; + + //note("Filling RRType %u", rrtype); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrtype); + + uint item_count = desc->length; + knot_rdata_item_t *items = + (knot_rdata_item_t *)malloc(item_count + * sizeof(knot_rdata_item_t)); + + for (int i = 0; i < item_count; ++i) { + uint size = 0; + int domain = 0; + knot_dname_t *dname = NULL; + int binary = 0; + int stored_size = 0; + + switch (desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: + dname = knot_dname_new_from_wire( + (uint8_t *)test_domains_ok[0].wire, + test_domains_ok[0].size, NULL); + assert(dname != NULL); + /* note("Created domain name: %s", + knot_dname_name(dname)); */ + //note("Domain name ptr: %p", dname); + domain = 1; + size = knot_dname_size(dname); + //note("Size of created domain name: %u", size); + assert(size < KNOT_MAX_RDATA_ITEM_SIZE); + // store size of the domain name + *(pos++) = size; + // copy the domain name + memcpy(pos, knot_dname_name(dname), size); + pos += size; + break; + default: + binary = 1; + size = rand() % KNOT_MAX_RDATA_ITEM_SIZE; + } + + if (binary) { + // Rewrite the actual 2 bytes in the data array + // with length. + // (this is a bit ugly, but does the work ;-) + knot_wire_write_u16(pos, size); + //*pos = size; + } + + //note("Filling %u bytes", size); + used += size; + assert(used < max_size); + + if (domain) { + items[i].dname = dname; + wire_size += knot_dname_size(dname); +/* note("Saved domain name ptr on index %d: %p", + i, items[i].dname); */ + } else { + free(dname); +// note("Saved raw data ptr on index %d: %p",i, pos); + items[i].raw_data = (uint16_t *)pos; + pos += size; + wire_size += size; + if (binary && !stored_size) { + wire_size -= 2; + } + } + } + + int res = knot_rdata_set_items(rdata, items, item_count); + if (res != 0) { + diag("knot_rdata_set_items() returned %d.", res); + free(items); + return -1; + } else { + free(items); + return wire_size; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks if all RDATA items in the given RDATA structure are correct. + * + * \return Number of errors encountered. Error is either if some RDATA item + * is not set (i.e. NULL) or if it has other than the expected value. + */ +static int check_rdata(const uint8_t *data, int max_size, uint16_t rrtype, + const knot_rdata_t *rdata) +{ + assert(rdata != NULL); + assert(data != NULL); + assert(max_size > 0); + + int errors = 0; + + const uint8_t *pos = data; + int used = 0; + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrtype); + uint item_count = desc->length; + //note("check_rdata(), RRType: %u", rrtype); + //note(" item count: %u", item_count); + + for (int i = 0; i < item_count; ++i) { + uint size = 0; + int domain = 0; + int binary = 0; + + //note(" item: %d", i); + + switch (desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: + //note(" domain name"); + domain = 1; + size = knot_dname_size(knot_rdata_item( + rdata, i)->dname); + break; + default: + size = + knot_wire_read_u16((uint8_t *) + (knot_rdata_item( + rdata, i)->raw_data)); + } + + assert(size > 0); + //note("Size: %u", size); + used += size; + assert(used < max_size); + + //note(" item size: %u", size); + + if (domain) { + /*note("Domain name ptr: %p", + knot_rdata_get_item(rdata, i)->dname);*/ + // check dname size + if (*pos != size) { + diag("Domain name stored in %d-th" + "RDATA has wrong size: %d" + " (should be %d)", size, *pos); + ++errors; + } else if (strncmp((char *)knot_dname_name( + knot_rdata_item(rdata, i)->dname), + (char *)(pos + 1), *pos) != 0) { + diag("Domain name stored in %d-th" + "RDATA item is wrong: %s (" + "should be %.*s)", i, + knot_dname_name(knot_rdata_item( + rdata, i)->dname), + *pos, (char *)(pos + 1)); + ++errors; + } + + pos += *pos + 1; + + continue; + } + + if (binary && + size != + knot_wire_read_u16( + (uint8_t *)(knot_rdata_item(rdata, i)->raw_data))) { + diag("Size of stored binary data is wrong:" + " %u (should be %u)", + knot_rdata_item(rdata, i)->raw_data[0] + 1, + size); + ++errors; + } + + if (strncmp((char *) + (&knot_rdata_item(rdata, i)->raw_data[0]), + (char *)pos, size) != 0) { +/* knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrtype); */ + + diag("Data stored in %d-th RDATA item are wrong.", i); + ++errors; + } + + pos += size; + } + + return errors; +} + +/*----------------------------------------------------------------------------*/ + +//static int convert_to_wire(const uint8_t *data, int max_size, uint16_t rrtype, +// uint8_t *data_wire) +//{ +// //note("Converting type %u", rrtype); + +// int wire_size = 0; +// const uint8_t *pos = data; +// uint8_t *pos_wire = data_wire; + +// knot_rrtype_descriptor_t *desc = +// knot_rrtype_descriptor_by_type(rrtype); +// uint item_count = desc->length; + +// for (int i = 0; i < item_count; ++i) { +// const uint8_t *from = NULL; +// uint to_copy = 0; + +// switch (desc->wireformat[i]) { +// case KNOT_RDATA_WF_COMPRESSED_DNAME: +// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: +// case KNOT_RDATA_WF_LITERAL_DNAME: +// // copy the domain name without its length +// from = pos + 1; +// to_copy = *pos; +// pos += *pos + 1; +///* note("Domain name in wire format (size %u): %s", +// to_copy, (char *)from); */ +// break; +// case KNOT_RDATA_WF_BYTE: +// //note(" 1byte int"); +// from = pos; +// to_copy = 1; +// pos += 1; +// break; +// case KNOT_RDATA_WF_SHORT: +// //note(" 2byte int"); +// from = pos; +// to_copy = 2; +// pos += 2; +// break; +// case KNOT_RDATA_WF_LONG: +// //note(" 4byte int"); +// from = pos; +// to_copy = 4; +// pos += 4; +// break; +// case KNOT_RDATA_WF_A: +// //note(" A"); +// from = pos; +// to_copy = 4; +// pos += 4; +// break; +// case KNOT_RDATA_WF_AAAA: +// //note(" AAAA"); +// from = pos; +// to_copy = 16; +// pos += 16; +// break; +// case KNOT_RDATA_WF_BINARY: +// case KNOT_RDATA_WF_APL: // saved as binary +// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary +// //note(" binary"); +// from = pos + 1; +// to_copy = *pos; +// pos += *pos + 1; +// break; +// case KNOT_RDATA_WF_TEXT: +// case KNOT_RDATA_WF_BINARYWITHLENGTH: +// //note(" text or binary with length (%u)", *pos); +// to_copy = *pos + 1; +// from = pos; +// pos += *pos + 1; +// break; +// default: +// assert(0); +// } + +// //note("Copying %u bytes from %p", to_copy, from); + +// assert(from != NULL); +// assert(to_copy != 0); + +// memcpy(pos_wire, from, to_copy); +// pos_wire += to_copy; +// wire_size += to_copy; + +// assert(wire_size < max_size); +// } + +// return wire_size; +//} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tests knot_rdata_set_item(). + * + * \retval > 0 on success. + * \retval 0 otherwise. + */ +static int test_rdata_set_item() +{ + knot_rdata_t *rdata = knot_rdata_new(); + knot_rdata_item_t item; + item.raw_data = RDATA_ITEM_PTR; + + int ret = knot_rdata_set_item(rdata, 0, item); + if (ret == 0) { + diag("knot_rdata_set_item() called on empty RDATA" + "returned %d instead of error (-1).", ret); + knot_rdata_free(&rdata); + return 0; + } + +// uint8_t *data = malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE); +// assert(data); + uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE]; + generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE); + + // set items through set_items() and then call set_item() + uint16_t rrtype = rand() % KNOT_RRTYPE_LAST + 1; + if (fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, rrtype, rdata) < 0) { + knot_rdata_free(&rdata); + diag("Error filling RDATA"); + return 0; + } + + uint8_t pos = rand() % knot_rrtype_descriptor_by_type(rrtype)->length; + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrtype); + + // if the rdata on this position is domain name, free it to avoid leaks + if (desc->wireformat[pos] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[pos] == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[pos] == KNOT_RDATA_WF_LITERAL_DNAME) { + knot_dname_free(&(rdata->items[pos].dname)); + } + + ret = knot_rdata_set_item(rdata, pos, item); + if (ret != 0) { + diag("knot_rdata_set_item() called on filled" + " RDATA returned %d instead of 0.", ret); + knot_rdata_free(&rdata); + return 0; + } + + if (knot_rdata_item(rdata, pos)->raw_data != RDATA_ITEM_PTR) { + diag("RDATA item on position %d is wrong: %p (should be %p).", + pos, knot_rdata_item(rdata, pos)->raw_data, + RDATA_ITEM_PTR); + knot_rdata_free(&rdata); + return 0; + } + + for (int x = 0; x < desc->length; x++) { + if (x != pos && ( + desc->wireformat[x] == + KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[x] == + KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[x] == + KNOT_RDATA_WF_LITERAL_DNAME)) { + knot_dname_free(&(rdata->items[x].dname)); + } + } + +// knot_rdata_free(&rdata); + return 1; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tests knot_rdata_set_items(). + * + * Iterates over the test_rdatas array and for each testing RDATA it creates + * the RDATA structure, sets its items (\see set_rdata_all()) and checks if the + * items are set properly (\see check_rdata()). + * + * \retval > 0 on success. + * \retval 0 otherwise. + */ +static int test_rdata_set_items() +{ + knot_rdata_t *rdata = NULL; + knot_rdata_item_t *item = (knot_rdata_item_t *)0xDEADBEEF; + int errors = 0; + + // check error return values + if (knot_rdata_set_items(rdata, NULL, 0) != KNOT_EBADARG) { + diag("Return value of knot_rdata_set_items() " + "when rdata == NULL is wrong"); + return 0; + } else { + rdata = knot_rdata_new(); + assert(rdata != NULL); + + if (knot_rdata_set_items(rdata, NULL, 0) != KNOT_EBADARG) { + diag("Return value of knot_rdata_set_items()" + " when items == NULL is wrong"); +// knot_rdata_free(&rdata); + return 0; + } else if (knot_rdata_set_items(rdata, item, 0) != + KNOT_EBADARG) { + diag("Return value of knot_rdata_set_items()" + " when count == 0" + "is wrong"); +// knot_rdata_free(&rdata); + return 0; + } +// knot_rdata_free(&rdata); + } + + // generate some random data +// uint8_t *data = malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE); + uint8_t data [KNOT_MAX_RDATA_WIRE_SIZE]; + generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE); + + for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) { + rdata = knot_rdata_new(); + + if (fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata) + < 0) { + ++errors; + } + errors += check_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, + rdata); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(i); + + for (int x = 0; x < desc->length; x++) { + if (desc->wireformat[x] == + KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[x] == + KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[x] == + KNOT_RDATA_WF_LITERAL_DNAME) { +// printf("freeing %p\n", rdata->items[x].dname); + knot_dname_free(&(rdata->items[x].dname)); + } + } + +// knot_rdata_free(&rdata); + } + + return (errors == 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tests knot_rdata_get_item(). + * + * \retval > 0 on success. + * \retval 0 otherwise. + */ +static int test_rdata_get_item() +{ + const knot_rdata_t *rdata = &TEST_RDATA; + + if (knot_rdata_item(rdata, TEST_RDATA.count) != NULL) { + diag("knot_rdata_get_item() called with" + "invalid position did not return NULL"); + return 0; + } + + int errors = 0; + if ((knot_rdata_item(rdata, 0)->dname) + != TEST_RDATA.items[0].dname) { + diag("RDATA item on position 0 is wrong: %p (should be %p)", + knot_rdata_item(rdata, 0), TEST_RDATA.items[0]); + ++errors; + } + if ((knot_rdata_item(rdata, 1)->raw_data) + != TEST_RDATA.items[1].raw_data) { + diag("RDATA item on position 0 is wrong: %p (should be %p)", + knot_rdata_item(rdata, 1), TEST_RDATA.items[1]); + ++errors; + } + if ((knot_rdata_item(rdata, 2)->raw_data) + != TEST_RDATA.items[2].raw_data) { + diag("RDATA item on position 0 is wrong: %p (should be %p)", + knot_rdata_item(rdata, 2), TEST_RDATA.items[2]); + ++errors; + } + + return (errors == 0); +} + +/*----------------------------------------------------------------------------*/ + +static int test_rdata_compare() +{ + int errors = 0; + + uint8_t format_rawdata = KNOT_RDATA_WF_BINARY; + + uint8_t format_dname = KNOT_RDATA_WF_LITERAL_DNAME; + + /* 123456 \w 654321 -> result -1 */ + if (knot_rdata_compare(&test_rdata[0], + &test_rdata[1], + &format_rawdata) != -1) { + diag("RDATA raw data comparison failed 0"); + errors++; + } + + /* 123456 \w 123456 -> result 0 */ + if (knot_rdata_compare(&test_rdata[0], + &test_rdata[0], + &format_rawdata) != 0) { + diag("RDATA raw data comparison failed 1 "); + errors++; + } + + /* 123456 \w 654321 -> result 1 */ + if (knot_rdata_compare(&test_rdata[1], + &test_rdata[0], + &format_rawdata) != 1) { + diag("RDATA raw data comparison failed 2"); + errors++; + } + + /* abcdef.example.com. \w abcdef.foo.com. -> result -1 */ + int ret = 0; + if ((ret = knot_rdata_compare(&test_rdata[2], + &test_rdata[3], + &format_dname)) >= 0) { + diag("RDATA dname comparison failed 3"); + errors++; + } + + /* abcdef.example.com. \w abcdef.example.com. -> result 0 */ + if (knot_rdata_compare(&test_rdata[2], + &test_rdata[2], + &format_dname) != 0) { + diag("RDATA dname comparison failed 4"); + errors++; + } + + /* abcdef.example.com. \w abcdef.foo.com -> result 1 */ + if (knot_rdata_compare(&test_rdata[3], + &test_rdata[2], + &format_dname) != 1) { + diag("RDATA dname comparison failed 5"); + errors++; + } + + + + + return (errors == 0); +} + +/*----------------------------------------------------------------------------*/ + +//static int test_rdata_wire_size() +//{ +// knot_rdata_t *rdata; +// int errors = 0; + +// // generate some random data +// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE]; +// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE); + +// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) { +// rdata = knot_rdata_new(); + +// int size = +// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata); + +// if (size < 0) { +// ++errors; +// } else { +// int counted_size = knot_rdata_wire_size(rdata, +// knot_rrtype_descriptor_by_type(i)->wireformat); +// if (size != counted_size) { +// diag("Wrong wire size computed (type %d):" +// " %d (should be %d)", +// i, counted_size, size); +// ++errors; +// } +// } + +// knot_rrtype_descriptor_t *desc = +// knot_rrtype_descriptor_by_type(i); + +// for (int x = 0; x < desc->length; x++) { +// if (desc->wireformat[x] == +// KNOT_RDATA_WF_UNCOMPRESSED_DNAME || +// desc->wireformat[x] == +// KNOT_RDATA_WF_COMPRESSED_DNAME || +// desc->wireformat[x] == +// KNOT_RDATA_WF_LITERAL_DNAME) { +// knot_dname_free(&(rdata->items[x].dname)); +// } +// } +// knot_rdata_free(&rdata); +// } + +// return (errors == 0); +//} + +/*----------------------------------------------------------------------------*/ + +//static int test_rdata_to_wire() +//{ +// knot_rdata_t *rdata; +// int errors = 0; + +// // generate some random data +// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE]; +// uint8_t data_wire[KNOT_MAX_RDATA_WIRE_SIZE]; +// uint8_t rdata_wire[KNOT_MAX_RDATA_WIRE_SIZE]; +// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE); + +// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) { +// rdata = knot_rdata_new(); + +// int size = +// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata); + +// int size_expected = +// convert_to_wire(data, KNOT_MAX_RDATA_WIRE_SIZE, i, +// data_wire); + +// if (size < 0) { +// ++errors; +// } else { +// if (size != size_expected) { +// diag("Wire format size (%u) not" +// " as expected (%u)", +// size, size_expected); +// ++errors; +// } else { +// if (knot_rdata_to_wire(rdata, +// knot_rrtype_descriptor_by_type(i)-> +// wireformat, rdata_wire, +// KNOT_MAX_RDATA_WIRE_SIZE) != 0) { +// diag("Error while converting RDATA" +// " to wire format."); +// ++errors; +// } else { +// if (strncmp((char *)data_wire, +// (char *)rdata_wire, size) +// != 0) { +// diag("RDATA converted to wire" +// "format does not match" +// " the expected value"); +// ++errors; +// } +// } +// } +// } + +// knot_rrtype_descriptor_t *desc = +// knot_rrtype_descriptor_by_type(i); + +// for (int x = 0; x < desc->length; x++) { +// if (desc->wireformat[x] == +// KNOT_RDATA_WF_UNCOMPRESSED_DNAME || +// desc->wireformat[x] == +// KNOT_RDATA_WF_COMPRESSED_DNAME || +// desc->wireformat[x] == +// KNOT_RDATA_WF_LITERAL_DNAME) { +// knot_dname_free(&(rdata->items[x].dname)); +// } +// } +// knot_rdata_free(&rdata); +// } + +// return (errors == 0); +//} + +static int test_rdata_free() +{ + return 0; +// knot_rdata_t *tmp_rdata; + +// tmp_rdata = knot_rdata_new(); + +// knot_rdata_free(&tmp_rdata); + +// return (tmp_rdata == NULL); +} +/* Can't test this with current implementation + * would be trying to free pointers on stack */ +static int test_rdata_deep_free() +{ + return 0; + +/* int errors = 0; + + knot_rdata_t *tmp_rdata; + + uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE]; + + for (int i = 0; i <= KNOT_RRTYPE_LAST; i++) { + tmp_rdata = knot_rdata_new(); + + fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, tmp_rdata); + + knot_rdata_deep_free(&tmp_rdata, i, 0); + errors += (tmp_rdata != NULL); + } + + return (errors == 0); */ +} + +/*----------------------------------------------------------------------------*/ + +static const int KNOT_RDATA_TEST_COUNT = 8; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_rdata_tests_count(int argc, char *argv[]) +{ + return KNOT_RDATA_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_rdata_tests_run(int argc, char *argv[]) +{ + int res = 0, + res_final = 1; + + res = test_rdata_create(); + ok(res, "rdata: create empty"); + res_final *= res; + + skip(!res, 6); + + todo(); + + ok(res = test_rdata_delete(), "rdata: delete"); + //res_final *= res; + + endtodo; + + ok(res = test_rdata_get_item(), "rdata: get item"); + res_final *= res; + + skip(!res, 4) + + ok(res = test_rdata_set_items(), "rdata: set items all at once"); + res_final *= res; + + skip(!res, 3); + + ok(res = test_rdata_set_item(), "rdata: set items one-by-one"); + res_final *= res; + + ok(res = test_rdata_compare(), "rdata: compare"); + res_final *= res; + +// ok(res = test_rdata_wire_size(), "rdata: wire size"); +// res_final *= res; + +// skip(!res, 1); + +// ok(res = test_rdata_to_wire(), "rdata: to wire"); +// res_final *= res; + +// endskip; /* test_rdata_wire_size() failed */ + + endskip; /* test_rdata_set_items() failed */ + + endskip; /* test_rdata_get_item() failed */ + + endskip; /* test_rdata_create() failed */ + + todo(); + + ok(res = test_rdata_deep_free(), "rdata: deep free"); + res_final *= res; + + ok(res = test_rdata_free(), "rdata: free"); + res_final *= res; + + endtodo; + + return res_final; +} diff --git a/src/tests/libknot/libknot/rdata_tests.h b/src/tests/libknot/libknot/rdata_tests.h new file mode 100644 index 0000000..1f43c91 --- /dev/null +++ b/src/tests/libknot/libknot/rdata_tests.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file rdata_tests.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * Contains unit tests for RDATA (knot_rdata_t) and RDATA item + * (knot_rdata_item_t) structures. + * + * Contains tests for: + * - creating empty RDATA structure with or without reserved space. + * - setting RDATA items one-by-one + * - setting RDATA items all at once + * + * As for now, the tests use several (TEST_RDATAS) RDATA structures, each + * with different number of RDATA items (given by test_rdatas). These are all + * initialized to pointers derived from RDATA_ITEM_PTR (first is RDATA_ITEM_PTR, + * second RDATA_ITEM_PTR + 1, etc.). The functions only test if the pointer + * is set properly. + * + * \todo It may be better to test also some RDATAs with predefined contents, + * such as some numbers, some domain name, etc. For this purpose, we'd + * need RDATA descriptors (telling the types of each RDATA item within an + * RDATA). + * + * \todo It will be fine to test all possible output values of all functions, + * e.g. test whether knot_rdata_get_item() returns NULL when passed an + * illegal position, etc. + */ +#ifndef _KNOTD_RDATA_TESTS_H_ +#define _KNOTD_RDATA_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api rdata_tests_api; + +#endif /* _KNOTD_RDATA_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/response_tests.c b/src/tests/libknot/libknot/response_tests.c new file mode 100644 index 0000000..93cf2df --- /dev/null +++ b/src/tests/libknot/libknot/response_tests.c @@ -0,0 +1,450 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <inttypes.h> + +//#define RESP_TEST_DEBUG +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "tests/libknot/libknot/response_tests.h" +#include "common/lists.h" +#include "libknot/common.h" +#include "libknot/util/error.h" +#include "libknot/packet/response.h" +#include "libknot/rdata.h" +#include "libknot/rrset.h" +#include "libknot/dname.h" +#include "libknot/util/wire.h" +#include "libknot/util/descriptor.h" +#include "libknot/edns.h" + +#ifdef TEST_WITH_LDNS +#include "ldns/ldns.h" +#endif + +static int knot_response_tests_count(int argc, char *argv[]); +static int knot_response_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api response_tests_api = { + "DNS library - response", //! Unit name + &knot_response_tests_count, //! Count scheduled tests + &knot_response_tests_run //! Run scheduled tests +}; + +static int test_response_init() +{ + int errors = 0; + int lived = 0; + lives_ok({ + if (knot_response_init(NULL) != KNOT_EBADARG) { + diag("Calling response_init with NULL packet did " + "not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + }, "response: init NULL tests"); + errors += lived != 1; + + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + assert(response); + response->max_size = KNOT_WIRE_HEADER_SIZE - 1; + if (knot_response_init(response) != KNOT_ESPACE) { + diag("Calling response_init too small packet did " + "not return KNOT_ESPACE!"); + errors++; + } + + return (errors == 0); +} + +static int test_response_init_query() +{ + int errors = 0; + int lived = 0; + lives_ok({ + if (knot_response_init_from_query(NULL, NULL) != + KNOT_EBADARG) { + diag("Calling response_init_query with NULL packet and " + "NULL query did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + knot_packet_set_max_size(response, + KNOT_PACKET_PREALLOC_RESPONSE); + knot_response_init(response); + lived = 0; + if (knot_response_init_from_query(response, NULL) != + KNOT_EBADARG) { + diag("Calling response_init_query with NULL query " + "did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + knot_packet_t *query = + knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); + if (knot_response_init_from_query(NULL, query) != + KNOT_EBADARG) { + diag("Calling response_init_query with NULL response " + "did not return KNOT_EBADARG!"); + errors++; + } + }, "response: init from query NULL tests"); + errors += lived != 1; + + /* Cannot test the rest of return values, since there is now constant + * controlling value that could return KNOT_EDNAMEPTR */ + + return (errors == 0); +} + +int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count) +{ + int i = 0; + while (i < count && + wire1[i] == wire2[i]) { + i++; + } + return (!(count == i)); +} + + +//static int test_response_clear() +//{ +// int errors = 0; +// int lived = 0; +// lives_ok({ +// knot_response_clear(NULL, 1); +// lived = 1; +// }, "response: clear NULL tests"); +// errors += lived != 1; + +// /* +// * Create new response, convert to wire, then add something, clear +// * the response, convert to wire again and compare wires. +// */ + +// knot_packet_t *response = +// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); +// knot_packet_set_max_size(response, KNOT_WIRE_HEADER_SIZE * 100); +// assert(knot_response_init(response) == KNOT_EOK); + +// uint8_t *original_wire = NULL; +// size_t original_size = 0; +// assert(knot_packet_to_wire(response, &original_wire, +// &original_size) == +// KNOT_EOK); +// /* Do something in question section. */ +//// test_dname_t test_dname; +//// test_dname.str = "ns8.nic.cz."; +//// knot_dname_t *dname = dname_from_test_dname_str(&test_dname); +//// assert(dname); + +// response->question.qtype = KNOT_RRTYPE_HINFO; +// response->question.qclass = KNOT_CLASS_CH; + +// uint8_t *question_changed_wire = NULL; +// size_t question_changed_size = 0; +// assert(knot_packet_to_wire(response, +// &question_changed_wire, +// &question_changed_size) == +// KNOT_EOK); + +// knot_response_set_aa(response); +// knot_response_set_tc(response); +// knot_response_set_rcode(response, knot_quick_rand()); + +// knot_response_clear(response, 0); +// uint8_t *new_wire = NULL; +// size_t new_size = 0; +// assert(knot_packet_to_wire(response, &new_wire, &new_size) == +// KNOT_EOK); +// if (question_changed_size != new_size) { +// diag("Wrong wire size after calling response_clear! " +// "got %d should be %d", new_size, question_changed_size); +// errors++; +// } else { +// if (compare_wires_simple(question_changed_wire, +// new_wire, new_size)) { +// diag("Wrong wire after calling response_clear! "); +// errors++; +// } +// } +// free(new_wire); + +// new_wire = NULL; +// new_size = 0; + +// /*!< \todo figure out this segfault! */ + +//// knot_response_clear(response, 1); +//// assert(knot_packet_to_wire(response, &new_wire, &new_size) == +//// KNOT_EOK); + +//// if (original_size != new_size) { +//// diag("Wrong wire size after calling response_clear!"); +//// errors++; +//// } else { +//// if (compare_wires_simple(original_wire, +//// new_wire, new_size)) { +//// diag("Wrong wire after calling response_clear!"); +//// errors++; +//// } +//// } + +//// free(new_wire); +//// free(original_wire); +//// free(question_changed_wire); +//// knot_packet_free(&response); + +// return (errors == 0); +//} + +static int test_response_add_opt() +{ + int errors = 0; + int lived = 0; + + knot_opt_rr_t opt; + opt.payload = 512; + opt.ext_rcode = 0; + opt.version = EDNS_VERSION_0; + opt.flags = 0; + opt.options = NULL; + opt.option_count = 0; + opt.options_max = 0; + opt.size = 25; // does it matter? + + lives_ok({ + if (knot_response_add_opt(NULL, NULL, 0) != KNOT_EBADARG) { + diag("Calling response add opt with NULL arguments " + "did not result to KNOT_EBADARG"); + errors++; + } + lived = 1; + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + lived = 0; + if (knot_response_add_opt(response, + NULL, 0) != KNOT_EBADARG) { + diag("Calling response add opt with NULL OPT RR " + "did not result to KNOT_EBADARG"); + errors++; + } + lived = 1; + + lived = 0; + if (knot_response_add_opt(NULL, + &opt, 0) != KNOT_EBADARG) { + diag("Calling response add opt with NULL response " + "did not result to KNOT_EBADARG"); + errors++; + } + lived = 1; + knot_packet_free(&response); + }, "response: add opt NULL tests"); + errors += lived != 1; + + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + knot_packet_set_max_size(response, KNOT_PACKET_PREALLOC_RESPONSE * 100); + assert(knot_response_init(response) == KNOT_EOK);; + + if (knot_response_add_opt(response, &opt, 0) != KNOT_EOK) { + diag("Adding valid OPT RR to response " + "did not return KNOT_EOK"); + errors++; + } + + opt.payload = response->max_size + 1; + if (knot_response_add_opt(response, &opt, 1) != KNOT_EPAYLOAD) { + diag("If OPT RR payload is bigger than response max size " + "response_add_opt does not return KNOT_EPAYLOAD!"); + errors++; + } + + opt.payload = 0; + if (knot_response_add_opt(response, &opt, 1) != KNOT_EBADARG) { + diag("Calling response_add_opt with OPT RR payload set to 0 " + "did not return KNOT_EBADARG"); + } + + knot_packet_free(&response); + return (errors == 0); +} + +static int test_response_add_generic(int (*func)(knot_packet_t *, + const knot_rrset_t *, + int, int, int)) +{ + int errors = 0; + int lived = 0; + + lives_ok({ + if (func(NULL, NULL, 0, 0, 0) != KNOT_EBADARG) { + diag("Calling response add rrset with NULL " + "arguments did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + lived = 0; + if (func(response, NULL, 0, 0, 0) != KNOT_EBADARG) { + diag("Calling response add rrset with NULL rrset " + "did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + knot_dname_t *owner = + knot_dname_new_from_str("ns.nic.cz.", + strlen("ns.nic.cz."), + NULL); + assert(owner); + knot_rrset_t *rrset = + knot_rrset_new(owner, KNOT_RRTYPE_A, + KNOT_CLASS_IN, 3600); + assert(rrset); + lived = 0; + if (func(NULL, rrset, 0, 0, 0) != KNOT_EBADARG) { + diag("Calling response add rrset with NULL response " + "did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + knot_rrset_deep_free(&rrset, 1, 0, 0); + knot_packet_free(&response); + }, "response: rrset adding NULL tests"); + errors += lived != 1; + + /*!< \todo Test case when KNOT_ESPACE should be returned. */ + /*!< \todo Compression and so on - should it be tested here? */ + + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + + knot_dname_t *owner = + knot_dname_new_from_str("ns12.nic.cz.", + strlen("ns12.nic.cz."), + NULL); + assert(owner); + knot_rrset_t *rrset = + knot_rrset_new(owner, KNOT_RRTYPE_NS, + KNOT_CLASS_IN, 3600); + assert(rrset); + if (func(response, rrset, 0, 0, 0) != KNOT_EOK) { + diag("Adding valid RRSet to response did not result to " + "KNOT_EOK"); + errors++; + } + + knot_rrset_deep_free(&rrset, 1, 0, 0); + knot_packet_free(&response); + + return (errors == 0); +} + +static void test_response_add_rrset() +{ + ok(test_response_add_generic(knot_response_add_rrset_answer), + "response: add answer rrset"); + ok(test_response_add_generic(knot_response_add_rrset_authority), + "response: add answer authority"); + ok(test_response_add_generic(knot_response_add_rrset_additional), + "response: add answer additional"); +} + +static int test_response_add_nsid() +{ + int errors = 0; + int lived = 0; + + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + + uint8_t *nsid = (uint8_t *)"knotDNS"; + uint16_t nsid_size = strlen((char *)nsid); + lives_ok({ + if (knot_response_add_nsid(NULL, + NULL, 1) != KNOT_EBADARG) { + diag("Calling response add nsid with NULL arguments " + "did not return KNOT_EBADARG"); + errors++; + } + lived = 1; + + lived = 0; + if (knot_response_add_nsid(NULL, nsid, + nsid_size) != KNOT_EBADARG) { + diag("Calling response add nsid with NULL response " + "did not return KNOT_EBADARG"); + errors++; + } + lived = 1; +// lived = 0; +// if (knot_response_add_nsid(response, nsid, +// 0) != KNOT_EBADARG) { +// diag("Calling response add nsid with zero size " +// "did not return KNOT_EBADARG"); +// errors++; +// } +// lived = 1; + }, "response: add nsid NULL tests"); + errors += lived != 1; + + if (knot_response_add_nsid(response, nsid, + nsid_size) != KNOT_EOK) { + diag("Adding valid nsid to response did not return KNOT_EOK"); + errors++; + } + + knot_packet_free(&response); + return (errors == 0); +} + +static const int KNOT_response_TEST_COUNT = 14; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_response_tests_count(int argc, char *argv[]) +{ + return KNOT_response_TEST_COUNT; +} + + +/*! Run all scheduled tests for given parameters. + */ +static int knot_response_tests_run(int argc, char *argv[]) +{ + ok(test_response_init(), "response: init"); + ok(test_response_init_query(), "response: init from query"); +// ok(test_response_clear(), "response: clear"); + ok(test_response_add_opt(), "response: add opt"); + test_response_add_rrset(); + ok(test_response_add_nsid(), "response: add nsid"); + return 1; +} diff --git a/src/tests/libknot/libknot/response_tests.h b/src/tests/libknot/libknot/response_tests.h new file mode 100644 index 0000000..c9a117b --- /dev/null +++ b/src/tests/libknot/libknot/response_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_response_TESTS_H_ +#define _KNOTD_response_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api response_tests_api; + +#endif /* _KNOTD_response_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/rrset_tests.c b/src/tests/libknot/libknot/rrset_tests.c new file mode 100644 index 0000000..fa75195 --- /dev/null +++ b/src/tests/libknot/libknot/rrset_tests.c @@ -0,0 +1,888 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "tests/libknot/libknot/rrset_tests.h" +#include "libknot/common.h" +#include "libknot/util/descriptor.h" +#include "libknot/rrset.h" +#include "libknot/dname.h" +#include "libknot/rdata.h" +#include "libknot/util/utils.h" +#include "libknot/zone/node.h" +#include "libknot/util/debug.h" + +static int knot_rrset_tests_count(int argc, char *argv[]); +static int knot_rrset_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api rrset_tests_api = { + "DNS library - rrset", //! Unit name + &knot_rrset_tests_count, //! Count scheduled tests + &knot_rrset_tests_run //! Run scheduled tests +}; + +/*----------------------------------------------------------------------------*/ +/* + * Unit implementation. + */ + +static knot_node_t *NODE_ADDRESS = (knot_node_t *)0xDEADBEEF; + +enum { TEST_RRSETS = 6 , TEST_RRSIGS = 6}; + +//void *RRSIG_ADDRESS = (void *)0xDEADBEEF; +//void *RRSIG_FIRST = RRSIG_ADDRESS + 10; + +struct test_domain { + char *str; + char *wire; + uint size; + char *labels; + short label_count; +}; + +struct test_rrset { + char *owner; + uint16_t type; + uint16_t rclass; + uint32_t ttl; + knot_rdata_t *rdata; + const knot_rrset_t *rrsigs; +}; + +/* this has to changed */ +static const char *signature_strings[TEST_RRSIGS] = +{"signature 1", "signature 2", "signature 3", + "signature 4", "signature 5", "signature 6"}; + +enum { + RR_DNAMES_COUNT = 3, + RR_ITEMS_COUNT = 3, + RR_RDATA_COUNT = 4, +}; + +enum { TEST_DOMAINS_OK = 8 }; + +static knot_dname_t RR_DNAMES[RR_DNAMES_COUNT] = + { {{}, (uint8_t *)"\7example\3com", 13, NULL}, //0's at the end are added + {{}, (uint8_t *)"\3ns1\7example\3com", 17, NULL}, + {{}, (uint8_t *)"\3ns2\7example\3com", 17, NULL} }; + +/* 192.168.1.1 */ +static uint8_t address[4] = {0xc0, 0xa8, 0x01, 0x01}; + +static knot_rdata_item_t RR_ITEMS[RR_ITEMS_COUNT] = + { {.dname = &RR_DNAMES[1]}, + {.dname = &RR_DNAMES[2]}, + {.raw_data = (uint16_t *)address} }; + +/*! \warning Do not change the order. */ +/* TODO this does not work as expected */ +static knot_rdata_t RR_RDATA[RR_RDATA_COUNT] = + { {&RR_ITEMS[0], 1, &RR_RDATA[0]}, /* first ns */ + {&RR_ITEMS[1], 1, &RR_RDATA[1]}, /* second ns */ + {&RR_ITEMS[0], 1, &RR_RDATA[3]}, /* both in cyclic list */ + {&RR_ITEMS[1], 1, &RR_RDATA[2]} }; + +/*! \warning Do not change the order in those, if you want to test some other + * feature with new dname, add it at the end of these arrays. + */ +static const struct test_domain + test_domains_ok[TEST_DOMAINS_OK] = { + { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21, + "\x0\x4\x9\x10", 4 }, + { "some.test.domain.com.", "\4some\4test\6domain\3com", 22, + "\x0\x5\xA\x11", 4 }, + { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21, + "\x0\x4\x9\x10", 4 }, + { "some.test.domain.com.", "\4some\4test\6domain\3com", 22, + "\x0\x5\xA\x11", 4 }, + { "test.domain.com.", "\4test\6domain\3com", 17, + "\x0\x5\xC", 3 }, + { ".", "\0", 1, + "", 0 }, + { "foo.bar.net.", "\3foo\3bar\3net", 13, + "\x0\x4\x8", 3}, + { "bar.net.", "\3bar\3net", 9, + "\x0\x4", 2} +}; + +static struct test_rrset test_rrsets[TEST_RRSETS] = { + { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN, + 3600, NULL, NULL }, + { "example2.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN, + 3600, NULL, NULL }, + { "example3.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN, + 3600, NULL, NULL }, + { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN, + 3600, NULL, NULL }, + { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN, + 3600, NULL, NULL }, + { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN, + 3600, NULL, NULL } +}; + +static const struct test_rrset test_rrsigs[TEST_RRSIGS] = { + { "example.com.", 46, 1, 3600, NULL }, + { "example2.com.", 46, 1, 3600, NULL }, + { "example3.com.", 46, 1, 3600, NULL }, + { "example4.com.", 46, 1, 3600, NULL }, + { "example5.com.", 46, 1, 3600, NULL }, + { "example6.com.", 46, 1, 3600, NULL } +}; + +static void generate_rdata(uint8_t *data, int size) +{ + for (int i = 0; i < size; ++i) { + data[i] = rand() % 256; + } +} + +static int fill_rdata_r(uint8_t *data, int max_size, uint16_t rrtype, + knot_rdata_t *rdata) +{ + assert(rdata != NULL); + assert(data != NULL); + assert(max_size > 0); + + uint8_t *pos = data; + int used = 0; + int wire_size = 0; + +// note("Filling RRType %u", rrtype); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrtype); + + uint item_count = desc->length; + knot_rdata_item_t *items = + (knot_rdata_item_t *)malloc(item_count + * sizeof(knot_rdata_item_t)); + + for (int i = 0; i < item_count; ++i) { + uint size = 0; + int domain = 0; + knot_dname_t *dname = NULL; + int binary = 0; + int stored_size = 0; + + switch (desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: + dname = knot_dname_new_from_wire( + (uint8_t *)test_domains_ok[0].wire, + test_domains_ok[0].size, NULL); + assert(dname != NULL); +// note("Created domain name: %s", +// knot_dname_name(dname)); +// note("Domain name ptr: %p", dname); + domain = 1; + size = knot_dname_size(dname); +// note("Size of created domain name: %u", size); + assert(size < KNOT_MAX_RDATA_ITEM_SIZE); + // store size of the domain name + *(pos++) = size; + // copy the domain name + memcpy(pos, knot_dname_name(dname), size); + pos += size; + break; + default: + binary = 1; + size = rand() % KNOT_MAX_RDATA_ITEM_SIZE; + } + + if (binary) { + // Rewrite the actual 2 bytes in the data array + // with length. + // (this is a bit ugly, but does the work ;-) + knot_wire_write_u16(pos, size); + //*pos = size; + } + + //note("Filling %u bytes", size); + used += size; + assert(used < max_size); + + if (domain) { + items[i].dname = dname; + wire_size += knot_dname_size(dname); +/* note("Saved domain name ptr on index %d: %p", + i, items[i].dname); */ + } else { + free(dname); +// note("Saved raw data ptr on index %d: %p",i, pos); + items[i].raw_data = (uint16_t *)pos; + pos += size; + wire_size += size; + if (binary && !stored_size) { + wire_size -= 2; + } + } + } + + int res = knot_rdata_set_items(rdata, items, item_count); + if (res != 0) { + diag("knot_rdata_set_items() returned %d.", res); + free(items); + return -1; + } else { + free(items); + return wire_size; + } +} + +/* fills test_rrsets with random rdata when empty */ +static void create_rdata() +{ + knot_rdata_t *r; + + uint8_t *data = + malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE); + + assert(data); + + for (int i = 0; i < TEST_RRSETS; i++) { + if (test_rrsets[i].rdata == NULL) { + r = knot_rdata_new(); + + /* from rdata tests */ + generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE); + if (fill_rdata_r(data, KNOT_MAX_RDATA_WIRE_SIZE, + test_rrsets[i].type, r) <= 0) { + diag("Error creating rdata!"); + + } + + test_rrsets[i].rdata = r; + } + } + + free(data); +} + +static int check_rrset(const knot_rrset_t *rrset, int i, + int check_rdata, int check_items, + int check_rrsigs) +{ + /* following implementation should be self-explanatory */ + int errors = 0; + + if (rrset == NULL) { + diag("RRSet not created!"); + return 1; + } + + char *owner = knot_dname_to_str(rrset->owner); + if (strcmp(owner, test_rrsets[i].owner) != 0) { + diag("OWNER domain name wrong: '%s' (should be '%s')", + owner, test_rrsets[i].owner); + ++errors; + } + free(owner); + + if (rrset->type != test_rrsets[i].type) { + diag("TYPE wrong: %u (should be: %u)", rrset->type, + test_rrsets[i].type); + ++errors; + } + + if (rrset->rclass != test_rrsets[i].rclass) { + diag("CLASS wrong: %u (should be: %u)", rrset->rclass, + test_rrsets[i].rclass); + ++errors; + } + + if (rrset->ttl != test_rrsets[i].ttl) { + diag("TTL wrong: %u (should be: %u)", rrset->ttl, + test_rrsets[i].ttl); + ++errors; + } + + if (check_rdata) { + /* TODO use rdata_compare */ + knot_rdata_t *rdata = rrset->rdata; + + if (rdata == NULL) { + diag("There are no RDATAs in the RRSet"); + ++errors; + } + + if (rdata != NULL) { + while (rdata->next != NULL && + rdata->next != rrset->rdata) { + rdata = rdata->next; + } + if (rdata->next == NULL) { + diag("The list of RDATAs is not cyclic!"); + ++errors; + } else { + assert(rdata->next == rrset->rdata); + } + } + } + + if (check_items) { + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + if (knot_rdata_compare(rrset->rdata, + test_rrsets[i].rdata, + desc->wireformat) != 0) { + diag("Rdata items do not match."); + errors++; + } + } + + /* TODO this deserves a major improvement!!! */ + + /* + * Will work only with null terminated strings, + * consider changing to more versatile implementation + */ + + /* How about, once it's tested, using rdata_compare */ + + if (check_rrsigs) { + + const knot_rrset_t *rrsigs; + + rrsigs = knot_rrset_rrsigs(rrset); + if (strcmp((const char *)rrsigs->rdata->items[0].raw_data, + signature_strings[i])) { + diag("Signatures are not equal" + "to those set when creating." + "Comparing %s with %s", + rrsigs->rdata->items[0].raw_data, + signature_strings[i]); + errors++; + } + } + return errors; +} + +static int test_rrset_create() +{ + int errors = 0; + + for (int i = 0; i < TEST_RRSETS; ++i) { + knot_dname_t *owner = knot_dname_new_from_str( + test_rrsets[i].owner, + strlen(test_rrsets[i].owner), + NODE_ADDRESS); + if (owner == NULL) { + diag("Error creating owner domain name!"); + return 0; + } + knot_rrset_t *rrset = knot_rrset_new(owner, + test_rrsets[i].type, + test_rrsets[i].rclass, + test_rrsets[i].ttl); + + errors += check_rrset(rrset, i, 0, 0, 0); + + knot_rrset_free(&rrset); + knot_dname_free(&owner); + } + + //diag("Total errors: %d", errors); + + return (errors == 0); +} + +/* Not implemented - no way how to test unfreed memory from here (yet) */ +static int test_rrset_delete() +{ + return 0; +} + +static int test_rrset_add_rdata() +{ + /* rdata add */ + int errors = 0; + for (int i = 0; i < TEST_RRSETS; i++) { + knot_dname_t *owner = knot_dname_new_from_str( + test_rrsets[i].owner, + strlen(test_rrsets[i].owner), + NODE_ADDRESS); + if (owner == NULL) { + diag("Error creating owner domain name!"); + return 0; + } + + knot_rrset_t *rrset = knot_rrset_new(owner, + test_rrsets[i].type, + test_rrsets[i].rclass, + test_rrsets[i].ttl); + + knot_rrset_add_rdata(rrset, test_rrsets[i].rdata); + + errors += check_rrset(rrset, i, 1, 0, 0); + + knot_rrset_free(&rrset); + knot_dname_free(&owner); + } + + /* test whether adding works properly = keeps order of added elements */ + + /* + * Beware, this is dependent on the internal structure of rrset and + * may change. + */ + + knot_rrset_t *rrset = knot_rrset_new(NULL, 0, 0, 0); + + knot_rdata_t *r; + + knot_rdata_item_t *item; + + static const char *test_strings[10] = + { "-2", "9", "2", "10", "1", "5", "8", "4", "6", "7" }; + + /* add items */ + + for (int i = 0; i < 10; i++) { + r = knot_rdata_new(); + item = malloc(sizeof(knot_rdata_item_t)); + item->raw_data = (uint16_t *)test_strings[i]; + //following statement creates a copy + knot_rdata_set_items(r, item, 1); + knot_rrset_add_rdata(rrset, r); + free(item); + } + + knot_rdata_t *tmp = rrset->rdata; + + /* check if order has been kept */ + + int i = 0; + while (tmp->next != rrset->rdata && !errors) { + if (strcmp(test_strings[i], (char *)tmp->items[0].raw_data)) { + diag("Adding RDATA error!, is %s should be %s", + tmp->items[0].raw_data, test_strings[i]); + errors++; + } + i++; + tmp = tmp->next; + + } + + tmp = rrset->rdata; + + knot_rdata_t *next; + + while (tmp->next != rrset->rdata) { + next = tmp->next; + knot_rdata_free(&tmp); + tmp = next; + } + + knot_rdata_free(&tmp); + + knot_rrset_free(&rrset); + + return (errors == 0); +} + +static int test_rrset_rrsigs() +{ + int errors = 0; + + knot_rdata_item_t *item; + + knot_rdata_t *tmp; + + knot_dname_t *owner; + + knot_rrset_t *rrset; + + /* Gets rrsigs and checks, if signatures are the same */ + + for (int i = 0; i < TEST_RRSETS; i++) { + owner = knot_dname_new_from_str(test_rrsets[i].owner, + strlen(test_rrsets[i].owner), NODE_ADDRESS); + if (owner == NULL) { + diag("Error creating owner domain name!"); + return 0; + } + + rrset = knot_rrset_new(owner, test_rrsets[i].type, + test_rrsets[i].rclass, test_rrsets[i].ttl); + + knot_rrset_add_rdata(rrset, test_rrsets[i].rdata); + + //owners are the same + + assert(TEST_RRSETS == TEST_RRSIGS); + + knot_rrset_t *rrsig = knot_rrset_new(owner, + test_rrsigs[i].type, + test_rrsigs[i].rclass, + test_rrsigs[i].ttl); + + tmp = knot_rdata_new(); + item = malloc(sizeof(knot_rdata_item_t)); + /* signature is just a string, + * should be sufficient for testing */ + item->raw_data = (uint16_t *)signature_strings[i]; + knot_rdata_set_items(tmp, item, 1); + knot_rrset_add_rdata(rrsig, tmp); + + if (knot_rrset_set_rrsigs(rrset, rrsig) + != 0) { + diag("Could not set rrsig"); + errors++; + } + errors += check_rrset(rrset, i, 0, 0, 1); + knot_rrset_free(&rrset); + free(item); + knot_rdata_free(&tmp); + knot_rrset_free(&rrsig); + } + return (errors == 0); +} + +static int test_rrset_merge() +{ + knot_rrset_t *merger1; + knot_rrset_t *merger2; + knot_dname_t *owner1; + knot_dname_t *owner2; + + int r; + + owner1 = knot_dname_new_from_str(test_rrsets[3].owner, + strlen(test_rrsets[3].owner), NULL); + merger1 = knot_rrset_new(owner1, test_rrsets[3].type, + test_rrsets[3].rclass, + test_rrsets[3].ttl); + + knot_rrset_add_rdata(merger1, test_rrsets[3].rdata); + + owner2 = knot_dname_new_from_str(test_rrsets[4].owner, + strlen(test_rrsets[4].owner), NULL); + merger2 = knot_rrset_new(owner2, test_rrsets[4].type, + test_rrsets[4].rclass, + test_rrsets[4].ttl); + + knot_rrset_add_rdata(merger2, test_rrsets[4].rdata); + +// knot_rrset_dump(merger1, 1); + + int ret = 0; + if ((ret = knot_rrset_merge((void **)&merger1, + (void **)&merger2)) != 0) { + diag("Could not merge rrsets. (reason %d)", ret); + return 0; + } + +// knot_rrset_dump(merger1, 1); + + r = check_rrset(merger1, 5, 1, 1, 0); + + knot_rrset_free(&merger1); + knot_rrset_free(&merger2); + + if (r) { + diag("Merged rdata are wrongly set."); + return 0; + } + + return 1; +} + +static int test_rrset_owner(knot_rrset_t **rrsets) +{ + int errors = 0; + for (int i = 0; i < TEST_RRSETS; i++) { + char *dname_str = + knot_dname_to_str(knot_rrset_owner(rrsets[i])); + if (strcmp(dname_str, test_rrsets[i].owner)) { + diag("Got wrong value for owner from rrset."); + errors++; + } + free(dname_str); + } + return errors; +} + +static int test_rrset_type(knot_rrset_t **rrsets) +{ + int errors = 0; + for (int i = 0; i < TEST_RRSETS; i++) { + if (knot_rrset_type(rrsets[i]) != test_rrsets[i].type) { + errors++; + diag("Got wrong value for type from rrset."); + } + } + return errors; +} + +static int test_rrset_class(knot_rrset_t **rrsets) +{ + int errors = 0; + for (int i = 0; i < TEST_RRSETS; i++) { + if (knot_rrset_class(rrsets[i]) != test_rrsets[i].rclass) { + errors++; + diag("Got wrong value for class from rrset."); + } + } + + return errors; +} + +static int test_rrset_ttl(knot_rrset_t **rrsets) +{ + int errors = 0; + for (int i = 0; i < TEST_RRSETS; i++) { + if (knot_rrset_ttl(rrsets[i]) != test_rrsets[i].ttl) { + errors++; + diag("Got wrong value for ttl from rrset."); + } + } + return errors; +} + +static int test_rrset_ret_rdata(knot_rrset_t **rrsets) +{ + int errors = 0; + + knot_rrtype_descriptor_t *desc; + + for (int i = 0; i < TEST_RRSETS; i++) { + + desc = knot_rrtype_descriptor_by_type(rrsets[i]->type); + assert(desc); + +// knot_rdata_dump(test_rrsets[i].rdata, 1); + // knot_rdata_dump(rrsets[i]->rdata, 1); + + if (knot_rdata_compare(knot_rrset_rdata(rrsets[i]), + test_rrsets[i].rdata, + desc->wireformat)) { + errors++; + diag("Got wrong value for rdata from rrset."); + } + } + return errors; +} + +static int test_rrset_get_rdata(knot_rrset_t **rrsets) +{ + int errors = 0; + + knot_rrtype_descriptor_t *desc; + + for (int i = 0; i < TEST_RRSETS; i++) { + desc = knot_rrtype_descriptor_by_type(rrsets[i]->type); + assert(desc); + if (knot_rdata_compare(knot_rrset_get_rdata(rrsets[i]), + test_rrsets[i].rdata, + desc->wireformat)) { + errors++; + diag("Got wrong value for rdata from rrset. (Get)"); + } + } + return errors; +} + +static int test_rrset_ret_rrsigs(knot_rrset_t **rrsets) +{ + int errors = 0; + + for (int i = 0; i < TEST_RRSETS; i++) { + /* TODO should I test the insides of structure as well? */ + if (knot_rrset_rrsigs(rrsets[i]) != test_rrsets[i].rrsigs) { + errors++; + diag("Got wrong value for rrsigs from rrset."); + } + } + return errors; +} + +static int test_rrset_getters(uint type) +{ + int errors = 0; + + knot_rrset_t *rrsets[TEST_RRSETS]; + + for (int i = 0; i < TEST_RRSETS; i++) { + knot_dname_t *owner = knot_dname_new_from_str( + test_rrsets[i].owner, + strlen(test_rrsets[i].owner), + NODE_ADDRESS); + if (owner == NULL) { + diag("Error creating owner domain name!"); + return 0; + } + rrsets[i] = knot_rrset_new(owner, + test_rrsets[i].type, + test_rrsets[i].rclass, + test_rrsets[i].ttl); + + knot_rrset_add_rdata(rrsets[i], test_rrsets[i].rdata); + } + + switch (type) { + case 0: { + errors += test_rrset_owner(rrsets); + break; + } + case 1: { + errors += test_rrset_type(rrsets); + break; + } + case 2: { + errors += test_rrset_class(rrsets); + break; + } + case 3: { + errors += test_rrset_ttl(rrsets); + break; + } + case 4: { + errors += test_rrset_ret_rdata(rrsets); + break; + } + case 5: { + errors += test_rrset_get_rdata(rrsets); + break; + } + case 6: { + errors += test_rrset_ret_rrsigs(rrsets); + break; + } + } /* switch */ + + for (int i = 0; i < TEST_RRSETS; i++) { + knot_dname_free(&rrsets[i]->owner); + knot_rrset_free(&rrsets[i]); + } + + + return (errors == 0); +} + +static int test_rrset_deep_free() +{ + /*!< \warning Cannot be run when some rdata are on stack! */ + int errors = 0; + + knot_rrset_t *tmp_rrset; + knot_dname_t *owner; + for (int i = 0; i < TEST_RRSETS; i++) { + owner = knot_dname_new_from_str( + test_rrsets[i].owner, + strlen(test_rrsets[i].owner), + NODE_ADDRESS); + if (owner == NULL) { + diag("Error creating owner domain name!"); + return 0; + } + + tmp_rrset = knot_rrset_new(owner, + test_rrsets[i].type, + test_rrsets[i].rclass, + test_rrsets[i].ttl); + + knot_rrset_add_rdata(tmp_rrset, test_rrsets[i].rdata); + + knot_rrset_deep_free(&tmp_rrset, 1, 1, 0); + + errors += (tmp_rrset != NULL); + } + + return (errors == 0); +} + +/*----------------------------------------------------------------------------*/ + +static const int KNOT_RRSET_TEST_COUNT = 13; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_rrset_tests_count(int argc, char *argv[]) +{ + return KNOT_RRSET_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_rrset_tests_run(int argc, char *argv[]) +{ + int res = 0, + res_final = 1; + +/* for (int i = 0; i < 4; i++) { + knot_rdata_dump(&RR_RDATA[i], 2, 1); + printf("%p %p\n", &RR_RDATA[i], (&RR_RDATA)[i]->next); + } */ + + create_rdata(); + + res = test_rrset_create(); + ok(res, "rrset: create"); + res_final *= res; + + skip(!res, 11); + + todo(); + + ok(res = test_rrset_delete(), "rrset: delete"); + //res_final *= res; + + endtodo; + + ok(res = test_rrset_getters(0), "rrset: owner"); + res_final *= res; + + ok(res = test_rrset_getters(1), "rrset: type"); + res_final *= res; + + ok(res = test_rrset_getters(2), "rrset: class"); + res_final *= res; + + ok(res = test_rrset_getters(3), "rrset: ttl"); + res_final *= res; + + ok(res = test_rrset_getters(4), "rrset: rdata"); + res_final *= res; + + ok(res = test_rrset_getters(5), "rrset: get rdata"); + res_final *= res; + + ok(res = test_rrset_getters(6), "rrset: rrsigs"); + res_final *= res; + + ok(res = test_rrset_add_rdata(), "rrset: add_rdata"); + res_final *= res; + + ok(res = test_rrset_rrsigs(), "rrset: rrsigs manipulation"); + res_final *= res; + + ok(res = test_rrset_merge(), "rrset: rdata merging"); + res_final *= res; + + ok(res = test_rrset_deep_free(), "rrset: deep free"); + res_final *= res; + + endskip; /* !res_create */ + + return res_final; +} diff --git a/src/tests/libknot/libknot/rrset_tests.h b/src/tests/libknot/libknot/rrset_tests.h new file mode 100644 index 0000000..b0787d6 --- /dev/null +++ b/src/tests/libknot/libknot/rrset_tests.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file rrset_tests.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * Contains unit tests for RRSet (knot_rrset_t) and its API. + * + * Contains tests for: + * - + */ +#ifndef _KNOTD_RRSET_TESTS_H_ +#define _KNOTD_RRSET_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api rrset_tests_api; + +#endif /* _KNOTD_RRSET_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/zone_tests.c b/src/tests/libknot/libknot/zone_tests.c new file mode 100644 index 0000000..2fdd61a --- /dev/null +++ b/src/tests/libknot/libknot/zone_tests.c @@ -0,0 +1,853 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "tests/libknot/libknot/zone_tests.h" +#include "libknot/common.h" +#include "libknot/zone/dname-table.h" +#include "libknot/zone/zone.h" +#include "libknot/util/error.h" +#include "libknot/zone/node.h" + +static int knot_zone_tests_count(int argc, char *argv[]); +static int knot_zone_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api zone_tests_api = { + "DNS library - zone", //! Unit name + &knot_zone_tests_count, //! Count scheduled tests + &knot_zone_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +enum { TEST_NODES_GOOD = 7, TEST_NODES_BAD = 1, TRAVERSAL_TYPES = 3}; + +struct zone_test_node { + knot_dname_t owner; + knot_node_t *parent; +}; + +static struct zone_test_node test_apex = +{{{}, (uint8_t *)"\3com\0", 5, (uint8_t *)"\x0", 1}, (knot_node_t *)NULL}; + +static struct zone_test_node test_nodes_bad[TEST_NODES_BAD] = { + {{{},(uint8_t *)"\5other\6domain\0", 14, (uint8_t *)"\x0\x6", 2}, + (knot_node_t *)NULL} +}; + +static struct zone_test_node test_nodes_good[TEST_NODES_GOOD] = { + {{{}, (uint8_t *)"\7example\3com\0", 13, (uint8_t *)"\x0\x8", 2}, + (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\3www\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3}, + (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\7another\6domain\3com\0", 20, (uint8_t *)"\x0\x8\xF", 3}, + (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\5mail1\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3}, + (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\5mail2\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3}, + (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\3smb\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3}, + (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\4smtp\7example\3com\0", 18, (uint8_t *)"\x0\x5\xD", 3}, + (knot_node_t *)NULL}, +}; + +static int test_zone_check_node(const knot_node_t *node, + const struct zone_test_node *test_node, + int test_parent) +{ + return (node->owner == &test_node->owner) && + ((test_parent) ? node->parent == test_node->parent : 1); +} + +static int test_zone_create(knot_zone_contents_t **zone) +{ +// knot_dname_t *dname = knot_dname_new_from_wire( +// test_apex.owner.name, test_apex.owner.size, NULL); +// assert(dname); + + knot_node_t *node = knot_node_new(&test_apex.owner, + test_apex.parent, 0); + if (node == NULL) { + diag("zone: Could not create zone apex."); + return 0; + } + + *zone = knot_zone_contents_new(node, 0, 0, NULL); + + if ((*zone) == NULL) { + diag("zone: Failed to create zone."); + knot_node_free(&node, 1, 0); + return 0; + } + + if ((*zone)->apex != node) { + diag("zone: Zone apex not set right."); + knot_node_free(&node, 1, 0); + return 0; + } + + return 1; +} + +static int test_zone_add_node(knot_zone_contents_t *zone, int nsec3) +{ + /* + * NSEC3 nodes are de facto identical to normal nodes, so there is no + * need for separate tests. The only difference is where are they stored + * in the zone structure. + */ + + int errors = 0; + int res = 0; + + //note("Good nodes"); + + for (int i = 0; i < TEST_NODES_GOOD; ++i) { + knot_node_t *node = knot_node_new(&test_nodes_good[i].owner, + test_nodes_good[i].parent, 0); + if (node == NULL) { + diag("zone: Could not create node."); + return 0; + } + + if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, node, 0, 0, 0) + : knot_zone_contents_add_node(zone, node, 0, 0, 0))) != 0) { + diag("zone: Failed to insert node into zone (returned" + " %d).", res); + knot_node_free(&node, 0, 0); + ++errors; + } + /* TODO check values in the node as well */ + } + + //note("Bad nodes"); + + for (int i = 0; i < TEST_NODES_BAD; ++i) { + knot_node_t *node = knot_node_new(&test_nodes_bad[i].owner, + test_nodes_bad[i].parent, 0); + if (node == NULL) { + diag("zone: Could not create node."); + return 0; + } + + if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, node, 0, 0, 0) + : knot_zone_contents_add_node(zone, node, 0, 0, 0))) != + KNOT_EBADZONE) { + diag("zone: Inserting wrong node did not result in" + "proper return value (%d instead of %d).", res, + KNOT_EBADZONE); + ++errors; + } + knot_node_free(&node, 0, 0); + } + + //note("NULL zone"); + + note("Inserting into NULL zone...\n"); + + knot_node_t *node = knot_node_new(&test_nodes_good[0].owner, + test_nodes_good[0].parent, 0); + if (node == NULL) { + diag("zone: Could not create node."); + return 0; + } + + if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(NULL, node, 0, 0, 0) + : knot_zone_contents_add_node(NULL, node, 0, 0, 0))) != KNOT_EBADARG) { + diag("zone: Inserting node to NULL zone did not result in" + "proper return value (%d instead of %d)", res, + KNOT_EBADARG); + ++errors; + } + + knot_node_free(&node, 0, 0); + + //note("NULL node"); + note("Inserting NULL node...\n"); + + if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, NULL, 0, 0, 0) + : knot_zone_contents_add_node(zone, NULL, 0, 0, 0))) != KNOT_EBADARG) { + diag("zone: Inserting NULL node to zone did not result in" + "proper return value (%d instead of %d)", res, + KNOT_EBADARG); + ++errors; + } + + if (!nsec3) { + //note("Inserting Apex again...\n"); + + node = knot_node_new(&test_apex.owner, test_apex.parent, 0); + if (node == NULL) { + diag("zone: Could not create node."); + return 0; + } + + //note("Apex again"); + + if ((res = knot_zone_contents_add_node(zone, node, 0, 0, 0)) != + KNOT_EBADZONE) { + diag("zone: Inserting zone apex again did not result in" + "proper return value (%d instead of -2)", + KNOT_EBADZONE); + ++errors; + } + + knot_node_free(&node, 0, 0); + } + + // check if all nodes are inserted + //int nodes = 0; + if (!nsec3 + && !test_zone_check_node(knot_zone_contents_apex(zone), &test_apex, !nsec3)) { + diag("zone: Apex of zone not right."); +// diag("Apex owner: %s (%p), apex parent: %p\n", +// knot_dname_to_str(knot_zone_apex(zone)->owner), +// knot_zone_apex(zone)->owner, +// knot_zone_apex(zone)->parent); +// diag("Should be: owner: %s (%p), parent: %p\n", +// knot_dname_to_str(&test_apex.owner), +// &test_apex.owner, +// test_apex.parent); + ++errors; + } + //++nodes; + for (int i = 0; i < TEST_NODES_GOOD; ++i) { + const knot_node_t *n = ((nsec3) ? knot_zone_contents_find_nsec3_node( + zone, &test_nodes_good[i].owner) : + knot_zone_contents_find_node(zone, &test_nodes_good[i].owner)); + if (n == NULL) { + diag("zone: Missing node with owner %s", + test_nodes_good[i].owner.name); + ++errors; + continue; + } + + if (!test_zone_check_node(n, &test_nodes_good[i], !nsec3)) { + diag("zone: Node does not match: owner: %s (should be " + "%s), parent: %p (should be %p)", + n->owner->name, test_nodes_good[i].owner.name, + n->parent, test_nodes_good[i].parent); + ++errors; + } + //++nodes; + } + + //note("zone: %d nodes in the zone (including apex)", nodes); + + return (errors == 0); +} + +static int test_zone_get_node(knot_zone_contents_t *zone, int nsec3) +{ + int errors = 0; + + for (int i = 0; i < TEST_NODES_GOOD; ++i) { + if (((nsec3) ? knot_zone_contents_get_nsec3_node( + zone, &test_nodes_good[i].owner) + : knot_zone_contents_get_node(zone, &test_nodes_good[i].owner)) + == NULL) { + diag("zone: Node (%s) not found in zone.", + (char *)test_nodes_good[i].owner.name); + ++errors; + } + } + + for (int i = 0; i < TEST_NODES_BAD; ++i) { + if (((nsec3) ? knot_zone_contents_get_nsec3_node( + zone, &test_nodes_bad[i].owner) + : knot_zone_contents_get_node(zone, &test_nodes_bad[i].owner)) + != NULL) { + diag("zone: Node (%s) found in zone even if it should" + "not be there.", + (char *)test_nodes_bad[i].owner.name); + ++errors; + } + } + + if (((nsec3) + ? knot_zone_contents_get_nsec3_node(NULL, &test_nodes_good[0].owner) + : knot_zone_contents_get_node(NULL, &test_nodes_good[0].owner)) != NULL) { + diag("zone: Getting node from NULL zone did not result in" + "proper return value (NULL)"); + ++errors; + } + + if (((nsec3) ? knot_zone_contents_get_nsec3_node(zone, NULL) + : knot_zone_contents_get_node(zone, NULL)) != NULL) { + diag("zone: Getting node with NULL owner from zone did not " + "result in proper return value (NULL)"); + ++errors; + } + + if (!nsec3 && knot_zone_contents_get_node(zone, &test_apex.owner) == NULL) { + diag("zone: Getting zone apex from the zone failed"); + ++errors; + } + + return (errors == 0); +} + +static int test_zone_find_node(knot_zone_contents_t *zone, int nsec3) +{ + int errors = 0; + + for (int i = 0; i < TEST_NODES_GOOD; ++i) { + if (((nsec3) ? knot_zone_contents_find_nsec3_node( + zone, &test_nodes_good[i].owner) + : knot_zone_contents_find_node(zone, &test_nodes_good[i].owner)) + == NULL) { + diag("zone: Node (%s) not found in zone.", + (char *)test_nodes_good[i].owner.name); + ++errors; + } + } + + for (int i = 0; i < TEST_NODES_BAD; ++i) { + if (((nsec3) ? knot_zone_contents_find_nsec3_node( + zone, &test_nodes_bad[i].owner) + : knot_zone_contents_find_node(zone, &test_nodes_bad[i].owner)) + != NULL) { + diag("zone: Node (%s) found in zone even if it should" + "not be there.", + (char *)test_nodes_bad[i].owner.name); + ++errors; + } + } + + if (((nsec3) + ? knot_zone_contents_find_nsec3_node(NULL, &test_nodes_good[0].owner) + : knot_zone_contents_find_node(NULL, &test_nodes_good[0].owner)) != NULL) { + diag("zone: Finding node from NULL zone did not result in" + "proper return value (NULL)"); + ++errors; + } + + if (((nsec3) ? knot_zone_contents_find_nsec3_node(zone, NULL) + : knot_zone_contents_find_node(zone, NULL)) != NULL) { + diag("zone: Finding node with NULL owner from zone did not " + "result in proper return value (NULL)"); + ++errors; + } + + if (!nsec3 && knot_zone_contents_find_node(zone, &test_apex.owner) == NULL) { + diag("zone: Finding zone apex from the zone failed"); + ++errors; + } + + return (errors == 0); +} + +//static void test_zone_destroy_node_from_tree(knot_node_t *node, +// void *data) +//{ +// UNUSED(data); +// knot_node_free(&node, 0); +//} + +/* explained below */ +static size_t node_index = 0; + +/*! \brief + * This function will overwrite parent field in node structure - + * we don't (and can't, with current structures) use it in these tests anyway. + * Since zone structure itself has no count field, only option known to me + * is (sadly) to use a global variable. + */ +static void tmp_apply_function(knot_node_t *node, void *data) +{ + node->parent = (knot_node_t *)node_index; + node_index++; +} + +/* \note Since I am unaware of a way how to get a return value from traversal + * functions, I will use (hopefully for the last time here) global variable + */ + +static int compare_ok = 1; + +static void tmp_compare_function(knot_node_t *node, void *data) +{ + /* node_index will start set to zero */ + if (node->parent != (knot_node_t *)node_index) { + compare_ok = 0; + return; + } else if (!compare_ok) { + diag("Traversal function has partially set values right"); + } + node->parent = NULL; + node_index++; +} + +static int test_zone_tree_apply(knot_zone_contents_t *zone, + int type, int nsec3) +{ + + assert(node_index == 0); + assert(compare_ok == 1); + + int (*traversal_func)(knot_zone_contents_t *zone, + void (*function)(knot_node_t *node, + void *data), + void *data); + + switch (type) { + case 0: { + if (nsec3) { + traversal_func = + &knot_zone_contents_nsec3_apply_postorder; + diag("Testing postorder traversal"); + } else { + traversal_func = + &knot_zone_contents_tree_apply_postorder; + diag("Testing postorder traversal - NSEC3"); + } + break; + } + case 1: { + if (nsec3) { + traversal_func = + &knot_zone_contents_nsec3_apply_inorder; + diag("Testing inorder traversal"); + } else { + traversal_func = + &knot_zone_contents_tree_apply_inorder; + diag("Testing inorder traversal - NSEC3"); + } + break; + } + case 2: { + if (nsec3) { + traversal_func = + &knot_zone_contents_nsec3_apply_inorder_reverse; + diag("Testing inorder reverse traversal"); + } else { + traversal_func = + &knot_zone_contents_tree_apply_inorder_reverse; + diag("Testing inorder reverse " + "traversal - NSEC3"); + } + break; + } + default: { + diag("Unknown traversal function type"); + return 0; + } + } + + /* + * This will iterate through tree and set node->parent field values + * from 0 to number of nodes. + */ + + traversal_func(zone, &tmp_apply_function, NULL); + + node_index = 0; + + /* + * This will check whether the values were set accordingly. + */ + + traversal_func(zone, &tmp_compare_function, NULL); + + int ret = compare_ok; + + compare_ok = 1; + node_index = 0; + + return (ret); +} + +/* Tests all kinds of zone traversals, explainded above */ +static int test_zone_traversals(knot_zone_contents_t *zone) +{ + for (int i = 0; i < TRAVERSAL_TYPES; i++) { + for (int j = 0; j < 2; j++) { + if (!test_zone_tree_apply(zone, i, j)) { + return 0; + } + } + } + return 1; +} + +struct zone_test_param { + /* Times 2 so that we don't have to mess with mallocs. */ + knot_node_t *knot_node_array[TEST_NODES_GOOD * 5]; + knot_dname_t *table_node_array[TEST_NODES_GOOD * 5]; + size_t count; +}; + +static void tree_node_to_array(knot_node_t *node, void *data) +{ + struct zone_test_param *param = (struct zone_test_param *)data; + param->knot_node_array[param->count++] = node; +} + +static void tree_dname_node_to_array(knot_dname_t *node, + void *data) +{ + struct zone_test_param *param = (struct zone_test_param *)data; + param->table_node_array[param->count++] = node; +} + +extern int compare_wires_simple(uint8_t *w1, uint8_t *w2, uint count); +static int test_zone_shallow_copy() +{ + int errors = 0; + int lived = 0; + knot_dname_t *apex_dname = + knot_dname_new_from_str("a.ns.nic.cz.", + strlen("a.ns.nic.cz"), NULL); + assert(apex_dname); + knot_node_t *apex_node = + knot_node_new(apex_dname, NULL, 0); + assert(apex_node); + lives_ok({ + if (knot_zone_contents_shallow_copy(NULL, NULL) != KNOT_EBADARG) { + diag("Calling zone_shallow_copy with NULL " + "arguments did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + lived = 0; + knot_zone_contents_t *zone = knot_zone_contents_new(apex_node, + 0, 1, 0); + if (knot_zone_contents_shallow_copy(zone, NULL) != KNOT_EBADARG) { + diag("Calling zone_shallow_copy with NULL destination " + "zone argument did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_contents_shallow_copy(NULL, &zone) != KNOT_EBADARG) { + diag("Calling zone_shallow_copy with NULL source " + "zone argument did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_contents_shallow_copy(zone, &zone) != KNOT_EBADARG) { + diag("Calling zone_shallow_copy with identical source " + "and destination zone did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + knot_zone_contents_free(&zone); + }, "zone: shallow copy NULL tests"); + errors += lived != 1; + + knot_dname_t *d = knot_dname_deep_copy(&test_nodes_good[0].owner); + if (d == NULL) { + return 0; + } + knot_node_t *n = knot_node_new(d, NULL, 0); + + /* example.com. */ +// knot_zone_t *from_zone = +// knot_zone_new(knot_node_new(&test_nodes_good[0].owner, +// test_nodes_good[0].parent, 0), 10, 1); + knot_zone_t *from_zone = knot_zone_new(n, 10, 1); + knot_zone_contents_t *from = knot_zone_get_contents(from_zone); + + /* Add nodes to zone. */ + for (int i = 1; i < TEST_NODES_GOOD; ++i) { + knot_dname_t *d = knot_dname_deep_copy(&test_nodes_good[i].owner); + if (d == NULL) { + return 0; + } + knot_node_t *node = knot_node_new(d, test_nodes_good[i].parent, + 0); + if (node == NULL) { + diag("zone: Could not create node."); + return 0; + } + + if (knot_zone_contents_add_node(from, node, 1, 1, 1) != KNOT_EOK) { + diag("zone: Could not add node. %s", + knot_dname_to_str(node->owner)); +// return 0; + } + } + + /* Make a copy of zone */ + knot_zone_contents_t *to = NULL; + int ret = 0; + if ((ret = knot_zone_contents_shallow_copy(from, &to) != KNOT_EOK)) { + diag("Could not copy zone! %s", knot_strerror(ret)); + return 0; + } + + assert(to); + + /* Compare non-tree parts of the zone. */ +// if (from->data != to->data) { +// diag("Zone data field wrong after shallow copy!"); +// errors++; +// } + +// if (from->dtor != to->dtor) { +// diag("Zone data destructor field wrong after shallow copy!"); +// errors++; +// } + + if (from->node_count != to->node_count) { + diag("Zone node count data field wrong after shallow copy!"); + errors++; + } + +// if (from->version != to->version) { +// diag("Zone version data field wrong after shallow copy!"); +// errors++; +// } + + if (from->apex != to->apex) { + diag("Zone apex differ after shallow copy!"); + } + + if (compare_wires_simple((uint8_t *)(&from->nsec3_params), + (uint8_t *)(&to->nsec3_params), + sizeof(from->nsec3_params)) != 0) { + diag("Nsec3_params data field wrong after shallow copy!"); + errors++; + } + + if (from->nodes == to->nodes) { + diag("Copied zones have identical trees!"); + errors++; + } + + if (from->nsec3_nodes == to->nsec3_nodes) { + diag("Copied zones have identical trees!"); + errors++; + } + + /* Compare nodes, convert tree to array then compare those arrays. */ + struct zone_test_param param1; + memset(¶m1, 0, sizeof(struct zone_test_param)); + + knot_zone_contents_tree_apply_inorder(from, tree_node_to_array, + (void *)¶m1); + + struct zone_test_param param2; + memset(¶m2, 0, sizeof(struct zone_test_param)); + + knot_zone_contents_tree_apply_inorder(to, tree_node_to_array, + (void *)¶m2); + + if (param1.count != param2.count) { + diag("wrong tree"); + return 0; + } + + for (int i = 0; i < param1.count; i++) { + if (param1.knot_node_array[i] != + param2.knot_node_array[i]) { + diag("wrong tree"); + return 0; + } + } + + param1.count = 0; + knot_dname_table_tree_inorder_apply(from->dname_table, + tree_dname_node_to_array, + (void *)¶m1); + + param2.count = 0; + knot_dname_table_tree_inorder_apply(to->dname_table, + tree_dname_node_to_array, + (void *)¶m2); + + if (param1.count != param2.count) { + diag("wrong table count"); + return 0; + } + + for (int i = 0; i < param1.count; i++) { + if (param1.table_node_array[i] != param2.table_node_array[i]) { + diag("wrong table nodes"); + errors++; + } + } + +#ifdef USE_HASH_TABLE + if (from->table) { + if (from->table == to->table) { + diag("hash tables after shallow copy are identical!"); + return 0; + } + uint i; + if (hashsize(from->table->table_size_exp) != + hashsize(to->table->table_size_exp)) { + diag("hash tables after shallow copy error!"); + return 0; + } + + if (from->table->table_count != to->table->table_count) { + diag("hash tables after shallow copy error!"); + return 0; + } + + for (uint t = 0; t < from->table->table_count; ++t) { + for (i = 0; i < + hashsize(from->table->table_size_exp); i++) { + if (from->table->tables[t][i] == NULL) { + if (to->table->tables[t][i] != NULL) { + diag("hash table item error"); + } + continue; + } + if ((from->table->tables[t])[i]->key_length != + (to->table->tables[t])[i]->key_length) { + diag("hash table key lengths error!"); + return 0; + } + if ((from->table->tables[t])[i]->key != + (to->table->tables[t])[i]->key) { + diag("hash table key error!"); + return 0; + } + if ((from->table->tables[t])[i]->value != + (to->table->tables[t])[i]->value) { + diag("hash table value error!"); + return 0; + } + } + } + + ck_stash_item_t *item1 = from->table->stash; + ck_stash_item_t *item2 = to->table->stash; + while (item1 != NULL && item2 != NULL) { + if (item1->item->key_length != + item2->item->key_length) { + diag("hash stash key length error!"); + return 0; + } + if (item1->item->key != item2->item->key) { + diag("hash stash key error!"); + return 0; + } + if (item1->item->value != item2->item->value) { + diag("hash stash value error!"); + return 0; + } + + item1 = item1->next; + item2 = item2->next; + } + } else { + if (to->table) { + diag("Hash table is not set to NULL " + "after shallow copy!"); + errors++; + } + } +#endif + +// knot_zone_deep_free(&from_zone, 0); +// knot_zone_contents_free(&to); + return (errors == 0); + +} + +//static int test_zone_free(knot_zone_t **zone) +//{ +// knot_zone_tree_apply_postorder(*zone, +// test_zone_destroy_node_from_tree, +// NULL); +// knot_zone_nsec3_apply_postorder(*zone, +// test_zone_destroy_node_from_tree, +// NULL); +// knot_zone_free(zone); +// return (*zone == NULL); +//} + +static const int KNOT_ZONE_TEST_COUNT = 10; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_zone_tests_count(int argc, char *argv[]) +{ + return KNOT_ZONE_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_zone_tests_run(int argc, char *argv[]) +{ + int res = 0, + res_final = 0; + + knot_zone_contents_t *zone = NULL; + + ok((res = test_zone_create(&zone)), "zone: create"); + res_final *= res; + + skip(!res, 6); + + ok((res = test_zone_add_node(zone, 0)), "zone: add node"); + res_final *= res; + + skip(!res, 2); + + ok((res = test_zone_get_node(zone, 0)), "zone: get node"); + res_final *= res; + + skip(!res, 1); + + ok((res = test_zone_find_node(zone, 0)), "zone: find node"); + res_final *= res; + + endskip; // get node failed + + endskip; // add node failed + + ok((res = test_zone_add_node(zone, 1)), "zone: add nsec3 node"); + res_final *= res; + + skip(!res, 2); + + ok((res = test_zone_get_node(zone, 1)), "zone: get nsec3 node"); + res_final *= res; + + skip(!res, 1); + + ok((res = test_zone_find_node(zone, 1)), "zone: find nsec3 node"); + res_final *= res; + + endskip; // get nsec3 node failed + + endskip; // add nsec3 node failed + + ok(res = test_zone_traversals(zone), "zone: traversals"); + res_final *= res; + + ok((res = test_zone_shallow_copy()), "zone: shallow copy"); + res_final *= res; + +// ok((res = test_zone_free(&zone)), "zone: free"); +// res_final *= res; + + endskip; // create failed + + return res_final; +} diff --git a/src/tests/libknot/libknot/zone_tests.h b/src/tests/libknot/libknot/zone_tests.h new file mode 100644 index 0000000..5539709 --- /dev/null +++ b/src/tests/libknot/libknot/zone_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_ZONE_TESTS_H_ +#define _KNOTD_ZONE_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api zone_tests_api; + +#endif /* _KNOTD_ZONE_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/zone_tree_tests.c b/src/tests/libknot/libknot/zone_tree_tests.c new file mode 100644 index 0000000..c26746e --- /dev/null +++ b/src/tests/libknot/libknot/zone_tree_tests.c @@ -0,0 +1,758 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <assert.h> + +#include "tests/libknot/libknot/zone_tree_tests.h" +#include "libknot/zone/zone-tree.h" +#include "libknot/util/error.h" + +static int knot_zone_tree_tests_count(int argc, char *argv[]); +static int knot_zone_tree_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api zone_tree_tests_api = { + "DNS library - zone tree", //! Unit name + &knot_zone_tree_tests_count, //! Count scheduled tests + &knot_zone_tree_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +static int test_tree_init() +{ + int errors = 0; + int lived = 0; + + lives_ok({ + if (knot_zone_tree_init(NULL) != KNOT_EBADARG) { + diag("Calling knot_zone_tree_init with NULL " + "tree did not return KNOT_EBADARG!"); + errors++; + } + lived = 1; + }, "zone tree: init NULL tests"); + errors += lived != 1; + + return (errors == 0); +} + +static int test_tree_insert() +{ + int errors = 0; + int lived = 0; + + knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t)); + assert(tree); + knot_zone_tree_init(tree); + knot_node_t *node = + knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.", + strlen("a.ns.nic.cz."), + NULL), + NULL, 0); + assert(node); + + lives_ok({ + if (knot_zone_tree_insert(NULL, NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_insert(tree, NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_insert(NULL, node) != KNOT_EBADARG) { + errors++; + } + lived = 1; + }, "zone tree: insert NULL tests"); + if (errors) { + diag("Zone tree insert did not return KNOT_EBADARG " + "when given wrong arguments"); + } + errors += lived != 1; + + if (knot_zone_tree_insert(tree, node) != KNOT_EOK) { + diag("Calling zone tree insert with valid arguments " + "did not return KNOT_EOK"); + errors++; + } + + /* Sorting will be tested in traversal functions. */ + return (errors == 0); +} + +static int test_tree_finding() +{ + int errors = 0; + int lived = 0; + + knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t)); + assert(tree); + knot_zone_tree_init(tree); + const knot_node_t *node = + knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.", + strlen("a.ns.nic.cz."), + NULL), + NULL, 0); + assert(node); + + lives_ok({ + if (knot_zone_tree_find(NULL, NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_find(tree, NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_find(tree, node->owner, + NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + const knot_node_t *found_node = NULL; + lived = 0; + if (knot_zone_tree_find(NULL, node->owner, + &found_node) != KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_find(tree, NULL, + &found_node) != KNOT_EBADARG) { + errors++; + } + lived = 1; + }, "zone tree: find NULL tests"); + if (errors) { + diag("Zone tree find did not return KNOT_EBADARG " + "when given wrong arguments"); + } + + errors += lived != 1; + + /* Insert node */ + assert(knot_zone_tree_insert(tree, (knot_node_t *)node) == KNOT_EOK); + + knot_node_t *found_node = NULL; + if (knot_zone_tree_find(tree, node->owner, + (const knot_node_t **)&found_node) != + KNOT_EOK) { + diag("Calling zone tree find with valid arguments did " + "not return KNOT_EOK"); + errors++; + } + + if (found_node != node) { + diag("Zone tree find did not return right node"); + errors++; + } + + if (knot_zone_tree_get(tree, node->owner, &found_node) != + KNOT_EOK) { + diag("Calling zone tree get with valid arguments did " + "not return KNOT_EOK"); + errors++; + } + + if (found_node != node) { + diag("Zone tree get did not return right node"); + errors++; + } + + /* Try to search for node not in tree. */ + knot_dname_t *alien_dname = + knot_dname_new_from_str("this.name.is.not.in.the.tree.", + strlen("this.name.is.not.in.the.tree."), + NULL); + + if (knot_zone_tree_find(tree, alien_dname, + (const knot_node_t **)&found_node) != + KNOT_EOK) { + diag("Calling zone tree find with valid arguments did " + "not return KNOT_EOK"); + errors++; + } + + if (found_node != NULL) { + diag("Zone tree find returned node that was not in the tree!"); + errors++; + } + + if (knot_zone_tree_get(tree, alien_dname, &found_node) != + KNOT_EOK) { + diag("Calling zone tree get with valid arguments did " + "not return KNOT_EOK"); + errors++; + } + + if (found_node != NULL) { + diag("Zone tree get returned node that was not in the tree!"); + errors++; + } + + return (errors == 0); +} + +static int test_tree_finding_less_or_equal() +{ + diag("Issue nr.: 1145"); + int errors = 0; + int lived = 0; + + knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t)); + assert(tree); + knot_zone_tree_init(tree); + const knot_node_t *node = + knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.", + strlen("a.ns.nic.cz"), + NULL), + NULL, 0); + assert(node); + + lives_ok({ + if (knot_zone_tree_find_less_or_equal(NULL, + NULL, + NULL, + NULL, 0) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_find_less_or_equal(tree, NULL, + NULL, NULL, 0) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_find_less_or_equal(tree, + node->owner, + NULL, + NULL, 0) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + const knot_node_t *found_node = NULL; + lived = 0; + if (knot_zone_tree_find_less_or_equal(NULL, node->owner, + &found_node, NULL, 0) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + const knot_node_t *previous_node = NULL; + lived = 0; + if (knot_zone_tree_find_less_or_equal(tree, NULL, + &found_node, + &previous_node, 0) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + }, "zone tree: tree find less or equal NULL tests"); + if (errors) { + diag("Zone tree find did not return KNOT_EBADARG " + "when given wrong arguments"); + } + + if (!lived) { + errors++; + } + + const knot_node_t *previous_node = NULL; + + /* Insert node - exact match. */ + assert(knot_zone_tree_insert(tree, (knot_node_t *)node) == KNOT_EOK); + + + const knot_node_t *found_node = NULL; + if (knot_zone_tree_find_less_or_equal(tree, + node->owner, + &found_node, + &previous_node, 0) <= 0) { + diag("Calling zone tree find less with valid arguments did " + "not return KNOT_EOK"); + errors++; + } + + if (found_node != node) { + diag("Zone tree find did not return right node"); + errors++; + } + + if (knot_zone_tree_get_less_or_equal(tree, node->owner, + (knot_node_t **)&found_node, + (knot_node_t **)&previous_node, 0) <= + 0) { + diag("Calling zone tree get less with valid arguments did " + "not return KNOT_EOK"); + errors++; + } + + if (found_node != node) { + diag("Zone tree get less did not return right node"); + errors++; + } + + knot_dname_t *less_dname = + knot_dname_new_from_str("ns.nic.cz.", + strlen("ns.nic.cz."), + NULL); + + assert(knot_dname_compare(less_dname, node->owner) < 0); + + if (knot_zone_tree_find_less_or_equal(tree, + less_dname, + &found_node, + &previous_node, 0) <= 0) { + diag("Calling zone tree find less or equal " + "with valid arguments did " + "not return > 0"); + errors++; + } + + if (found_node != node) { + diag("Zone tree find less or equal did not return right node"); + errors++; + } + + if (knot_zone_tree_get_less_or_equal(tree, less_dname, + (knot_node_t **)&found_node, + (knot_node_t **)&previous_node, 0) <= + 0) { + diag("Calling zone tree less or equal with valid arguments did " + "not return > 0"); + errors++; + } + + if (found_node != node) { + diag("Zone tree get less or equal did not return right node"); + errors++; + } + + /* Try to search for node not in tree. */ + knot_dname_t *alien_dname = + knot_dname_new_from_str("this.name.is.not.in.the.tree.", + strlen("this.name.is.not.in.the.tree."), + NULL); + + if (knot_zone_tree_find_less_or_equal(tree, alien_dname, + &found_node, + &previous_node, 0) != + 0) { + diag("Calling zone tree find less with valid arguments did " + "not return 0"); + errors++; + } + + if (knot_zone_tree_get_less_or_equal(tree, + alien_dname, + (knot_node_t **)&found_node, + (knot_node_t **)&previous_node, 0) != + 0) { + diag("Calling zone tree get with valid arguments did " + "not return 0"); + errors++; + } + + /* Set node previous label. */ + knot_node_t *tmp_node = + knot_node_new(knot_dname_new_from_str("ns.nic.cz.", + strlen("ns.nic.cz"), + NULL), NULL, 0); + assert(tmp_node); + knot_node_set_parent((knot_node_t *)node, tmp_node); + + if (knot_zone_tree_find_less_or_equal(tree, node->owner, + &found_node, + &previous_node, 0) <= + 0) { + diag("Calling zone tree find with valid arguments did " + "not return > 0"); + errors++; + } + + if (found_node != node || previous_node != tmp_node) { + diag("Zone tree find did not return valid nodes!"); + errors++; + } + + + if (knot_zone_tree_get_less_or_equal(tree, node->owner, + (knot_node_t **)&found_node, + (knot_node_t **)&previous_node, 0) <= + 0) { + diag("Calling zone tree get with valid arguments did " + "not return > 0"); + errors++; + } + + if (found_node != node || previous_node != tmp_node) { + diag("Zone get find did not return valid nodes!"); + errors++; + } + + return (errors == 0); +} + +static int test_tree_remove() +{ + int errors = 0; + int lived = 0; + + knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t)); + assert(tree); + knot_zone_tree_init(tree); + knot_node_t *node = + knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.", + strlen("a.ns.nic.cz"), + NULL), + NULL, 0); + assert(node); + + /* Add node. */ + int ret = knot_zone_tree_insert(tree, node); + assert(ret == 0); + assert(ret == 0); + + lives_ok({ + if (knot_zone_tree_remove(NULL, NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_remove(tree, NULL, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_remove(tree, node->owner, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_remove(NULL, node->owner, NULL) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + knot_zone_tree_node_t *deleted_node = NULL; + lived = 0; + if (knot_zone_tree_remove(NULL, node->owner, &deleted_node) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_remove(tree, NULL, &deleted_node) != + KNOT_EBADARG) { + errors++; + } + lived = 1; + }, "zone tree: remove NULL tests"); + if (errors) { + diag("Zone tree remove did not return KNOT_EBADARG " + "when given wrong arguments"); + } + + errors += lived != 1; + + knot_zone_tree_node_t *removed_node = NULL; + + /* Remove previously inserted node. */ + if (knot_zone_tree_remove(tree, node->owner, &removed_node) != + KNOT_EOK) { + diag("Could not remove previously inserted node!"); + errors++; + } + + if (removed_node == NULL || removed_node->node != node) { + diag("Wrong node was removed!"); + errors++; + } + + /* + * Try remove the node again - it should not be there and + * removed_node should be NULL. + */ + + if (knot_zone_tree_remove(tree, node->owner, &removed_node) != + KNOT_EOK) { + diag("Could not remove previously inserted node!"); + errors++; + } + + if (removed_node != NULL) { + diag("Zone tree remove returned previously removed node!"); + errors++; + } + + return (errors == 0); + +} + +struct test_zone_tree_args { + knot_node_t *array[10 * 1024]; + size_t count; +}; + +static void add_to_array(knot_zone_tree_node_t *node, void *data) +{ + struct test_zone_tree_args *args = + (struct test_zone_tree_args *)data; + args->array[args->count++] = node->node; +} + +static int test_traversal(knot_node_t **nodes, + size_t node_count, + uint code) +{ + int errors = 0; + int lived = 0; + + int (*trav_func)(knot_zone_tree_t *, + void (*)(knot_zone_tree_node_t *, void *), + void *); + + trav_func = (code) ? knot_zone_tree_reverse_apply_inorder : + knot_zone_tree_forward_apply_inorder; + + knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t)); + assert(tree); + knot_zone_tree_init(tree); + + lives_ok({ + if (trav_func(NULL, NULL, NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (trav_func(tree, NULL, NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (trav_func(NULL, add_to_array, NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + }, "zone tree: traversal NULL tests"); + + if (errors) { + diag("Traversal function did not return KNOT_EBADARG " + "when given NULL parameters"); + } + + errors += lived != 1; + + /* Add nodes to tree. */ + for (int i = 0; i < node_count; i++) { + assert(knot_zone_tree_insert(tree, nodes[i]) == KNOT_EOK); + } + + struct test_zone_tree_args args; + args.count = 0; + + trav_func(tree, add_to_array, &args); + + if (args.count != node_count) { + diag("Traversal function traversed more nodes than it " + "should have!"); + return ++errors; + } + + for (int i = 0; i < node_count; i++) { + int match = nodes[i] == args.array[i]; + if (!match) { + diag("Traversal function returned nodes in wrong " + "order!"); + errors++; + } + } + + return errors; +} + +static int test_tree_traversals() +{ + /*!< \todo I can test inorder and reverse inorder, but I don't know + * how to test others. It is somehow tested in zone tests. */ + int errors = 0; + + /* Create few nodes. (5 should be enough) */ + knot_node_t *nodes[5]; + for (int i = 0; i < 5; i++) { + char owner_string[20]; + owner_string[0] = i + '0'; + memcpy(owner_string + 1, ".ns.test.cz.", + strlen(".ns.test.cz.") + 1); + nodes[i] = + knot_node_new(knot_dname_new_from_str(owner_string, + strlen(owner_string), + NULL), NULL, 0); + } + + if (test_traversal(nodes, 5, 0)) { + diag("Inorder traversal failed"); + errors++; + } + + for (int i = 0; i < 5; i++) { + char owner_string[20]; + owner_string[0] = (5 - i) + '0'; + memcpy(owner_string + 1, ".ns.test.cz.", + strlen(".ns.test.cz.") + 1); + nodes[i] = + knot_node_new(knot_dname_new_from_str(owner_string, + strlen(owner_string), + NULL), NULL, 0); + } + + if (test_traversal(nodes, 5, 1)) { + diag("Reverse inorder traversal failed"); + errors++; + } + + return (errors == 0); +} + +static int test_tree_shallow_copy() +{ + int errors = 0; + int lived = 0; + + knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t)); + assert(tree); + knot_zone_tree_init(tree); + + lives_ok({ + if (knot_zone_tree_shallow_copy(NULL, NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_shallow_copy(tree, NULL) != KNOT_EBADARG) { + errors++; + } + lived = 1; + lived = 0; + if (knot_zone_tree_shallow_copy(NULL, tree) != KNOT_EBADARG) { + errors++; + } + lived = 1; + }, "zone tree: shallow copy NULL tests"); + if (errors) { + diag("Zone tree shallow copy did not return KNOT_EBADARG when " + "given NULL arguments"); + } + errors += lived != 1; + + /* Create few nodes. (5 should be enough) */ + knot_node_t *nodes[5]; + for (int i = 0; i < 5; i++) { + char owner_string[20]; + owner_string[0] = i + '0'; + memcpy(owner_string + 1, ".ns.test.cz.", + strlen(".ns.test.cz.") + 1); + nodes[i] = + knot_node_new(knot_dname_new_from_str(owner_string, + strlen(owner_string), + NULL), NULL, 0); + /* Insert node to tree. */ + assert(knot_zone_tree_insert(tree, nodes[i]) == KNOT_EOK); + } + + /* Create shallow copy. */ + knot_zone_tree_t *new_tree = malloc(sizeof(knot_zone_tree_t)); + assert(new_tree); + knot_zone_tree_init(new_tree); + + if (knot_zone_tree_shallow_copy(tree, new_tree) != KNOT_EOK) { + diag("Zone tree shallow copy did not return KNOT_EOK " + "when executed with valid parameters"); + return 0; + } + + /* Traverse the tree twice and check that arrays are the same. */ + struct test_zone_tree_args args1; + args1.count = 0; + + knot_zone_tree_forward_apply_inorder(tree, add_to_array, + &args1); + + + struct test_zone_tree_args args2; + args2.count = 0; + knot_zone_tree_forward_apply_inorder(new_tree, add_to_array, + &args2); + + if (args1.count != args2.count) { + diag("Zone tree created by shallow copy has wrong count" + "of nodes"); + return 0; + } + + for (int i = 0; i < args1.count; i++) { + if (args1.array[i] != args2.array[i]) { + diag("Zone tree created by shallow copy has wrong " + "nodes"); + errors++; + } + } + + return (errors == 0); + +} + + +static const int KNOT_ZONE_TREE_TEST_COUNT = 14; + +static int knot_zone_tree_tests_count(int argc, char *argv[]) +{ + return KNOT_ZONE_TREE_TEST_COUNT; +} + +static int knot_zone_tree_tests_run(int argc, char *argv[]) +{ + ok(test_tree_init(), "zone tree: init"); + ok(test_tree_insert(), "zone tree: insertion"); + ok(test_tree_finding(), "zone tree: finding"); + todo(); + ok(test_tree_finding_less_or_equal(), "zone tree: find less or equal"); + endtodo; + ok(test_tree_remove(), "zone tree: removal"); + ok(test_tree_traversals(), "zone tree: traversals"); + ok(test_tree_shallow_copy(), "zone tree: shallow copy"); + + return 1; +} diff --git a/src/tests/libknot/libknot/zone_tree_tests.h b/src/tests/libknot/libknot/zone_tree_tests.h new file mode 100644 index 0000000..4cea88c --- /dev/null +++ b/src/tests/libknot/libknot/zone_tree_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTDZONE_TREE_TESTS_H_ +#define _KNOTDZONE_TREE_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api zone_tree_tests_api; + +#endif /* _KNOTDZONE_TREE_TESTS_H_ */ diff --git a/src/tests/libknot/libknot/zonedb_tests.c b/src/tests/libknot/libknot/zonedb_tests.c new file mode 100644 index 0000000..7b45587 --- /dev/null +++ b/src/tests/libknot/libknot/zonedb_tests.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "tests/libknot/libknot/zonedb_tests.h" + + +static int zonedb_tests_count(int argc, char *argv[]); +static int zonedb_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api zonedb_tests_api = { + "Zone database", //! Unit name + &zonedb_tests_count, //! Count scheduled tests + &zonedb_tests_run //! Run scheduled tests +}; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int zonedb_tests_count(int argc, char *argv[]) +{ + return 0; +} + +/*! Run all scheduled tests for given parameters. + */ +static int zonedb_tests_run(int argc, char *argv[]) +{ + return 0; +} diff --git a/src/tests/libknot/libknot/zonedb_tests.h b/src/tests/libknot/libknot/zonedb_tests.h new file mode 100644 index 0000000..0c4f8ef --- /dev/null +++ b/src/tests/libknot/libknot/zonedb_tests.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_ZONEDB_TESTS_H_ +#define _KNOTD_ZONEDB_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api zonedb_tests_api; + +#endif /* _KNOTD_ZONEDB_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/files/parsed_data b/src/tests/libknot/realdata/files/parsed_data Binary files differnew file mode 100644 index 0000000..fe22b90 --- /dev/null +++ b/src/tests/libknot/realdata/files/parsed_data diff --git a/src/tests/libknot/realdata/files/parsed_data_queries b/src/tests/libknot/realdata/files/parsed_data_queries Binary files differnew file mode 100644 index 0000000..5857c87 --- /dev/null +++ b/src/tests/libknot/realdata/files/parsed_data_queries diff --git a/src/tests/libknot/realdata/files/raw_data b/src/tests/libknot/realdata/files/raw_data Binary files differnew file mode 100644 index 0000000..502005e --- /dev/null +++ b/src/tests/libknot/realdata/files/raw_data diff --git a/src/tests/libknot/realdata/files/raw_data_queries b/src/tests/libknot/realdata/files/raw_data_queries Binary files differnew file mode 100644 index 0000000..9062d5a --- /dev/null +++ b/src/tests/libknot/realdata/files/raw_data_queries diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.c b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c new file mode 100644 index 0000000..d0216c7 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c @@ -0,0 +1,411 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <assert.h> +#include <stdarg.h> + +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "tests/libknot/realdata/libknot/dname_tests_realdata.h" +#include "libknot/dname.h" +#include "libknot/common.h" + +#include "common/print.h" +#include "common/lists.h" + +static int knot_dname_tests_count(int argc, char *argv[]); +static int knot_dname_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api dname_tests_api = { + "DNS library - dname", //! Unit name + &knot_dname_tests_count, //! Count scheduled tests + &knot_dname_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +int check_domain_name(const knot_dname_t *dname, + const test_dname_t *test_dname) +{ + int errors = 0; + + if (dname == NULL) { + diag("Domain name not created!"); + return 1; + } + +// diag("test_dname: %p, dname: %p", test_dname, dname); + // check size + if (knot_dname_size(dname) != test_dname->size) { + diag("Bad size of the created domain name: %u (should be %u).", + knot_dname_size(dname), test_dname->size); + ++errors; + } else { + // check wire format + uint size = knot_dname_size(dname); + if (strncmp((char *)knot_dname_name(dname), + (char *)test_dname->wire, size) != 0) { + diag("The wire format of the created " + "domain name is wrong:" + " '%.*s' (should be '%.*s').", + size, knot_dname_name(dname), + size, test_dname->wire); + ++errors; + } + } + // check labels + if (test_dname->label_count != dname->label_count) { + diag("Label count of the created domain name is wrong:" + " %d (should be %d)\n", dname->label_count, + test_dname->label_count); + ++errors; + } + if (strncmp((char *)dname->labels, (char *)test_dname->labels, + test_dname->label_count) != 0) { + diag("Label offsets of the created domain name are wrong.\n"); + hex_print((char *)dname->labels, test_dname->label_count); + hex_print((char *)test_dname->labels, test_dname->label_count); + ++errors; + } + + return errors; +} + +static int test_dname_create_from_str(const list *dname_list) +{ + int errors = 0; + knot_dname_t *dname = NULL; + + /* Test with real data. */ + node *n = NULL; + WALK_LIST(n, *dname_list) { + //note("testing domain: %s", test_domains_ok[i].str); + test_dname_t *test_dname = (test_dname_t *)n; + dname = knot_dname_new_from_str(test_dname->str, + strlen(test_dname->str), NULL); + errors += check_domain_name(dname, test_dname); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +static int test_dname_create_from_wire(const list *dname_list) +{ + int errors = 0; + knot_dname_t *dname = NULL; + + node *n = NULL; + WALK_LIST(n, *dname_list) { + test_dname_t *test_dname = (test_dname_t *)n; + dname = knot_dname_new_from_wire(test_dname->wire, + test_dname->size, NULL); + errors += check_domain_name(dname, test_dname); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +static int test_dname_to_str(const list *dname_list) +{ + int errors = 0; + + /* + * Converts dname wireformat to string represenation, which is compared + * with entries in test_domains structure. + */ + + knot_dname_t *dname = NULL; + + /* Test with real data. */ + node *n = NULL; + WALK_LIST(n, *dname_list) { + //note("testing domain: %s", test_domains_ok[i].str); + test_dname_t *test_dname = (test_dname_t *)n; + dname = knot_dname_new_from_wire( + test_dname->wire, + test_dname->size, + NULL); + if (dname == NULL) { + ERR_ALLOC_FAILED; + return 0; + } + + char *name_str = knot_dname_to_str(dname); + if (strcmp(name_str, test_dname->str) != 0) { + diag("Presentation format of domain name wrong:" + " %s (should be %s)", + name_str, test_dname->str); + ++errors; + } + free(name_str); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +static int test_dname_is_fqdn(const list *dname_list) +{ + int errors = 0; + + knot_dname_t *dname; + + /* All dnames from real data are fqdn */ + + node *n = NULL; + WALK_LIST(n, *dname_list) { + test_dname_t *test_dname = (test_dname_t *)n; + dname = knot_dname_new_from_wire(test_dname->wire, + test_dname->size, NULL); + errors += !knot_dname_is_fqdn(dname); + knot_dname_free(&dname); + } + + return (errors == 0); +} + +//static int check_wires(const uint8_t *wire1, uint size1, +// uint8_t *wire2, uint size2) +//{ +// if (size1 != size2) { +// return 0; +// } + +// int i; + +// for (i = 0; (i < size1); i++) { +// if (wire1[i] != wire2[i]) { +// return 0; +// } +// } + +// return 1; +//} + +///* \note not to be run separately */ +//static int test_dname_name(knot_dname_t **dnames_fqdn, +// knot_dname_t **dnames_non_fqdn) +//{ +// assert(dnames_fqdn); +// assert(dnames_non_fqdn); + +// int errors = 0; + +// for (int i = 0; i < TEST_DOMAINS_OK; i++) { +// const uint8_t *tmp_name; +// tmp_name = knot_dname_name(dnames_fqdn[i]); +// if (!check_wires(tmp_name, dnames_fqdn[i]->size, +// (uint8_t *)test_domains_ok[i].wire, +// test_domains_ok[i].size)) { +// diag("Got bad name value from structure: " +// "%s, should be: %s", +// tmp_name, test_domains_ok[i].wire); +// errors++; +// } +// } + +// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { +// const uint8_t *tmp_name; +// tmp_name = knot_dname_name(dnames_non_fqdn[i]); +// if (!check_wires(tmp_name, dnames_non_fqdn[i]->size, +// (uint8_t *)test_domains_non_fqdn[i].wire, +// test_domains_non_fqdn[i].size)) { +// diag("Got bad name value from structure: " +// "%s, should be: %s", +// tmp_name, test_domains_non_fqdn[i].wire); +// errors++; +// } +// } + +// return errors; +//} + +///* \note not to be run separately */ +//static int test_dname_size(knot_dname_t **dnames_fqdn, +// knot_dname_t **dnames_non_fqdn) +//{ +// assert(dnames_fqdn); +// assert(dnames_non_fqdn); + +// int errors = 0; + +// for (int i = 0; i < TEST_DOMAINS_OK; i++) { +// uint8_t tmp_size; +// if ((tmp_size = knot_dname_size(dnames_fqdn[i])) != +// test_domains_ok[i].size) { +// diag("Got bad size value from structure: " +// "%u, should be: %u", +// tmp_size, test_domains_ok[i].size); +// errors++; +// } +// } + +// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { +// uint8_t tmp_size; +// if ((tmp_size = knot_dname_size(dnames_non_fqdn[i])) != +// test_domains_non_fqdn[i].size) { +// diag("Got bad size value from structure: " +// "%u, should be: %u", +// tmp_size, test_domains_non_fqdn[i].size); +// errors++; +// } +// } + +// return errors; +//} + +///* \note not to be run separately */ +//static int test_dname_node(knot_dname_t **dnames_fqdn, +// knot_dname_t **dnames_non_fqdn) +//{ +// assert(dnames_fqdn); +// assert(dnames_non_fqdn); + +// int errors = 0; + +// for (int i = 0; i < TEST_DOMAINS_OK; i++) { +// const knot_node_t *tmp_node; +// if ((tmp_node = knot_dname_node(dnames_fqdn[i])) != +// NODE_ADDRESS) { +// diag("Got bad node value from structure: " +// "%p, should be: %p", +// tmp_node, NODE_ADDRESS); +// errors++; +// } +// } + +// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { +// const knot_node_t *tmp_node; +// if ((tmp_node = knot_dname_node(dnames_non_fqdn[i])) != +// NODE_ADDRESS) { +// diag("Got bad node value from structure: " +// "%s, should be: %s", +// tmp_node, NODE_ADDRESS); +// errors++; +// } +// } + +// return errors; +//} + +//static int test_dname_getters(uint type) +//{ +// int errors = 0; + +// knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK]; +// knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN]; + +// for (int i = 0; i < TEST_DOMAINS_OK; i++) { +// dnames_fqdn[i] = knot_dname_new_from_wire( +// (uint8_t *)test_domains_ok[i].wire, +// test_domains_ok[i].size, NODE_ADDRESS); +// assert(dnames_fqdn[i] != NULL); +// } + +// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { +// dnames_non_fqdn[i] = knot_dname_new_from_wire( +// (uint8_t *)test_domains_non_fqdn[i].wire, +// test_domains_non_fqdn[i].size, NODE_ADDRESS); +// assert(dnames_non_fqdn[i] != NULL); +// } + +// switch (type) { +// case 0: { +// errors += test_dname_name(dnames_fqdn, dnames_non_fqdn); +// break; +// } + +// case 1: { +// errors += test_dname_size(dnames_fqdn, dnames_non_fqdn); +// break; +// } + +// case 2: { +// errors += test_dname_node(dnames_fqdn, dnames_non_fqdn); +// break; +// } +// } /* switch */ + +// for (int i = 0; i < TEST_DOMAINS_OK; i++) { +// knot_dname_free(&dnames_fqdn[i]); +// } + +// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { +// knot_dname_free(&dnames_non_fqdn[i]); +// } + +// return (errors == 0); +//} + +static const int KNOT_DNAME_TEST_COUNT = 4; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_dname_tests_count(int argc, char *argv[]) +{ + return KNOT_DNAME_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_dname_tests_run(int argc, char *argv[]) +{ + const test_data_t *data = data_for_knot_tests; + + int res = 0, + res_str = 0, + res_wire = 0, + res_str_non_fqdn = 0, + res_final = 1; + + ok((res_str = test_dname_create_from_str(&data->dname_list)), + "dname: create from string"); + ok((res_wire = test_dname_create_from_wire(&data->dname_list)), + "dname: create from wire"); + + res_final *= res_str; + res_final *= res_wire; + res_final *= res_str_non_fqdn; + +// res = test_dname_getters(0); +// ok(res, "dname: name"); + +// res = test_dname_getters(1); +// ok(res, "dname: size"); + +// res = test_dname_getters(2); +// ok(res, "dname: node"); + +// skip(!res_str || !res_wire || !res_str_non_fqdn, 2); + + ok((res = test_dname_to_str(&data->dname_list)), + "dname: convert to str"); + res_final *= res; + +// endskip; /* !res_str || !res_wire */ + + ok((res = test_dname_is_fqdn(&data->dname_list)), "dname: fqdn"); + res_final *= res; + + return res_final; +} diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.h b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h new file mode 100644 index 0000000..a7d75aa --- /dev/null +++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_DNAME_TESTS_H_ +#define _KNOTD_DNAME_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api dname_tests_api; + +#endif /* _KNOTD_DNAME_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.c b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c new file mode 100644 index 0000000..257d480 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c @@ -0,0 +1,563 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "tests/libknot/realdata/libknot/edns_tests_realdata.h" +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "libknot/common.h" +#include "libknot/edns.h" + +static int knot_edns_tests_count(int argc, char *argv[]); +static int knot_edns_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api edns_tests_api = { + "DNS library - EDNS", //! Unit name + &knot_edns_tests_count, //! Count scheduled tests + &knot_edns_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +///* Creates actual knot_opt_rr_t variable from test_edns_t variable */ +//static knot_opt_rr_t *opt_rr_from_test_edns(test_edns_t *test_edns) +//{ +// knot_opt_rr_t *ret = knot_edns_new(); + +// CHECK_ALLOC_LOG(ret, NULL); + +// ret->flags = test_edns->flags; +// ret->ext_rcode = test_edns->ext_rcode; +// ret->payload = test_edns->payload; +// ret->version = test_edns->version; + +// for (int i = 0; i < test_edns->option_count; i++) { +// if (knot_edns_add_option(ret, test_edns->options[i].code, +// test_edns->options[i].length, +// test_edns->options[i].data) != 0) { +// knot_edns_free(&ret); +// return NULL; +// } +// } + +// return ret; +//} + +///* simple wire compare - 0 if same, 1 otherwise */ +//static int edns_compare_wires(uint8_t *wire1, +// uint8_t *wire2, +// uint16_t length) +//{ +// for (uint i = 0; i < length; i++) { +// if (wire1[i] != wire2[i]) { +// return 1; +// } +// } + +// return 0; +//} + +//static int check_edns(const knot_opt_rr_t *edns, +// const test_edns_t *test_edns) +//{ +// if (edns->option_count != test_edns->option_count) { +// diag("Option count is wrong"); +// return -1; +// } + +// for (int i = 0; i < edns->option_count; i++) { +// /* check options */ +// if (edns->options[i].code != test_edns->options[i].code) { +// diag("Code in options is wrong"); +// return -1; +// } + +// if (edns->options[i].length != test_edns->options[i].length) { +// diag("Length in options is wrong"); +// return -1; +// } + +// if (edns_compare_wires(edns->options[i].data, +// test_edns->options[i].data, +// edns->options[i].length) != 0) { +// diag("Data in options are wrong"); +// return -1; +// } +// } + +// if (edns->version != test_edns->version) { +// diag("Version is wrong"); +// return -1; +// } + +// if (edns->flags != test_edns->flags) { +// diag("Flags are wrong"); +// return -1; +// } + +// if (edns->size != test_edns->size) { +// diag("Size is wrong"); +// return -1; +// } + +// return 0; +//} + +//static int test_edns_get_payload(const knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// if (knot_edns_get_payload(edns) != +// test_edns->payload) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_get_ext_rcode(const knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// if (knot_edns_get_ext_rcode(edns) != +// test_edns->ext_rcode) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_get_flags(const knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// if (knot_edns_get_flags(edns) != +// test_edns->flags) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_get_version(const knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// if (knot_edns_get_version(edns) != +// test_edns->version) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_do(const knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// if (knot_edns_do(edns) != +// (test_edns->flags & KNOT_EDNS_DO_MASK)) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_size(knot_opt_rr_t *edns, test_edns_t *test_edns) +//{ +// diag("%d %d\n", edns->size, test_edns->size); +// if (knot_edns_size(edns) != +// test_edns->size) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_set_payload(knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// knot_edns_set_payload(edns, test_edns->payload); + +// if (edns->payload != +// test_edns->payload) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_set_ext_rcode(knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// knot_edns_set_ext_rcode(edns, test_edns->ext_rcode); +// if (edns->ext_rcode != +// test_edns->ext_rcode) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_set_version(knot_opt_rr_t *edns, +// test_edns_t *test_edns) +//{ +// knot_edns_set_version(edns, +// test_edns->version); + +// if (edns->version != +// test_edns->version) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_set_do(knot_opt_rr_t *edns) +//{ +// knot_edns_set_do(edns); + +// if (!knot_edns_do(edns)) { +// return 0; +// } else { +// return 1; +// } +//} + +//static int test_edns_getters(uint type) +//{ +// int errors = 0; +// for (int i = 0; i < TEST_EDNS; i++) { +// knot_opt_rr_t *edns = +// opt_rr_from_test_edns(&(test_edns_data[i])); +// if (edns == NULL) { +// ERR_ALLOC_FAILED; +// return -1; +// } + +// switch(type) { +// case 0: +// if (test_edns_get_payload(edns, +// &test_edns_data[i]) != 1) { +// diag("Got wrong payload!"); +// errors++; +// } +// break; +// case 1: +// if (test_edns_get_ext_rcode(edns, +// &test_edns_data[i]) != 1) { +// diag("Got wrong extended RCODE!"); +// errors++; +// } +// break; +// case 2: +// if (test_edns_get_flags(edns, +// &test_edns_data[i]) != 1) { +// diag("Got wrong flags!"); + +// errors++; +// } +// break; +// case 3: +// if (test_edns_get_version(edns, +// &test_edns_data[i]) != 1) { +// diag("Got wrong version!"); +// errors++; +// } +// break; +// case 4: +// if (test_edns_do(edns, +// &test_edns_data[i]) != 1) { +// diag("Got wrong DO bit!"); +// errors++; +// } +// break; +// case 5: +// if (test_edns_size(edns, +// &test_edns_data[i]) != 1) { +// diag("Got wrong size!"); +// errors++; +// } +// break; +// default: +// diag("Unknown option"); +// errors++; +// } /* switch */ + +// knot_edns_free(&edns); +// } + +// return (errors == 0); +//} + +//static int test_edns_setters(uint type) +//{ +// int errors = 0; +// for (int i = 0; i < TEST_EDNS; i++) { +// knot_opt_rr_t *edns = +// opt_rr_from_test_edns(&(test_edns_data[i])); +// if (edns == NULL) { +// ERR_ALLOC_FAILED; +// return -1; +// } + +// switch(type) { +// case 0: +// if (test_edns_set_payload(edns, +// &test_edns_data[i]) != 1) { +// diag("Set wrong payload!"); +// errors++; +// } +// break; +// case 1: +// if (test_edns_set_ext_rcode(edns, +// &test_edns_data[i]) != 1) { +// diag("Set wrong ext_rcode"); +// errors++; +// } +// break; +// case 2: +// if (test_edns_set_version(edns, +// &test_edns_data[i]) != 1) { +// diag("Set wrong version!"); +// errors++; +// } +// break; +// case 3: +// if (test_edns_set_do(edns) != 1) { +// diag("Set wrong DO bit!"); +// errors++; +// } +// break; +// default: +// diag("Unknown option"); +// errors++; +// } /* switch */ + +// knot_edns_free(&edns); +// } + +// return (errors == 0); +//} + +//static int test_edns_wire() +//{ +// /* +// * Tests to_wire and from_wire in one test. +// */ +// for (int i = 0; i < TEST_EDNS; i++) { +// /* Creates instance from test_edns_t. */ +// knot_opt_rr_t *edns = +// opt_rr_from_test_edns(&(test_edns_data[i])); +// if (edns == NULL) { +// ERR_ALLOC_FAILED; +// return -1; +// } + +// uint8_t *wire = NULL; +// wire = malloc(sizeof(uint8_t) * edns->size); +// CHECK_ALLOC_LOG(wire, 0); + +// /* Converts EDNS to wire. */ +// short wire_size = knot_edns_to_wire(edns, wire, 100); + +// if (wire_size == -1) { +// diag("Could not create EDNS wire"); +// return 0; +// } + +// knot_opt_rr_t *edns_from_wire = knot_edns_new(); +// if (edns == NULL) { +// return 0; +// } + +// /* TODO use some constant */ +// /* Creates new EDNS from wire */ +// if (knot_edns_new_from_wire(edns_from_wire, +// wire, +// 100) <= 0) { +// diag("Could not create from wire"); +// return 0; +// } + +// /* Checks whether EDNS created from wire is the same */ +// if (check_edns(edns_from_wire, +// &(test_edns_data[i])) != 0) { +// diag("EDNS created from wire is different from the " +// "original one"); +// } + +// free(wire); +// knot_edns_free(&edns_from_wire); +// knot_edns_free(&edns); +// } +// return 1; +//} + +//static int test_edns_add_option() +//{ +// /* +// * Create empty EDNS and add options one by one, testing their presence. +// */ +// for (int i = 0; i < TEST_EDNS; i++) { +// knot_opt_rr_t *edns = knot_edns_new(); +// assert(edns->option_count == 0); + +// if (edns == NULL) { +// ERR_ALLOC_FAILED; +// return 0; +// } + +// for (int j = 0; j < test_edns_data[i].option_count; j++) { +// if (knot_edns_add_option(edns, +// test_edns_data[i].options[j].code, +// test_edns_data[i].options[j].length, +// test_edns_data[i].options[j]. +// data) != 0) { +// diag("Could not add option"); +// return 0; +// } + +// if (edns->options[j].code != +// test_edns_data[i].options[j].code) { +// diag("Option code wrongly added!"); +// return 0; +// } + +// if (edns->options[j].length != +// test_edns_data[i].options[j].length) { +// diag("Option length wrongly added!"); +// return 0; +// } + +// if (edns_compare_wires(edns->options[j].data, +// test_edns_data[i]. +// options[j].data, +// edns->options[j].length) != 0) { +// diag("Option wire wrongly added!"); +// return 0; +// } +// } +// knot_edns_free(&edns); +// } +// return 1; +//} + +//static int test_edns_has_option() +//{ +// /* +// * Create empty EDNS and add options one by one, testing their presence +// */ +// for (int i = 0; i < TEST_EDNS; i++) { +// knot_opt_rr_t *edns = knot_edns_new(); +// assert(edns->option_count == 0); + +// if (edns == NULL) { +// ERR_ALLOC_FAILED; +// return 0; +// } + +// for (int j = 0; j < test_edns_data[i].option_count; j++) { +// if (knot_edns_add_option(edns, +// test_edns_data[i].options[j].code, +// test_edns_data[i].options[j].length, +// test_edns_data[i].options[j]. +// data) != 0) { +// diag("Could not add option"); +// return 0; +// } + +// if (knot_edns_has_option(edns, +// test_edns_data[i].options[j].code) != 1) { +// diag("Option not found!"); +// return 0; +// } +// } +// knot_edns_free(&edns); +// } +// return 1; +//} + +static const int KNOT_EDNS_TESTS_COUNT = 0; + +///*! This helper routine should report number of +// * scheduled tests for given parameters. +// */ +static int knot_edns_tests_count(int argc, char *argv[]) +{ + return KNOT_EDNS_TESTS_COUNT; +} + +///*! Run all scheduled tests for given parameters. +// */ +static int knot_edns_tests_run(int argc, char *argv[]) +{ +// int res = 0; + int res_final = 1; + +// res = test_edns_getters(0); +// ok(res, "EDNS: get payload"); +// res_final *= res; + +// res = test_edns_getters(1); +// ok(res, "EDNS: get extenden RCODE"); +// res_final *= res; + +// res = test_edns_getters(2); +// ok(res, "EDNS: get flags"); +// res_final *= res; + +// res = test_edns_getters(3); +// ok(res, "EDNS: get version"); +// res_final *= res; + +// res = test_edns_getters(4); +// ok(res, "EDNS: do"); +// res_final *= res; + +// res = test_edns_getters(5); +// ok(res, "EDNS: size"); +// res_final *= res; + +// res = test_edns_setters(0); +// ok(res, "EDNS: set payload"); +// res_final *= res; + +// res = test_edns_setters(1); +// ok(res, "EDNS: set extended RCODE"); +// res_final *= res; + +// res = test_edns_setters(2); +// ok(res, "EDNS: set version"); +// res_final *= res; + +// res = test_edns_setters(3); +// ok(res, "EDNS: set DO"); +// res_final *= res; + +// res = test_edns_add_option(); +// ok(res, "EDNS: add option"); +// res_final *= res; + +// res = test_edns_has_option(); +// ok(res, "EDNS: has option"); +// res_final *= res; + +// res = test_edns_wire(); +// ok(res, "EDNS: to_wire and from_wire"); +// res_final *= res; + + return res_final; +} diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.h b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h new file mode 100644 index 0000000..cfa64b0 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h @@ -0,0 +1,35 @@ +/*! + * \file edns_tests.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * Contains unit tests for ENDS API + * + * Contains tests for: + * - ENDS API + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD__EDNS_TESTS_H_ +#define _KNOTD__EDNS_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api edns_tests_api; + +#endif /* _KNOTD__EDNS_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.c b/src/tests/libknot/realdata/libknot/node_tests_realdata.c new file mode 100644 index 0000000..3218c8e --- /dev/null +++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.c @@ -0,0 +1,385 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "tests/libknot/realdata/libknot/node_tests_realdata.h" +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "libknot/dname.h" +#include "libknot/zone/node.h" +#include "libknot/util/descriptor.h" + +static int knot_node_tests_count(int argc, char *argv[]); +static int knot_node_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api node_tests_api = { + "DNS library - node", //! Unit name + &knot_node_tests_count, //! Count scheduled tests + &knot_node_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +/* TODO It would be wise not to name variables totally same as structures ... */ +knot_dname_t *dname_from_test_dname(const test_dname_t *test_dname) +{ + assert(test_dname != NULL); + knot_dname_t *ret = knot_dname_new_from_wire(test_dname->wire, + test_dname->size, + NULL); + CHECK_ALLOC(ret, NULL); + + return ret; +} + +static knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset) +{ + assert(test_rrset != NULL); + knot_dname_t *owner = dname_from_test_dname(test_rrset->owner); + CHECK_ALLOC(owner, NULL); + + knot_rrset_t *ret = knot_rrset_new(owner, test_rrset->type, + test_rrset->rclass, + test_rrset->ttl); + if (ret == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&owner); + return NULL; + } + + return ret; +} + +static int test_node_create(const list *node_list) +{ + /* Tests creation of node by comparing with test_node struct */ + knot_node_t *tmp; + int errors = 0; + + node *n = NULL; + WALK_LIST(n, *node_list) { + const test_node_t *tmp_node = (test_node_t *)n; + assert(tmp_node); + + knot_dname_t *owner = + dname_from_test_dname(tmp_node->owner); + if (owner == NULL) { + return 0; + } + tmp = knot_node_new(owner, + (knot_node_t *)tmp_node->parent, 0); + if (tmp == NULL || + (strncmp((char *)tmp->owner->name, + (char *)tmp_node->owner->wire, + tmp->owner->size) != 0) || + tmp->parent != (knot_node_t *)tmp_node->parent || + tmp->rrset_tree == NULL) { + errors++; + diag("Failed to create node structure"); + } + knot_node_free(&tmp, 0, 0); + } + + return (errors == 0); +} + +static int test_node_add_rrset(list *rrset_list) +{ + knot_node_t *tmp; + knot_rrset_t *rrset; + int errors = 0; + + node *n = NULL; + WALK_LIST(n, *rrset_list) { + test_rrset_t *test_rrset = (test_rrset_t *)n; + rrset = rrset_from_test_rrset(test_rrset); + if (rrset == NULL) { + diag("Could not create rrset from test data"); + return 0; + } + + /* create node from test_node structure. Always the first one.*/ + knot_dname_t *owner = + dname_from_test_dname(test_rrset->owner); + if (owner == NULL) { + diag("Could not create owner from test data"); + return 0; + } + + tmp = knot_node_new(owner, NULL, 0); + + if (knot_node_add_rrset(tmp, rrset, 0) != 0) { + errors++; + diag("Failed to insert rrset into node"); + } + + /* check if rrset is really there */ + + const knot_rrset_t *rrset_from_node = NULL; + if ((rrset_from_node = + knot_node_rrset(tmp, rrset->type)) == NULL) { + errors++; + diag("Inserted rrset could not be found"); + continue; + } + + /* compare rrset from node with original rrset */ + + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + + int cmp = 0; + + if ((rrset_from_node->rdata == NULL) && + (rrset->rdata == NULL)) { + cmp = 0; + } else if ((rrset_from_node->rdata != NULL) && + (rrset->rdata != NULL)) { + cmp = knot_rdata_compare(rrset_from_node->rdata, + rrset->rdata, + desc->wireformat); + } else { /* one is not NULL and other is -> error */ + cmp = 1; + } + + if (!((rrset_from_node->type == rrset->type) && + (rrset_from_node->rclass == rrset->rclass) && + (rrset_from_node->ttl == rrset->ttl) && + (rrset_from_node->rrsigs == rrset->rrsigs) && + (cmp == 0))) { + errors++; + diag("Values in found rrset are wrong"); + } + + knot_node_free(&tmp, 1, 0); + } + + return (errors == 0); +} + +//static int test_node_get_rrset() +//{ +// knot_node_t *tmp; +// knot_rrset_t *rrset; +// int errors = 0; + +// knot_node_t *nodes[TEST_NODES]; + +// for (int i = 0; i < TEST_NODES && !errors; i++) { +// tmp = knot_node_new(&test_nodes[i].owner, +// test_nodes[i].parent); +// nodes[i] = tmp; +// for (int j = 0; j < RRSETS; j++) { +// knot_node_add_rrset(tmp, &rrsets[j]); +// } +// } + +// for (int i = 0; i < TEST_NODES && !errors; i++) { +// for (int j = 0; j < RRSETS; j++) { +// rrset = &rrsets[j]; +// if (knot_node_rrset(nodes[i], rrset->type) +// != rrset) { +// errors++; +// diag("Failed to get proper rrset from node"); +// } +// } +// knot_node_free(&nodes[i], 0); +// } + +// return (errors == 0); +//} + +//static int test_node_get_parent() +//{ +// knot_node_t *tmp; +// knot_rrset_t *rrset; +// int errors = 0; + +// knot_node_t *nodes[TEST_NODES]; + +// for (int i = 0; i < TEST_NODES && !errors; i++) { +// tmp = knot_node_new(&test_nodes[i].owner, +// test_nodes[i].parent); +// nodes[i] = tmp; +// rrset = &rrsets[i]; +// knot_node_add_rrset(tmp, rrset); +// } + +// for (int i = 0; i < TEST_NODES && !errors; i++) { +// rrset = &rrsets[i]; +// if (knot_node_parent(nodes[i]) != test_nodes[i].parent) { +// errors++; +// diag("Failed to get proper parent from node"); +// } +// knot_node_free(&nodes[i], 0); +// } +// return (errors == 0); +//} + +//static int test_node_sorting() +//{ +// knot_node_t *tmp = NULL; +// knot_rrset_t *rrset = NULL; +// int errors = 0; + +// knot_dname_t *owner = dname_from_test_dname(test_nodes[0].owner); + +// tmp = knot_node_new(owner, +// (knot_node_t *)test_nodes[0].parent); + +// /* Will add rrsets to node. */ +// knot_node_add_rrset(tmp, rrset); +// } + +// const skip_node_t *node = skip_first(tmp->rrsets); + +// int last = *((uint16_t *)node->key); + +// /* TODO there is now an API function knot_node_rrsets ... */ + +// /* Iterates through skip list and checks, whether it is sorted. */ + +// while ((node = skip_next(node)) != NULL) { +// if (last > *((uint16_t *)node->key)) { +// errors++; +// diag("RRset sorting error"); +// } +// last = *((uint16_t *)node->key); +// } + +// knot_node_free(&tmp, 1); +// return (errors == 0); +//} + +//static int test_node_delete() +//{ +// int errors = 0; + +// knot_node_t *tmp_node; + +// for (int i = 0; i < TEST_NODES; i++) { +// knot_dname_t *owner = +// dname_from_test_dname(test_nodes[i].owner); +// tmp_node = knot_node_new(owner, +// (knot_node_t *)test_nodes[i].parent); + +// knot_node_free(&tmp_node, 1); + +// errors += (tmp_node != NULL); +// } + +// return (errors == 0); +//} + +//static int test_node_set_parent() +//{ +// knot_node_t *tmp_parent = (knot_node_t *)0xABCDEF; +// int errors = 0; + +// knot_node_t *tmp_node; + +// for (int i = 0; i < TEST_NODES; i++) { +// tmp_node = knot_node_new(&test_nodes[i].owner, +// test_nodes[i].parent); + +// knot_node_set_parent(tmp_node, tmp_parent); + +// if (tmp_node->parent != tmp_node->parent) { +// diag("Parent node is wrongly set."); +// errors++; +// } +// knot_node_free(&tmp_node, 0); +// } +// return (errors == 0); +//} + +//static int test_node_free_rrsets() +//{ +// int errors = 0; + +// knot_node_t *tmp_node; + +// for (int i = 0; i < TEST_NODES; i++) { +// knot_dname_t *owner = +// dname_from_test_dname(test_nodes[i].owner); +// if (owner == NULL) { +// return 0; +// } + +// tmp_node = knot_node_new(owner, +// (knot_node_t *)test_nodes[i].parent); + +// knot_node_free_rrsets(tmp_node, 0); + +// errors += (tmp_node->rrsets != NULL); + +// knot_node_free(&tmp_node, 1); +// } +// return (errors == 0); +//} + +static const int KNOT_NODE_TEST_COUNT = 2; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_node_tests_count(int argc, char *argv[]) +{ + return KNOT_NODE_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_node_tests_run(int argc, char *argv[]) +{ + test_data_t *data = data_for_knot_tests; + int res = 0, + res_final = 1; + + res = test_node_create(&data->node_list); + ok(res, "node: create"); + res_final *= res; + + + ok((res = test_node_add_rrset(&data->rrset_list)), "node: add"); + res_final *= res; + +// ok((res = test_node_get_rrset()), "node: get"); +// res_final *= res; + +// ok((res = test_node_get_parent()), "node: get parent"); +// res_final *= res; + +// ok((res = test_node_set_parent()), "node: set parent"); +// res_final *= res; + +// ok((res = test_node_sorting()), "node: sort"); +// res_final *= res; + +// ok((res = test_node_free_rrsets()), "node: free rrsets"); +// res_final *= res; + +// endskip; + +// ok((res = test_node_delete()), "node: delete"); +// //res_final *= res; + + return res_final; +} diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.h b/src/tests/libknot/realdata/libknot/node_tests_realdata.h new file mode 100644 index 0000000..a90179f --- /dev/null +++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_NODE_TESTS_H_ +#define _KNOTD_NODE_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api node_tests_api; + +#endif /* _KNOTD_NODE_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.c b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c new file mode 100644 index 0000000..08c0882 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c @@ -0,0 +1,679 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* blame: jan.kadlec@nic.cz */ + +#include <assert.h> + +#include <config.h> +#include "knot/common.h" +#include "packet_tests_realdata.h" +#include "libknot/util/error.h" +#include "libknot/packet/packet.h" +#include "libknot/packet/response.h" +/* *test_t structures */ +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#ifdef TEST_WITH_LDNS +#include "ldns/ldns.h" +#endif + +static int packet_tests_count(int argc, char *argv[]); +static int packet_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api packet_tests_api = { + "DNS library - packet", //! Unit name + &packet_tests_count, //! Count scheduled tests + &packet_tests_run //! Run scheduled tests +}; + +#ifdef TEST_WITH_LDNS +/* Compares one rdata knot with rdata from ldns. + * Comparison is done through comparing wireformats. + * Returns 0 if rdata are the same, 1 otherwise + */ +int compare_rr_rdata(knot_rdata_t *rdata, ldns_rr *rr, + uint16_t type) +{ + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + for (int i = 0; i < rdata->count; i++) { + /* check for ldns "descriptors" as well */ + + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) { + if (rdata->items[i].dname->size != + ldns_rdf_size(ldns_rr_rdf(rr, i))) { + diag("%s", rdata->items[i].dname->name); + diag("%s", ldns_rdf_data(ldns_rr_rdf(rr, i))); + diag("%d", ldns_rdf_size(ldns_rr_rdf(rr, i))); + diag("%d", rdata->items[i].dname->size); + diag("Dname sizes in rdata differ"); + return 1; + } + if (compare_wires_simple(rdata->items[i].dname->name, + ldns_rdf_data(ldns_rr_rdf(rr, i)), + rdata->items[i].dname->size) != 0) { + diag("%s", rdata->items[i].dname->name); + diag("%s", ldns_rdf_data(ldns_rr_rdf(rr, i))); + diag("Dname wires in rdata differ"); + return 1; + } + } else { + /* Compare sizes first, then actual data */ + if (rdata->items[i].raw_data[0] != + ldns_rdf_size(ldns_rr_rdf(rr, i))) { + /* \note ldns stores the size including the + * length, knot does not */ + diag("Raw data sizes in rdata differ"); + diag("knot: %d ldns: %d", + rdata->items[i].raw_data[0], + ldns_rdf_size(ldns_rr_rdf(rr, i))); +// hex_print((char *) +// (rdata->items[i].raw_data + 1), +// rdata->items[i].raw_data[0]); +// hex_print((char *)ldns_rdf_data(ldns_rr_rdf(rr, +// i)), +// ldns_rdf_size(ldns_rr_rdf(rr, i))); + if (abs(rdata->items[i].raw_data[0] - + ldns_rdf_size(ldns_rr_rdf(rr, i))) != 1) { + return 1; + } + } + if (compare_wires_simple((uint8_t *) + (rdata->items[i].raw_data + 1), + ldns_rdf_data(ldns_rr_rdf(rr, i)), + rdata->items[i].raw_data[0]) != 0) { +// hex_print((char *) +// (rdata->items[i].raw_data + 1), +// rdata->items[i].raw_data[0]); +// hex_print((char *) +// ldns_rdf_data(ldns_rr_rdf(rr, i)), +// rdata->items[i].raw_data[0]); + diag("Raw data wires in rdata differ in item " + "%d", i); + + return 1; + } + } + } + + return 0; +} + +int compare_rrset_w_ldns_rr(const knot_rrset_t *rrset, + ldns_rr_list *rr_set, char check_rdata) +{ + /* We should have only one rrset from ldns, although it is + * represented as rr_list ... */ + + int errors = 0; + + ldns_rr *rr = ldns_rr_list_rr(rr_set, 0); + assert(rr); + assert(rrset); + + /* compare headers */ + + if (rrset->owner->size != ldns_rdf_size(ldns_rr_owner(rr))) { + char *tmp_dname = knot_dname_to_str(rrset->owner); + diag("RRSet owner names differ in length"); + diag("ldns: %d, knot: %d", ldns_rdf_size(ldns_rr_owner(rr)), + rrset->owner->size); + diag("%s", tmp_dname); + diag("%s", ldns_rdf_data(ldns_rr_owner(rr))); + free(tmp_dname); + errors++; + } + + if (compare_wires_simple(rrset->owner->name, + ldns_rdf_data(ldns_rr_owner(rr)), + rrset->owner->size) != 0) { + diag("RRSet owner wireformats differ"); + diag("%s \\w %s\n", rrset->owner->name, + ldns_rdf_data(ldns_rr_owner(rr))); + errors++; + } + + if (rrset->type != ldns_rr_get_type(rr)) { + diag("RRset types differ"); + diag("knot type: %d Ldns type: %d", rrset->type, + ldns_rr_get_type(rr)); + errors++; + } + + if (rrset->rclass != ldns_rr_get_class(rr)) { + diag("RRset classes differ"); + errors++; + } + + if (rrset->ttl != ldns_rr_ttl(rr)) { + diag("RRset TTLs differ"); + diag("knot: %d ldns: %d", rrset->ttl, ldns_rr_ttl(rr)); + errors++; + } + + /* compare rdatas */ + + if (rrset->rdata == NULL) { + diag("RRSet has no RDATA!"); + return errors; + } + knot_rdata_t *tmp_rdata = rrset->rdata; + + int i = 0; + + while ((rr = ldns_rr_list_pop_rr(rr_set))) { + assert(rr); + + if (compare_rr_rdata(tmp_rdata, rr, rrset->type) != 0) { + diag("Rdata differ"); + return 1; + } + + tmp_rdata = tmp_rdata->next; + i++; + } + +//// if (check_rdata) { +//// if (compare_rr_rdata(rrset->rdata, rr, rrset->type) != 0) { +//// diag("Rdata differ"); +//// errors++; +//// } +//// } + + return errors; +} + +int compare_rrsets_w_ldns_rrlist(const knot_rrset_t **rrsets, + ldns_rr_list *rrlist, int count) +{ + int errors = 0; + + /* There are no rrsets currenty. Everything is just rr */ + + ldns_rr_list *rr_set = NULL; + + ldns_rr_list_sort(rrlist); + + if (count < 0) { + return 0; + } + + for (int i = 0; i < count ; i++) { + /* normally ldns_pop_rrset or such should be here */ + + rr_set = ldns_rr_list_pop_rrset(rrlist); + /* Get one rr from list. */ + ldns_rr *rr = ldns_rr_list_rr(rr_set, 0); + assert(rr); + + if (rr_set == NULL) { + diag("Ldns and knot structures have different " + "counts of rrsets."); + diag("knot: %d ldns: %d", + count, (count - 1) - i); + return -1; + } + +// diag("RRset from ldns is %d long", ldns_rr_list_rr_count(rr_set)); + +// diag("Got type from ldns: %d (%d)\n", ldns_rr_get_type(rr), i); + + int j = 0; + for (j = 0; j < count; j++) { +// diag("Got type from knot: %d\n", rrsets[j]->type); + if (rrsets[j]->type == ldns_rr_get_type(rr) && + rrsets[j]->owner->size == + ldns_rdf_size(ldns_rr_owner(rr)) && + (compare_wires_simple(ldns_rdf_data(ldns_rr_owner(rr)), rrsets[j]->owner->name, + rrsets[j]->owner->size) == 0)) { + errors += compare_rrset_w_ldns_rr(rrsets[j], + rr_set, 1); + break; + } + } + if (j == count) { + diag("There was no RRSet of the same type!"); +// errors++; + } + } + + return errors; +} + +int check_packet_w_ldns_packet(knot_packet_t *packet, + ldns_pkt *ldns_packet, + int check_header, + int check_question, + int check_body, + int check_edns) +{ + int errors = 0; + if (check_header) { +// if (packet->header.id != ldns_pkt_id(ldns_packet)) { +// diag("response ID does not match - %d %d", +// packet->header.id, +// ldns_pkt_id(ldns_packet)); +// errors++; +// } + + /* qdcount is always 1 in knot's case */ + + /* TODO check flags1 and flags2 - no API for that, + * write my own */ + + if (packet->header.ancount != + ldns_pkt_ancount(ldns_packet)) { + diag("Answer RRSet count wrongly converted"); + errors++; + } + + if (packet->header.nscount != + ldns_pkt_nscount(ldns_packet)) { + diag("Authority RRSet count wrongly converted.\n" + "got %d should be %d", + packet->header.nscount, + ldns_pkt_nscount(ldns_packet)); + errors++; + } + + /* - 1 because ldns does not include OPT_RR to additional " + "section */ + int minus = (!ldns_pkt_edns_version(ldns_packet)) ? 1 : 0; +// int minus = 0; + + if ((packet->header.arcount - minus) != + ldns_pkt_arcount(ldns_packet)) { + diag("Additional RRSet count wrongly converted.\n" + "got %d should be %d", + packet->header.arcount, + ldns_pkt_arcount(ldns_packet)); + errors++; + } + + /*!< \todo Check OPT RR! */ + + if (errors) { + return errors; + } + } + /* Header checked */ + + /* Question section */ + + int ret = 0; + if (check_question) { + knot_rrset_t *question_rrset = + knot_rrset_new(packet-> + question.qname, + packet-> + question.qtype, + packet-> + question.qclass, + 3600); + + if ((ret = compare_rrset_w_ldns_rr(question_rrset, + ldns_pkt_question(ldns_packet), 0)) != 0) { + diag("Question rrsets wrongly converted"); + errors++; + } + knot_rrset_free(&question_rrset); + } + + if (check_body) { + + /* other RRSets */ + + if ((ret = + compare_rrsets_w_ldns_rrlist(packet->answer, + ldns_pkt_answer(ldns_packet), + knot_packet_answer_rrset_count(packet))) != 0) { + diag("Answer rrsets wrongly converted"); + errors++; + } + + + + if ((ret = compare_rrsets_w_ldns_rrlist(packet->authority, + ldns_pkt_authority(ldns_packet), + knot_packet_authority_rrset_count(packet))) != 0) { + diag("Authority rrsets wrongly converted - %d", ret); + errors++; + } + + /* We don't want to test OPT RR, which is the last rrset + * in the additional section */ + + if ((ret = compare_rrsets_w_ldns_rrlist(packet->additional, + ldns_pkt_additional(ldns_packet), + knot_packet_additional_rrset_count(packet) - 1)) != 0) { + diag("Additional rrsets wrongly converted"); + errors++; + } + + } + + if (check_edns) { + + /* OPT RR */ + + if (ldns_pkt_edns(ldns_packet)) { + /* if (packet->edns_packet == NULL) { + diag("ldns has edns section, knot has not"); + return 1; + } */ + + knot_opt_rr_t *opt = &(packet->opt_rr); + + if (ldns_pkt_edns_udp_size(ldns_packet) != + knot_edns_get_payload(opt)) { + diag("Payloads in EDNS are different"); + errors++; + } + + if (ldns_pkt_edns_version(ldns_packet) != + knot_edns_get_version(opt)) { + diag("Versions in EDNS are different"); + errors++; + } + + if (ldns_pkt_edns_extended_rcode(ldns_packet) != + knot_edns_get_ext_rcode(opt)) { + diag("Extended rcodes in EDNS are different"); + errors++; + } + + /* TODO parse flags do bit, z value ... */ + } + } + + return errors; +} +#endif + +extern knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset); +extern knot_dname_t *dname_from_test_dname(const test_dname_t *test_dname); + +/* Converts knot_rrset_t to knot_opt_rr */ +static knot_opt_rr_t *opt_rrset_to_opt_rr(knot_rrset_t *rrset) +{ + if (rrset == NULL) { + return NULL; + } + + knot_opt_rr_t *opt_rr = knot_edns_new(); + assert(opt_rr); + + knot_edns_set_payload(opt_rr, rrset->rclass); + + knot_edns_set_ext_rcode(opt_rr, rrset->ttl); + + /* TODO rdata? mostly empty, I guess, but should be done */ + + return opt_rr; +} + +knot_packet_t *packet_from_test_response(test_response_t *test_packet) +{ + knot_rrset_t *parsed_opt = NULL; + + for (int j = 0; j < test_packet->arcount; j++) { + if (test_packet->additional[j]->type == + KNOT_RRTYPE_OPT) { + parsed_opt = + rrset_from_test_rrset( + test_packet->additional[j]); + assert(parsed_opt); + break; + } + } + + knot_opt_rr_t *opt_rr = NULL; + if (parsed_opt != NULL) { + opt_rr = + opt_rrset_to_opt_rr(parsed_opt); + assert(opt_rr); + } else { + opt_rr = NULL; + } + + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + knot_packet_set_max_size(packet, 1024 * 10); + + if (opt_rr != NULL) { + packet->opt_rr = *opt_rr; + } + + packet->header.id = test_packet->id; + packet->header.qdcount = test_packet->qdcount; + + packet->question.qname = dname_from_test_dname(test_packet->qname); + packet->size += test_packet->qname->size; + packet->question.qtype = test_packet->qtype; + packet->question.qclass = test_packet->qclass; + + packet->size += 4; + + packet->answer = + malloc(sizeof(knot_rrset_t *) * test_packet->ancount); + assert(packet->answer); + + for (int j = 0; j < test_packet->ancount; j++) { + if (&(test_packet->answer[j])) { + packet->answer[packet->an_rrsets++] = + rrset_from_test_rrset(test_packet->answer[j]); + } + } + + packet->authority = + malloc(sizeof(knot_rrset_t *) * test_packet->nscount); + assert(packet->answer); + + for (int j = 0; j < test_packet->nscount; j++) { + if (&(test_packet->authority[j])) { + packet->authority[packet->ns_rrsets++] = + rrset_from_test_rrset(test_packet->authority[j]); + } + } + + packet->authority = + malloc(sizeof(knot_rrset_t *) * test_packet->arcount); + assert(packet->answer); + + for (int j = 0; j < test_packet->arcount; j++) { + if (&(test_packet->additional[j])) { + if (test_packet->additional[j]->type == + KNOT_RRTYPE_OPT) { + continue; + } + packet->additional[packet->ar_rrsets++] = + rrset_from_test_rrset(test_packet->additional[j]); + } + } + + return packet; +} + +static int test_packet_parse_from_wire(list raw_response_list) +{ +#ifdef TEST_WITH_LDNS + int errors = 0; + + node *n = NULL; + WALK_LIST(n ,raw_response_list) { + test_raw_packet_t *raw_packet = (test_raw_packet_t *)n; + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + int ret = 0; + if ((ret = + knot_packet_parse_from_wire(packet, raw_packet->data, + raw_packet->size, 0)) != + KNOT_EOK) { + diag("Warning: could not parse wire! " + "(might be caused by malformed dump) - " + "knot error: %s", knot_strerror(ret)); +// hex_print(raw_packet->data, +// raw_packet->size); + continue; + } + + ldns_pkt *ldns_packet = NULL; + + if (ldns_wire2pkt(&ldns_packet, raw_packet->data, + raw_packet->size) != LDNS_STATUS_OK) { + diag("Could not parse wire using ldns"); + diag("%s", + ldns_get_errorstr_by_id(ldns_wire2pkt(&ldns_packet, + raw_packet->data, + raw_packet->size))); + return 0; + } + + if (check_packet_w_ldns_packet(packet, ldns_packet, 1, + 1, 1, 1) != 0) { + diag("Wrongly created packet"); + errors++; + } + + ldns_pkt_free(ldns_packet); + knot_packet_free(&packet); + } + + return (errors == 0); +#endif +#ifndef TEST_WITH_LDNS + diag("Enable ldns to test this feature"); + return 0; +#endif +} + +static int test_packet_to_wire(list raw_response_list) +{ +#ifdef TEST_WITH_LDNS + int errors = 0; + /*!< \todo test queries too! */ +// /* We'll need data from both lists. */ +// test_packet_t **test_packets = NULL; +// uint test_packet_count = 0; +// node *n = NULL; +// WALK_LIST(n, response_list) { +// test_packet_count++; +// } + +// test_packets = +// malloc(sizeof(test_packet_t *) * test_packet_count); +// assert(test_packets); +// int i = 0; +// WALK_LIST(n, response_list) { +// test_packets[i++] = (test_response_t *)n; +// } + +// test_raw_packet_t **test_packets = NULL; +// uint test_packet_count = 0; +// n = NULL; +// WALK_LIST(n, raw_response_list) { +// test_packet_count++; +// } + +// test_packets = +// malloc(sizeof(test_raw_packet_t *) * test_packet_count); +// assert(test_packets); +// i = 0; +// WALK_LIST(n, raw_response_list) { +// test_packets[i++] = (test_raw_packet_t *)n; +// } + +// assert(test_response_count == test_packet_count); + node *n = NULL; + WALK_LIST(n, raw_response_list) { + /* Create packet from raw response. */ + knot_packet_t *packet = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(packet); + test_raw_packet_t *raw_packet = (test_raw_packet_t *)n; + if (knot_packet_parse_from_wire(packet, raw_packet->data, + raw_packet->size, 0) != + KNOT_EOK) { + diag("Warning: could not parse wire! " + "(might be caused be malformed dump)"); + continue; + } + knot_packet_set_max_size(packet, 1024 * 10); + /* Use this packet to create wire */ + uint8_t *wire = NULL; + size_t size = 0; + if (knot_packet_to_wire(packet, &wire ,&size) != KNOT_EOK) { + diag("Could not convert packet to wire"); + } + /* Create ldns packet from created wire */ + ldns_pkt *ldns_packet = NULL; + + if (ldns_wire2pkt(&ldns_packet, wire, + size) != LDNS_STATUS_OK) { + diag("Could not parse wire using ldns"); + /*!< \todo get rid of this */ + diag("%s", + ldns_get_errorstr_by_id(ldns_wire2pkt(&ldns_packet, + wire, + size))); + return 0; + } + + if (check_packet_w_ldns_packet(packet, ldns_packet, 1, 1, 1, + 1) != 0) { + diag("Packet wrongly converted to wire!"); + errors++; + } + knot_packet_free(&packet); + ldns_pkt_free(ldns_packet); + } + + return (errors == 0); +#endif +#ifndef TEST_WITH_LDNS + diag("Enable ldns to test this feature!"); + return 0; +#endif +} + +static const uint KNOT_PACKET_TEST_COUNT = 2; + +static int packet_tests_count(int argc, char *argv[]) +{ + return KNOT_PACKET_TEST_COUNT; +} + +static int packet_tests_run(int argc, char *argv[]) +{ + const test_data_t *data = data_for_knot_tests; + + int res = 0; + todo(); + ok(res = test_packet_parse_from_wire(data->raw_packet_list), + "packet: from wire"); + diag("Resolve issue with arcount."); + endtodo; +// skip(!res, 1); + ok(test_packet_to_wire(data->raw_packet_list), "packet: to wire"); +// endskip; + + return 1; +} + diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.h b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h new file mode 100644 index 0000000..c0e0479 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_PACKET_REALDATA_TESTS_H_ +#define _KNOTD_PACKET_REALDATA_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api packet_tests_api; + +#endif /* _KNOTD_PACKET_REALDATA_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c new file mode 100644 index 0000000..f4ba64c --- /dev/null +++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c @@ -0,0 +1,329 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <assert.h> + +#include "tests/libknot/realdata/libknot/rdata_tests_realdata.h" +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "libknot/common.h" +#include "libknot/rdata.h" +#include "libknot/util/descriptor.h" +#include "libknot/util/utils.h" +#include "libknot/util/error.h" + +static int knot_rdata_tests_count(int argc, char *argv[]); +static int knot_rdata_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api rdata_tests_api = { + "DNS library - rdata", //! Unit name + &knot_rdata_tests_count, //! Count scheduled tests + &knot_rdata_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +extern int check_domain_name(const knot_dname_t *dname, + const test_dname_t *test_dname); + +extern int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count); + +/*! + * \brief Checks if all RDATA items in the given RDATA structure are correct. + * + * \return Number of errors encountered. Error is either if some RDATA item + * is not set (i.e. NULL) or if it has other than the expected value. + */ +static int check_rdata(const knot_rdata_t *rdata, + const test_rdata_t *test_rdata) +{ + assert(rdata != NULL); + assert(test_rdata != NULL); + + int errors = 0; + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(test_rdata->type); + //note("check_rdata(), RRType: %u", rrtype); + + for (int i = 0; i < desc->length; ++i) { + + switch (desc->wireformat[i]) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + case KNOT_RDATA_WF_LITERAL_DNAME: + if (check_domain_name(rdata->items[i].dname, + test_rdata->items[i].dname) != 0) { + errors++; + diag("Rdata contains wrong dname item"); + } + break; + default: + if (test_rdata->items[i].raw_data[0] != + rdata->items[i].raw_data[0]) { + diag("Raw rdata in items have different " + "sizes!"); + return 0; + } + + errors += + compare_wires_simple( + (uint8_t *)test_rdata->items[i].raw_data, + (uint8_t *)rdata->items[i].raw_data, + (uint)rdata->items[i].raw_data[0]); + } + } + return errors; +} + +extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname); + +///*! +// * \brief Tests knot_rdata_set_item(). +// * +// * \retval > 0 on success. +// * \retval 0 otherwise. +// */ +//static int test_rdata_set_item(list rdata_list) +//{ +// node *n = NULL; +// WALK_LIST(n, rdata_list) { +// knot_rdata_t *rdata = knot_rdata_new(); +// assert(rdata); +// test_rdata_t *test_rdata = (test_rdata_t *)n; + +// knot_rrtype_descriptor_t *desc = +// knot_rrtype_descriptor_by_type(test_rdata->type); +// for (int i = 0; i < test_rdata->count; i++) { +// knot_rdata_item_t item; +// if (test_rdata->items[i].type == TEST_ITEM_DNAME) { +// item.dname = +// dname_from_test_dname( +// test_rdata->items[i].dname); +// } else { +// item.raw_data = test_rdata->items[i].raw_data; +// } +// if (knot_rdata_set_item(rdata, i, item) != 0) { +// diag("Could not set item, rdata count: %d", +// rdata->count); +// return 0; +// } +// } + +// /* Check that all items are OK */ +// if (check_rdata(rdata, test_rdata) != 0) { +// return 0; +// } +// } +// return 1; +//} + +static knot_rdata_item_t *items_from_test_items(test_item_t *test_items, + size_t count) +{ + knot_rdata_item_t *items = + malloc(sizeof(knot_rdata_item_t) * count); + assert(items); + for (int i = 0; i < count; i++) { + if (test_items[i].type == TEST_ITEM_DNAME) { + items[i].dname = + dname_from_test_dname(test_items[i].dname); + } else { + items[i].raw_data = test_items[i].raw_data; + } + } + + return items; +} + +static int test_rdata_set_items(list rdata_list) +{ + int errors = 0; + + // check error return values + knot_rdata_t *rdata = knot_rdata_new(); + assert(rdata); + + node *n = NULL; + WALK_LIST(n, rdata_list) { + test_rdata_t *test_rdata = (test_rdata_t *)n; + knot_rdata_t *rdata = knot_rdata_new(); + + /* create dnslib items from tests items. */ + knot_rdata_item_t *items = + items_from_test_items(test_rdata->items, + test_rdata->count); + + assert(items); + assert(test_rdata->count > 0); + assert(rdata->items == NULL); + + if (knot_rdata_set_items(rdata, items, + test_rdata->count) != 0) { + diag("Could not set items!"); + errors++; + } + + if (check_rdata(rdata, test_rdata) != 0) { + diag("Wrong rdata after knot_rdata_set_items!"); + errors++; + } + + knot_rdata_free(&rdata); + } + + return (errors == 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Tests knot_rdata_get_item(). + * + * \retval > 0 on success. + * \retval 0 otherwise. + */ +static int test_rdata_get_item(list rdata_list) +{ + node *n = NULL; + WALK_LIST(n, rdata_list) { + test_rdata_t *test_rdata = (test_rdata_t *)n; + knot_rdata_t *rdata = knot_rdata_new(); + assert(rdata); + knot_rdata_item_t *items = + items_from_test_items(test_rdata->items, + test_rdata->count); + assert(knot_rdata_set_items(rdata, items, + test_rdata->count) == 0); + knot_rdata_item_t *new_items = + malloc(sizeof(knot_rdata_item_t) * test_rdata->count); + for (int i = 0; i < test_rdata->count; i++) { + knot_rdata_item_t *item = + knot_rdata_get_item(rdata, i); + if (item == NULL) { + diag("Could not get item"); + return 0; + } + new_items[i] = *item; + } + + knot_rdata_free(&rdata); + free(items); + + knot_rdata_t *new_rdata = knot_rdata_new(); + assert(new_rdata); + assert(knot_rdata_set_items(new_rdata, + new_items, + test_rdata->count) == 0); + + if (check_rdata(new_rdata, test_rdata) != 0) { + diag("Wrong rdata created using rdata_get_item"); + return 0; + } + + knot_rdata_free(&new_rdata); + free(new_items); + } + + return 1; +} + +//static int test_rdata_wire_size() +//{ +// knot_rdata_t *rdata; +// int errors = 0; + +// // generate some random data +// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE]; +// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE); + +// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) { +// rdata = knot_rdata_new(); + +// int size = +// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata); + +// if (size < 0) { +// ++errors; +// } else { +// int counted_size = knot_rdata_wire_size(rdata, +// knot_rrtype_descriptor_by_type(i)->wireformat); +// if (size != counted_size) { +// diag("Wrong wire size computed (type %d):" +// " %d (should be %d)", +// i, counted_size, size); +// ++errors; +// } +// } + +// knot_rrtype_descriptor_t *desc = +// knot_rrtype_descriptor_by_type(i); + +// for (int x = 0; x < desc->length; x++) { +// if (desc->wireformat[x] == +// KNOT_RDATA_WF_UNCOMPRESSED_DNAME || +// desc->wireformat[x] == +// KNOT_RDATA_WF_COMPRESSED_DNAME || +// desc->wireformat[x] == +// KNOT_RDATA_WF_LITERAL_DNAME) { +// knot_dname_free(&(rdata->items[x].dname)); +// } +// } +// knot_rdata_free(&rdata); +// } + +// return (errors == 0); +//} + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ + +static const int KNOT_RDATA_TEST_COUNT = 2; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_rdata_tests_count(int argc, char *argv[]) +{ + return KNOT_RDATA_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_rdata_tests_run(int argc, char *argv[]) +{ + test_data_t *data = data_for_knot_tests; + int res = 0, + res_final = 1; + + ok(res = test_rdata_set_items(data->rdata_list), + "rdata: set items all at once"); + res_final *= res; + + ok(res = test_rdata_get_item(data->rdata_list), + "rdata: get item"); + res_final *= res; + +// ok(res = test_rdata_set_item(data->rdata_list), +// "rdata: set items one-by-one"); +// res_final *= res; + + return res_final; +} diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h new file mode 100644 index 0000000..570b2b1 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h @@ -0,0 +1,53 @@ +/*! + * \file rdata_tests.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * Contains unit tests for RDATA (knot_rdata_t) and RDATA item + * (knot_rdata_item_t) structures. + * + * Contains tests for: + * - creating empty RDATA structure with or without reserved space. + * - setting RDATA items one-by-one + * - setting RDATA items all at once + * + * As for now, the tests use several (TEST_RDATAS) RDATA structures, each + * with different number of RDATA items (given by test_rdatas). These are all + * initialized to pointers derived from RDATA_ITEM_PTR (first is RDATA_ITEM_PTR, + * second RDATA_ITEM_PTR + 1, etc.). The functions only test if the pointer + * is set properly. + * + * \todo It may be better to test also some RDATAs with predefined contents, + * such as some numbers, some domain name, etc. For this purpose, we'd + * need RDATA descriptors (telling the types of each RDATA item within an + * RDATA). + * + * \todo It will be fine to test all possible output values of all functions, + * e.g. test whether knot_rdata_get_item() returns NULL when passed an + * illegal position, etc. + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_RDATA_TESTS_H_ +#define _KNOTD_RDATA_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api rdata_tests_api; + +#endif /* _KNOTD_RDATA_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.c b/src/tests/libknot/realdata/libknot/response_tests_realdata.c new file mode 100644 index 0000000..5bbda36 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.c @@ -0,0 +1,173 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* blame: jan.kadlec@nic.cz */ + +#include <assert.h> + +#include "packet_tests_realdata.h" +#include "knot/common.h" +#include "libknot/util/error.h" +#include "libknot/packet/packet.h" +#include "libknot/packet/response.h" +/* *test_t structures */ +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#ifdef TEST_WITH_LDNS +#include "ldns/packet.h" +#endif + +static int response_tests_count(int argc, char *argv[]); +static int response_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api response_tests_api = { + "DNS library - response", //! Unit name + &response_tests_count, //! Count scheduled tests + &response_tests_run //! Run scheduled tests +}; + +#ifdef TEST_WITH_LDNS +extern int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count); +extern int compare_rr_rdata(knot_rdata_t *rdata, ldns_rr *rr, uint16_t type); +extern int compare_rrset_w_ldns_rr(const knot_rrset_t *rrset, + ldns_rr *rr, char check_rdata); +extern int compare_rrsets_w_ldns_rrlist(const knot_rrset_t **rrsets, + ldns_rr_list *rrlist, int count); + +extern int check_packet_w_ldns_packet(knot_packet_t *packet, + ldns_pkt *ldns_packet, + int check_header, + int check_question, + int check_body, + int check_edns); +#endif + +extern knot_packet_t *packet_from_test_response(test_response_t *response); + +static int test_response_init_from_query(list query_list) +{ + int errors = 0; + node *n = NULL; + WALK_LIST(n, query_list) { + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + knot_packet_t *query = + packet_from_test_response((test_response_t *)n); + assert(query); + knot_packet_set_max_size(response, 1024 * 10); + if (knot_response_init_from_query(response, + query) != KNOT_EOK) { + diag("Could not init response from query!"); + errors++; + } + knot_packet_free(&response); + knot_packet_free(&query); + } + return (errors == 0); +} + +//static int test_response_add_opt(list opt_list) +//{ +// int errors = 0; +// node *n = NULL; +// WALK_LIST(n, query_list) { +// knot_packet_t *response = +// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); +// assert(response); +// knot_opt_rr_t *opt = +// opt_from_test_opt((test_opt_t *)n); +// assert(query); +// if (knot_response_add_opt(response, +// opt, 1)!= KNOT_EOK) { +// diag("Could not add OPT RR to response!"); +// errors++; +// } +// knot_packet_free(&response); +// knot_opt_rr_free(&opt); +// } +// return (errors == 0); +//} + +extern knot_rrset_t *rrset_from_test_rrset(test_rrset_t *test_rrset); + +static int test_response_add_generic(int (*func)(knot_packet_t *, + const knot_rrset_t *, + int, int, int), + list rrset_list) +{ + /*!< \todo Now adding only one RRSet at the time, try more, use nodes */ + int errors = 0; + node *n = NULL; + WALK_LIST(n, rrset_list) { + knot_packet_t *response = + knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + assert(response); + knot_packet_set_max_size(response, + KNOT_PACKET_PREALLOC_RESPONSE * 100); + assert(knot_response_init(response) == KNOT_EOK); + + knot_rrset_t *rrset = + rrset_from_test_rrset((test_rrset_t *)n); + assert(rrset); + + int ret = 0; + if ((ret = func(response, rrset, 0, 1, 0)) != KNOT_EOK) { + diag("Could not add RRSet to response! Returned: %d", + ret); + diag("(owner: %s type %s)", + ((test_rrset_t *)n)->owner->str, + knot_rrtype_to_string(( + (test_rrset_t *)n)->type)); + errors++; + } + knot_packet_free(&response); + knot_rrset_deep_free(&rrset, 1, 1, 1); + } + + return (errors == 0); +} + +static void test_response_add_rrset(list rrset_list) +{ + ok(test_response_add_generic(knot_response_add_rrset_answer, + rrset_list), + "response: add answer rrset"); + ok(test_response_add_generic(knot_response_add_rrset_authority, + rrset_list), + "response: add authority rrset"); + ok(test_response_add_generic(knot_response_add_rrset_additional, + rrset_list), + "response: add additional rrset"); +} + +static const uint KNOT_response_TEST_COUNT = 4; + +static int response_tests_count(int argc, char *argv[]) +{ + return KNOT_response_TEST_COUNT; +} + +static int response_tests_run(int argc, char *argv[]) +{ + const test_data_t *data = data_for_knot_tests; + +// int res = 0; + ok(test_response_init_from_query(data->query_list), + "response: init from query"); + test_response_add_rrset(data->rrset_list); + return 1; +} diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.h b/src/tests/libknot/realdata/libknot/response_tests_realdata.h new file mode 100644 index 0000000..731604b --- /dev/null +++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_PACKET_response_TESTS_H_ +#define _KNOTD_PACKET_response_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api response_tests_api; + +#endif /* _KNOTD_PACKET_response_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c new file mode 100644 index 0000000..cb59f4c --- /dev/null +++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c @@ -0,0 +1,289 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "tests/libknot/realdata/libknot/rrset_tests_realdata.h" +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "libknot/common.h" +#include "libknot/util/descriptor.h" +#include "libknot/rrset.h" +#include "libknot/dname.h" +#include "libknot/rdata.h" +#include "libknot/util/utils.h" +#include "libknot/zone/node.h" +#include "libknot/util/debug.h" + +static int knot_rrset_tests_count(int argc, char *argv[]); +static int knot_rrset_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api rrset_tests_api = { + "DNS library - rrset", //! Unit name + &knot_rrset_tests_count, //! Count scheduled tests + &knot_rrset_tests_run //! Run scheduled tests +}; + +/*----------------------------------------------------------------------------*/ +/* + * Unit implementation. + */ + +/* count1 == count2 */ +int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count) +{ + int i = 0; + while (i < count && + wire1[i] == wire2[i]) { + i++; + } + return (!(count == i)); +} + + +knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset) +{ +// diag("owner: %s\n", test_rrset->owner->str); + knot_dname_t *owner = + knot_dname_new_from_wire(test_rrset->owner->wire, + test_rrset->owner->size, NULL); + +// diag("Created owner: %s (%p) from %p\n", knot_dname_to_str(owner), +// owner, test_rrset->owner); + + if (!owner) { + return NULL; + } + + knot_rrset_t *ret = knot_rrset_new(owner, test_rrset->type, + test_rrset->rclass, + test_rrset->ttl); + + /* Add rdata to rrset. */ + knot_rdata_t *rdata = knot_rdata_new(); + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(test_rrset->type); + + node *n = NULL; + WALK_LIST(n, test_rrset->rdata_list) { + test_rdata_t *test_rdata = (test_rdata_t *)n; + if (test_rdata->count != desc->length) { + diag("Malformed RRSet data!"); + knot_rdata_free(&rdata); + return ret; + } + assert(test_rdata->type == test_rrset->type); + /* Add items to the actual rdata. */ + rdata->items = malloc(sizeof(knot_rdata_item_t) * desc->length); + if (rdata->items == NULL) { + return NULL; + } +// diag("Rdata type: %s\n", knot_rrtype_to_string(test_rrset->type)); + for (int i = 0; i < desc->length; i++) { + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) { +// diag("%p\n", test_rdata->items[i].raw_data); + assert(test_rdata->items[i].type == TEST_ITEM_DNAME); + rdata->items[i].dname = + knot_dname_new_from_wire(test_rdata->items[i].dname->wire, + test_rdata->items[i].dname->size, + NULL); + } else { +// diag("%p\n", test_rdata->items[i].dname); + assert(test_rdata->items[i].type == TEST_ITEM_RAW_DATA); + assert(test_rdata->items[i].raw_data != NULL); + rdata->items[i].raw_data = test_rdata->items[i].raw_data; + } + } + } + + rdata->next = rdata; + + ret->rdata = rdata; + + return ret; +} + +extern int check_domain_name(knot_dname_t *dname, test_dname_t *test_dname); + +int check_rrset(const knot_rrset_t *rrset, + const test_rrset_t *test_rrset, + int check_rdata, int check_items, + int check_rrsigs) +{ + /* following implementation should be self-explanatory */ + int errors = 0; + + if (rrset == NULL) { + diag("RRSet not created!"); + return 1; + } + + errors += check_domain_name(rrset->owner, test_rrset->owner); + + if (rrset->type != test_rrset->type) { + diag("TYPE wrong: %u (should be: %u)", rrset->type, + test_rrset->type); + ++errors; + } + + if (rrset->rclass != test_rrset->rclass) { + diag("CLASS wrong: %u (should be: %u)", rrset->rclass, + test_rrset->rclass); + ++errors; + } + + if (rrset->ttl != test_rrset->ttl) { + diag("TTL wrong: %u (should be: %u)", rrset->ttl, + test_rrset->ttl); + ++errors; + } + + if (check_rdata) { + /* TODO use rdata_compare */ + knot_rdata_t *rdata = rrset->rdata; + + if (rdata == NULL) { + diag("There are no RDATAs in the RRSet"); + ++errors; + } + + if (rdata != NULL) { + while (rdata->next != NULL && + rdata->next != rrset->rdata) { + rdata = rdata->next; + } + if (rdata->next == NULL) { + diag("The list of RDATAs is not cyclic!"); + ++errors; + } else { + assert(rdata->next == rrset->rdata); + } + } + } + + /* Iterate rrset rdata list and compare items. */ + if (check_items && rrset->rdata != NULL) { + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + node *n = NULL; + knot_rdata_t *tmp_rdata = rrset->rdata; + WALK_LIST(n, test_rrset->rdata_list) { + test_rdata_t *test_rdata = (test_rdata_t *)n; + for (int i = 0; i < desc->length; i++) { + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME) { + errors += check_domain_name(tmp_rdata->items[i].dname, + test_rdata->items[i].dname); + } else { + assert(tmp_rdata != NULL); + errors += compare_wires_simple((uint8_t *)tmp_rdata->items[i].raw_data, + (uint8_t *)test_rdata->items[i].raw_data, + test_rdata->items[i].raw_data[0]); + } + } + } + } else if (check_items && rrset->rdata == NULL) { + diag("Could not test items, since rdata is empty!"); + } + + if (check_rrsigs) { + /* there are currently no rrsigs */ + } + return errors; +} + +extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname); + +static int test_rrset_create(const list rrset_list) +{ + int errors = 0; + + /* Test with real data. */ + node *n = NULL; + WALK_LIST(n, rrset_list) { + test_rrset_t *test_rrset = (test_rrset_t *)n; + knot_rrset_t *rrset = + knot_rrset_new(dname_from_test_dname + (test_rrset->owner), + test_rrset->type, + test_rrset->rclass, + test_rrset->ttl); + assert(rrset); + errors += check_rrset(rrset, test_rrset, 0, 0, 0); + knot_rrset_deep_free(&rrset, 1, 0, 0); + } + + return (errors == 0); +} + +static int test_rrset_add_rdata(list rrset_list) +{ + int errors = 0; + node *n = NULL; + WALK_LIST(n, rrset_list) { + test_rrset_t *test_rrset = (test_rrset_t *)n; + knot_rrset_t *tmp_rrset = rrset_from_test_rrset(test_rrset); + /* TODO use all the rdata */ + assert(tmp_rrset->rdata->next = tmp_rrset->rdata); + knot_rrset_t *rrset = + knot_rrset_new(dname_from_test_dname + (test_rrset->owner), + test_rrset->type, + test_rrset->rclass, + test_rrset->ttl); + assert(rrset); + knot_rrset_add_rdata(rrset, tmp_rrset->rdata); + errors += check_rrset(rrset, test_rrset, 1, 1, 1); + knot_rrset_free(&tmp_rrset); + knot_rrset_deep_free(&rrset, 1, 1, 0); + + } + return (errors == 0); +} + +static const int KNOT_RRSET_TEST_COUNT = 2; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_rrset_tests_count(int argc, char *argv[]) +{ + return KNOT_RRSET_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_rrset_tests_run(int argc, char *argv[]) +{ + test_data_t *data = data_for_knot_tests; + + int res = 0, + res_final = 1; + + res = test_rrset_create(data->rrset_list); + ok(res, "rrset: create"); + res_final *= res; + + ok(res = test_rrset_add_rdata(data->rrset_list), "rrset: add_rdata"); + res_final *= res; + + return res_final; +} diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h new file mode 100644 index 0000000..cc3b705 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h @@ -0,0 +1,35 @@ +/*! + * \file rrset_tests.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * Contains unit tests for RRSet (knot_rrset_t) and its API. + * + * Contains tests for: + * - + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_RRSET_TESTS_H_ +#define _KNOTD_RRSET_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api rrset_tests_api; + +#endif /* _KNOTD_RRSET_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.c b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c new file mode 100644 index 0000000..445997f --- /dev/null +++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c @@ -0,0 +1,335 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "tests/libknot/realdata/libknot/zone_tests_realdata.h" +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "libknot/common.h" +#include "libknot/zone/zone.h" +#include "libknot/util/error.h" +#include "libknot/zone/node.h" + +static int knot_zone_tests_count(int argc, char *argv[]); +static int knot_zone_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api zone_tests_api = { + "DNS library - zone", //! Unit name + &knot_zone_tests_count, //! Count scheduled tests + &knot_zone_tests_run //! Run scheduled tests +}; + +/* + * Unit implementation. + */ + +extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname); +extern knot_rrset_t *rrset_from_test_rrset(test_rrset_t *test_rrset); + +static knot_node_t *node_from_test_node(const test_node_t *test_node) +{ + knot_dname_t *owner = dname_from_test_dname(test_node->owner); + /* TODO parent? */ + knot_node_t *new_node = knot_node_new(owner, NULL, 0); + node *n = NULL; + WALK_LIST(n, test_node->rrset_list) { + test_rrset_t *test_rrset = (test_rrset_t *)n; + knot_rrset_t *rrset = rrset_from_test_rrset(test_rrset); + assert(rrset); + assert(knot_node_add_rrset(new_node, rrset, 0) == 0); + } + + return new_node; +} + +static int test_zone_create(list node_list) +{ +// knot_dname_t *dname = knot_dname_new_from_wire( +// test_apex.owner.name, test_apex.owner.size, NULL); +// assert(dname); + int errors = 0; + + node *n = NULL; + WALK_LIST(n, node_list) { + test_node_t *test_node = (test_node_t *)n; + knot_node_t *node = node_from_test_node(test_node); + assert(node); + + knot_zone_t *zone = knot_zone_new(node, 0, 0); + if (zone == NULL) { + diag("Could not create zone with owner: %s\n", + test_node->owner->str); + errors++; + } + knot_node_free_rrsets(node, 1); + knot_node_free(&node, 0, 0); + } + + return (errors == 0); +} + +//static int test_zone_add_node(knot_zone_t *zone, int nsec3) +//{ +// /* +// * NSEC3 nodes are de facto identical to normal nodes, so there is no +// * need for separate tests. The only difference is where are they stored +// * in the zone structure. +// */ + +// int errors = 0; +// int res = 0; + +// //note("Good nodes"); + +// for (int i = 0; i < TEST_NODES_GOOD; ++i) { +// knot_node_t *node = knot_node_new(&test_nodes_good[i].owner, +// test_nodes_good[i].parent); +// if (node == NULL) { +// diag("zone: Could not create node."); +// return 0; +// } + +// if ((res = ((nsec3) ? knot_zone_add_nsec3_node(zone, node) +// : knot_zone_add_node(zone, node))) != 0) { +// diag("zone: Failed to insert node into zone (returned" +// " %d).", res); +// knot_node_free(&node, 0); +// ++errors; +// } +// /* TODO check values in the node as well */ +// } + +// //note("Bad nodes"); + +// for (int i = 0; i < TEST_NODES_BAD; ++i) { +// knot_node_t *node = knot_node_new(&test_nodes_bad[i].owner, +// test_nodes_bad[i].parent); +// if (node == NULL) { +// diag("zone: Could not create node."); +// return 0; +// } + +// if ((res = ((nsec3) ? knot_zone_add_nsec3_node(zone, node) +// : knot_zone_add_node(zone, node))) != +// KNOT_EBADZONE) { +// diag("zone: Inserting wrong node did not result in" +// "proper return value (%d instead of %d).", res, +// KNOT_EBADZONE); +// ++errors; +// } +// knot_node_free(&node, 0); +// } + +// // check if all nodes are inserted +// //int nodes = 0; +// if (!nsec3 +// && !test_zone_check_node(knot_zone_apex(zone), &test_apex)) { +// diag("zone: Apex of zone not right."); +//// diag("Apex owner: %s (%p), apex parent: %p\n", +//// knot_dname_to_str(knot_zone_apex(zone)->owner), +//// knot_zone_apex(zone)->owner, +//// knot_zone_apex(zone)->parent); +//// diag("Should be: owner: %s (%p), parent: %p\n", +//// knot_dname_to_str(&test_apex.owner), +//// &test_apex.owner, +//// test_apex.parent); +// ++errors; +// } +// //++nodes; +// for (int i = 0; i < TEST_NODES_GOOD; ++i) { +// const knot_node_t *n = ((nsec3) ? knot_zone_find_nsec3_node( +// zone, &test_nodes_good[i].owner) : +// knot_zone_find_node(zone, &test_nodes_good[i].owner)); +// if (n == NULL) { +// diag("zone: Missing node with owner %s", +// test_nodes_good[i].owner.name); +// ++errors; +// continue; +// } + +// if (!test_zone_check_node(n, &test_nodes_good[i])) { +// diag("zone: Node does not match: owner: %s (should be " +// "%s), parent: %p (should be %p)", +// node->owner->name, test_nodes_good[i].owner.name, +// node->parent, test_nodes_good[i].parent); +// ++errors; +// } +// //++nodes; +// } + +// //note("zone: %d nodes in the zone (including apex)", nodes); + +// return (errors == 0); +//} + +//static int test_zone_get_node(knot_zone_t *zone, int nsec3) +//{ +// int errors = 0; + +// for (int i = 0; i < TEST_NODES_GOOD; ++i) { +// if (((nsec3) ? knot_zone_get_nsec3_node( +// zone, &test_nodes_good[i].owner) +// : knot_zone_get_node(zone, &test_nodes_good[i].owner)) +// == NULL) { +// diag("zone: Node (%s) not found in zone.", +// (char *)test_nodes_good[i].owner.name); +// ++errors; +// } +// } + +// for (int i = 0; i < TEST_NODES_BAD; ++i) { +// if (((nsec3) ? knot_zone_get_nsec3_node( +// zone, &test_nodes_bad[i].owner) +// : knot_zone_get_node(zone, &test_nodes_bad[i].owner)) +// != NULL) { +// diag("zone: Node (%s) found in zone even if it should" +// "not be there.", +// (char *)test_nodes_bad[i].owner.name); +// ++errors; +// } +// } + +// if (((nsec3) +// ? knot_zone_get_nsec3_node(NULL, &test_nodes_good[0].owner) +// : knot_zone_get_node(NULL, &test_nodes_good[0].owner)) != NULL) { +// diag("zone: Getting node from NULL zone did not result in" +// "proper return value (NULL)"); +// ++errors; +// } + +// if (((nsec3) ? knot_zone_get_nsec3_node(zone, NULL) +// : knot_zone_get_node(zone, NULL)) != NULL) { +// diag("zone: Getting node with NULL owner from zone did not " +// "result in proper return value (NULL)"); +// ++errors; +// } + +// if (!nsec3 && knot_zone_get_node(zone, &test_apex.owner) == NULL) { +// diag("zone: Getting zone apex from the zone failed"); +// ++errors; +// } + +// return (errors == 0); +//} + +//static int test_zone_find_node(knot_zone_t *zone, int nsec3) +//{ +// int errors = 0; + +// for (int i = 0; i < TEST_NODES_GOOD; ++i) { +// if (((nsec3) ? knot_zone_find_nsec3_node( +// zone, &test_nodes_good[i].owner) +// : knot_zone_find_node(zone, &test_nodes_good[i].owner)) +// == NULL) { +// diag("zone: Node (%s) not found in zone.", +// (char *)test_nodes_good[i].owner.name); +// ++errors; +// } +// } + +// for (int i = 0; i < TEST_NODES_BAD; ++i) { +// if (((nsec3) ? knot_zone_find_nsec3_node( +// zone, &test_nodes_bad[i].owner) +// : knot_zone_find_node(zone, &test_nodes_bad[i].owner)) +// != NULL) { +// diag("zone: Node (%s) found in zone even if it should" +// "not be there.", +// (char *)test_nodes_bad[i].owner.name); +// ++errors; +// } +// } + +// if (((nsec3) +// ? knot_zone_find_nsec3_node(NULL, &test_nodes_good[0].owner) +// : knot_zone_find_node(NULL, &test_nodes_good[0].owner)) != NULL) { +// diag("zone: Finding node from NULL zone did not result in" +// "proper return value (NULL)"); +// ++errors; +// } + +// if (((nsec3) ? knot_zone_find_nsec3_node(zone, NULL) +// : knot_zone_find_node(zone, NULL)) != NULL) { +// diag("zone: Finding node with NULL owner from zone did not " +// "result in proper return value (NULL)"); +// ++errors; +// } + +// if (!nsec3 && knot_zone_find_node(zone, &test_apex.owner) == NULL) { +// diag("zone: Finding zone apex from the zone failed"); +// ++errors; +// } + +// return (errors == 0); +//} + +static const int KNOT_ZONE_TEST_COUNT = 1; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int knot_zone_tests_count(int argc, char *argv[]) +{ + return KNOT_ZONE_TEST_COUNT; +} + +/*! Run all scheduled tests for given parameters. + */ +static int knot_zone_tests_run(int argc, char *argv[]) +{ + int res = 0, + res_final = 0; + + test_data_t *data = data_for_knot_tests; + + ok((res = test_zone_create(data->node_list)), "zone: create"); + res_final *= res; + +// skip(!res, 6); + +// ok((res = test_zone_add_node(zone, 0)), "zone: add node"); +// res_final *= res; + +// skip(!res, 2); + +// skip(!res, 1); + +// ok((res = test_zone_find_node(zone, 0)), "zone: find node"); +// res_final *= res; + +// endskip; // get node failed + +// endskip; // add node failed + +// ok((res = test_zone_add_node(zone, 1)), "zone: add nsec3 node"); +// res_final *= res; + +// skip(!res, 2); + +// skip(!res, 1); + +// ok((res = test_zone_find_node(zone, 1)), "zone: find nsec3 node"); +// res_final *= res; + +// endskip; // get nsec3 node failed + +// endskip; // add nsec3 node failed + +// endskip; // create failed + + return res_final; +} diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.h b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h new file mode 100644 index 0000000..5539709 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_ZONE_TESTS_H_ +#define _KNOTD_ZONE_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api zone_tests_api; + +#endif /* _KNOTD_ZONE_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c new file mode 100644 index 0000000..96d1517 --- /dev/null +++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "tests/libknot/realdata/libknot/zonedb_tests_realdata.h" + + +static int zonedb_tests_count(int argc, char *argv[]); +static int zonedb_tests_run(int argc, char *argv[]); + +/*! Exported unit API. + */ +unit_api zonedb_tests_api = { + "Zone database", //! Unit name + &zonedb_tests_count, //! Count scheduled tests + &zonedb_tests_run //! Run scheduled tests +}; + +/*! This helper routine should report number of + * scheduled tests for given parameters. + */ +static int zonedb_tests_count(int argc, char *argv[]) +{ + return 0; +} + +/*! Run all scheduled tests for given parameters. + */ +static int zonedb_tests_run(int argc, char *argv[]) +{ + return 0; +} diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h new file mode 100644 index 0000000..0c4f8ef --- /dev/null +++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_ZONEDB_TESTS_H_ +#define _KNOTD_ZONEDB_TESTS_H_ + +#include "common/libtap/tap_unit.h" + +/* Unit API. */ +unit_api zonedb_tests_api; + +#endif /* _KNOTD_ZONEDB_TESTS_H_ */ diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.c b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c new file mode 100644 index 0000000..71a9c3d --- /dev/null +++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c @@ -0,0 +1,1300 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> + +#include "common/libtap/tap.h" +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" +#include "libknot/util/descriptor.h" + +#include "tests/libknot/realdata/parsed_data.rc" +#include "tests/libknot/realdata/raw_data.rc" +TREE_DEFINE(test_node, avl); + +/* Virtual I/O over memory. */ +static int mem_read(void *dst, size_t n, const char **src, + unsigned *remaining) +{ +// printf("reading %u\n", n); + if (n > *remaining) { + return 0; + } + + + memcpy(dst, *src, n); + *src += n; + *remaining -= n; +// printf("remaining %u\n", *remaining); + return 1; +} + +static int load_raw_packets(test_data_t *data, uint32_t *count, + const char *src, unsigned src_size) +{ + + uint16_t tmp_size = 0; + + /* Packets are stored like this: [size][packet_data]+ */ + + if(!mem_read(count, sizeof(uint32_t), &src, &src_size)) { + return -1; + } + + for (int i = 0; i < *count; i++) { + uint16_t query = 0; + if (!mem_read(&query, sizeof(query), &src, &src_size)) { + return -1; + } + + if(!mem_read(&tmp_size, sizeof(uint16_t), &src, &src_size)) { + return -1; + } + + test_raw_packet_t *packet = malloc(sizeof(test_raw_packet_t)); + + + packet->size = tmp_size; + packet->data = malloc(sizeof(uint8_t) * (tmp_size)); + if(!mem_read(packet->data, + sizeof(uint8_t) * tmp_size, &src, &src_size)) { + return -1; + } + + if (query) { + add_tail(&data->raw_query_list, (void *)packet); + } else { + add_tail(&data->raw_response_list, (void *)packet); + } + + test_raw_packet_t *new_packet = + malloc(sizeof(test_raw_packet_t)); + assert(new_packet); + new_packet->data = packet->data; + new_packet->size = packet->size; + + add_tail(&data->raw_packet_list, (void *)new_packet); + } + + return 0; +} + +/* Returns size of type where avalailable */ +size_t wireformat_size_load(uint wire_type) +{ + switch(wire_type) { + case KNOT_RDATA_WF_BYTE: + return 1; + break; + case KNOT_RDATA_WF_SHORT: + return 2; + break; + case KNOT_RDATA_WF_LONG: + return 4; + break; + case KNOT_RDATA_WF_A: + return 4; + break; + case KNOT_RDATA_WF_AAAA: + return 16; + break; + default: /* unknown size */ + return 0; + break; + } /* switch */ +} + +static int add_label(uint8_t **labels, const uint8_t label, + uint *label_count) +{ + void *ret = realloc(*labels, sizeof(uint8_t) * (*label_count + 1)); + if (ret == NULL) { + return -1; + } + + *labels = ret; + (*labels)[(*label_count)++] = label; + + return 0; +} +/* Dnames are stored label by label in the dump */ +/* TODO STRING AS WELL */ +static test_dname_t *load_test_dname(const char **src, + unsigned *src_size) +{ + test_dname_t *ret = malloc(sizeof(test_dname_t)); + CHECK_ALLOC_LOG(ret, NULL); + + ret->size = 0; + ret->str = NULL; + ret->labels = NULL; + ret->wire = NULL; + ret->label_count = 0; + ret->next = NULL; + ret->prev = NULL; + + uint8_t label_size = 0; + uint8_t *label_wire = NULL; + uint8_t *labels = NULL; + char *dname_str = NULL; + uint label_count = 0; + uint dname_length = 0; + do { + /* Read label size */ + if (!mem_read(&label_size, + sizeof(uint8_t), + src, + src_size)) { + fprintf(stderr, "Faulty read\n"); + return NULL; + } + +// diag("%d", label_size); + + add_label(&labels, ret->size, &label_count); + + dname_length += label_size + 1; + + label_wire = malloc(sizeof(uint8_t) * (label_size + 2)); + + if (label_wire == NULL) { + ERR_ALLOC_FAILED; + free(ret); + return NULL; + } + + label_wire[0] = label_size; + + /* Read label wire */ + if (!mem_read(label_wire + 1, + sizeof(uint8_t) * + label_size, + src, + src_size)) { + free(label_wire); + fprintf(stderr, "Faulty read\n"); + return NULL; + } + + label_wire[label_size + 1] = '\0'; + + dname_str = malloc(sizeof(char) * (label_size + 2)); + + if (label_size != 0) { + /* n - 1 : . */ + dname_str[label_size] = '.'; + dname_str[label_size + 1] = '\0'; + + memcpy(dname_str, label_wire + 1, label_size); + } + + if (ret->size == 0) { + ret->wire = malloc(sizeof(uint8_t) * (label_size + 2)); + if (ret->wire == NULL) { + ERR_ALLOC_FAILED; + free(ret); + return NULL; + } + + memcpy(ret->wire, label_wire, label_size + 2); + + if (label_size != 0) { + + ret->str = + malloc(sizeof(char) * (label_size + 2)); + if (ret->str == NULL) { + ERR_ALLOC_FAILED; + free(ret->wire); + free(ret); + return NULL; + } + + memcpy(ret->str, dname_str, label_size + 2); + } + + ret->size = label_size + 2; + } else { + /* Concatenate */ + void *p = realloc(ret->wire, + ret->size + (label_size + 2)); + if (p == NULL) { + ERR_ALLOC_FAILED; + free(ret->wire); + free(ret->labels); + free(ret); + return NULL; + } + ret->wire = p; + + /* TODO Safe concat? But I set the values myself, right? */ + /* or maybe memcpy... */ + strcat((char *)ret->wire, (char *)label_wire); + assert(ret->wire); + + + if (label_size != 0) { + + p = realloc(ret->str, + ret->size + (label_size + 2)); + if (p == NULL) { + ERR_ALLOC_FAILED; + free(ret->wire); + free(ret->str); + free(ret->labels); + free(ret); + return NULL; + } + ret->str = p; + + strcat(ret->str, dname_str); + assert(ret->str); + } + + ret->size += label_size + 2; + } + + free(label_wire); + free(dname_str); + + } while (label_size != 0); + + /*!< \warning even wireformat is ended with 0 every time !!! */ + + /* Root domain */ +// if (ret->size == 0) { +// assert(ret->wire == NULL); + +// ret->wire = malloc(sizeof(uint8_t) * 1); +// if (ret->wire == NULL) { +// ERR_ALLOC_FAILED; +// free(ret); +// return NULL; +// } + +// ret->wire[0] = '\0'; + +// ret->labels = malloc(sizeof(uint8_t) * 1); +// if (ret->labels == NULL) { +// ERR_ALLOC_FAILED; +// free(ret->wire); +// free(ret); +// return NULL; +// } + +// ret->labels[0] = '\0'; +// ret->label_count = 1; +// } + +// printf("OK: %s (%d)\n",ret->str, ret->size); + + ret->labels = labels; + ret->size = ret->size - (label_count); + ret->label_count = --label_count; + ret->next = NULL; + ret->prev = NULL; + + assert(ret != NULL); + + return ret; +} + +/*! + * \brief Reads dname label by label + */ +static test_rdata_t *load_response_rdata(uint16_t type, + const char **src, + unsigned *src_size) +{ + +#ifdef RESP_TEST_DEBUG + fprintf(stderr, "reading rdata for type: %s\n", + knot_rrtype_to_string(type)); +#endif + /* + * Binary format of rdata is as following: + * [total_length(except for some types) - see below][rdata_item]+ + * Dname items are read label by label + */ + + test_rdata_t *rdata = malloc(sizeof(test_rdata_t)); + + CHECK_ALLOC_LOG(rdata, NULL); + + rdata->count = 0; + rdata->items = NULL; + rdata->type = 0; + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + assert(desc != NULL); + + rdata->type = type; + + test_item_t *items = + malloc(sizeof(test_item_t) * desc->length); + + if (items == NULL) { + ERR_ALLOC_FAILED; + free(rdata); + return NULL; + } + + /* TODO consider realloc */ + + uint16_t total_raw_data_length = 0; + uint8_t raw_data_length; + + /* + * These types have no length, unfortunatelly (python library + * does not provide this) + */ + /* TODO the are more types with no length for sure ... */ + + if (type != KNOT_RRTYPE_A && + type != KNOT_RRTYPE_NS && + type != KNOT_RRTYPE_AAAA) { + if (!mem_read(&total_raw_data_length, + sizeof(total_raw_data_length), src, src_size)) { + free(rdata); + free(items); + fprintf(stderr, "Faulty read\n"); + return NULL; + } + } + + size_t total_read = 0; + + int i; + + /* + * TODO save number of items + * in the dump - of minor importance, however + */ + for (i = 0; i < desc->length; i++) { + if ((desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME)) { + unsigned tmp_remaining = *src_size; + items[i].dname = load_test_dname(src, src_size); + + if (items[i].dname == NULL) { + fprintf(stderr, "Could not load DNAME!\n"); + free(rdata); + free(items); + + /* TODO something like Marek's purge */ + + return NULL; + } + +// diag("Created DNAME %p item: %d %s %s\n", +// items[i].dname, i, knot_rrtype_to_string(type), +// items[i].dname->str); + + rdata->count++; + items[i].type = TEST_ITEM_DNAME; + items[i].raw_data = NULL; + total_read += tmp_remaining - *src_size; + } else { + if (desc->wireformat[i] == + KNOT_RDATA_WF_BINARYWITHLENGTH) { + if (!mem_read(&raw_data_length, + sizeof(raw_data_length), src, src_size)) { + return NULL; + } + + total_read++; + + items[i].raw_data = + malloc(sizeof(uint8_t) * + (raw_data_length + 3)); + + items[i].raw_data[0] = + (uint16_t) raw_data_length + 1; + + /* let's store the length again */ + + ((uint8_t *)items[i].raw_data)[2] = + raw_data_length; + + if (!mem_read(((uint8_t *) + items[i].raw_data) + 3, + sizeof(uint8_t) * (raw_data_length), + src, src_size)) { + fprintf(stderr, "Wrong read!\n"); + return NULL; + } + + rdata->count++; + items[i].type = TEST_ITEM_RAW_DATA; + items[i].dname = NULL; + total_read += sizeof(uint8_t) * raw_data_length; +/* printf("read len (from wire): %d\n", + items[i].raw_data[0]); + hex_print((char *)items[i].raw_data + 1, + items[i].raw_data[0]); + */ + } else { + /* Other type than dname or BINARYWITHLENGTH */ + /* Set dname to NULL */ + items[i].dname = NULL; + + uint16_t size_fr_desc = + (uint16_t) + wireformat_size_load(desc->wireformat[i]); +#ifdef RESP_TEST_DEBUG + fprintf(stderr, "reading %d\n", size_fr_desc); +#endif + + if (size_fr_desc == 0) { /* unknown length */ +/* size_fr_desc = wireformat_size_n(type, + items, + i); + */ + if ((i != desc->length - 1) && + desc->wireformat[i] != + KNOT_RDATA_WF_TEXT ) { + fprintf(stderr, + "I dont know how " + "to parse this type: %d\n", + type); + return NULL; + } else { + size_fr_desc = + total_raw_data_length - + total_read; + if (desc->wireformat[i] == + KNOT_RDATA_WF_TEXT) { + break; + } + +// fprintf(stderr, +// "Guessed size: %d" +// " for type: %s" +// " and index: %d\n", +// size_fr_desc, +// knot_rrtype_to_string(type), +// i); + } + } + + items[i].raw_data = + malloc(sizeof(uint8_t) * size_fr_desc + 2); + +// diag("creating raw_data for item %d type %s %p\n", +// i, knot_rrtype_to_string(type), +// items[i].raw_data); + + if (items[i].raw_data == NULL) { + ERR_ALLOC_FAILED; + free(rdata); + free(items); + return NULL; + } + + items[i].raw_data[0] = size_fr_desc; + + if (!mem_read(items[i].raw_data + 1, + size_fr_desc, + src, src_size)) { + fprintf(stderr, "Wrong read\n!"); + return NULL; + } + + rdata->count++; + items[i].type = TEST_ITEM_RAW_DATA; + items[i].dname = NULL; + total_read += size_fr_desc; + +#ifdef RESP_TEST_DEBUG + fprintf(stderr, + "read len (from descriptor): %d\n", + items[i].raw_data[0]); +/* hex_print((char *)items[i].raw_data + 1, + items[i].raw_data[0]); */ + + if (desc->zoneformat[i] == + KNOT_RDATA_ZF_ALGORITHM) { + hex_print((char *)items[i].raw_data, + items[i].raw_data[0] + 2); + } else { + hex_print((char *)items[i].raw_data, + items[i].raw_data[0] + 2); + } +#endif + } + } + } + +/* if (knot_rdata_set_items(rdata, items, i) != 0) { + diag("Error: could not set items\n"); + return NULL; + } */ + + rdata->items = items; + + return rdata; +} + +static test_rrset_t *load_response_rrset(const char **src, unsigned *src_size, + char is_question) +{ + test_rrset_t *rrset = NULL; + uint16_t rrset_type = 0; + uint16_t rrset_class = 0; + uint32_t rrset_ttl = 0; + + /* Each rrset will only have one rdata entry */ + + /* + * RRSIGs will be read as separate RRSets because that's the way they + * are stored in responses + */ + + /* Read owner first */ + + uint8_t dname_size; +// uint8_t *dname_wire = NULL; + + rrset = malloc(sizeof(test_rrset_t)); + + rrset->rrsigs = NULL; + + CHECK_ALLOC_LOG(rrset, NULL); + + init_list(&rrset->rdata_list); + + /* TODO change in dump, size is useless now! */ + if (!mem_read(&dname_size, sizeof(dname_size), src, src_size)) { + free(rrset); + return NULL; + } + +/* dname_wire = malloc(sizeof(uint8_t) * dname_size); + + CHECK_ALLOC_LOG(dname_wire, NULL); + + if (!mem_read(dname_wire, sizeof(uint8_t) * dname_size, src, + src_size)) { + free(dname_wire); + return NULL; + } */ + + test_dname_t *owner = load_test_dname(src, src_size); + + if (owner == NULL) { + free(rrset); + return NULL; + } + +#ifdef RESP_TEST_DEBUG + { + fprintf(stderr, "Got owner: %s", owner->str); + } +#endif + /* Read other data */ + + if (!mem_read(&rrset_type, sizeof(rrset_type), src, src_size)) { + return NULL; + } + + if (!mem_read(&rrset_class, sizeof(rrset_class), src, src_size)) { + return NULL; + } + + if (!is_question) { + if (!mem_read(&rrset_ttl, sizeof(rrset_ttl), src, src_size)) { + return NULL; + } + } else { + rrset_ttl = 0; + } + +// rrset = knot_rrset_new(owner, rrset_type, rrset_class, rrset_ttl); + + rrset->owner = owner; + rrset->type = rrset_type; + rrset->rclass = rrset_class; + rrset->ttl = rrset_ttl; + + /* Question rrsets have no rdata */ + + if (!is_question) { + test_rdata_t *tmp_rdata; + + tmp_rdata = load_response_rdata(rrset->type, src, src_size); + + if (tmp_rdata == NULL) { + fprintf(stderr, + "Could not load rrset rdata - type: %d", + rrset->type); + free(rrset); + return NULL; + } + + assert(tmp_rdata->type == rrset->type); + + add_tail(&rrset->rdata_list, (node *)tmp_rdata); + } + + return rrset; +} + +static test_response_t *load_parsed_response(const char **src, + unsigned *src_size) +{ + /* Loads parsed response/query from binary format, + * which is as following: + * [id][qdcount][ancount][nscount][arcount] + * [question_rrset+][answer_rrset+][authority_rrset+] + * [additional_rrset]+ + */ + + test_response_t *resp = malloc(sizeof(test_response_t)); + + CHECK_ALLOC_LOG(resp, NULL); + + if (!mem_read(&resp->id, sizeof(resp->id), src, src_size)) { + free(resp); + return NULL; + } + +#ifdef RESP_TEST_DEBUG + fprintf(stderr, "id %d\n", resp->id); +#endif + + if (!mem_read(&resp->qdcount, sizeof(resp->qdcount), src, src_size)) { + free(resp); + return NULL; + } + +#ifdef RESP_TEST_DEBUG + fprintf(stderr, "qdcount: %d\n", resp->qdcount); +#endif + + if (!mem_read(&resp->ancount, sizeof(resp->ancount), src, src_size)) { + free(resp); + return NULL; + } + +#ifdef RESP_TEST_DEBUG + fprintf(stderr, "ancount: %d\n", resp->ancount); +#endif + + if (!mem_read(&resp->nscount, sizeof(resp->nscount), src, src_size)) { + free(resp); + return NULL; + } + +#ifdef RESP_TEST_DEBUG + fprintf(stderr, "nscount: %d\n", resp->nscount); +#endif + + if (!mem_read(&resp->arcount, sizeof(resp->arcount), src, src_size)) { + free(resp); + return NULL; + } + +#ifdef RESP_TEST_DEBUG + fprintf(stderr, "arcount: %d\n", resp->arcount); +#endif + + if (!mem_read(&resp->query, sizeof(resp->query), src, src_size)) { + free(resp); + return NULL; + } + + test_rrset_t **question_rrsets; + + question_rrsets = malloc(sizeof(test_rrset_t *) * resp->qdcount); + + for (int i = 0; i < resp->qdcount; i++) { + question_rrsets[i] = load_response_rrset(src, src_size, 1); + if (question_rrsets[i] == NULL) { + fprintf(stderr, "Could not load question rrsets\n"); + + for (int j = 0; j < i; j++) { + free(question_rrsets[i]); + } + free(question_rrsets); + free(resp); + return NULL; + } + } + + /* only one question in our case */ + + resp->qname = question_rrsets[0]->owner; + resp->qtype = question_rrsets[0]->type; + resp->qclass = question_rrsets[0]->rclass; + + resp->question = NULL; + +/* for (int i = 0; i < resp->qdcount; i++) { + knot_rrset_free(&(question_rrsets[i])); + } */ + + free(question_rrsets); + + test_rrset_t *tmp_rrset = NULL; + + if (resp->ancount > 0) { + resp->answer = + malloc(sizeof(test_rrset_t *) * resp->ancount); + } else { + resp->answer = NULL; + } + + for (int i = 0; i < resp->ancount; i++) { + tmp_rrset = load_response_rrset(src, src_size, 0); + resp->answer[i] = tmp_rrset; + if (resp->answer[i] == NULL) { + fprintf(stderr, "Could not load answer rrsets\n"); + free(resp->answer); + free(resp); + return NULL; + } + } + + if (resp->nscount > 0) { + resp->authority = + malloc(sizeof(test_rrset_t *) * resp->nscount); + } else { + resp->authority = NULL; + } + + for (int i = 0; i < resp->nscount; i++) { + tmp_rrset = load_response_rrset(src, src_size, 0); + resp->authority[i] = tmp_rrset; + if (resp->authority[i] == NULL) { + fprintf(stderr, "Could not load authority rrsets\n"); + free(resp->authority); + free(resp->answer); + free(resp); + return NULL; + } + } + + if (resp->arcount > 0) { + resp->additional = + malloc(sizeof(test_rrset_t *) * resp->arcount); + } else { + resp->additional = NULL; + } + + for (int i = 0; i < resp->arcount; i++) { + tmp_rrset = load_response_rrset(src, src_size, 0); + if (tmp_rrset == NULL) { + fprintf(stderr, "Could not load rrset (additional)\n"); + free(resp->additional); + free(resp->authority); + free(resp->answer); + free(resp); + return NULL; + } + + resp->additional[i] = tmp_rrset; + } + + /* this will never be used */ + + resp->flags1 = 0; + resp->flags2 = 0; + + return resp; +} + +static void test_dname_free(test_dname_t **dname) +{ + assert(dname != NULL && *dname != NULL); + free((*dname)->labels); +// free((*dname)->str); + free((*dname)->wire); + + free(*dname); + *dname = NULL; +} + +static int wire_is_dname(uint type) +{ + return (type == KNOT_RDATA_WF_COMPRESSED_DNAME || + type == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + type == KNOT_RDATA_WF_LITERAL_DNAME); +} + +static void test_rdata_free(test_rdata_t **rdata) +{ + assert(rdata != NULL && *rdata != NULL); + + /* Free all the items */ + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type((*rdata)->type); + + for (int i = 0; i < (*rdata)->count; i++) { + if ((wire_is_dname(desc->wireformat[i])) && + ((*rdata)->items[i].dname != NULL)) { + test_dname_free(&(*rdata)->items[i].dname); + } else if ((*rdata)->items[i].raw_data != NULL) { + free((*rdata)->items[i].raw_data); + (*rdata)->items[i].raw_data = NULL; + } + } +// free((*rdata)->items); +// free(*rdata); + *rdata = NULL; +} + +static void test_rrset_free(test_rrset_t **rrset) +{ + assert(rrset && *rrset); + + test_dname_free(&(*rrset)->owner); + /* Free all the rdatas */ + node *n = NULL, *nxt = NULL; + WALK_LIST_DELSAFE(n, nxt, (*rrset)->rdata_list) { + test_rdata_t *tmp_rdata = (test_rdata_t *)n; + assert(tmp_rdata); + if (tmp_rdata != NULL) { + test_rdata_free(&tmp_rdata); + } + } + + free(*rrset); + *rrset = NULL; +} + +static void test_response_free(test_response_t **response) +{ + assert(response && *response); + if ((*response)->qname != NULL) { + test_dname_free(&(*response)->qname); + } + + if ((*response)->additional != NULL) { + for (int j = 0; j < (*response)->arcount; j++) { + test_rrset_free(&((*response)->additional[j])); + } + + free((*response)->additional); + } + + if ((*response)->answer != NULL) { + for (int j = 0; j < (*response)->ancount; j++) { + test_rrset_free(&((*response)->answer[j])); + } + + free((*response)->answer); + } + + if ((*response)->authority != NULL) { + for (int j = 0; j < (*response)->nscount; j++) { + test_rrset_free(&((*response)->authority[j])); + } + + free((*response)->authority); + } + + free((*response)); + *response = NULL; +} + +static void get_and_save_data_from_rdata(test_rdata_t *rdata, + test_data_t *data, uint16_t type) +{ + /* We only want to extract dnames */ + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + + if (rdata->count == 0) { +// diag("Rdata count not set!\n"); + rdata->count = desc->length; + } + + for(int i = 0; i < rdata->count; i++) { + if ((desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME)) { + add_tail(&data->dname_list, + (node *)rdata->items[i].dname); + test_item_t *temp_item = malloc(sizeof(test_item_t)); + temp_item->dname = rdata->items[i].dname; + temp_item->type = TEST_ITEM_DNAME; + temp_item->raw_data = NULL; + add_tail(&data->item_list, (node *)temp_item); + } else { + test_item_t *temp_item = malloc(sizeof(test_item_t)); + temp_item->dname = NULL; + temp_item->type = TEST_ITEM_RAW_DATA; + temp_item->raw_data = rdata->items[i].raw_data; + add_tail(&data->item_list, (node *)temp_item); + } + } +} + +static void get_and_save_data_from_rrset(const test_rrset_t *rrset, + test_data_t *data) +{ +// knot_rrtype_descriptor_t *desc = +// knot_rrtype_descriptor_by_type(rrset->type); + /* RDATA are in a list. */ + node *n = NULL; + int i = 0; + WALK_LIST(n, rrset->rdata_list) { + test_rdata_t *tmp_rdata = (test_rdata_t *)n; + assert(tmp_rdata); + assert(&data->rdata_list); + assert(&data->rdata_list != &rrset->rdata_list); + assert(tmp_rdata->type == rrset->type); + + test_rdata_t *new_rdata = malloc(sizeof(test_rdata_t)); + new_rdata->count = tmp_rdata->count; + new_rdata->items = tmp_rdata->items; + new_rdata->type = tmp_rdata->type; + + add_tail(&data->rdata_list, (node *)new_rdata); + get_and_save_data_from_rdata(tmp_rdata, data, rrset->type); + i++; + } + assert(i == 1); +} + +static int add_rrset_to_node(const test_rrset_t *rrset, test_data_t *data) +{ + /* First, create node from rrset */ + test_node_t *tmp_node = malloc(sizeof(test_node_t)); + memset(tmp_node, 0, sizeof(test_node_t)); + CHECK_ALLOC_LOG(tmp_node, -1); + + tmp_node->owner = rrset->owner; + tmp_node->parent = NULL; + tmp_node->rrset_count = 0; + + /* Will not be used in list now */ + tmp_node->prev = NULL; + tmp_node->next = NULL; + + +// printf("%s\n", rrset->owner->wire); +// getchar(); + +/* tmp_node->avl_left = NULL; + tmp_node->avl_right = NULL; + tmp_node->avl_height = 0; */ + + test_node_t *found_node = + TREE_FIND(data->node_tree, test_node, avl, tmp_node); + + if (found_node == NULL) { + /* Insert new node with current rrset */ + init_list(&tmp_node->rrset_list); + add_tail(&tmp_node->rrset_list, (node *)rrset); + tmp_node->rrset_count++; + + TREE_INSERT(data->node_tree, test_node, avl, tmp_node); + } else { + free(tmp_node); + /* append rrset */ + + add_tail(&found_node->rrset_list, (node *)rrset); + found_node->rrset_count++; + } + + return 0; +} + +static void get_and_save_data_from_response(const test_response_t *response, + test_data_t *data) +{ + /* Go through all the rrsets in the response */ + + for (int i = 0; i < response->ancount; i++) { + assert(response->answer[i]); + /* Add rrset to the list of rrsets - there will be duplicates + * But not the same pointers */ + add_tail(&data->rrset_list, (node *)response->answer[i]); + get_and_save_data_from_rrset(response->answer[i], data); + if (add_rrset_to_node(response->answer[i], data) != 0) { + return; + } + } + + for (int i = 0; i < response->arcount; i++) { + /* Add rrset to the list of rrsets - there will be duplicates */ + assert(response->additional[i]); + add_tail(&data->rrset_list, (node *)response->additional[i]); + get_and_save_data_from_rrset(response->additional[i], data); + if (add_rrset_to_node(response->additional[i], data) != 0) { + return; + } + } + + for (int i = 0; i < response->nscount; i++) { + assert(response->authority[i]); + /* Add rrset to the list of rrsets - there will be duplicates */ + add_tail(&data->rrset_list, (node *)response->authority[i]); + get_and_save_data_from_rrset(response->authority[i], data); + if (add_rrset_to_node(response->authority[i], data) != 0) { + return; + } + } + +// for (int i = 0; i < response->qdcount; i++) { +// /* Add rrset to the list of rrsets - there will be duplicates */ +// add_tail(&data->rrset_list, (node *)response->question[i]); +// get_and_save_data_from_rrset(response->question[i], data); +// } +} + +static int load_parsed_responses(test_data_t *data, uint32_t *count, + const char* src, unsigned src_size) +{ + if (!mem_read(count, sizeof(*count), &src, &src_size)) { + fprintf(stderr, "Wrong read\n"); + return -1; + } + +// *responses = malloc(sizeof(test_response_t *) * *count); + + for (int i = 0; i < *count; i++) { + test_response_t *tmp_response = + load_parsed_response(&src, &src_size); + + if (tmp_response == NULL) { + fprintf(stderr, "Could not load response - %d" + "- returned NULL\n", + i); + return -1; + } + + if (tmp_response->query) { + add_tail(&data->query_list, (node *)tmp_response); + } else { + add_tail(&data->response_list, (node *)tmp_response); + } + + /* Create new node */ + test_response_t *resp = malloc(sizeof(test_response_t)); + assert(resp); + memcpy(resp, tmp_response, sizeof(test_response_t)); + add_tail(&data->packet_list, + (node *)resp); + } + + return 0; +} + +//void free_parsed_responses(test_response_t ***responses, uint32_t *count) +//{ +// if (*responses != NULL) { +// for (int i = 0; i < *count; i++) { +// free_parsed_response((*responses)[i]); +// } +// free(*responses); +// } +//} + +static int compare_nodes(test_node_t *node1, test_node_t *node2) +{ + assert(node1->owner && node2->owner); + /*!< \warning Wires have to be \0 terminated. */ + return (strcmp((char *)node1->owner->wire, (char *)node2->owner->wire)); +} + +static int init_data(test_data_t *data) +{ + if (data == NULL) { + return 0; + } + + /* Initialize all the lists */ + init_list(&data->dname_list); + init_list(&data->edns_list); + init_list(&data->node_list); + init_list(&data->response_list); + init_list(&data->rdata_list); + init_list(&data->rrset_list); + init_list(&data->item_list); + init_list(&data->raw_response_list); + init_list(&data->raw_query_list); + init_list(&data->raw_packet_list); + init_list(&data->query_list); + init_list(&data->packet_list); + + data->node_tree = malloc(sizeof(avl_tree_test_t)); + CHECK_ALLOC_LOG(data->node_tree, 0); + + TREE_INIT(data->node_tree, compare_nodes); + + return 1; +} + +static void print_stats(test_data_t *data) +{ + uint resp_count = 0, dname_count = 0, node_count = 0, + rdata_count = 0, rrset_count = 0, item_count = 0, query_count = 0, + raw_query_count = 0, response_count = 0, packet_count = 0, + raw_packet_count = 0, raw_response_count = 0; + + node *n = NULL; /* Will not be used */ + + WALK_LIST(n, data->response_list) { + resp_count++; + } + + WALK_LIST(n, data->rrset_list) { +// node *tmp = NULL; +// assert(((test_rrset_t *)n)->owner); +// WALK_LIST(tmp, ((test_rrset_t *)n)->rdata_list) { +// test_rdata_t *rdata = (test_rdata_t *)tmp; +// assert(rdata->type == ((test_rrset_t *)n)->type); +// } + rrset_count++; + } + + WALK_LIST(n, data->rdata_list) { + rdata_count++; + } + + WALK_LIST(n, data->dname_list) { + dname_count++; + } + + WALK_LIST(n, data->node_list) { + node_count++; + } + + WALK_LIST(n, data->item_list) { + item_count++; + } + + WALK_LIST(n, data->raw_response_list) { + raw_response_count++; + } + + WALK_LIST(n, data->query_list) { + query_count++; + } + + WALK_LIST(n, data->response_list) { + response_count++; + } + + WALK_LIST(n, data->raw_query_list) { + raw_query_count++; + } + + WALK_LIST(n, data->packet_list) { + packet_count++; + } + + WALK_LIST(n, data->raw_packet_list) { + raw_packet_count++; + } + + printf("Loaded: Responses: %d RRSets: %d RDATAs: %d Dnames: %d " + "Nodes: %d Items: %d Raw_responses: %d Queries: %d \n" + "Raw_queries; %d Total packets: %d Total_raw_packets: %d\n", resp_count, rrset_count, + rdata_count, dname_count, node_count, item_count, + raw_response_count, query_count, raw_query_count, packet_count, + raw_packet_count); +} + +static void save_node_to_list(test_node_t *n, void *p) +{ + test_data_t *data = (test_data_t *)p; + + add_tail(&data->node_list, (node *)n); +} + +static void del_node(test_node_t *n, void *p) +{ +// test_data_t *data = (test_data_t *)p; + free(n); +} + + +void free_data(test_data_t **data) +{ + assert(data && *data); + /* We will free all the data using responses + * (others are just references )*/ + node *n = NULL, *nxt = NULL; + WALK_LIST_DELSAFE(n, nxt, (*data)->response_list) { + test_response_t *tmp_response = (test_response_t *)n; + if (tmp_response != NULL) { + test_response_free(&tmp_response); + } + } + + TREE_POST_ORDER_APPLY((*data)->node_tree, test_node, avl, del_node, + NULL); + + free((*data)->node_tree); + + free(*data); + *data = NULL; +} + +test_data_t *create_test_data_from_dump() +{ + test_data_t *ret = malloc(sizeof(test_data_t)); + CHECK_ALLOC_LOG(ret, NULL); + + if (!init_data(ret)) { + free(ret); + return NULL; + } + + uint32_t raw_packet_count = 0; + + if (load_raw_packets(ret, &raw_packet_count, raw_data_rc, + raw_data_rc_size) != 0) { + fprintf(stderr, "Could not load raw_data, quitting"); + /* TODO walk the lists*/ + free(ret); + return NULL; + } + + uint32_t response_count = 0; + + if (load_parsed_responses(ret, &response_count, parsed_data_rc, + parsed_data_rc_size) != 0) { + fprintf(stderr, "Could not load responses, quitting"); + /* TODO walk the lists*/ + free(ret); + return NULL; + } + + /* For each parsed response - create more data from it. */ + /* Probably not the most effective way, but it is better than to + * rewrite most of the code .*/ + + node *n = NULL; + + WALK_LIST(n , ret->response_list) { + get_and_save_data_from_response((test_response_t *)n, ret); + } + + /* Create list from AVL tree */ + + TREE_FORWARD_APPLY(ret->node_tree, test_node, avl, + save_node_to_list, ret); + + print_stats(ret); + + return ret; +} diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.h b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h new file mode 100644 index 0000000..8f57944 --- /dev/null +++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h @@ -0,0 +1,179 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KNOT_TESTS_LOADER_H +#define KNOT_TESTS_LOADER_H + +#include <stdint.h> + +#include "libknot/common.h" +#include "common/lists.h" +#include "common/tree.h" + + +/* Parsed raw packet*/ +struct test_raw_packet { + struct node *next, *prev; + uint size; + uint8_t *data; +}; + +typedef struct test_raw_packet test_raw_packet_t; + +/* Test type definitions */ + +struct test_dname { + struct node *next, *prev; + char *str; + uint8_t *wire; + uint size; + uint8_t *labels; + short label_count; +}; + +typedef struct test_dname test_dname_t; + +struct test_edns_options { + struct node *next, *prev; + uint16_t code; + uint16_t length; + uint8_t *data; +}; + +struct test_edns { + struct node *next, *prev; + struct test_edns_options *options; + uint16_t payload; + uint8_t ext_rcode; + uint8_t version; + uint16_t flags; + uint16_t *wire; + short option_count; + short options_max; + short size; +}; + +typedef struct test_edns test_edns_t; + +typedef TREE_HEAD(avl_tree_test, test_node) avl_tree_test_t; + +struct test_node { + struct node *next, *prev; + test_dname_t *owner; + short rrset_count; + struct test_node *parent; + list rrset_list; + + TREE_ENTRY(test_node) avl; +}; + +typedef struct test_node test_node_t; + +enum item_type { + TEST_ITEM_DNAME, + TEST_ITEM_RAW_DATA +}; + +typedef enum item_type item_type_t; + +struct test_item { + uint16_t *raw_data; + test_dname_t *dname; + item_type_t type; +}; + +typedef struct test_item test_item_t; + +struct test_rdata { + struct node *next, *prev; + uint count; + uint type; /*!< Might be handy */ + test_item_t *items; +}; + +typedef struct test_rdata test_rdata_t; + +struct test_rrset { + struct node *next, *prev; + test_dname_t *owner; + uint16_t type; + uint16_t rclass; + uint32_t ttl; + struct test_rrset *rrsigs; + uint16_t *wire; + list rdata_list; +}; + +typedef struct test_rrset test_rrset_t; + +struct test_response { + struct node *next, *prev; + /* This is basically same thing as actual response structure */ + uint16_t query; + test_dname_t *qname; + uint16_t qclass; + uint16_t qtype; + uint16_t id; + uint8_t flags1; + uint8_t flags2; + uint16_t qdcount; + uint16_t ancount; + uint16_t nscount; + uint16_t arcount; + + /* Arrays of rrsets */ + + test_rrset_t **question; + test_rrset_t **answer; + test_rrset_t **authority; + test_rrset_t **additional; + + short size; + + /* what about the rest of the values? + * they cannot be modified from API, but this is probably the best + * place to test them as well */ +}; + +typedef struct test_response test_response_t; + +/*!< \brief contains lists of all the structures */ +struct test_data { + list dname_list; + list edns_list; + list rdata_list; + list node_list; + list rrset_list; + list response_list; + list raw_response_list; + list query_list; + list raw_query_list; + list item_list; + /* responses and queries together */ + list packet_list; + list raw_packet_list; + + avl_tree_test_t *node_tree; +}; + +typedef struct test_data test_data_t; + +/*!< \brief Parses resource with data and creates all possible structures. */ +test_data_t *create_test_data_from_dump(); + +test_data_t *data_for_knot_tests; + +#endif // KNOT_TESTS_LOADER_H diff --git a/src/tests/libknot/realdata/unittests_libknot_realdata.c b/src/tests/libknot/realdata/unittests_libknot_realdata.c new file mode 100644 index 0000000..e557c43 --- /dev/null +++ b/src/tests/libknot/realdata/unittests_libknot_realdata.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +//#include "knot/common.h" +#include "common/libtap/tap_unit.h" + +#include "tests/libknot/realdata/libknot_tests_loader_realdata.h" + +// Units to test +#include "tests/libknot/realdata/libknot/dname_tests_realdata.h" +#include "tests/libknot/realdata/libknot/response_tests_realdata.h" +//#include "libknot/edns_tests.h" +#include "tests/libknot/realdata/libknot/node_tests_realdata.h" +#include "tests/libknot/realdata/libknot/rdata_tests_realdata.h" +//#include "libknot/response_tests_realdata.h" +#include "tests/libknot/realdata/libknot/rrset_tests_realdata.h" +//#include "libknot/zone_tests_realdata.h" +#include "tests/libknot/realdata/libknot/zonedb_tests_realdata.h" +#include "tests/libknot/realdata/libknot/packet_tests_realdata.h" + +#include "common/lists.h" +// Run all loaded units +int main(int argc, char *argv[]) +{ + data_for_knot_tests = create_test_data_from_dump(); + + if (data_for_knot_tests == NULL) { + diag("Data could not be loaded!"); + return 0; + } + + // Open log +// log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING)); + + // Build test set + unit_api *tests[] = { + + /* DNS units */ +// &cuckoo_tests_api, //! Cuckoo hashing unit + &dname_tests_api, //! DNS library (dname) unit +// &edns_tests_api, //! DNS library (EDNS0) unit + &node_tests_api, //! DNS library (node) unit + &rdata_tests_api, //! DNS library (rdata) unit + &packet_tests_api, +// &response_tests_api, //! DNS library (response) unit + &response_tests_api, //! DNS library (response) unit + &rrset_tests_api, //! DNS library (rrset) unit +// &zone_tests_api, //! DNS library (zone) unit +// &zonedb_tests_api, //! DNS library (zonedb) unit + NULL + }; + + // Plan number of tests + int id = 0; + int test_count = 0; + note("Units:"); + while (tests[id] != NULL) { + note("- %s : %d tests", tests[id]->name, + tests[id]->count(argc, argv)); + test_count += tests[id]->count(argc, argv); + ++id; + } + + plan(test_count); + + // Run tests + id = 0; + while (tests[id] != NULL) { + diag("Testing unit: %s", tests[id]->name); + tests[id]->run(argc, argv); + ++id; + } + +// log_close(); + + // Evaluate + return exit_status(); +} + diff --git a/src/tests/libknot/unittests_libknot.c b/src/tests/libknot/unittests_libknot.c new file mode 100644 index 0000000..62d4b90 --- /dev/null +++ b/src/tests/libknot/unittests_libknot.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include "knot/common.h" +#include "common/libtap/tap_unit.h" + +// Units to test +#include "tests/libknot/libknot/cuckoo_tests.h" +#include "tests/libknot/libknot/dname_tests.h" +#include "tests/libknot/libknot/edns_tests.h" +#include "tests/libknot/libknot/node_tests.h" +#include "tests/libknot/libknot/rdata_tests.h" +#include "tests/libknot/libknot/response_tests.h" +#include "tests/libknot/libknot/rrset_tests.h" +#include "tests/libknot/libknot/zone_tests.h" +#include "tests/libknot/libknot/dname_table_tests.h" +#include "tests/libknot/libknot/nsec3_tests.h" +#include "tests/libknot/libknot/packet_tests.h" +#include "tests/libknot/libknot/query_tests.h" +#include "tests/libknot/libknot/zonedb_tests.h" +#include "tests/libknot/libknot/zone_tree_tests.h" + +// Run all loaded units +int main(int argc, char *argv[]) +{ + // Open log +// log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING)); + + // Build test set + unit_api *tests[] = { + + /* DNS units */ + &cuckoo_tests_api, //! Cuckoo hashing unit + &dname_tests_api, //! DNS library (dname) unit + &edns_tests_api, //! DNS library (EDNS0) unit + &zone_tests_api, //! DNS library (zone) unit + &node_tests_api, //! DNS library (node) unit + &rdata_tests_api, //! DNS library (rdata) unit + &response_tests_api, //! DNS library (response) unit + &rrset_tests_api, //! DNS library (rrset) unit + &dname_table_tests_api, + &nsec3_tests_api, + &packet_tests_api, + &query_tests_api, + &zonedb_tests_api, //! DNS library (zonedb) unit + &zone_tree_tests_api, + NULL + }; + + // Plan number of tests + int id = 0; + int test_count = 0; + note("Units:"); + while (tests[id] != NULL) { + note("- %s : %d tests", tests[id]->name, + tests[id]->count(argc, argv)); + test_count += tests[id]->count(argc, argv); + ++id; + } + + plan(test_count); + + // Run tests + id = 0; + while (tests[id] != NULL) { + diag("Testing unit: %s", tests[id]->name); + tests[id]->run(argc, argv); + ++id; + } + +// log_close(); + + // Evaluate + return exit_status(); +} + diff --git a/src/tests/unittests_main.c b/src/tests/unittests_main.c new file mode 100644 index 0000000..2d57ed2 --- /dev/null +++ b/src/tests/unittests_main.c @@ -0,0 +1,84 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include "knot/common.h" +#include "common/libtap/tap_unit.h" + +// Units to test +#include "tests/common/slab_tests.h" +#include "tests/common/skiplist_tests.h" +#include "tests/common/events_tests.h" +#include "tests/common/da_tests.h" +#include "tests/common/acl_tests.h" +#include "tests/common/fdset_tests.h" +#include "tests/knot/dthreads_tests.h" +#include "tests/knot/journal_tests.h" +#include "tests/knot/server_tests.h" +#include "tests/knot/conf_tests.h" + +// Run all loaded units +int main(int argc, char *argv[]) +{ + // Open log + log_init(); + log_levels_set(LOGT_SYSLOG, LOG_ANY, 0); + + // Build test set + unit_api *tests[] = { + /* Core data structures. */ + &journal_tests_api, //! Journal unit + &slab_tests_api, //! SLAB allocator unit + &skiplist_tests_api, //! Skip list unit + &dthreads_tests_api, //! DThreads testing unit + &events_tests_api, //! Events testing unit + &da_tests_api, //! Dynamic array unit + &acl_tests_api, //! ACLs + &fdset_tests_api, //! FDSET polling wrapper + + /* Server parts. */ + &conf_tests_api, //! Configuration parser tests + &server_tests_api, //! Server unit + NULL + }; + + // Plan number of tests + int id = 0; + int test_count = 0; + note("Units:"); + while (tests[id] != NULL) { + note("- %s : %d tests", tests[id]->name, + tests[id]->count(argc, argv)); + test_count += tests[id]->count(argc, argv); + ++id; + } + + plan(test_count); + + // Run tests + id = 0; + while (tests[id] != NULL) { + diag("Testing unit: %s", tests[id]->name); + tests[id]->run(argc, argv); + ++id; + } + + log_close(); + + // Evaluate + return exit_status(); +} + diff --git a/src/zcompile/LICENSE b/src/zcompile/LICENSE new file mode 100644 index 0000000..55faacf --- /dev/null +++ b/src/zcompile/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2001-2006, NLnet Labs. All rights reserved. + +This software is open source. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +Neither the name of the NLNET LABS nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/zcompile/parser-descriptor.c b/src/zcompile/parser-descriptor.c new file mode 100644 index 0000000..41e7f2d --- /dev/null +++ b/src/zcompile/parser-descriptor.c @@ -0,0 +1,535 @@ +/*! + * \file parser-descriptor.c + * + * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>, + * most of the work by NLnet Labs. + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \brief Contains resource record descriptor and its API + * + * \addtogroup zoneparser + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <assert.h> +#include <string.h> +#include <sys/types.h> + +//#include "common.h" +#include "zcompile/parser-descriptor.h" +/* TODO this has to be removed - move tokens to separate file + but can it be done?) */ +#include "zcompile/zcompile.h" +/* FIXME: Generate .y and .l to zoneparser/ */ +#include "zparser.h" + +enum desclen { PARSER_RRTYPE_DESCRIPTORS_LENGTH = 32770 }; // used to be 101 + +/* Taken from RFC 1035, section 3.2.4. */ +static knot_lookup_table_t dns_rrclasses[] = { + { PARSER_CLASS_IN, "IN" }, /* the Internet */ + { PARSER_CLASS_CS, "CS" }, /* the CSNET class (Obsolete) */ + { PARSER_CLASS_CH, "CH" }, /* the CHAOS class */ + { PARSER_CLASS_HS, "HS" }, /* Hesiod */ + { 0, NULL } +}; +static parser_rrtype_descriptor_t + knot_rrtype_descriptors[PARSER_RRTYPE_DESCRIPTORS_LENGTH] = { + /* 0 */ + { 0, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 1 */ + { PARSER_RRTYPE_A, T_A, "A", 1, { PARSER_RDATA_WF_A }, true }, + /* 2 */ + { PARSER_RRTYPE_NS, T_NS, "NS", 1, + { PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 3 */ + { PARSER_RRTYPE_MD, T_MD, "MD", 1, + { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true }, + /* 4 */ + { PARSER_RRTYPE_MF, T_MF, "MF", 1, + { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true }, + /* 5 */ + { PARSER_RRTYPE_CNAME, T_CNAME, "CNAME", 1, + { PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 6 */ + { PARSER_RRTYPE_SOA, T_SOA, "SOA", 7, + { PARSER_RDATA_WF_COMPRESSED_DNAME, PARSER_RDATA_WF_COMPRESSED_DNAME, + PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, + PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG }, true }, + /* 7 */ + { PARSER_RRTYPE_MB, T_MB, "MB", 1, + { PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 8 */ + { PARSER_RRTYPE_MG, T_MG, "MG", 1, + { PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 9 */ + { PARSER_RRTYPE_MR, T_MR, "MR", 1, + { PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 10 */ + { PARSER_RRTYPE_NULL, T_NULL, NULL, 1, + { PARSER_RDATA_WF_BINARY }, true }, + /* 11 */ + { PARSER_RRTYPE_WKS, T_WKS, "WKS", 2, + { PARSER_RDATA_WF_A, PARSER_RDATA_WF_BINARY }, true }, + /* 12 */ + { PARSER_RRTYPE_PTR, T_PTR, "PTR", 1, + { PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 13 */ + { PARSER_RRTYPE_HINFO, T_HINFO, "HINFO", 2, + { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, true }, + /* 14 */ + { PARSER_RRTYPE_MINFO, T_MINFO, "MINFO", 2, + { PARSER_RDATA_WF_COMPRESSED_DNAME, + PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 15 */ + { PARSER_RRTYPE_MX, T_MX, "MX", 2, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 16 */ /* This is obscure, but I guess there's no other way */ + { PARSER_RRTYPE_TXT, T_TXT, "TXT", PARSER_MAX_RDATA_ITEMS, + { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false }, + /* 17 */ + { PARSER_RRTYPE_RP, T_RP, "RP", 2, + { PARSER_RDATA_WF_COMPRESSED_DNAME, + PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 18 */ + { PARSER_RRTYPE_AFSDB, T_AFSDB, "AFSDB", 2, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 19 */ + { PARSER_RRTYPE_X25, T_X25, "X25", 1, + { PARSER_RDATA_WF_TEXT }, true }, + /* 20 */ + { PARSER_RRTYPE_ISDN, T_ISDN, "ISDN", 2, + { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false }, + /* 21 */ + { PARSER_RRTYPE_RT, T_RT, "RT", 2, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true }, + /* 22 */ + { PARSER_RRTYPE_NSAP, T_NSAP, "NSAP", 1, + { PARSER_RDATA_WF_BINARY }, true }, + /* 23 */ + { 23, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 24 */ + { PARSER_RRTYPE_SIG, T_SIG, "SIG", 9, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, + PARSER_RDATA_WF_SHORT,PARSER_RDATA_WF_UNCOMPRESSED_DNAME, + PARSER_RDATA_WF_BINARY }, true }, + /* 25 */ + { PARSER_RRTYPE_KEY, T_KEY, "KEY", 4, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true }, + /* 26 */ + { PARSER_RRTYPE_PX, T_PX, "PX", 3, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_UNCOMPRESSED_DNAME, + PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true }, + /* 27 */ + { 27, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 28 */ + { PARSER_RRTYPE_AAAA, T_AAAA, "AAAA", 1, + { PARSER_RDATA_WF_AAAA }, true }, + /* 29 */ + { PARSER_RRTYPE_LOC, T_LOC, "LOC", 1, + { PARSER_RDATA_WF_BINARY }, true }, + /* 30 */ + { PARSER_RRTYPE_NXT, T_NXT, "NXT", 2, + { PARSER_RDATA_WF_UNCOMPRESSED_DNAME, + PARSER_RDATA_WF_BINARY }, true }, + /* 31 */ + { 31, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 32 */ + { 32, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 33 */ + { PARSER_RRTYPE_SRV, T_SRV, "SRV", 4, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT, + PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, + true }, + /* 34 */ + { 34, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 35 */ + { PARSER_RRTYPE_NAPTR, T_NAPTR, "NAPTR", 6, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true }, + /* 36 */ + { PARSER_RRTYPE_KX, T_KX, "KX", 2, + { PARSER_RDATA_WF_SHORT, + PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true }, + /* 37 */ + { PARSER_RRTYPE_CERT, T_CERT, "CERT", 4, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true }, + /* 38 */ + { PARSER_RRTYPE_A6, T_A6, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 39 */ + { PARSER_RRTYPE_DNAME, T_DNAME, "DNAME", 1, + { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true }, + /* 40 */ + { 40, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 41 */ + /* OPT has its parser token, but should never be in zone file... */ + { PARSER_RRTYPE_OPT, T_OPT, "OPT", 1, + { PARSER_RDATA_WF_BINARY }, true }, + /* 42 */ + { PARSER_RRTYPE_APL, T_APL, "APL", PARSER_MAX_RDATA_ITEMS, + { PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL, + PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL }, false }, + /* 43 */ + { PARSER_RRTYPE_DS, T_DS, "DS", 4, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true }, + /* 44 */ + { PARSER_RRTYPE_SSHFP, T_SSHFP, "SSHFP", 3, + { PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BINARY }, true }, + /* 45 */ + { PARSER_RRTYPE_IPSECKEY, T_IPSECKEY, "IPSECKEY", 5, + { PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_IPSECGATEWAY, + PARSER_RDATA_WF_BINARY }, false }, + /* 46 */ + { PARSER_RRTYPE_RRSIG, T_RRSIG, "RRSIG", 9, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_LONG, + PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, + PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BINARY, + PARSER_RDATA_WF_BINARY }, true }, + /* 47 */ + { PARSER_RRTYPE_NSEC, T_NSEC, "NSEC", 2, + { PARSER_RDATA_WF_BINARY, PARSER_RDATA_WF_BINARY }, true }, + /* 48 */ + { PARSER_RRTYPE_DNSKEY, T_DNSKEY, "DNSKEY", 4, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true }, + /* 49 */ + { PARSER_RRTYPE_DHCID, T_DHCID, "DHCID", 1, { PARSER_RDATA_WF_BINARY }, true }, + /* 50 */ + { PARSER_RRTYPE_NSEC3, T_NSEC3, "NSEC3", 6, + { PARSER_RDATA_WF_BYTE, /* hash type */ + PARSER_RDATA_WF_BYTE, /* flags */ + PARSER_RDATA_WF_SHORT, /* iterations */ + PARSER_RDATA_WF_BINARYWITHLENGTH, /* salt */ + PARSER_RDATA_WF_BINARYWITHLENGTH, /* next hashed name */ + PARSER_RDATA_WF_BINARY /* type bitmap */ }, true }, + /* 51 */ + { PARSER_RRTYPE_NSEC3PARAM, T_NSEC3PARAM, "NSEC3PARAM", 4, + { PARSER_RDATA_WF_BYTE, /* hash type */ + PARSER_RDATA_WF_BYTE, /* flags */ + PARSER_RDATA_WF_SHORT, /* iterations */ + PARSER_RDATA_WF_BINARYWITHLENGTH /* salt */ }, true }, + /* 52 */ + + + /* In NSD they have indices between 52 and 99 filled with + unknown types. TODO add here if it's really needed? */ + /* it is indeed needed, in rrtype_from_string */ + + /* There's a GNU extension that works like this: [first ... last] = value */ + + [53 ... 98] = { PARSER_RRTYPE_TYPEXXX, T_UTYPE, NULL, 1, { PARSER_RDATA_WF_BINARY }}, + + /* 99 */ + [99] = { PARSER_RRTYPE_SPF, T_SPF, "SPF", PARSER_MAX_RDATA_ITEMS, + { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT, + PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false }, + [100 ... 32768] = { PARSER_RRTYPE_TYPEXXX, T_UTYPE, NULL, 1, { PARSER_RDATA_WF_BINARY }}, + /* 32769 */ + [32769] = { PARSER_RRTYPE_DLV, T_DLV, "DLV", 4, + { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY } }, +}; + +parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_type(uint16_t type) +{ + if (type <= PARSER_RRTYPE_DLV) { + return &knot_rrtype_descriptors[type]; + } + return &knot_rrtype_descriptors[0]; +} + +/* I see a lot of potential here to speed up zone parsing - this is O(n) * + * could be better */ +parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_name(const char *name) +{ + if (!name) { + return NULL; + } + + if (strcasecmp(name, "IN") == 0) { + return NULL; + } + + if (isdigit((int)name[0])) { + return NULL; + } + +// /* The most common - A and NS. */ +// if (strcasecmp(name, "NS") == 0) { +// return &knot_rrtype_descriptors[2]; +// } + +// if (strcasecmp(name, "A") == 0) { +// return &knot_rrtype_descriptors[1]; +// } + +// /* Then RRSIG */ +// if (strcasecmp(name, "RRSIG") == 0) { +// return &knot_rrtype_descriptors[46]; +// } + +// /* Then DS */ +// if (strcasecmp(name, "DS") == 0) { +// return &knot_rrtype_descriptors[43]; +// } +// /* Then NSEC3 */ +// if (strcasecmp(name, "NSEC3") == 0) { +// return &knot_rrtype_descriptors[50]; +// } +// /* Then NSEC */ +// if (strcasecmp(name, "NSEC") == 0) { +// return &knot_rrtype_descriptors[47]; +// } + + int i; + + for (i = 0; i < PARSER_RRTYPE_LAST + 1; ++i) { + if (knot_rrtype_descriptors[i].name && + strcasecmp(knot_rrtype_descriptors[i].name, name) == 0) { + return &knot_rrtype_descriptors[i]; + } + } + + if (knot_rrtype_descriptors[PARSER_RRTYPE_DLV].name && + strcasecmp(knot_rrtype_descriptors[PARSER_RRTYPE_DLV].name, + name) == 0) { + return &knot_rrtype_descriptors[PARSER_RRTYPE_DLV]; + } + + return NULL; +} + +const char *parser_rrtype_to_string(uint16_t rrtype) +{ + static char buf[20]; + parser_rrtype_descriptor_t *descriptor = + parser_rrtype_descriptor_by_type(rrtype); + if (descriptor->name) { + return descriptor->name; + } else { + snprintf(buf, sizeof(buf), "TYPE%d", (int) rrtype); + return buf; + } +} + +uint16_t parser_rrtype_from_string(const char *name) +{ + char *end; + long rrtype; + parser_rrtype_descriptor_t *entry; + + entry = parser_rrtype_descriptor_by_name(name); + if (entry) { + return entry->type; + } + + if (strlen(name) < 5) { + return 0; + } + + if (strncasecmp(name, "TYPE", 4) != 0) { + return 0; + } + + if (!isdigit((int)name[4])) { + return 0; + } + + /* The rest from the string must be a number. */ + rrtype = strtol(name + 4, &end, 10); + if (*end != '\0') { + return 0; + } + if (rrtype < 0 || rrtype > 65535L) { + return 0; + } + + return (uint16_t) rrtype; +} + +const char *parser_rrclass_to_string(uint16_t rrclass) +{ + static char buf[20]; + knot_lookup_table_t *entry = knot_lookup_by_id(dns_rrclasses, + rrclass); + if (entry) { + assert(strlen(entry->name) < sizeof(buf)); + knot_strlcpy(buf, entry->name, sizeof(buf)); + } else { + snprintf(buf, sizeof(buf), "CLASS%d", (int) rrclass); + } + return buf; +} + +uint16_t parser_rrclass_from_string(const char *name) +{ + char *end; + long rrclass; + knot_lookup_table_t *entry; + + entry = knot_lookup_by_name(dns_rrclasses, name); + if (entry) { + return (uint16_t) entry->id; + } + + if (strlen(name) < 6) { + return 0; + } + + if (strncasecmp(name, "CLASS", 5) != 0) { + return 0; + } + + if (!isdigit((int)name[5])) { + return 0; + } + + // The rest from the string must be a number. + rrclass = strtol(name + 5, &end, 10); + if (*end != '\0') { + return 0; + } + if (rrclass < 0 || rrclass > 65535L) { + return 0; + } + + return (uint16_t) rrclass; +} + diff --git a/src/zcompile/parser-descriptor.h b/src/zcompile/parser-descriptor.h new file mode 100644 index 0000000..c7865dd --- /dev/null +++ b/src/zcompile/parser-descriptor.h @@ -0,0 +1,278 @@ +/*! + * \file parser-descriptor.h + * + * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>, + * most of the work by NLnet Labs. + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \brief Contains resource record descriptor and its API + * + * \addtogroup zoneparser + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _KNOTD_PARSER_DESCRIPTOR_H_ +#define _KNOTD_PARSER_DESCRIPTOR_H_ + +#include <stdint.h> +#include <stdbool.h> + +#include "libknot/util/utils.h" + +enum parser_mxrdtln { + PARSER_MAX_RDATA_ITEMS = 64, + PARSER_MAX_RDATA_ITEM_SIZE = 255, + PARSER_MAX_RDATA_WIRE_SIZE = + PARSER_MAX_RDATA_ITEMS * PARSER_MAX_RDATA_ITEM_SIZE +}; +//#define MAXRDATALEN 64 + +/* 64 is in NSD. Seems a little too much, but I'd say it's not a real issue. */ + +/*! + * \brief Enum containing RR class codes. + */ +enum parser_rr_class { + PARSER_CLASS_IN = 1, + PARSER_CLASS_CS, + PARSER_CLASS_CH, + PARSER_CLASS_HS, + PARSER_CLASS_NONE = 254, + PARSER_CLASS_ANY = 255 +}; + +typedef enum parser_rr_class parser_rr_class_t; + +enum parser_rr_type { + PARSER_RRTYPE_UNKNOWN, /*!< 0 - an unknown type */ + PARSER_RRTYPE_A, /*!< 1 - a host address */ + PARSER_RRTYPE_NS, /*!< 2 - an authoritative name server */ + PARSER_RRTYPE_MD, /*!< 3 - a mail destination (Obsolete - use MX) */ + PARSER_RRTYPE_MF, /*!< 4 - a mail forwarder (Obsolete - use MX) */ + PARSER_RRTYPE_CNAME, /*!< 5 - the canonical name for an alias */ + PARSER_RRTYPE_SOA, /*!< 6 - marks the start of a zone of authority */ + PARSER_RRTYPE_MB, /*!< 7 - a mailbox domain name (EXPERIMENTAL) */ + PARSER_RRTYPE_MG, /*!< 8 - a mail group member (EXPERIMENTAL) */ + PARSER_RRTYPE_MR, /*!< 9 - a mail rename domain name (EXPERIMENTAL) */ + PARSER_RRTYPE_NULL, /*!< 10 - a null RR (EXPERIMENTAL) */ + PARSER_RRTYPE_WKS, /*!< 11 - a well known service description */ + PARSER_RRTYPE_PTR, /*!< 12 - a domain name pointer */ + PARSER_RRTYPE_HINFO, /*!< 13 - host information */ + PARSER_RRTYPE_MINFO, /*!< 14 - mailbox or mail list information */ + PARSER_RRTYPE_MX, /*!< 15 - mail exchange */ + PARSER_RRTYPE_TXT, /*!< 16 - text strings */ + PARSER_RRTYPE_RP, /*!< 17 - RFC1183 */ + PARSER_RRTYPE_AFSDB, /*!< 18 - RFC1183 */ + PARSER_RRTYPE_X25, /*!< 19 - RFC1183 */ + PARSER_RRTYPE_ISDN, /*!< 20 - RFC1183 */ + PARSER_RRTYPE_RT, /*!< 21 - RFC1183 */ + PARSER_RRTYPE_NSAP, /*!< 22 - RFC1706 */ + + PARSER_RRTYPE_SIG = 24, /*!< 24 - 2535typecode */ + PARSER_RRTYPE_KEY, /*!< 25 - 2535typecode */ + PARSER_RRTYPE_PX, /*!< 26 - RFC2163 */ + + PARSER_RRTYPE_AAAA = 28, /*!< 28 - ipv6 address */ + PARSER_RRTYPE_LOC, /*!< 29 - LOC record RFC1876 */ + PARSER_RRTYPE_NXT, /*!< 30 - 2535typecode */ + + PARSER_RRTYPE_SRV = 33, /*!< 33 - SRV record RFC2782 */ + + PARSER_RRTYPE_NAPTR = 35, /*!< 35 - RFC2915 */ + PARSER_RRTYPE_KX, /*!< 36 - RFC2230 Key Exchange Delegation Record */ + PARSER_RRTYPE_CERT, /*!< 37 - RFC2538 */ + PARSER_RRTYPE_A6, /*!< 38 - RFC2874 */ + PARSER_RRTYPE_DNAME, /*!< 39 - RFC2672 */ + + PARSER_RRTYPE_OPT = 41, /*!< 41 - Pseudo OPT record... */ + PARSER_RRTYPE_APL, /*!< 42 - RFC3123 */ + PARSER_RRTYPE_DS, /*!< 43 - RFC 4033, 4034, and 4035 */ + PARSER_RRTYPE_SSHFP, /*!< 44 - SSH Key Fingerprint */ + PARSER_RRTYPE_IPSECKEY, /*!< 45 - public key for ipsec use. RFC 4025 */ + PARSER_RRTYPE_RRSIG, /*!< 46 - RFC 4033, 4034, and 4035 */ + PARSER_RRTYPE_NSEC, /*!< 47 - RFC 4033, 4034, and 4035 */ + PARSER_RRTYPE_DNSKEY, /*!< 48 - RFC 4033, 4034, and 4035 */ + PARSER_RRTYPE_DHCID, /*!< 49 - RFC4701 DHCP information */ + /*! + * \brief 50 - NSEC3, secure denial, prevents zonewalking + */ + PARSER_RRTYPE_NSEC3, + /*! + * \brief 51 - NSEC3PARAM at zone apex nsec3 parameters + */ + PARSER_RRTYPE_NSEC3PARAM, + + /* TODO consider some better way of doing this, indices too high */ + + PARSER_RRTYPE_SPF = 99, /*!< RFC 4408 */ + + // not designating any RRs + PARSER_RRTYPE_TSIG = 250, + PARSER_RRTYPE_IXFR = 251, + PARSER_RRTYPE_AXFR = 252, + /*! + * \brief A request for mailbox-related records (MB, MG or MR) + */ + PARSER_RRTYPE_MAILB = 253, + /*! + * \brief A request for mail agent RRs (Obsolete - see MX) + */ + PARSER_RRTYPE_MAILA = 254, + PARSER_RRTYPE_ANY = 255, /*!< any type (wildcard) */ + + // totally weird numbers (cannot use for indexing) + PARSER_RRTYPE_TA = 32768, /*!< DNSSEC Trust Authorities */ + PARSER_RRTYPE_DLV = 32769, /*!< RFC 4431 */ + PARSER_RRTYPE_TYPEXXX = 32770 +}; + +/*! + * \brief Enum containing RR type codes. + * + * \todo Not all indices can be used for indexing. + */ +typedef enum parser_rr_type parser_rr_type_t; + +static uint const PARSER_RRTYPE_LAST = PARSER_RRTYPE_NSEC3PARAM; + +enum parser_rdata_wireformat { + /*! + * \brief Possibly compressed domain name. + */ + PARSER_RDATA_WF_COMPRESSED_DNAME = 50, + PARSER_RDATA_WF_UNCOMPRESSED_DNAME = 51, /*!< Uncompressed domain name. */ + PARSER_RDATA_WF_LITERAL_DNAME = 52, /*!< Literal (not downcased) dname. */ + PARSER_RDATA_WF_BYTE = 1, /*!< 8-bit integer. */ + PARSER_RDATA_WF_SHORT = 2, /*!< 16-bit integer. */ + PARSER_RDATA_WF_LONG = 4, /*!< 32-bit integer. */ + PARSER_RDATA_WF_TEXT = 53, /*!< Text string. */ + PARSER_RDATA_WF_A = 58, /*!< 32-bit IPv4 address. */ + PARSER_RDATA_WF_AAAA = 16, /*!< 128-bit IPv6 address. */ + PARSER_RDATA_WF_BINARY = 54, /*!< Binary data (unknown length). */ + /*! + * \brief Binary data preceded by 1 byte length + */ + PARSER_RDATA_WF_BINARYWITHLENGTH = 55, + PARSER_RDATA_WF_APL = 56, /*!< APL data. */ + PARSER_RDATA_WF_IPSECGATEWAY = 57 /*!< IPSECKEY gateway ip4, ip6 or dname. */ +}; + +/*! + * \brief Enum containing wireformat codes. Taken from NSD's "dns.h" + */ +typedef enum parser_rdatawireformat parser_rdata_wireformat_t; + +struct parser_rrtype_descriptor { + uint16_t type; /*!< RR type */ + int token; /*< Token used in zoneparser */ + const char *name; /*!< Textual name. */ + uint8_t length; /*!< Maximum number of RDATA items. */ + /*! + * \brief rdata_wireformat_type + */ + uint8_t wireformat[PARSER_MAX_RDATA_ITEMS]; + bool fixed_items; /*!< Has fixed number of RDATA items? */ +}; + +/*! + * \brief Structure holding RR descriptor + */ +typedef struct parser_rrtype_descriptor parser_rrtype_descriptor_t; + +/*! + * \brief Gets RR descriptor for given RR type. + * + * \param type Code of RR type whose descriptor should be returned. + * + * \return RR descriptor for given type code, NULL descriptor if + * unknown type. + * + * \todo Change return value to const. + */ +parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_type(uint16_t type); + +/*! + * \brief Gets RR descriptor for given RR name. + * + * \param name Mnemonic of RR type whose descriptor should be returned. + * + * \return RR descriptor for given name, NULL descriptor if + * unknown type. + * + * \todo Change return value to const. + */ +parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_name(const char *name); + +/*! + * \brief Converts numeric type representation to mnemonic string. + * + * \param rrtype Type RR type code to be converted. + * + * \return Mnemonic string if found, str(TYPE[rrtype]) otherwise. + */ +const char *parser_rrtype_to_string(uint16_t rrtype); + +/*! + * \brief Converts mnemonic string representation of a type to numeric one. + * + * \param name Mnemonic string to be converted. + * + * \return Correct code if found, 0 otherwise. + */ +uint16_t parser_rrtype_from_string(const char *name); + +/*! + * \brief Converts numeric class representation to string one. + * + * \param rrclass Class code to be converted. + * + * \return String represenation of class if found, + * str(CLASS[rrclass]) otherwise. + */ +const char *parser_rrclass_to_string(uint16_t rrclass); + +/*! + * \brief Converts string representation of a class to numeric one. + * + * \param name Class string to be converted. + * + * \return Correct code if found, 0 otherwise. + */ +uint16_t parser_rrclass_from_string(const char *name); + +#endif /* _KNOTD_PARSER_DESCRIPTOR_H_ */ + +/*! @} */ diff --git a/src/zcompile/parser-util.c b/src/zcompile/parser-util.c new file mode 100644 index 0000000..e7733ef --- /dev/null +++ b/src/zcompile/parser-util.c @@ -0,0 +1,2435 @@ +/*! + * \file parser-util.c + * + * \author NLnet Labs + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \brief utility functions for zone parser. + * + * \addtogroup zoneparser + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> +#include <assert.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <time.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <netdb.h> + +//#include "common.h" +#include "common/base32hex.h" +#include "zcompile/parser-util.h" +#include "zcompile/zcompile.h" +#include "libknot/util/descriptor.h" +#include "libknot/util/utils.h" +#include "zcompile/zcompile-error.h" + +#define IP6ADDRLEN (128/8) +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 +#define APL_NEGATION_MASK 0x80U + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int inet_pton(int af, const char *src, void *dst) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +//int my_b32_pton(const char *src, uint8_t *target, size_t tsize) +//{ +// char ch; +// size_t p = 0; + +// memset(target, '\0', tsize); +// while ((ch = *src++)) { +// uint8_t d; +// size_t b; +// size_t n; + +// if (p + 5 >= tsize * 8) { +// return -1; +// } + +// if (isspace(ch)) { +// continue; +// } + +// if (ch >= '0' && ch <= '9') { +// d = ch - '0'; +// } else if (ch >= 'A' && ch <= 'V') { +// d = ch - 'A' + 10; +// } else if (ch >= 'a' && ch <= 'v') { +// d = ch - 'a' + 10; +// } else { +// return -1; +// } + +// b = 7 - p % 8; +// n = p / 8; + +// if (b >= 4) { +// target[n] |= d << (b - 4); +// } else { +// target[n] |= d >> (4 - b); +// target[n+1] |= d << (b + 4); +// } +// p += 5; +// } +// return (p + 7) / 8; +//} + + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +int inet_pton4(const char *src, uint8_t *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + uint8_t tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + uint32_t new = *tp * 10 + (pch - digits); + + if (new > 255) { + return (0); + } + *tp = new; + if (! saw_digit) { + if (++octets > 4) { + return (0); + } + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) { + return (0); + } + *++tp = 0; + saw_digit = 0; + } else { + return (0); + } + } + if (octets < 4) { + return (0); + } + + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +int inet_pton6(const char *src, uint8_t *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + uint32_t val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') { + return (0); + } + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) { + pch = strchr((xdigits = xdigits_u), ch); + } + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) { + return (0); + } + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) { + return (0); + } + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) { + return (0); + } + *tp++ = (uint8_t)(val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) { + return (0); + } + *tp++ = (uint8_t)(val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) { + return (0); + } + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} + + +#ifndef IN6ADDRSZ +#define IN6ADDRSZ 16 /* IPv6 T_AAAA */ +#endif + +#ifndef INT16SZ +#define INT16SZ 2 /* for systems without 16-bit ints */ +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +//const char *inet_ntop(int af, const void *src, char *dst, size_t size) +//{ +// switch (af) { +// case AF_INET: +// return (inet_ntop4(src, dst, size)); +// case AF_INET6: +// return (inet_ntop6(src, dst, size)); +// default: +// errno = EAFNOSUPPORT; +// return (NULL); +// } +// /* NOTREACHED */ +//} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +const char *inet_ntop4(const u_char *src, char *dst, size_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + int l; + + l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); + if (l <= 0 || l >= (int)size) { + errno = ENOSPC; + return (NULL); + } + knot_strlcpy(dst, tmp, size); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +const char *inet_ntop6(const u_char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + char *tp, *ep; + struct { + int base, len; + } best, cur; + best.base = cur.base =-1; + best.len = cur.len = 0; + u_int words[IN6ADDRSZ / INT16SZ]; + int i; + int advance; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < IN6ADDRSZ; i++) { + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + } + + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) { + cur.base = i, cur.len = 1; + } else { + cur.len++; + } + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) { + best = cur; + } + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) { + best = cur; + } + } + if (best.base != -1 && best.len < 2) { + best.base = -1; + } + + /* + * Format the result. + */ + tp = tmp; + ep = tmp + sizeof(tmp); + for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) { + if (tp + 1 >= ep) { + return (NULL); + } + *tp++ = ':'; + } + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) { + if (tp + 1 >= ep) { + return (NULL); + } + *tp++ = ':'; + } + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src + 12, tp, (size_t)(ep - tp))) { + return (NULL); + } + tp += strlen(tp); + break; + } + advance = snprintf(tp, ep - tp, "%x", words[i]); + if (advance <= 0 || advance >= ep - tp) { + return (NULL); + } + tp += advance; + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (IN6ADDRSZ / INT16SZ)) { + if (tp + 1 >= ep) { + return (NULL); + } + *tp++ = ':'; + } + if (tp + 1 >= ep) { + return (NULL); + } + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + knot_strlcpy(dst, tmp, size); + return (dst); +} + + +static int b64rmap_initialized = 0; +static uint8_t b64rmap[256]; + +static const uint8_t b64rmap_special = 0xf0; +static const uint8_t b64rmap_end = 0xfd; +static const uint8_t b64rmap_space = 0xfe; +static const uint8_t b64rmap_invalid = 0xff; + +/** + * Initializing the reverse map is not thread safe. + * Which is fine for NSD. For now... + **/ +void b64_initialize_rmap() +{ + int i; + char ch; + + /* Null: end of string, stop parsing */ + b64rmap[0] = b64rmap_end; + + for (i = 1; i < 256; ++i) { + ch = (char)i; + /* Whitespaces */ + if (isspace(ch)) { + b64rmap[i] = b64rmap_space; + } + /* Padding: stop parsing */ + else if (ch == Pad64) { + b64rmap[i] = b64rmap_end; + } + /* Non-base64 char */ + else { + b64rmap[i] = b64rmap_invalid; + } + } + + /* Fill reverse mapping for base64 chars */ + for (i = 0; Base64[i] != '\0'; ++i) { + b64rmap[(uint8_t)Base64[i]] = i; + } + + b64rmap_initialized = 1; +} + +int b64_pton_do(char const *src, uint8_t *target, size_t targsize) +{ + int tarindex, state, ch; + uint8_t ofs; + + state = 0; + tarindex = 0; + + while (1) { + ch = *src++; + ofs = b64rmap[ch]; + + if (ofs >= b64rmap_special) { + /* Ignore whitespaces */ + if (ofs == b64rmap_space) { + continue; + } + /* End of base64 characters */ + if (ofs == b64rmap_end) { + break; + } + /* A non-base64 character. */ + return (-1); + } + + switch (state) { + case 0: + if ((size_t)tarindex >= targsize) { + return (-1); + } + target[tarindex] = ofs << 2; + state = 1; + break; + case 1: + if ((size_t)tarindex + 1 >= targsize) { + return (-1); + } + target[tarindex] |= ofs >> 4; + target[tarindex+1] = (ofs & 0x0f) + << 4 ; + tarindex++; + state = 2; + break; + case 2: + if ((size_t)tarindex + 1 >= targsize) { + return (-1); + } + target[tarindex] |= ofs >> 2; + target[tarindex+1] = (ofs & 0x03) + << 6; + tarindex++; + state = 3; + break; + case 3: + if ((size_t)tarindex >= targsize) { + return (-1); + } + target[tarindex] |= ofs; + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + break; + } + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) { + return (-1); + } + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + return (-1); + } + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target[tarindex] != 0) { + return (-1); + } + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) { + return (-1); + } + } + + return (tarindex); +} + + +int b64_pton_len(char const *src) +{ + int tarindex, state, ch; + uint8_t ofs; + + state = 0; + tarindex = 0; + + while (1) { + ch = *src++; + ofs = b64rmap[ch]; + + if (ofs >= b64rmap_special) { + /* Ignore whitespaces */ + if (ofs == b64rmap_space) { + continue; + } + /* End of base64 characters */ + if (ofs == b64rmap_end) { + break; + } + /* A non-base64 character. */ + return (-1); + } + + switch (state) { + case 0: + state = 1; + break; + case 1: + tarindex++; + state = 2; + break; + case 2: + tarindex++; + state = 3; + break; + case 3: + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + break; + } + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) { + return (-1); + } + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) { + return (-1); + } + + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) { + return (-1); + } + } + + return (tarindex); +} + +int b64_pton(char const *src, uint8_t *target, size_t targsize) +{ + if (!b64rmap_initialized) { + b64_initialize_rmap(); + } + + if (target) { + return b64_pton_do(src, target, targsize); + } else { + return b64_pton_len(src); + } +} + +void set_bit(uint8_t bits[], size_t index) +{ + /* + * The bits are counted from left to right, so bit #0 is the + * left most bit. + */ + bits[index / 8] |= (1 << (7 - index % 8)); +} + +uint32_t strtoserial(const char *nptr, const char **endptr) +{ + uint32_t i = 0; + uint32_t serial = 0; + + for (*endptr = nptr; **endptr; (*endptr)++) { + switch (**endptr) { + case ' ': + case '\t': + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i *= 10; + i += (**endptr - '0'); + break; + default: + break; + } + } + serial += i; + return serial; +} + +inline void write_uint32(void *dst, uint32_t data) +{ +#ifdef ALLOW_UNALIGNED_ACCESSES + *(uint32_t *) dst = htonl(data); +#else + uint8_t *p = (uint8_t *) dst; + p[0] = (uint8_t)((data >> 24) & 0xff); + p[1] = (uint8_t)((data >> 16) & 0xff); + p[2] = (uint8_t)((data >> 8) & 0xff); + p[3] = (uint8_t)(data & 0xff); +#endif +} + +uint32_t strtottl(const char *nptr, const char **endptr) +{ + uint32_t i = 0; + uint32_t seconds = 0; + + for (*endptr = nptr; **endptr; (*endptr)++) { + switch (**endptr) { + case ' ': + case '\t': + break; + case 's': + case 'S': + seconds += i; + i = 0; + break; + case 'm': + case 'M': + seconds += i * 60; + i = 0; + break; + case 'h': + case 'H': + seconds += i * 60 * 60; + i = 0; + break; + case 'd': + case 'D': + seconds += i * 60 * 60 * 24; + i = 0; + break; + case 'w': + case 'W': + seconds += i * 60 * 60 * 24 * 7; + i = 0; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i *= 10; + i += (**endptr - '0'); + break; + default: + seconds += i; + return seconds; + } + } + seconds += i; + return seconds; +} + +/* Number of days per month (except for February in leap years). */ +static const int mdays[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static int is_leap_year(int year) +{ + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); +} + +static int leap_days(int y1, int y2) +{ + --y1; + --y2; + return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400); +} + +/* + * Code adapted from Python 2.4.1 sources (Lib/calendar.py). + */ +time_t mktime_from_utc(const struct tm *tm) +{ + int year = 1900 + tm->tm_year; + time_t days = 365 * (year - 1970) + leap_days(1970, year); + time_t hours; + time_t minutes; + time_t seconds; + int i; + + for (i = 0; i < tm->tm_mon; ++i) { + days += mdays[i]; + } + if (tm->tm_mon > 1 && is_leap_year(year)) { + ++days; + } + days += tm->tm_mday - 1; + + hours = days * 24 + tm->tm_hour; + minutes = hours * 60 + tm->tm_min; + seconds = minutes * 60 + tm->tm_sec; + + return seconds; +} + +/*!< Following functions are conversions from text to wire. */ + +//#define DEBUG_UNKNOWN_RDATA + +#ifdef DEBUG_UNKNOWN_RDATA +#define dbg_rdata(msg...) fprintf(stderr, msg) +#define DBG_RDATA(cmds) do { cmds } while (0) +#else +#define dbg_rdata(msg...) +#define DBG_RDATA(cmds) +#endif + + + +#define IP6ADDRLEN (128/8) +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 +#define APL_NEGATION_MASK 0x80U +#define APL_LENGTH_MASK (~APL_NEGATION_MASK) + +//#define ZP_DEBUG + +#ifdef ZP_DEBUG +#define dbg_zp(msg...) fprintf(stderr, msg) +#else +#define dbg_zp(msg...) +#endif + + +/*! + * \brief Return data of raw data item. + * + * \param item Item. + * \return uint16_t * Raw data. + */ +static inline uint16_t * rdata_atom_data(knot_rdata_item_t item) +{ + return (uint16_t *)(item.raw_data + 1); +} + +/*! + * \brief Return type of RRSet covered by given RRSIG. + * + * \param rrset RRSIG. + * \return uint16_t Type covered. + */ +uint16_t rrsig_type_covered(knot_rrset_t *rrset) +{ + assert(rrset->rdata->items[0].raw_data[0] == sizeof(uint16_t)); + + return ntohs(*(uint16_t *) rdata_atom_data(rrset->rdata->items[0])); +} + +/*! + * \brief Checks if item contains domain. + * + * \param type Type of RRSet. + * \param index Index to check. + * + * \return > 1 if item is domain, 0 otherwise. + */ +static inline int rdata_atom_is_domain(uint16_t type, size_t index) +{ + const knot_rrtype_descriptor_t *descriptor + = knot_rrtype_descriptor_by_type(type); + return (index < descriptor->length + && (descriptor->wireformat[index] == + KNOT_RDATA_WF_COMPRESSED_DNAME || + descriptor->wireformat[index] == + KNOT_RDATA_WF_UNCOMPRESSED_DNAME)); +} + +/*! + * \brief Returns which wireformat type is on given index. + * + * \param type Type of RRSet. + * \param index Index. + * + * \return uint8_t Wireformat type. + */ +static inline uint8_t rdata_atom_wireformat_type(uint16_t type, size_t index) +{ + const knot_rrtype_descriptor_t *descriptor = + knot_rrtype_descriptor_by_type(type); + assert(index < descriptor->length); + return descriptor->wireformat[index]; +} + +/*! + * \brief Converts rdata wireformat to rdata items. + * + * \param wireformat Wireformat/. + * \param rrtype RR type. + * \param data_size Size of wireformat. + * \param items created rdata items. + * + * \return Number of items converted. + */ +static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, + uint16_t rrtype, + const uint16_t data_size, + knot_rdata_item_t **items) +{ + dbg_rdata("read length: %d\n", data_size); + uint16_t const *end = (uint16_t *)((uint8_t *)wireformat + (data_size)); + dbg_rdata("set end pointer: %p which means length: %d\n", end, + (uint8_t *)end - (uint8_t *)wireformat); + size_t i; + knot_rdata_item_t *temp_rdatas = + malloc(sizeof(*temp_rdatas) * MAXRDATALEN); + if (temp_rdatas == NULL) { + ERR_ALLOC_FAILED; + return KNOTDZCOMPILE_ENOMEM; + } + memset(temp_rdatas, 0, sizeof(*temp_rdatas) * MAXRDATALEN); + + knot_rrtype_descriptor_t *descriptor = + knot_rrtype_descriptor_by_type(rrtype); + + assert(descriptor->length <= MAXRDATALEN); + + dbg_rdata("will be parsing %d items, total size: %d\n", + descriptor->length, data_size); + + for (i = 0; i < descriptor->length; ++i) { + int is_domain = 0; + int is_wirestore = 0; + size_t length = 0; + length = 0; + int required = descriptor->length; + + switch (rdata_atom_wireformat_type(rrtype, i)) { + case KNOT_RDATA_WF_COMPRESSED_DNAME: + case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + is_domain = 1; + break; + case KNOT_RDATA_WF_LITERAL_DNAME: + is_domain = 1; + is_wirestore = 1; + break; + case KNOT_RDATA_WF_BYTE: + length = sizeof(uint8_t); + break; + case KNOT_RDATA_WF_SHORT: + length = sizeof(uint16_t); + break; + case KNOT_RDATA_WF_LONG: + length = sizeof(uint32_t); + break; + case KNOT_RDATA_WF_TEXT: + case KNOT_RDATA_WF_BINARYWITHLENGTH: + /* Length is stored in the first byte. */ + length = 1; + if ((uint8_t *)wireformat + length <= (uint8_t *)end) { + // length += wireformat[length - 1]; + length += *((uint8_t *)wireformat); + dbg_rdata("%d: set new length: %d\n", i, + length); + } + /*if (buffer_position(packet) + length <= end) { + length += buffer_current(packet)[length - 1]; + }*/ + break; + case KNOT_RDATA_WF_A: + length = sizeof(in_addr_t); + break; + case KNOT_RDATA_WF_AAAA: + length = IP6ADDRLEN; + break; + case KNOT_RDATA_WF_BINARY: + /* Remaining RDATA is binary. */ + dbg_rdata("%d: guessing length from pointers: %p %p\n", + i, + wireformat, end); + length = (uint8_t *)end - (uint8_t *)wireformat; +// length = end - buffer_position(packet); + break; + case KNOT_RDATA_WF_APL: + length = (sizeof(uint16_t) /* address family */ + + sizeof(uint8_t) /* prefix */ + + sizeof(uint8_t)); /* length */ + if ((uint8_t *)wireformat + length <= (uint8_t *)end) { + /* Mask out negation bit. */ + length += (wireformat[length - 1] + & APL_LENGTH_MASK); + } + break; + case KNOT_RDATA_WF_IPSECGATEWAY: + switch (rdata_atom_data(temp_rdatas[1])[0]) { + /* gateway type */ + default: + case IPSECKEY_NOGATEWAY: + length = 0; + break; + case IPSECKEY_IP4: + length = 4; + break; + case IPSECKEY_IP6: + length = IP6ADDRLEN; + break; + case IPSECKEY_DNAME: + is_domain = 1; + is_wirestore = 1; + break; + } + break; + } + + if (is_domain) { + knot_dname_t *dname; + + if (!required && (wireformat == end)) { + break; + } + + dname = knot_dname_new_from_str((char *)wireformat, + length, + NULL); + + if (dname == NULL) { + dbg_rdata("malformed dname!\n"); + /*! \todo rdata purge */ + free(temp_rdatas); + return KNOTDZCOMPILE_EBRDATA; + } + dbg_rdata("%d: created dname: %s\n", i, + knot_dname_to_str(dname)); + + if (is_wirestore) { + /*temp_rdatas[i].raw_data = + (uint16_t *) region_alloc( + region, sizeof(uint16_t) + dname->name_size); + temp_rdatas[i].data[0] = dname->name_size; + memcpy(temp_rdatas[i].data+1, dname_name(dname), + dname->name_size); */ + temp_rdatas[i].raw_data = + malloc(sizeof(uint16_t) + + sizeof(uint8_t) * dname->size); + if (temp_rdatas[i].raw_data == NULL) { + ERR_ALLOC_FAILED; + /*! \todo rdata purge */ + free(temp_rdatas); + return KNOTDZCOMPILE_ENOMEM; + } + + temp_rdatas[i].raw_data[0] = dname->size; + memcpy(temp_rdatas[i].raw_data + 1, + dname->name, dname->size); + + knot_dname_release(dname); + } else { + temp_rdatas[i].dname = dname; + } + + } else { + dbg_rdata("%d :length: %d %d %p %p\n", i, length, + end - wireformat, + wireformat, end); + if ((uint8_t *)wireformat + length > (uint8_t *)end) { + if (required) { + /* Truncated RDATA. */ + /*! \todo rdata purge */ + free(temp_rdatas); + dbg_rdata("truncated rdata\n"); + return KNOTDZCOMPILE_EBRDATA; + } else { + break; + } + } + + assert(wireformat <= end); /*!< \todo remove! */ + dbg_rdata("calling init with: %p and length : %d\n", + wireformat, length); + temp_rdatas[i].raw_data = alloc_rdata_init(wireformat, + length); + if (temp_rdatas[i].raw_data == NULL) { + ERR_ALLOC_FAILED; + /*! \todo rdata purge */ + free(temp_rdatas); + return -1; + } + +// temp_rdatas[i].raw_data[0] = length; +// memcpy(temp_rdatas[i].raw_data + 1, wireformat, length); + +/* temp_rdatas[i].data = (uint16_t *) region_alloc( + region, sizeof(uint16_t) + length); + temp_rdatas[i].data[0] = length; + buffer_read(packet, + temp_rdatas[i].data + 1, length); */ + } + dbg_rdata("%d: adding length: %d (remaining: %d)\n", i, length, + (uint8_t *)end - ((uint8_t *)wireformat + length)); +// hex_print(temp_rdatas[i].raw_data + 1, length); + wireformat = (uint16_t *)((uint8_t *)wireformat + length); +// wireformat = wireformat + length; + dbg_rdata("wire: %p\n", wireformat); + dbg_rdata("remaining now: %d\n", + end - wireformat); + + } + + dbg_rdata("%p %p\n", wireformat, (uint8_t *)wireformat); + + if (wireformat < end) { + /* Trailing garbage. */ + dbg_rdata("w: %p e: %p %d\n", wireformat, end, end - wireformat); +// region_destroy(temp_region); + free(temp_rdatas); + return KNOTDZCOMPILE_EBRDATA; + } + + *items = temp_rdatas; + /* *rdatas = (rdata_atom_type *) region_alloc_init( + region, temp_rdatas, i * sizeof(rdata_atom_type)); */ + return (ssize_t)i; +} + +/* Taken from RFC 2535, section 7. */ +knot_lookup_table_t dns_algorithms[] = { + { 1, "RSAMD5" }, /* RFC 2537 */ + { 2, "DH" }, /* RFC 2539 */ + { 3, "DSA" }, /* RFC 2536 */ + { 4, "ECC" }, + { 5, "RSASHA1" }, /* RFC 3110 */ + { 252, "INDIRECT" }, + { 253, "PRIVATEDNS" }, + { 254, "PRIVATEOID" }, + { 0, NULL } +}; + +/* Taken from RFC 4398, section 2.1. */ +knot_lookup_table_t dns_certificate_types[] = { + /* 0 Reserved */ + { 1, "PKIX" }, /* X.509 as per PKIX */ + { 2, "SPKI" }, /* SPKI cert */ + { 3, "PGP" }, /* OpenPGP packet */ + { 4, "IPKIX" }, /* The URL of an X.509 data object */ + { 5, "ISPKI" }, /* The URL of an SPKI certificate */ + { 6, "IPGP" }, /* The fingerprint and URL of an OpenPGP packet */ + { 7, "ACPKIX" }, /* Attribute Certificate */ + { 8, "IACPKIX" }, /* The URL of an Attribute Certificate */ + { 253, "URI" }, /* URI private */ + { 254, "OID" }, /* OID private */ + /* 255 Reserved */ + /* 256-65279 Available for IANA assignment */ + /* 65280-65534 Experimental */ + /* 65535 Reserved */ + { 0, NULL } +}; + +/* Imported from lexer. */ +extern int hexdigit_to_int(char ch); + +extern uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE]; +extern uint16_t nsec_highest_rcode; + +/*! + * \brief Allocate SIZE+sizeof(uint16_t) bytes and store SIZE in the first + * element. Return a pointer to the allocation. + * + * \param size How many bytes to allocate. + */ +static uint16_t * alloc_rdata(size_t size) +{ + uint16_t *result = malloc(sizeof(uint16_t) + size); + *result = size; + return result; +} + +uint16_t *alloc_rdata_init(const void *data, size_t size) +{ + uint16_t *result = malloc(sizeof(uint16_t) + size); + if (result == NULL) { + return NULL; + } + *result = size; + memcpy(result + 1, data, size); + return result; +} + +/* + * These are parser function for generic zone file stuff. + */ +uint16_t * zparser_conv_hex(const char *hex, size_t len) +{ + /* convert a hex value to wireformat */ + uint16_t *r = NULL; + uint8_t *t; + int i; + + if (len % 2 != 0) { + zc_error_prev_line("number of hex digits " + "must be a multiple of 2"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else if (len > MAX_RDLENGTH * 2) { + zc_error_prev_line("hex data exceeds maximum rdata length (%d)", + MAX_RDLENGTH); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + /* the length part */ + + r = alloc_rdata(len / 2); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + t = (uint8_t *)(r + 1); + + /* Now process octet by octet... */ + while (*hex) { + *t = 0; + for (i = 16; i >= 1; i -= 15) { + if (isxdigit((int)*hex)) { + *t += hexdigit_to_int(*hex) * i; + } else { + zc_error_prev_line( + "illegal hex character '%c'", + (int) *hex); + parser->error_occurred = + KNOTDZCOMPILE_EBRDATA; + free(r); + return NULL; + } + ++hex; + } + ++t; + } + } + + return r; +} + +/* convert hex, precede by a 1-byte length */ +uint16_t * zparser_conv_hex_length(const char *hex, size_t len) +{ + uint16_t *r = NULL; + uint8_t *t; + int i; + if (len % 2 != 0) { + zc_error_prev_line("number of hex digits must be a " + "multiple of 2"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else if (len > 255 * 2) { + zc_error_prev_line("hex data exceeds 255 bytes"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + uint8_t *l; + + /* the length part */ + r = alloc_rdata(len / 2 + 1); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + + t = (uint8_t *)(r + 1); + + l = t++; + *l = '\0'; + + /* Now process octet by octet... */ + while (*hex) { + *t = 0; + for (i = 16; i >= 1; i -= 15) { + if (isxdigit((int)*hex)) { + *t += hexdigit_to_int(*hex) * i; + } else { + zc_error_prev_line( + "illegal hex character '%c'", + (int) *hex); + parser->error_occurred = + KNOTDZCOMPILE_EBRDATA; + free(r); + return NULL; + } + ++hex; + } + ++t; + ++*l; + } + } + return r; +} + +uint16_t * zparser_conv_time(const char *time) +{ + /* convert a time YYHM to wireformat */ + uint16_t *r = NULL; + struct tm tm; + + /* Try to scan the time... */ + if (!strptime(time, "%Y%m%d%H%M%S", &tm)) { + zc_error_prev_line("date and time is expected"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + uint32_t l = htonl(mktime_from_utc(&tm)); + r = alloc_rdata_init(&l, sizeof(l)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_services(const char *protostr, char *servicestr) +{ + /* + * Convert a protocol and a list of service port numbers + * (separated by spaces) in the rdata to wireformat + */ + uint16_t *r = NULL; + uint8_t *p; + uint8_t bitmap[65536/8]; + char sep[] = " "; + char *word; + int max_port = -8; + /* convert a protocol in the rdata to wireformat */ + struct protoent *proto; + + memset(bitmap, 0, sizeof(bitmap)); + + proto = getprotobyname(protostr); + if (!proto) { + proto = getprotobynumber(atoi(protostr)); + } + if (!proto) { + zc_error_prev_line("unknown protocol '%s'", protostr); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + return NULL; + } + + char *sp = 0; + while ((word = strtok_r(servicestr, sep, &sp))) { + struct servent *service; + int port; + + service = getservbyname(word, proto->p_name); + if (service) { + /* Note: ntohs not ntohl! Strange but true. */ + port = ntohs((uint16_t) service->s_port); + } else { + char *end; + port = strtol(word, &end, 10); + if (*end != '\0') { + zc_error_prev_line( + "unknown service '%s' for" + " protocol '%s'", + word, protostr); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + continue; + } + } + + if (port < 0 || port > 65535) { + zc_error_prev_line("bad port number %d", port); + } else { + set_bit(bitmap, port); + if (port > max_port) { + max_port = port; + } + } + } + + r = alloc_rdata(sizeof(uint8_t) + max_port / 8 + 1); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + + p = (uint8_t *)(r + 1); + *p = proto->p_proto; + memcpy(p + 1, bitmap, *r); + + return r; +} + +uint16_t * zparser_conv_serial(const char *serialstr) +{ + uint16_t *r = NULL; + uint32_t serial; + const char *t; + + serial = strtoserial(serialstr, &t); + if (*t != '\0') { + zc_error_prev_line("serial is expected"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + serial = htonl(serial); + r = alloc_rdata_init(&serial, sizeof(serial)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_period(const char *periodstr) +{ + /* convert a time period (think TTL's) to wireformat) */ + uint16_t *r = NULL; + uint32_t period; + const char *end; + + /* Allocate required space... */ + period = strtottl(periodstr, &end); + if (*end != '\0') { + zc_error_prev_line("time period is expected"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + period = htonl(period); + r = alloc_rdata_init(&period, sizeof(period)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_short(const char *text) +{ + uint16_t *r = NULL; + uint16_t value; + char *end; + + value = htons((uint16_t) strtol(text, &end, 10)); + if (*end != '\0') { + zc_error_prev_line("integer value is expected"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + r = alloc_rdata_init(&value, sizeof(value)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_byte(const char *text) +{ + uint16_t *r = NULL; + uint8_t value; + char *end; + + value = (uint8_t) strtol(text, &end, 10); + if (*end != '\0') { + zc_error_prev_line("integer value is expected"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + r = alloc_rdata_init(&value, sizeof(value)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_algorithm(const char *text) +{ + const knot_lookup_table_t *alg; + uint8_t id; + + alg = knot_lookup_by_name(dns_algorithms, text); + if (alg) { + id = (uint8_t) alg->id; + } else { + char *end; + id = (uint8_t) strtol(text, &end, 10); + if (*end != '\0') { + zc_error_prev_line("algorithm is expected"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + return NULL; + } + } + + uint16_t *r = alloc_rdata_init(&id, sizeof(id)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + + return r; +} + +uint16_t * zparser_conv_certificate_type(const char *text) +{ + /* convert a algoritm string to integer */ + const knot_lookup_table_t *type; + uint16_t id; + + type = knot_lookup_by_name(dns_certificate_types, text); + if (type) { + id = htons((uint16_t) type->id); + } else { + char *end; + id = htons((uint16_t) strtol(text, &end, 10)); + if (*end != '\0') { + zc_error_prev_line("certificate type is expected"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + return NULL; + } + } + + uint16_t *r = alloc_rdata_init(&id, sizeof(id)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + + return r; +} + +uint16_t * zparser_conv_a(const char *text) +{ + in_addr_t address; + uint16_t *r = NULL; + + if (inet_pton(AF_INET, text, &address) != 1) { + zc_error_prev_line("invalid IPv4 address '%s'", text); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + r = alloc_rdata_init(&address, sizeof(address)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + + return r; +} + +uint16_t * zparser_conv_aaaa(const char *text) +{ + uint8_t address[IP6ADDRLEN]; + uint16_t *r = NULL; + + if (inet_pton(AF_INET6, text, address) != 1) { + zc_error_prev_line("invalid IPv6 address '%s'", text); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + r = alloc_rdata_init(address, sizeof(address)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_text(const char *text, size_t len) +{ + uint16_t *r = NULL; + + dbg_zp("Converting text: %s\n", text); + + if (len > 255) { + zc_error_prev_line("text string is longer than 255 characters," + " try splitting it into multiple parts"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + uint8_t *p; + r = alloc_rdata(len + 1); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + p = (uint8_t *)(r + 1); + *p = len; + memcpy(p + 1, text, len); + } + return r; +} + +uint16_t * zparser_conv_dns_name(const uint8_t *name, size_t len) +{ + uint16_t *r = NULL; + uint8_t *p = NULL; + r = alloc_rdata(len); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + p = (uint8_t *)(r + 1); + memcpy(p, name, len); + + return r; +} + +uint16_t * zparser_conv_b32(const char *b32) +{ + uint8_t buffer[B64BUFSIZE]; + uint16_t *r = NULL; + size_t i = B64BUFSIZE - 1; + + if (strcmp(b32, "-") == 0) { + r = alloc_rdata_init("", 1); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + return r; + } + + /*!< \todo BLEEDING EYES! */ + + char b32_copy[strlen(b32) + 1]; + + for (int i = 0; i < strlen(b32); i++) { + b32_copy[i] = toupper(b32[i]); + } + + /*!< \todo BLEEDING EYES! */ + b32_copy[strlen(b32)] = '\0'; + + if (!base32hex_decode(b32_copy, + strlen(b32_copy), (char *)buffer + 1, &i)) { + zc_error_prev_line("invalid base32 data"); + parser->error_occurred = 1; + } else { + buffer[0] = i; /* store length byte */ + r = alloc_rdata_init(buffer, i + 1); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_b64(const char *b64) +{ + uint8_t buffer[B64BUFSIZE]; + uint16_t *r = NULL; + int i; + + i = b64_pton(b64, buffer, B64BUFSIZE); + if (i == -1) { + zc_error_prev_line("invalid base64 data\n"); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + r = alloc_rdata_init(buffer, i); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_rrtype(const char *text) +{ + uint16_t *r = NULL; + uint16_t type = knot_rrtype_from_string(text); + + if (type == 0) { + zc_error_prev_line("unrecognized RR type '%s'", text); + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + } else { + type = htons(type); + r = alloc_rdata_init(&type, sizeof(type)); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + } + return r; +} + +uint16_t * zparser_conv_nxt(uint8_t nxtbits[]) +{ + /* nxtbits[] consists of 16 bytes with some zero's in it + * copy every byte with zero to r and write the length in + * the first byte + */ + uint16_t i; + uint16_t last = 0; + + for (i = 0; i < 16; i++) { + if (nxtbits[i] != 0) { + last = i + 1; + } + } + + uint16_t *r = alloc_rdata_init(nxtbits, last); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + return NULL; + } + + return r; +} + + +/* we potentially have 256 windows, each one is numbered. empty ones + * should be discarded + */ +uint16_t * zparser_conv_nsec(uint8_t nsecbits[NSEC_WINDOW_COUNT] + [NSEC_WINDOW_BITS_SIZE]) +{ + /* nsecbits contains up to 64K of bits which represent the + * types available for a name. Walk the bits according to + * nsec++ draft from jakob + */ + uint16_t *r; + uint8_t *ptr; + size_t i, j; + uint16_t window_count = 0; + uint16_t total_size = 0; + uint16_t window_max = 0; + + /* The used windows. */ + int used[NSEC_WINDOW_COUNT]; + /* The last byte used in each the window. */ + int size[NSEC_WINDOW_COUNT]; + + window_max = 1 + (nsec_highest_rcode / 256); + + /* used[i] is the i-th window included in the nsec + * size[used[0]] is the size of window 0 + */ + + /* walk through the 256 windows */ + for (i = 0; i < window_max; ++i) { + int empty_window = 1; + /* check each of the 32 bytes */ + for (j = 0; j < NSEC_WINDOW_BITS_SIZE; ++j) { + if (nsecbits[i][j] != 0) { + size[i] = j + 1; + empty_window = 0; + } + } + if (!empty_window) { + used[window_count] = i; + window_count++; + } + } + + for (i = 0; i < window_count; ++i) { + total_size += sizeof(uint16_t) + size[used[i]]; + } + + r = alloc_rdata(total_size); + if (r == NULL) { + ERR_ALLOC_FAILED; + parser->error_occurred = KNOTDZCOMPILE_EBRDATA; + return NULL; + } + ptr = (uint8_t *)(r + 1); + + /* now walk used and copy it */ + for (i = 0; i < window_count; ++i) { + ptr[0] = used[i]; + ptr[1] = size[used[i]]; + memcpy(ptr + 2, &nsecbits[used[i]], size[used[i]]); + ptr += size[used[i]] + 2; + } + + return r; +} + +/* Parse an int terminated in the specified range. */ +static int parse_int(const char *str, + char **end, + int *result, + const char *name, + int min, + int max) +{ + long value; + value = strtol(str, end, 10); + if (value < min || value > max) { + zc_error_prev_line("%s must be within the range [%d .. %d]", + name, + min, + max); + return 0; + } else { + *result = (int) value; + return 1; + } +} + +/* RFC1876 conversion routines */ +static uint32_t poweroften[10] = {1, 10, 100, 1000, 10000, 100000, + 1000000, 10000000, 100000000, 1000000000 + }; + +/* + * Converts ascii size/precision X * 10**Y(cm) to 0xXY. + * Sets the given pointer to the last used character. + * + */ +static uint8_t precsize_aton(char *cp, char **endptr) +{ + unsigned int mval = 0, cmval = 0; + uint8_t retval = 0; + int exponent; + int mantissa; + + while (isdigit((int)*cp)) { + mval = mval * 10 + hexdigit_to_int(*cp++); + } + + if (*cp == '.') { /* centimeters */ + cp++; + if (isdigit((int)*cp)) { + cmval = hexdigit_to_int(*cp++) * 10; + if (isdigit((int)*cp)) { + cmval += hexdigit_to_int(*cp++); + } + } + } + + if (mval >= poweroften[7]) { + /* integer overflow possible for *100 */ + mantissa = mval / poweroften[7]; + exponent = 9; /* max */ + } else { + cmval = (mval * 100) + cmval; + + for (exponent = 0; exponent < 9; exponent++) + if (cmval < poweroften[exponent+1]) { + break; + } + + mantissa = cmval / poweroften[exponent]; + } + if (mantissa > 9) { + mantissa = 9; + } + + retval = (mantissa << 4) | exponent; + + if (*cp == 'm') { + cp++; + } + + *endptr = cp; + + return (retval); +} + +/* + * Parses a specific part of rdata. + * + * Returns: + * + * number of elements parsed + * zero on error + * + */ +uint16_t * zparser_conv_loc(char *str) +{ + uint16_t *r; + uint32_t *p; + int i; + int deg, min, secs; /* Secs is stored times 1000. */ + uint32_t lat = 0, lon = 0, alt = 0; + /* encoded defaults: version=0 sz=1m hp=10000m vp=10m */ + uint8_t vszhpvp[4] = {0, 0x12, 0x16, 0x13}; + char *start; + double d; + + for (;;) { + deg = min = secs = 0; + + /* Degrees */ + if (*str == '\0') { + zc_error_prev_line("unexpected end of LOC data"); + return NULL; + } + + if (!parse_int(str, &str, °, "degrees", 0, 180)) { + return NULL; + } + if (!isspace((int)*str)) { + zc_error_prev_line("space expected after degrees"); + return NULL; + } + ++str; + + /* Minutes? */ + if (isdigit((int)*str)) { + if (!parse_int(str, &str, &min, "minutes", 0, 60)) { + return NULL; + } + if (!isspace((int)*str)) { + zc_error_prev_line("space expected after minutes"); + return NULL; + } + ++str; + } + + /* Seconds? */ + if (isdigit((int)*str)) { + start = str; + if (!parse_int(str, &str, &i, "seconds", 0, 60)) { + return NULL; + } + + if (*str == '.' && !parse_int(str + 1, &str, &i, + "seconds fraction", + 0, 999)) { + return NULL; + } + + if (!isspace((int)*str)) { + zc_error_prev_line("space expected after seconds"); + return NULL; + } + + if (sscanf(start, "%lf", &d) != 1) { + zc_error_prev_line("error parsing seconds"); + } + + if (d < 0.0 || d > 60.0) { + zc_error_prev_line( + "seconds not in range 0.0 .. 60.0"); + } + + secs = (int)(d * 1000.0 + 0.5); + ++str; + } + + switch (*str) { + case 'N': + case 'n': + lat = ((uint32_t)1 << 31) + + (deg * 3600000 + min * 60000 + secs); + break; + case 'E': + case 'e': + lon = ((uint32_t)1 << 31) + + (deg * 3600000 + min * 60000 + secs); + break; + case 'S': + case 's': + lat = ((uint32_t)1 << 31) - + (deg * 3600000 + min * 60000 + secs); + break; + case 'W': + case 'w': + lon = ((uint32_t)1 << 31) - + (deg * 3600000 + min * 60000 + secs); + break; + default: + zc_error_prev_line( + "invalid latitude/longtitude: '%c'", *str); + return NULL; + } + ++str; + + if (lat != 0 && lon != 0) { + break; + } + + if (!isspace((int)*str)) { + zc_error_prev_line("space expected after" + " latitude/longitude"); + return NULL; + } + ++str; + } + + /* Altitude */ + if (*str == '\0') { + zc_error_prev_line("unexpected end of LOC data"); + return NULL; + } + + if (!isspace((int)*str)) { + zc_error_prev_line("space expected before altitude"); + return NULL; + } + ++str; + + start = str; + + /* Sign */ + if (*str == '+' || *str == '-') { + ++str; + } + + /* Meters of altitude... */ + int ret = strtol(str, &str, 10); + UNUSED(ret); // Result checked in following switch + + switch (*str) { + case ' ': + case '\0': + case 'm': + break; + case '.': + if (!parse_int(str + 1, &str, &i, "altitude fraction", 0, 99)) { + return NULL; + } + if (!isspace((int)*str) && *str != '\0' && *str != 'm') { + zc_error_prev_line("altitude fraction must be a number"); + return NULL; + } + break; + default: + zc_error_prev_line("altitude must be expressed in meters"); + return NULL; + } + if (!isspace((int)*str) && *str != '\0') { + ++str; + } + + if (sscanf(start, "%lf", &d) != 1) { + zc_error_prev_line("error parsing altitude"); + } + + alt = (uint32_t)(10000000.0 + d * 100 + 0.5); + + if (!isspace((int)*str) && *str != '\0') { + zc_error_prev_line("unexpected character after altitude"); + return NULL; + } + + /* Now parse size, horizontal precision and vertical precision if any */ + for (i = 1; isspace((int)*str) && i <= 3; i++) { + vszhpvp[i] = precsize_aton(str + 1, &str); + + if (!isspace((int)*str) && *str != '\0') { + zc_error_prev_line("invalid size or precision"); + return NULL; + } + } + + /* Allocate required space... */ + r = alloc_rdata(16); + if (r == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + p = (uint32_t *)(r + 1); + + memmove(p, vszhpvp, 4); + write_uint32(p + 1, lat); + write_uint32(p + 2, lon); + write_uint32(p + 3, alt); + + return r; +} + +/* + * Convert an APL RR RDATA element. + */ +uint16_t * zparser_conv_apl_rdata(char *str) +{ + int negated = 0; + uint16_t address_family; + uint8_t prefix; + uint8_t maximum_prefix; + uint8_t length; + uint8_t address[IP6ADDRLEN]; + char *colon = strchr(str, ':'); + char *slash = strchr(str, '/'); + int af; + int rc; + uint16_t rdlength; + uint16_t *r; + uint8_t *t; + char *end; + long p; + + if (!colon) { + zc_error_prev_line("address family separator is missing"); + return NULL; + } + if (!slash) { + zc_error_prev_line("prefix separator is missing"); + return NULL; + } + + *colon = '\0'; + *slash = '\0'; + + if (*str == '!') { + negated = 1; + ++str; + } + + if (strcmp(str, "1") == 0) { + address_family = htons(1); + af = AF_INET; + length = sizeof(in_addr_t); + maximum_prefix = length * 8; + } else if (strcmp(str, "2") == 0) { + address_family = htons(2); + af = AF_INET6; + length = IP6ADDRLEN; + maximum_prefix = length * 8; + } else { + zc_error_prev_line("invalid address family '%s'", str); + return NULL; + } + + rc = inet_pton(af, colon + 1, address); + if (rc == 0) { + zc_error_prev_line("invalid address '%s'", colon + 1); + return NULL; + } else if (rc == -1) { + char ebuf[256]; + zc_error_prev_line("inet_pton failed: %s", + strerror_r(errno, ebuf, sizeof(ebuf))); + return NULL; + } + + /* Strip trailing zero octets. */ + while (length > 0 && address[length - 1] == 0) { + --length; + } + + + p = strtol(slash + 1, &end, 10); + if (p < 0 || p > maximum_prefix) { + zc_error_prev_line("prefix not in the range 0 .. %d", + maximum_prefix); + return NULL; + } else if (*end != '\0') { + zc_error_prev_line("invalid prefix '%s'", slash + 1); + return NULL; + } + prefix = (uint8_t) p; + + rdlength = (sizeof(address_family) + sizeof(prefix) + sizeof(length) + + length); + r = alloc_rdata(rdlength); + if (r == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + t = (uint8_t *)(r + 1); + + memcpy(t, &address_family, sizeof(address_family)); + t += sizeof(address_family); + memcpy(t, &prefix, sizeof(prefix)); + t += sizeof(prefix); + memcpy(t, &length, sizeof(length)); + if (negated) { + *t |= APL_NEGATION_MASK; + } + t += sizeof(length); + memcpy(t, address, length); + + return r; +} + +/* + * Below some function that also convert but not to wireformat + * but to "normal" (int,long,char) types + */ + +uint32_t zparser_ttl2int(const char *ttlstr, int *error) +{ + /* convert a ttl value to a integer + * return the ttl in a int + * -1 on error + */ + + uint32_t ttl; + const char *t; + + ttl = strtottl(ttlstr, &t); + if (*t != 0) { + zc_error_prev_line("invalid TTL value: %s", ttlstr); + *error = 1; + } + + return ttl; +} + +void zadd_rdata_wireformat(uint16_t *data) +{ + parser->temporary_items[parser->rdata_count].raw_data = data; + parser->rdata_count++; +} + +/** + * Used for TXT RR's to grow with undefined number of strings. + */ +void zadd_rdata_txt_wireformat(uint16_t *data, int first) +{ + dbg_zp("Adding text!\n"); +// hex_print(data + 1, data[0]); + knot_rdata_item_t *rd; + + /* First STR in str_seq, allocate 65K in first unused rdata + * else find last used rdata */ + if (first) { + rd = &parser->temporary_items[parser->rdata_count]; +// if ((rd->data = (uint8_t *) region_alloc(parser->rr_region, +// sizeof(uint8_t) + 65535 * sizeof(uint8_t))) == NULL) { +// zc_error_prev_line("Could not allocate memory for TXT RR"); +// return; +// } + rd->raw_data = alloc_rdata(65535 * sizeof(uint8_t)); + if (rd->raw_data == NULL) { + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + } + parser->rdata_count++; + rd->raw_data[0] = 0; + } else { +// assert(0); + rd = &parser->temporary_items[parser->rdata_count-1]; + } + + if ((size_t)rd->raw_data[0] + (size_t)data[0] > 65535) { + zc_error_prev_line("too large rdata element"); + return; + } + + memcpy((uint8_t *)rd->raw_data + 2 + rd->raw_data[0], + data + 1, data[0]); + rd->raw_data[0] += data[0]; + free(data); + dbg_zp("Item after add\n"); +// hex_print(rd->raw_data + 1, rd->raw_data[0]); +} + +void zadd_rdata_domain(knot_dname_t *dname) +{ + knot_dname_retain(dname); +// printf("Adding rdata name: %s %p\n", dname->name, dname); + parser->temporary_items[parser->rdata_count].dname = dname; + parser->rdata_count++; +} + +void parse_unknown_rdata(uint16_t type, uint16_t *wireformat) +{ + dbg_rdata("parsing unknown rdata for type: %d\n", type); +// buffer_type packet; + uint16_t size; + ssize_t rdata_count; + ssize_t i; + knot_rdata_item_t *items = NULL; + + if (wireformat) { + size = *wireformat; + } else { + return; + } + +// buffer_create_from(&packet, wireformat + 1, *wireformat); + rdata_count = rdata_wireformat_to_rdata_atoms(wireformat + 1, type, + size, &items); +// dbg_rdata("got %d items\n", rdata_count); + dbg_rdata("wf to items returned error: %s (%d)\n", + error_to_str(knot_zcompile_error_msgs, rdata_count), + rdata_count); + if (rdata_count < 0) { + zc_error_prev_line("bad unknown RDATA\n"); + /*!< \todo leaks */ + return; + } + + for (i = 0; i < rdata_count; ++i) { + if (rdata_atom_is_domain(type, i)) { + zadd_rdata_domain(items[i].dname); + } else { + //XXX won't this create size two times? + zadd_rdata_wireformat((uint16_t *)items[i].raw_data); + } + } + free(items); + /* Free wireformat */ + free(wireformat); +} + +void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE], + uint16_t index) +{ + /* + * The bits are counted from left to right, so bit #0 is the + * left most bit. + */ + uint8_t window = index / 256; + uint8_t bit = index % 256; + + bits[window][bit / 8] |= (1 << (7 - bit % 8)); +} + diff --git a/src/zcompile/parser-util.h b/src/zcompile/parser-util.h new file mode 100644 index 0000000..57258dc --- /dev/null +++ b/src/zcompile/parser-util.h @@ -0,0 +1,357 @@ +/*! + * \file parser-util.h + * + * \author NLnet Labs + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * Minor modifications by CZ.NIC, z.s.p.o. + * + * \brief Zone compiler utility functions. + * + * \addtogroup zoneparser + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _KNOTD_PARSER_UTIL_H_ +#define _KNOTD_PARSER_UTIL_H_ + +#include <assert.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <time.h> +#include <netinet/in.h> +#include <netdb.h> + +#include "zcompile/zcompile.h" +#include "libknot/util/descriptor.h" + +int inet_pton4(const char *src, uint8_t *dst); +int inet_pton6(const char *src, uint8_t *dst); +//int my_b32_pton(const char *src, uint8_t *target, size_t tsize); +const char *inet_ntop4(const u_char *src, char *dst, size_t size); +const char *inet_ntop6(const u_char *src, char *dst, size_t size); +int inet_pton(int af, const char *src, void *dst); +void b64_initialize_rmap(); +int b64_pton_do(char const *src, uint8_t *target, size_t targsize); +int b64_pton_len(char const *src); +int b64_pton(char const *src, uint8_t *target, size_t targsize); +void set_bit(uint8_t bits[], size_t index); +uint32_t strtoserial(const char *nptr, const char **endptr); +void write_uint32(void *dst, uint32_t data); +uint32_t strtottl(const char *nptr, const char **endptr); +time_t mktime_from_utc(const struct tm *tm); + +/*!< Conversions from text to wire. */ +/*! + * \brief Converts hex text format to wireformat. + * + * \param hex String to be converted. + * \param len Length of string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_hex(const char *hex, size_t len); + +/*! + * \brief Converts hex text format with length to wireformat. + * + * \param hex String to be converted/. + * \param len Length of string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_hex_length(const char *hex, size_t len); + +/*! + * \brief Converts time string to wireformat. + * + * \param time Time string to be converted. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_time(const char *time); +/*! + * \brief Converts a protocol and a list of service port numbers + * (separated by spaces) in the rdata to wireformat + * + * \param protostr Protocol string. + * \param servicestr Service string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_services(const char *protostr, char *servicestr); + +/*! + * \brief Converts serial to wireformat. + * + * \param serialstr Serial string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_serial(const char *serialstr); +/*! + * \brief Converts period to wireformat. + * + * \param periodstr Period string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_period(const char *periodstr); + +/*! + * \brief Converts short int to wireformat. + * + * \param text String containing short int. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_short(const char *text); + +/*! + * \brief Converts long int to wireformat. + * + * \param text String containing long int. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_long(const char *text); + +/*! + * \brief Converts byte to wireformat. + * + * \param text String containing byte. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_byte(const char *text); + +/*! + * \brief Converts A rdata string to wireformat. + * + * \param text String containing A rdata. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_a(const char *text); + +/*! + * \brief Converts AAAA rdata string to wireformat. + * + * \param text String containing AAAA rdata. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_aaaa(const char *text); + +/*! + * \brief Converts text string to wireformat. + * + * \param text Text string. + * \param len Length of string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_text(const char *text, size_t len); + +/*! + * \brief Converts domain name string to wireformat. + * + * \param name Domain name string. + * \param len Length of string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_dns_name(const uint8_t* name, size_t len); + +/*! + * \brief Converts base32 encoded string to wireformat. + * TODO consider replacing with our implementation. + * + * \param b32 Base32 encoded string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_b32(const char *b32); + +/*! + * \brief Converts base64 encoded string to wireformat. + * TODO consider replacing with our implementation. + * + * \param b64 Base64 encoded string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_b64(const char *b64); + +/*! + * \brief Converts RR type string to wireformat. + * + * \param rr RR type string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_rrtype(const char *rr); + +/*! + * \brief Converts NXT string to wireformat. + * + * \param nxtbits NXT string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_nxt(uint8_t *nxtbits); + +/*! + * \brief Converts NSEC bitmap to wireformat. + * + * \param nsecbits[][] NSEC bits. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_nsec(uint8_t nsecbits[NSEC_WINDOW_COUNT] + [NSEC_WINDOW_BITS_SIZE]); +/*! + * \brief Converts LOC string to wireformat. + * + * \param str LOC string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_loc(char *str); + +/*! + * \brief Converts algorithm string to wireformat. + * + * \param algstr Algorithm string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_algorithm(const char *algstr); + +/*! + * \brief Converts certificate type string to wireformat. + * + * \param typestr Certificate type mnemonic string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_certificate_type(const char *typestr); + +/*! + * \brief Converts APL data to wireformat. + * + * \param str APL data string. + * + * \return Converted wireformat. + */ +uint16_t *zparser_conv_apl_rdata(char *str); + +/*! + * \brief Parses unknown rdata. + * + * \param type Type of data. + * \param wireformat Wireformat of data. + * + * \return Converted wireformat. + */ +void parse_unknown_rdata(uint16_t type, uint16_t *wireformat); + +/*! + * \brief Converts TTL string to int. + * + * \param ttlstr String + * \param error Error code. + * + * \return Converted wireformat. + */ +uint32_t zparser_ttl2int(const char *ttlstr, int* error); + +/*! + * \brief Adds wireformat to temporary list of rdata items. + * + * \param data Wireformat to be added. + */ +void zadd_rdata_wireformat(uint16_t *data); + +/*! + * \brief Adds TXT wireformat to temporary list of rdata items. + * + * \param data Wireformat to be added. + * \param first This is first text to be added. + */ +void zadd_rdata_txt_wireformat(uint16_t *data, int first); + +/*! + * \brief Cleans after using zadd_rdata_txt_wireformat(). + */ +void zadd_rdata_txt_clean_wireformat(); + +/*! + * \brief Adds domain name to temporary list of rdata items. + * + * \param domain Domain name to be added. + */ +void zadd_rdata_domain(knot_dname_t *domain); + +/*! + * \brief Sets bit in NSEC bitmap. + * + * \param bits[][] NSEC bitmaps. + * \param index Index on which bit is to be set. + */ +void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE], + uint16_t index); + +/*! + * \brief Allocate and init wireformat. + * + * \param data Data to be copied into newly created wireformat. + * \param size Size of data. + * + * \return Allocated wireformat. + */ +uint16_t *alloc_rdata_init(const void *data, size_t size); +uint16_t rrsig_type_covered(knot_rrset_t *rrset); + + +#endif /* _KNOTD_PARSER_UTIL_H_ */ + +/*! @} */ diff --git a/src/zcompile/tests/unittests_zp_main.c b/src/zcompile/tests/unittests_zp_main.c new file mode 100644 index 0000000..5d8c5e9 --- /dev/null +++ b/src/zcompile/tests/unittests_zp_main.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include "knot/common.h" +#include "common/libtap/tap_unit.h" + +// Units to test +#include "zcompile_tests.c" + +// Run all loaded units +int main(int argc, char *argv[]) +{ + // Open log + //log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING)); + + // Build test set + unit_api *tests[] = { + &zoneparser_tests_api, //! Zoneparser unit + NULL + }; + + // Plan number of tests + int id = 0; + int test_count = 0; + note("Units:"); + while (tests[id] != NULL) { + note("- %s : %d tests", tests[id]->name, + tests[id]->count(argc, argv)); + test_count += tests[id]->count(argc, argv); + ++id; + } + + plan(test_count); + + // Run tests + id = 0; + while (tests[id] != NULL) { + diag("Testing unit: %s", tests[id]->name); + tests[id]->run(argc, argv); + ++id; + } + + //log_close(); + + // Evaluate + return exit_status(); +} + diff --git a/src/zcompile/tests/zcompile_tests.c b/src/zcompile/tests/zcompile_tests.c new file mode 100644 index 0000000..5d3dce6 --- /dev/null +++ b/src/zcompile/tests/zcompile_tests.c @@ -0,0 +1,425 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "libknot/zone/zone.h" +#include "knot/zone/zone-load.h" +#include "knot/common.h" +#include "libknot/rrset.h" +#include "libknot/util/descriptor.h" +#include "zcompile/zcompile.h" + +#ifdef TEST_WITH_LDNS +#include "ldns/ldns.h" +#endif + +static int zoneparser_tests_count(int argc, char *argv[]); +static int zoneparser_tests_run(int argc, char *argv[]); + +/* + * Unit API. + */ +unit_api zoneparser_tests_api = { + "Zoneparser", + &zoneparser_tests_count, + &zoneparser_tests_run +}; + +#ifdef TEST_WITH_LDNS +/* + * Unit implementation. + */static int compare_wires_simple_zp(uint8_t *wire1, + uint8_t *wire2, uint count) +{ + int i = 0; + while (i < count && + wire1[i] == wire2[i]) { + i++; + } + return (!(count == i)); +} + +/* compares only one rdata */ +static int compare_rr_rdata_silent(knot_rdata_t *rdata, ldns_rr *rr, + uint16_t type) +{ + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + for (int i = 0; i < rdata->count; i++) { + /* TODO check for ldns "descriptors" as well */ + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME || + desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) { + assert(ldns_rr_rdf(rr, i)); + if (rdata->items[i].dname->size != + ldns_rdf_size(ldns_rr_rdf(rr, i))) { + return 1; + } + if (compare_wires_simple_zp(rdata->items[i].dname->name, + ldns_rdf_data(ldns_rr_rdf(rr, i)), + rdata->items[i].dname->size) != 0) { + return 1; + } + } else { + if (ldns_rr_rdf(rr, i) == NULL && + rdata->items[i].raw_data[0] != 0) { + return 1; + } else { + continue; + } + if (rdata->items[i].raw_data[0] != + ldns_rdf_size(ldns_rr_rdf(rr, i))) { + + /* ldns stores the size including the + * length, dnslib does not */ + if (abs(rdata->items[i].raw_data[0] - + ldns_rdf_size(ldns_rr_rdf(rr, i))) != 1) { + return 1; + } + } + if (compare_wires_simple_zp((uint8_t *) + (rdata->items[i].raw_data + 1), + ldns_rdf_data(ldns_rr_rdf(rr, i)), + rdata->items[i].raw_data[0]) != 0) { + return 1; + } + } + } + return 0; +} + +static int compare_rrset_w_ldns_rrset(const knot_rrset_t *rrset, + ldns_rr_list *rrs, + char check_rdata, char verbose) +{ + /* We should have only one rrset from ldns, although it is + * represented as rr_list ... */ + + /* TODO errors */ + + assert(rrs); + assert(rrset); + + ldns_rr_list_sort(rrs); + + /* compare headers */ + + ldns_rr *rr = ldns_rr_list_rr(rrs, 0); + + if (rrset->owner->size != ldns_rdf_size(ldns_rr_owner(rr))) { + diag("RRSet owner names differ in length"); + if (!verbose) { + return 1; + } + diag("ldns: %d, dnslib: %d", ldns_rdf_size(ldns_rr_owner(rr)), + rrset->owner->size); + diag("%s", knot_dname_to_str(rrset->owner)); + diag("%s", ldns_rdf_data(ldns_rr_owner(rr))); + return 1; + } + + if (compare_wires_simple_zp(rrset->owner->name, + ldns_rdf_data(ldns_rr_owner(rr)), + rrset->owner->size) != 0) { + diag("RRSet owner wireformats differ"); + return 1; + } + + if (rrset->type != ldns_rr_get_type(rr)) { + diag("RRset types differ"); + if (!verbose) { + return 1; + } + diag("Dnslib type: %d Ldns type: %d", rrset->type, + ldns_rr_get_type(rr)); + return 1; + } + + if (rrset->rclass != ldns_rr_get_class(rr)) { + diag("RRset classes differ"); + return 1; + } + + if (rrset->ttl != ldns_rr_ttl(rr)) { + diag("RRset TTLs differ"); + if (!verbose) { + return 1; + } + diag("dnslib: %d ldns: %d", rrset->ttl, ldns_rr_ttl(rr)); + return 1; + } + + if (!check_rdata) { + return 0; + } + + /* compare rdatas */ + + /* sort dnslib rdata */ + + knot_rdata_t *tmp_rdata = rrset->rdata; + + rr = ldns_rr_list_pop_rr(rrs); + + char found; + + while (rr != NULL) { + found = 0; + tmp_rdata = rrset->rdata; + while (!found && + tmp_rdata->next != rrset->rdata) { + if (compare_rr_rdata_silent(tmp_rdata, rr, + rrset->type) == 0) { + found = 1; + } + tmp_rdata = tmp_rdata->next; + } + + if (!found && + compare_rr_rdata_silent(tmp_rdata, rr, rrset->type) == 0) { + found = 1; + } + + /* remove the found rdata from list */ + if (!found) { + diag("RRsets rdata differ"); + return 1; + } + ldns_rr_free(rr); + + rr = ldns_rr_list_pop_rr(rrs); + } + + return 0; +} + +int compare_zones(knot_zone_contents_t *zone, + ldns_rr_list *ldns_list, char verbose) +{ + /* TODO currently test fail when encountering first error - + * it should finish going through the zone */ + knot_rrset_t *tmp_rrset = NULL; + + knot_dname_t *tmp_dname = NULL; + + knot_node_t *node = NULL; + + ldns_rr_list *ldns_rrset = ldns_rr_list_pop_rrset(ldns_list); + + if (ldns_rrset == NULL) { + diag("Error: empty node"); + return 1; + } + + ldns_rr *rr = NULL; + + /* + * Following cycle works like this: First, we get RR from ldns rrset, + * then we search for the node containing the rrset, then we get the + * rrset, which is then compared with whole ldns rrset. + */ + + /* ldns_rr_list_pop_rrset should pop the first rrset */ + while (ldns_rrset != NULL) { + rr = ldns_rr_list_rr(ldns_rrset, 0); + tmp_dname = + knot_dname_new_from_wire(ldns_rdf_data(ldns_rr_owner(rr)), + ldns_rdf_size(ldns_rr_owner(rr)), + NULL); + + node = knot_zone_contents_get_node(zone, tmp_dname); + + if (node == NULL) { + node = knot_zone_contents_get_nsec3_node(zone, + tmp_dname); + } + + if (node == NULL) { + diag("Could not find node"); + diag("%s", knot_dname_to_str(tmp_dname)); + return 1; + } + + knot_dname_free(&tmp_dname); + + tmp_rrset = knot_node_get_rrset(node, + ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, + 0))); + + if (tmp_rrset == NULL && + (uint)(ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, 0))) != + (uint)KNOT_RRTYPE_RRSIG) { + diag("Could not find rrset"); + if (!verbose) { + return 1; + } + ldns_rr_list_print(stdout, ldns_rrset); + diag("%s", knot_dname_to_str(node->owner)); + return 1; + } else if ((uint)(ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, + 0))) == + (uint)KNOT_RRTYPE_RRSIG) { + knot_rrset_t *rrsigs = NULL; + /* read type covered from ldns rrset */ + for (int i = 0; i < ldns_rrset->_rr_count; i++) { + uint16_t type_covered = + ldns_rdf_data(ldns_rr_rdf( + ldns_rr_list_rr(ldns_rrset, i), 0))[1]; + + /* + * Dnslib stores RRSIGs separately - + * we have to find get it from its "parent" + * rrset. + */ + + tmp_rrset = knot_node_get_rrset(node, + type_covered); + + if (tmp_rrset == NULL) { + if (!verbose) { + return 1; + } + diag("following rrset " + "could not be found"); + ldns_rr_list_print(stdout, ldns_rrset); + return 1; + } + + if (rrsigs == NULL) { + rrsigs = tmp_rrset->rrsigs; + } else { + knot_rrset_merge((void *)&rrsigs, + (void *)&(tmp_rrset->rrsigs)); + } + } + tmp_rrset = rrsigs; + } + +/* diag("dnslib type: %d", tmp_rrset->type); + diag("dnslib dname: %s", tmp_rrset->owner->name); + + diag("ldns type: %d", + ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, 0))); + diag("ldns dname : %s", ldns_rdf_data(ldns_rr_owner( + ldns_rr_list_rr(ldns_rrset, 0)))); */ + +// knot_rrset_dump(tmp_rrset, 1); + + if (compare_rrset_w_ldns_rrset(tmp_rrset, ldns_rrset, + 1, 0) != 0) { + diag("RRSets did not match"); +// knot_rrset_dump(tmp_rrset, 1); + return 1; + } + + ldns_rr_list_deep_free(ldns_rrset); + + ldns_rrset = ldns_rr_list_pop_rrset(ldns_list); + + if (ldns_rrset == NULL) { + ldns_rrset = ldns_rr_list_pop_rrset(ldns_list); + } + } + + return 0; +} + +#endif + +static int test_zoneparser_zone_read(const char *origin, const char *filename, + const char *outfile) +{ +#ifndef TEST_WITH_LDNS + diag("Zoneparser tests without usage of ldns are not implemented"); + return 0; +#endif + +#ifdef TEST_WITH_LDNS + /* Calls zcompile. */ + parser = zparser_create(); + int ret = zone_read(origin, filename, outfile, 0); + if (ret != 0) { + diag("Could not load zone from file: %s", filename); + return 0; + } + + knot_zone_t *dnsl_zone = NULL; + zloader_t *loader = NULL; + if (knot_zload_open(&loader, outfile) != 0) { + diag("Could not create zone loader.\n"); + return 0; + } + dnsl_zone = knot_zload_load(loader); + remove(outfile); + if (!dnsl_zone) { + diag("Could not load dumped zone.\n"); + return 0; + } + + ldns_zone *ldns_zone = NULL; + FILE *f = fopen(filename, "r"); + if (ldns_zone_new_frm_fp(&ldns_zone, f, NULL, + 0, LDNS_RR_CLASS_IN) != LDNS_STATUS_OK) { + diag("Could not load zone from file: %s (ldns)", filename); + return 0; + } + +// ldns_zone_sort(ldns_zone); + + /* + * LDNS stores SOA record independently - create a list with all + * records in it. + */ + + ldns_rr_list *ldns_list = ldns_zone_rrs(ldns_zone); + + ldns_rr_list_push_rr(ldns_list, ldns_zone_soa(ldns_zone)); + + if (compare_zones(dnsl_zone->contents, ldns_list, 0) != 0) { + return 0; + } + + knot_zone_deep_free(&dnsl_zone, 0); + ldns_zone_free(ldns_zone); + fclose(f); + return 1; +#endif +} + +static const int ZONEPARSER_TEST_COUNT = 1; + +/*! API: return number of tests. */ +static int zoneparser_tests_count(int argc, char *argv[]) +{ + return ZONEPARSER_TEST_COUNT; +} + +/*! API: run tests. */ +static int zoneparser_tests_run(int argc, char *argv[]) +{ + if (argc == 3) { + ok(test_zoneparser_zone_read(argv[1], argv[2], + "foo_test_zone"), + "zoneparser: read (%s)", + argv[2]); + } else { + diag("Wrong parameters\n usage: " + "knot-zcompile-unittests origin zonefile"); + return 0; + } + return 1; +} diff --git a/src/zcompile/zcompile-error.c b/src/zcompile/zcompile-error.c new file mode 100644 index 0000000..9357cde --- /dev/null +++ b/src/zcompile/zcompile-error.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "zcompile/zcompile-error.h" + +#include "common/errors.h" + +/*! \brief Table linking error messages to error codes. */ +const error_table_t knot_zcompile_error_msgs[KNOTDZCOMPILE_ERROR_COUNT] = { + + /* Mapped errors. */ + {KNOTDZCOMPILE_EOK, "OK"}, + {KNOTDZCOMPILE_ENOMEM, "Not enough memory."}, + {KNOTDZCOMPILE_EINVAL, "Invalid parameter passed."}, + {KNOTDZCOMPILE_ENOTSUP, "Parameter not supported."}, + {KNOTDZCOMPILE_EBUSY, "Requested resource is busy."}, + {KNOTDZCOMPILE_EAGAIN, + "The system lacked the necessary resource, try again."}, + {KNOTDZCOMPILE_EACCES, + "Permission to perform requested operation is denied."}, + {KNOTDZCOMPILE_ECONNREFUSED, "Connection is refused."}, + {KNOTDZCOMPILE_EISCONN, "Already connected."}, + {KNOTDZCOMPILE_EADDRINUSE, "Address already in use."}, + {KNOTDZCOMPILE_ENOENT, "Resource not found."}, + {KNOTDZCOMPILE_ERANGE, "Value is out of range."}, + + /* Custom errors. */ + {KNOTDZCOMPILE_ERROR, "Generic error."}, + {KNOTDZCOMPILE_EBRDATA, "Malformed RDATA."}, + {KNOTDZCOMPILE_ESOA, "Multiple SOA records."}, + {KNOTDZCOMPILE_EBADSOA, "SOA record has different owner " + "than in config - parser will not continue!"}, + {KNOTDZCOMPILE_EBADNODE, "Error handling node."}, + {KNOTDZCOMPILE_EZONEINVAL, "Invalid zone file."}, + {KNOTDZCOMPILE_EPARSEFAIL, "Parser failed."}, + {KNOTDZCOMPILE_ENOIPV6, "IPv6 support disabled."}, + {KNOTDZCOMPILE_ESYNT, "Parser syntactic error."}, + {KNOTDZCOMPILE_ERROR, 0} +}; diff --git a/src/zcompile/zcompile-error.h b/src/zcompile/zcompile-error.h new file mode 100644 index 0000000..c6d999c --- /dev/null +++ b/src/zcompile/zcompile-error.h @@ -0,0 +1,90 @@ +/*! + * \file zcompile-error.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief Error codes and function for getting error message. + * + * \addtogroup zoneparser + * @{ + */ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOTD_ZCOMPILE_ERROR_H_ +#define _KNOTD_ZCOMPILE_ERROR_H_ + +#include "common/errors.h" + +/*! + * \brief Error codes used in the server. + * + * Some viable errors are directly mapped + * to libc errno codes. + */ +enum knot_zcompile_error { + + /* Directly mapped error codes. */ + KNOTDZCOMPILE_EOK = 0, + KNOTDZCOMPILE_ENOMEM = -ENOMEM, /*!< \brief Out of memory. */ + KNOTDZCOMPILE_EINVAL = -EINVAL, /*!< \brief Invalid parameter passed. */ + /*! + * \brief Parameter not supported. + */ + KNOTDZCOMPILE_ENOTSUP = -ENOTSUP, + KNOTDZCOMPILE_EBUSY = -EBUSY, /*!< \brief Requested resource is busy. */ + /*! + * \brief OS lacked necessary resources. + */ + KNOTDZCOMPILE_EAGAIN = -EAGAIN, + KNOTDZCOMPILE_EACCES = -EACCES, /*!< \brief Permission is denied. */ + /*! + * \brief Connection is refused. + */ + KNOTDZCOMPILE_ECONNREFUSED = -ECONNREFUSED, + KNOTDZCOMPILE_EISCONN = -EISCONN, /*!< \brief Already connected. */ + /*! + * \brief Address already in use. + */ + KNOTDZCOMPILE_EADDRINUSE = -EADDRINUSE, + KNOTDZCOMPILE_ENOENT = -ENOENT, /*!< \brief Resource not found. */ + KNOTDZCOMPILE_ERANGE = -ERANGE, /*!< \brief Value is out of range. */ + + /* Custom error codes. */ + KNOTDZCOMPILE_ERROR = -16384, /*!< \brief Generic error. */ + KNOTDZCOMPILE_ESYNT, /*!< \brief Syntax error. */ + KNOTDZCOMPILE_EBADNODE, /*!< \brief Node error. */ + KNOTDZCOMPILE_EBRDATA, /*!< \brief RDATA error. */ + KNOTDZCOMPILE_EBADSOA, /*!< \brief SOA owner error. */ + KNOTDZCOMPILE_ESOA, /*!< \brief Multiple SOA records. */ + + KNOTDZCOMPILE_EZONEINVAL, /*!< \brief Invalid zone file. */ + KNOTDZCOMPILE_EPARSEFAIL, /*!< \brief Parser fail. */ + KNOTDZCOMPILE_ENOIPV6, /*! \brief No IPv6 support. */ + + KNOTDZCOMPILE_ERROR_COUNT = 22 +}; + +typedef enum knot_zcompile_error knot_zcompile_error_t; + +/*! \brief Table linking error messages to error codes. */ +extern const error_table_t knot_zcompile_error_msgs[KNOTDZCOMPILE_ERROR_COUNT]; + +#endif /* _KNOTD_ZCOMPILE_ERROR_H_ */ + +/*! @} */ diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c new file mode 100644 index 0000000..ec3cbe2 --- /dev/null +++ b/src/zcompile/zcompile.c @@ -0,0 +1,639 @@ +/*! + * \file zcompile.c + * + * \author Jan Kadlec <jan.kadlec@nic.cz>. Minor portions of code taken from + * NSD. + * + * \brief Zone compiler. + * + * \addtogroup zoneparser + * @{ + */ + +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#include "common/base32hex.h" +#include "zcompile/zcompile.h" +#include "zcompile/parser-util.h" +#include "knot/zone/zone-dump-text.h" +#include "zparser.h" +#include "zcompile/zcompile-error.h" +#include "knot/zone/zone-dump.h" +#include "libknot/libknot.h" +#include "libknot/util/utils.h" + +/* Some global flags... */ +static int vflag = 0; +/* if -v then print progress each 'progress' RRs */ +static int progress = 10000; + +/* Total errors counter */ +static long int totalerrors = 0; +static long int totalrrs = 0; + +extern FILE *zp_get_in(void *scanner); + +//#define ZP_DEBUG + +#ifdef ZP_DEBUG +#define dbg_zp(msg...) fprintf(stderr, msg) +#else +#define dbg_zp(msg...) +#endif + +/*! + * \brief Adds RRSet to list. + * + * \param head Head of list. + * \param rrsig RRSet to be added. + */ +static int rrset_list_add(rrset_list_t **head, knot_rrset_t *rrsig) +{ + if (*head == NULL) { + *head = malloc(sizeof(rrset_list_t)); + if (*head == NULL) { + ERR_ALLOC_FAILED; + return KNOTDZCOMPILE_ENOMEM; + } + (*head)->next = NULL; + (*head)->data = rrsig; + } else { + rrset_list_t *tmp = malloc(sizeof(*tmp)); + if (tmp == NULL) { + ERR_ALLOC_FAILED; + return KNOTDZCOMPILE_ENOMEM; + } + tmp->next = *head; + tmp->data = rrsig; + *head = tmp; + } + + return KNOTDZCOMPILE_EOK; +} + +/*! + * \brief Deletes RRSet list. Sets pointer to NULL. + * + * \param head Head of list to be deleted. + */ +static void rrset_list_delete(rrset_list_t **head) +{ + rrset_list_t *tmp; + if (*head == NULL) { + return; + } + + while (*head != NULL) { + tmp = *head; + *head = (*head)->next; + free(tmp); + } + + *head = NULL; +} + +static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone, + knot_rrset_t *rrsig) +{ + assert(rrsig != NULL); + assert(rrsig->rdata->items[0].raw_data); + + knot_node_t *tmp_node = NULL; + + if (rrsig->type != KNOT_RRTYPE_NSEC3) { + tmp_node = knot_zone_contents_get_node(zone, rrsig->owner); + } else { + tmp_node = knot_zone_contents_get_nsec3_node(zone, + rrsig->owner); + } + + if (tmp_node == NULL) { + return KNOTDZCOMPILE_EINVAL; + } + + knot_rrset_t *tmp_rrset = + knot_node_get_rrset(tmp_node, rrsig->type); + + if (tmp_rrset == NULL) { + return KNOTDZCOMPILE_EINVAL; + } + + if (tmp_rrset->rrsigs != NULL) { + knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node, + KNOT_RRSET_DUPL_MERGE, 1); + knot_rrset_free(&rrsig); + } else { + knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node, + KNOT_RRSET_DUPL_SKIP, 1); + } + + return KNOTDZCOMPILE_EOK; +} + +static int find_rrset_for_rrsig_in_node(knot_zone_contents_t *zone, + knot_node_t *node, + knot_rrset_t *rrsig) +{ + assert(rrsig != NULL); + assert(rrsig->rdata->items[0].raw_data); + assert(node); + + assert(knot_dname_compare(rrsig->owner, node->owner) == 0); + + knot_rrset_t *tmp_rrset = + knot_node_get_rrset(node, rrsig_type_covered(rrsig)); + + if (tmp_rrset == NULL) { + return KNOTDZCOMPILE_EINVAL; + } + + if (tmp_rrset->rrsigs != NULL) { + if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node, + KNOT_RRSET_DUPL_MERGE, 1) < 0) { + return KNOTDZCOMPILE_EINVAL; + } + knot_rrset_free(&rrsig); + } else { + if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node, + KNOT_RRSET_DUPL_SKIP, 1) < 0) { + return KNOTDZCOMPILE_EINVAL; + } + } + + assert(tmp_rrset->rrsigs != NULL); + + return KNOTDZCOMPILE_EOK; +} + +static knot_node_t *create_node(knot_zone_contents_t *zone, + knot_rrset_t *current_rrset, + int (*node_add_func)(knot_zone_contents_t *zone, knot_node_t *node, + int create_parents, uint8_t, int), + knot_node_t *(*node_get_func)(const knot_zone_contents_t *zone, + const knot_dname_t *owner)) +{ + knot_node_t *node = + knot_node_new(current_rrset->owner, NULL, 0); + if (node_add_func(zone, node, 1, 0, 1) != 0) { + return NULL; + } + + current_rrset->owner = node->owner; + + return node; +} + +static void process_rrsigs_in_node(knot_zone_contents_t *zone, + knot_node_t *node) +{ + rrset_list_t *tmp = parser->node_rrsigs; + while (tmp != NULL) { + if (find_rrset_for_rrsig_in_node(zone, node, + tmp->data) != 0) { + rrset_list_add(&parser->rrsig_orphans, + tmp->data); + parser->rrsig_orphan_count++; + } + tmp = tmp->next; + } +} + +int process_rr(void) +{ + knot_zone_t *zone = parser->current_zone; + assert(zone != NULL); + knot_zone_contents_t *contents = knot_zone_get_contents(zone); + assert(contents != NULL); + knot_rrset_t *current_rrset = parser->current_rrset; + knot_rrset_t *rrset; + knot_rrtype_descriptor_t *descriptor = + knot_rrtype_descriptor_by_type(current_rrset->type); + + dbg_zp("%s\n", knot_dname_to_str(parser->current_rrset->owner)); + dbg_zp("type: %s\n", knot_rrtype_to_string(parser->current_rrset->type)); + dbg_zp("rdata count: %d\n", parser->current_rrset->rdata->count); +// hex_print(parser->current_rrset->rdata->items[0].raw_data, +// parser->current_rrset->rdata->items[0].raw_data[0]); + + if (descriptor->fixed_items) { + assert(current_rrset->rdata->count == descriptor->length); + } + + assert(current_rrset->rdata->count > 0); + + assert(knot_dname_is_fqdn(current_rrset->owner)); + + int (*node_add_func)(knot_zone_contents_t *, knot_node_t *, int, + uint8_t, int); + knot_node_t *(*node_get_func)(const knot_zone_contents_t *, + const knot_dname_t *); + + + /* If we have RRSIG of NSEC3 type first node will have + * to be created in NSEC3 part of the zone */ + + uint16_t type_covered = 0; + if (current_rrset->type == KNOT_RRTYPE_RRSIG) { + type_covered = rrsig_type_covered(current_rrset); + } + + if (current_rrset->type != KNOT_RRTYPE_NSEC3 && + type_covered != KNOT_RRTYPE_NSEC3) { + node_add_func = &knot_zone_contents_add_node; + node_get_func = &knot_zone_contents_get_node; + } else { + node_add_func = &knot_zone_contents_add_nsec3_node; + node_get_func = &knot_zone_contents_get_nsec3_node; + } + + if ((current_rrset->type == KNOT_RRTYPE_SOA) && (zone != NULL)) { + if (knot_node_rrset(knot_zone_contents_apex(contents), + KNOT_RRTYPE_SOA) != NULL) { + /* Receiving another SOA. */ + if (!knot_rrset_compare(current_rrset, + knot_node_rrset(knot_zone_contents_apex(contents), + KNOT_RRTYPE_SOA), KNOT_RRSET_COMPARE_WHOLE)) { + return KNOTDZCOMPILE_ESOA; + } else { + zc_warning_prev_line("encountered identical " + "extra SOA record"); + return KNOTDZCOMPILE_EOK; + } + } + } + + /*!< \todo Make sure the maximum RDLENGTH does not exceed 65535 bytes.*/ + + if (current_rrset->type == KNOT_RRTYPE_SOA) { + if (knot_dname_compare(current_rrset->owner, + parser->origin_from_config) != 0) { + zc_error_prev_line("SOA record has a different " + "owner than the one specified " + "in config! \n"); + /* Such SOA cannot even be added, because + * it would not be in the zone apex. */ + return KNOTDZCOMPILE_EBADSOA; + } + } + + if (current_rrset->type == KNOT_RRTYPE_RRSIG) { + /*!< \todo Still a leak somewhere. */ + knot_rrset_t *tmp_rrsig = + knot_rrset_new(current_rrset->owner, + KNOT_RRTYPE_RRSIG, + current_rrset->rclass, + current_rrset->ttl); + if (tmp_rrsig == NULL) { + return KNOTDZCOMPILE_ENOMEM; + } + + if (knot_rrset_add_rdata(tmp_rrsig, + current_rrset->rdata) != 0) { + return KNOTDZCOMPILE_EBRDATA; + } + + if (parser->last_node && + knot_dname_compare(parser->last_node->owner, + current_rrset->owner) != 0) { + /* RRSIG is first in the node, so we have to create it + * before we return + */ + if (parser->node_rrsigs != NULL) { + process_rrsigs_in_node(contents, + parser->last_node); + rrset_list_delete(&parser->node_rrsigs); + } + + if ((parser->last_node = create_node(contents, + current_rrset, node_add_func, + node_get_func)) == NULL) { + knot_rrset_free(&tmp_rrsig); + return KNOTDZCOMPILE_EBADNODE; + } + } + + if (rrset_list_add(&parser->node_rrsigs, tmp_rrsig) != 0) { + return KNOTDZCOMPILE_ENOMEM; + } + + return KNOTDZCOMPILE_EOK; + } + + assert(current_rrset->type != KNOT_RRTYPE_RRSIG); + + knot_node_t *node = NULL; + /* \note this could probably be much simpler */ + if (parser->last_node && current_rrset->type != KNOT_RRTYPE_SOA && + knot_dname_compare(parser->last_node->owner, + current_rrset->owner) == + 0) { + node = parser->last_node; + } else { + if (parser->last_node && parser->node_rrsigs) { + process_rrsigs_in_node(contents, + parser->last_node); + } + + rrset_list_delete(&parser->node_rrsigs); + + /* new node */ + node = node_get_func(contents, current_rrset->owner); + } + + if (node == NULL) { + if (parser->last_node && parser->node_rrsigs) { + process_rrsigs_in_node(contents, + parser->last_node); + } + + if ((node = create_node(contents, current_rrset, + node_add_func, + node_get_func)) == NULL) { + return KNOTDZCOMPILE_EBADNODE; + } + } + + rrset = knot_node_get_rrset(node, current_rrset->type); + if (!rrset) { + rrset = knot_rrset_new(current_rrset->owner, + current_rrset->type, + current_rrset->rclass, + current_rrset->ttl); + if (rrset == NULL) { + return KNOTDZCOMPILE_ENOMEM; + } + + if (knot_rrset_add_rdata(rrset, current_rrset->rdata) != 0) { + free(rrset); + return KNOTDZCOMPILE_EBRDATA; + } + + /* I chose skip, but there should not really be + * any rrset to skip */ + if (knot_zone_contents_add_rrset(contents, rrset, &node, + KNOT_RRSET_DUPL_SKIP, 1) < 0) { + free(rrset); + return KNOTDZCOMPILE_EBRDATA; + } + } else { + if (current_rrset->type != + KNOT_RRTYPE_RRSIG && rrset->ttl != + current_rrset->ttl) { + zc_error_prev_line( + "TTL does not match the TTL of the RRset"); + } + + if (knot_zone_contents_add_rrset(contents, current_rrset, + &node, + KNOT_RRSET_DUPL_MERGE, 1) < 0) { + return KNOTDZCOMPILE_EBRDATA; + } + } + + if (vflag > 1 && totalrrs > 0 && (totalrrs % progress == 0)) { + zc_error_prev_line("Total errors: %ld\n", totalrrs); + } + + parser->last_node = node; + + ++totalrrs; + + return KNOTDZCOMPILE_EOK; +} + +static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t + *head) +{ + uint found_rrsets = 0; + while (head != NULL) { + if (find_rrset_for_rrsig_in_zone(zone, head->data) == 0) { + found_rrsets += 1; + dbg_zp("RRSET succesfully found: owner %s type %s\n", + knot_dname_to_str(head->data->owner), + knot_rrtype_to_string(head->data->type)); + } + else { /* we can throw it away now */ + knot_rrset_free(&head->data); + } + head = head->next; + } + return found_rrsets; +} + +/* + * + * Opens a zone file. + * + * Returns: + * + * - pointer to the parser structure + * - NULL on error and errno set + * + */ +static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass, + knot_node_t *origin, void *scanner, knot_dname_t *origin_from_config) +{ + /* Open the zone file... */ + if (strcmp(filename, "-") == 0) { + zp_set_in(stdin, scanner); + filename = "<stdin>"; + } else { + FILE *f = fopen(filename, "r"); + if (f == NULL) { + return 0; + } + zp_set_in(f, scanner); + if (zp_get_in(scanner) == 0) { + return 0; + } + } + +// int fd = fileno(zp_get_in(scanner)); +// if (fd == -1) { +// return 0; +// } + +// if (fcntl(fd, F_SETLK, knot_file_lock(F_RDLCK, SEEK_SET)) == -1) { +// fprintf(stderr, "Could not lock zone file for read!\n"); +// return 0; +// } + + zparser_init(filename, ttl, rclass, origin, origin_from_config); + + return 1; +} + +/* + * Reads the specified zone into the memory + * + */ +int zone_read(const char *name, const char *zonefile, const char *outfile, + int semantic_checks) +{ + if (!outfile) { + zc_error_prev_line("Missing output file for '%s'\n", + zonefile); + return KNOTDZCOMPILE_EINVAL; + } + + /* Check that we can write to outfile. */ + FILE *f = fopen(outfile, "wb"); + if (f == NULL) { + fprintf(stderr, "Cannot write zone db to file '%s'\n", + outfile); + return KNOTDZCOMPILE_EINVAL; + } + fclose(f); + + +// char ebuf[256]; + + knot_dname_t *dname = + knot_dname_new_from_str(name, strlen(name), NULL); + if (dname == NULL) { + return KNOTDZCOMPILE_ENOMEM; + } + + knot_node_t *origin_node = knot_node_new(dname, NULL, 0); + + /*!< \todo Another copy is probably not needed. */ + knot_dname_t *origin_from_config = + knot_dname_new_from_str(name, strlen(name), NULL); + if (origin_from_config == NULL) { + return KNOTDZCOMPILE_ENOMEM; + } + + //assert(origin_node->next == NULL); + + assert(knot_node_parent(origin_node, 0) == NULL); + if (origin_node == NULL) { + knot_dname_release(dname); + return KNOTDZCOMPILE_ENOMEM; + } + + void *scanner = NULL; + zp_lex_init(&scanner); + if (scanner == NULL) { + return KNOTDZCOMPILE_ENOMEM; + } + + if (!zone_open(zonefile, 3600, KNOT_CLASS_IN, origin_node, scanner, + origin_from_config)) { + zc_error_prev_line("Cannot open '%s'\n", + zonefile); + zparser_free(); + return KNOTDZCOMPILE_EZONEINVAL; + } + + if (zp_parse(scanner) != 0) { +// int fd = fileno(zp_get_in(scanner)); +// if (fcntl(fd, F_SETLK, +// knot_file_lock(F_UNLCK, SEEK_SET)) == -1) { +// return KNOTDZCOMPILE_EACCES; +// } + + FILE *in_file = (FILE *)zp_get_in(scanner); + fclose(in_file); + zp_lex_destroy(scanner); + + return KNOTDZCOMPILE_ESYNT; + } + + knot_zone_contents_t *contents = + knot_zone_get_contents(parser->current_zone); + + FILE *in_file = (FILE *)zp_get_in(scanner); + fclose(in_file); + zp_lex_destroy(scanner); + + /* Unlock zone file. */ +// int fd = fileno(zp_get_in(scanner)); +// if (fcntl(fd, F_SETLK, knot_file_lock(F_UNLCK, SEEK_SET)) == -1) { +// fprintf(stderr, "Could not lock zone file for read!\n"); +// return 0; +// } + + dbg_zp("zp complete %p\n", parser->current_zone); + + if (parser->last_node && parser->node_rrsigs != NULL) { + /* assign rrsigs to last node in the zone*/ + process_rrsigs_in_node(contents, + parser->last_node); + rrset_list_delete(&parser->node_rrsigs); + } + + dbg_zp("zone parsed\n"); + + if (!(parser->current_zone && + knot_node_rrset(parser->current_zone->contents->apex, + KNOT_RRTYPE_SOA))) { + zc_error_prev_line("Zone file does not contain SOA record!\n"); + knot_zone_deep_free(&parser->current_zone, 1); + zparser_free(); + return KNOTDZCOMPILE_EZONEINVAL; + } + + uint found_orphans; + found_orphans = find_rrsets_orphans(contents, + parser->rrsig_orphans); + + dbg_zp("%u orphans found\n", found_orphans); + + rrset_list_delete(&parser->rrsig_orphans); + + if (found_orphans != parser->rrsig_orphan_count) { + fprintf(stderr, + "There are unassigned RRSIGs in the zone!\n"); + parser->errors++; + } + + knot_zone_contents_adjust(contents, 0); + + dbg_zp("rdata adjusted\n"); + + if (parser->errors != 0) { + fprintf(stderr, + "Parser finished with error, not dumping the zone!\n"); + } else { + if (knot_zdump_binary(contents, + outfile, semantic_checks, + zonefile) != 0) { + fprintf(stderr, "Could not dump zone!\n"); + totalerrors++; + } + dbg_zp("zone dumped.\n"); + } + + /* This is *almost* unnecessary */ + knot_zone_deep_free(&(parser->current_zone), 1); + + fflush(stdout); + totalerrors += parser->errors; + zparser_free(); + + return totalerrors; +} + +/*! @} */ diff --git a/src/zcompile/zcompile.h b/src/zcompile/zcompile.h new file mode 100644 index 0000000..33dd3ee --- /dev/null +++ b/src/zcompile/zcompile.h @@ -0,0 +1,207 @@ +/*! + * \file zoneparser.h + * + * \author modifications by Jan Kadlec <jan.kadlec@nic.cz>, most of the code + * by NLnet Labs. + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \brief Zone compiler. + * + * \addtogroup zoneparser + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _KNOTD_ZONEPARSER_H_ +#define _KNOTD_ZONEPARSER_H_ + +#include <stdio.h> + +#include "libknot/dname.h" +#include "libknot/rrset.h" +#include "libknot/zone/node.h" +#include "libknot/rdata.h" +#include "libknot/zone/zone.h" +#include "libknot/zone/dname-table.h" +#include "libknot/zone/dname-table.h" +#include "common/slab/slab.h" + +#define MAXRDATALEN 64 /*!< Maximum number of RDATA items. */ +#define MAXLABELLEN 63 /*!< Maximum label length. */ +#define MAXDOMAINLEN 255 /*!< Maximum domain name length */ +#define MAX_RDLENGTH 65535 /*!< Maximum length of RDATA item */ +#define MAXTOKENSLEN 512 /*!< Maximum number of tokens per entry. */ +#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ +#define ROOT (const uint8_t *)"\001" /*!< Root domain name. */ + +#define NSEC_WINDOW_COUNT 256 /*!< Number of NSEC windows. */ +#define NSEC_WINDOW_BITS_COUNT 256 /*!< Number of bits in NSEC window. */ +/*! \brief Size of NSEC window in bytes. */ +#define NSEC_WINDOW_BITS_SIZE (NSEC_WINDOW_BITS_COUNT / 8) + +/* + * RFC 4025 - codes for different types that IPSECKEY can hold. + */ +#define IPSECKEY_NOGATEWAY 0 +#define IPSECKEY_IP4 1 +#define IPSECKEY_IP6 2 +#define IPSECKEY_DNAME 3 + +#define LINEBUFSZ 1024 /*!< Buffer size for one line in zone file. */ + +struct lex_data { + size_t len; /*!< holds the label length */ + char *str; /*!< holds the data */ +}; + +#define DEFAULT_TTL 3600 + +int yylex_destroy(void *scanner); +int zp_parse(void *scanner); +void zp_set_in(FILE *f, void *scanner); +int zp_lex_init(void **scanner); +int zp_lex_destroy(void *scanner); + +/*! \todo Implement ZoneDB. */ +typedef void namedb_type; + +/*! + * \brief One-purpose linked list holding pointers to RRSets. + */ +struct rrset_list { + knot_rrset_t *data; /*!< List data. */ + struct rrset_list *next; /*!< Next node. */ +}; + +typedef struct rrset_list rrset_list_t; + +/*! + * \brief Main zoneparser structure. + */ +struct zparser { + const char *filename; /*!< File with zone. */ + uint32_t default_ttl; /*!< Default TTL. */ + uint16_t default_class; /*!< Default class. */ + knot_zone_t *current_zone; /*!< Current zone. */ + knot_node_t *origin; /*!< Origin node. */ + knot_dname_t *prev_dname; /*!< Previous dname. */ + knot_dname_t *origin_from_config; /*!< Zone origin from config. */ + knot_node_t *default_apex; /*!< Zone default apex. */ + + knot_node_t *last_node; /*!< Last processed node. */ + + char *dname_str; /*!< Temporary dname. */ + + int error_occurred; /*!< Error occured flag */ + unsigned int errors; /*!< Number of errors. */ + unsigned int line; /*!< Current line */ + + knot_rrset_t *current_rrset; /*!< Current RRSet. */ + knot_rdata_item_t *temporary_items; /*!< Temporary rdata items. */ + + /*! + * \brief list of RRSIGs that were not inside their nodes in zone file + */ + rrset_list_t *rrsig_orphans; + unsigned long rrsig_orphan_count; /*!< RRSIG orphan count */ + + knot_dname_t *root_domain; /*!< Root domain name. */ + slab_cache_t *parser_slab; /*!< Slab for parser. */ + rrset_list_t *node_rrsigs; /*!< List of RRSIGs in current node. */ + + int rdata_count; /*!< Count of parsed rdata. */ +}; + +typedef struct zparser zparser_type; + +extern zparser_type *parser; + +extern void zc_error_prev_line(const char *fmt, ...); + +/* used in zonec.lex */ + +void zc_error_prev_line(const char *fmt, ...); +void zc_warning_prev_line(const char *fmt, ...); + +/*! + * \brief Does all the processing of RR - saves to zone, assigns RRSIGs etc. + */ +int process_rr(); + +/*! + * \brief Parses and creates zone from given file. + * + * \param name Origin domain name string. + * \param zonefile File containing the zone. + * \param outfile File to save dump of the zone to. + * \param semantic_checks Enables or disables sematic checks. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int zone_read(const char *name, const char *zonefile, const char *outfile, + int semantic_checks); + +/*! + * \brief Creates zparser instance. + * + * + * \return Created zparser instance. + */ +zparser_type *zparser_create(); + +/*! + * \brief Inits zoneparser structure. + * + * \param filename Name of file with zone. + * \param ttl Default TTL. + * \param rclass Default class. + * \param origin Zone origin. + */ +void zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, + knot_node_t *origin, knot_dname_t *owner_from_config); + +/*! + * \brief Frees zoneparser structure. + * + */ +void zparser_free(); + +int save_dnames_in_table(knot_dname_table_t *table, + knot_rrset_t *rrset); + +#endif /* _KNOTD_ZONEPARSER_H_ */ + +/*! @} */ diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c new file mode 100644 index 0000000..cb862f8 --- /dev/null +++ b/src/zcompile/zcompile_main.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <unistd.h> +#include <stdlib.h> + +#include "zcompile/zcompile.h" +#include "zcompile/zcompile-error.h" +#include "common/errors.h" +#include <config.h> + +static void help(int argc, char **argv) +{ + printf("Usage: %s [parameters] origin zonefile\n", + argv[0]); + printf("Parameters:\n" + " -o <outfile> Override output file.\n" + " -v Verbose mode - additional runtime information.\n" + " -s Enable semantic checks.\n" + " -V Print version of the server.\n" + " -h Print help and usage.\n"); +} + +int main(int argc, char **argv) +{ + // Parse command line arguments + int c = 0; + int verbose = 0; + int semantic_checks = 0; + const char* origin = 0; + const char* zonefile = 0; + const char* outfile = 0; + while ((c = getopt (argc, argv, "o:vVsh")) != -1) { + switch (c) + { + case 'o': + outfile = optarg; + break; + case 'v': + verbose = 1; + break; + case 'V': + printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION); + return 0; + case 's': + semantic_checks = 1; + break; + case 'h': + case '?': + default: + if (optopt == 'o') { + fprintf (stderr, + "Option -%c requires an argument.\n", + optopt); + } + help(argc, argv); + return 1; + } + } + + UNUSED(verbose); + + // Check if there's at least two remaining non-option + if (argc - optind < 2) { + help(argc, argv); + return 1; + } + + origin = argv[optind]; + zonefile = argv[optind + 1]; + + // Initialize log (no output) + //log_init(0); + //log_levels_set(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_DEBUG)); + + printf("Parsing file '%s', origin '%s' ...\n", + zonefile, origin); + + parser = zparser_create(); + if (!parser) { + fprintf(stderr, "Failed to create parser.\n"); + //log_close(); + return 1; + } + + int error = zone_read(origin, zonefile, outfile, semantic_checks); + + if (error) { + /* FIXME! */ +// if (error < 0) { +// fprintf(stderr, "Finished with error: %s.\n", +// error_to_str(knot_zcompile_error_msgs, error)); +// } else { +// fprintf(stderr, "Finished with %u errors.\n"); +// } + } else { + printf("Compilation successful.\n"); + } + //log_close(); + + return error; +} diff --git a/src/zcompile/zlexer.l b/src/zcompile/zlexer.l new file mode 100644 index 0000000..c6c01fb --- /dev/null +++ b/src/zcompile/zlexer.l @@ -0,0 +1,531 @@ +%{ +/*! + * \file zlexer.l + * + * \author minor modifications by Jan Kadlec <jan.kadlec@nic.cz>, + * most of the code by NLnet Labs + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \brief lexical analyzer for (DNS) zone files. + * + * \addtogroup zoneparser + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include "common.h" + +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <assert.h> + +#include "zcompile/zcompile.h" +#include "libknot/dname.h" +#include "zcompile/parser-descriptor.h" +#include "zparser.h" + +#define YY_NO_INPUT + +/* Utils */ +extern void zc_error(const char *fmt, ...); +extern void zc_warning(const char *fmt, ...); + +void strip_string(char *str) +{ + char *start = str; + char *end = str + strlen(str) - 1; + + while (isspace(*start)) + ++start; + if (start > end) { + /* Completely blank. */ + str[0] = '\0'; + } else { + while (isspace(*end)) + --end; + *++end = '\0'; + + if (str != start) + memmove(str, start, end - start + 1); + } +} + +int hexdigit_to_int(char ch) +{ + switch (ch) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': case 'A': return 10; + case 'b': case 'B': return 11; + case 'c': case 'C': return 12; + case 'd': case 'D': return 13; + case 'e': case 'E': return 14; + case 'f': case 'F': return 15; + default: + abort(); + } +} + +extern uint32_t strtottl(const char *nptr, const char **endptr); + +#define YY_NO_UNPUT +#define MAXINCLUDES 10 + +#define scanner yyscanner +extern int zp_lex(YYSTYPE *lvalp, void *scanner); + +#if 0 +#define LEXOUT(s) printf s /* used ONLY when debugging */ +#else +#define LEXOUT(s) +#endif + +enum lexer_state { + EXPECT_OWNER, + PARSING_OWNER, + PARSING_TTL_CLASS_TYPE, + PARSING_RDATA +}; + +static YY_BUFFER_STATE include_stack[MAXINCLUDES]; +static zparser_type zparser_stack[MAXINCLUDES]; +static int include_stack_ptr = 0; + +static void pop_parser_state(void *scanner); +static void push_parser_state(FILE *input, void *scanner); +static int parse_token(void *scanner, int token, char *in_str, + enum lexer_state *lexer_state); + + +/*!< \todo does not compile */ +#ifndef yy_set_bol // compat definition, for flex 2.4.6 +#define yy_set_bol(at_bol) \ +{ \ + if (!yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ +} +#endif + +%} + +%option nounput +%option reentrant bison-bridge +%option prefix = "zp_" +%option outfile = "lex.yy.c" + +SPACE [ \t] +LETTER [a-zA-Z] +NEWLINE [\n\r] +ZONESTR [^ \t\n\r();.\"\$] +DOLLAR \$ +COMMENT ; +DOT \. +BIT [^\]\n]|\\. +ANY [^\"\n\\]|\\. + +%x incl bitlabel quotedstring + +%% + static int paren_open = 0; + static enum lexer_state lexer_state = EXPECT_OWNER; + +{SPACE}*{COMMENT}.* /* ignore */ +^{DOLLAR}TTL { lexer_state = PARSING_RDATA; return DOLLAR_TTL; } +^{DOLLAR}ORIGIN { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; } + + /* + * Handle $INCLUDE directives. See + * http://dinosaur.compilertools.net/flex/flex_12.html#SEC12. + */ +^{DOLLAR}INCLUDE { + BEGIN(incl); +} +<incl>\n | +<incl><<EOF>> { + int error_occurred = parser->error_occurred; + BEGIN(INITIAL); + zc_error("missing file name in $INCLUDE directive"); + yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ + ++parser->line; + parser->error_occurred = error_occurred; +} +<incl>.+ { + char *tmp; + /*! \todo pointer to origin. */ + void *origin = parser->origin; + /* domain_type *origin = parser->origin; */ + int error_occurred = parser->error_occurred; + + BEGIN(INITIAL); + if (include_stack_ptr >= MAXINCLUDES ) { + zc_error("includes nested too deeply, skipped (>%d)", + MAXINCLUDES); + } else { + FILE *input; + + /* Remove trailing comment. */ + tmp = strrchr(yytext, ';'); + if (tmp) { + *tmp = '\0'; + } + strip_string(yytext); + + /* Parse origin for include file. */ + tmp = strrchr(yytext, ' '); + if (!tmp) { + tmp = strrchr(yytext, '\t'); + } + if (tmp) { + /* split the original yytext */ + *tmp = '\0'; + strip_string(yytext); + + /*! \todo knot_dname_new_from_wire() (dname.h) + * which knot_node to pass as node? + */ + knot_dname_t *dname; + dname = knot_dname_new_from_wire((uint8_t*)tmp + 1, + strlen(tmp + 1), + NULL); + if (!dname) { + zc_error("incorrect include origin '%s'", + tmp + 1); + } else { + /*! \todo insert to zonedb. */ + /* origin = domain_table_insert( + parser->db->domains, dname); */ + } + } + + if (strlen(yytext) == 0) { + zc_error("missing file name in $INCLUDE directive"); + } else if (!(input = fopen(yytext, "r"))) { + char ebuf[256]; + zc_error("cannot open include file '%s': %s", + yytext, strerror_r(errno, ebuf, sizeof(ebuf))); + } else { + /* Initialize parser for include file. */ + char *filename = strdup(yytext); + push_parser_state(input, scanner); /* Destroys yytext. */ + parser->filename = filename; + parser->line = 1; + parser->origin = origin; + lexer_state = EXPECT_OWNER; + } + } + + parser->error_occurred = error_occurred; +} +<INITIAL><<EOF>> { + yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ + if (include_stack_ptr == 0) { + // from: http://stackoverflow.com/questions/1756275/bison-end-of-file + static int once = 0; + once++; + if (once > 1) { + yyterminate(); + } else { + return NL; + } + } else { + fclose(yyin); + pop_parser_state(scanner); + } +} +^{DOLLAR}{LETTER}+ { zc_warning("Unknown directive: %s", yytext); } +{DOT} { + LEXOUT((". ")); + return parse_token(scanner, '.', yytext, &lexer_state); +} +@ { + LEXOUT(("@ ")); + return parse_token(scanner, '@', yytext, &lexer_state); +} +\\# { + LEXOUT(("\\# ")); + return parse_token(scanner, URR, yytext, &lexer_state); +} +{NEWLINE} { + ++parser->line; + if (!paren_open) { + lexer_state = EXPECT_OWNER; + LEXOUT(("NL\n")); + return NL; + } else { + LEXOUT(("SP ")); + return SP; + } +} +\( { + if (paren_open) { + zc_error("nested parentheses"); + yyterminate(); + } + LEXOUT(("( ")); + paren_open = 1; + return SP; +} +\) { + if (!paren_open) { + zc_error("closing parentheses without opening parentheses"); + yyterminate(); + } + LEXOUT((") ")); + paren_open = 0; + return SP; +} +{SPACE}+ { + if (!paren_open && lexer_state == EXPECT_OWNER) { + lexer_state = PARSING_TTL_CLASS_TYPE; + LEXOUT(("PREV ")); + return PREV; + } + if (lexer_state == PARSING_OWNER) { + lexer_state = PARSING_TTL_CLASS_TYPE; + } + LEXOUT(("SP ")); + return SP; +} + + /* Bitlabels. Strip leading and ending brackets. */ +\\\[ { BEGIN(bitlabel); } +<bitlabel><<EOF>> { + zc_error("EOF inside bitlabel"); + BEGIN(INITIAL); +} +<bitlabel>{BIT}* { yymore(); } +<bitlabel>\n { ++parser->line; yymore(); } +<bitlabel>\] { + BEGIN(INITIAL); + yytext[yyleng - 1] = '\0'; + return parse_token(scanner, BITLAB, yytext, &lexer_state); +} + + /* Quoted strings. Strip leading and ending quotes. */ +\" { BEGIN(quotedstring); LEXOUT(("\" ")); } +<quotedstring><<EOF>> { + zc_error("EOF inside quoted string"); + BEGIN(INITIAL); +} +<quotedstring>{ANY}* { LEXOUT(("STR ")); yymore(); } +<quotedstring>\n { ++parser->line; yymore(); } +<quotedstring>\" { + LEXOUT(("\" ")); + BEGIN(INITIAL); + yytext[yyleng - 1] = '\0'; + return parse_token(scanner, STR, yytext, &lexer_state); +} + +({ZONESTR}|\\.|\\\n)+ { + /* Any allowed word. */ + return parse_token(scanner, STR, yytext, &lexer_state); +} +. { + zc_error("unknown character '%c' (\\%03d) seen - is this a zonefile?", + (int) yytext[0], (int) yytext[0]); +} +%% + +/* + * Analyze "word" to see if it matches an RR type, possibly by using + * the "TYPExxx" notation. If it matches, the corresponding token is + * returned and the TYPE parameter is set to the RR type value. + */ +static int +rrtype_to_token(const char *word, uint16_t *type) +{ + uint16_t t = parser_rrtype_from_string(word); + if (t != 0) { + parser_rrtype_descriptor_t *entry = 0; + entry = parser_rrtype_descriptor_by_type(t); + *type = t; + + /*! \todo entry should return associated token. + see nsd/dns.c */ + return entry->token; + } + + return 0; +} + + +/* + * Remove \DDD constructs from the input. See RFC 1035, section 5.1. + */ +static size_t +zoctet(char *text) +{ + /* + * s follows the string, p lags behind and rebuilds the new + * string + */ + char *s; + char *p; + + for (s = p = text; *s; ++s, ++p) { + assert(p <= s); + if (s[0] != '\\') { + /* Ordinary character. */ + *p = *s; + } else if (isdigit((int)s[1]) && isdigit((int)s[2]) && isdigit((int)s[3])) { + /* \DDD escape. */ + int val = (hexdigit_to_int(s[1]) * 100 + + hexdigit_to_int(s[2]) * 10 + + hexdigit_to_int(s[3])); + if (0 <= val && val <= 255) { + s += 3; + *p = val; + } else { + zc_warning("text escape \\DDD overflow"); + *p = *++s; + } + } else if (s[1] != '\0') { + /* \X where X is any character, keep X. */ + *p = *++s; + } else { + /* Trailing backslash, ignore it. */ + zc_warning("trailing backslash ignored"); + --p; + } + } + *p = '\0'; + return p - text; +} + +static int parse_token(void *scanner, int token, char *in_str, + enum lexer_state *lexer_state) +{ + size_t len = 0; + char *str = NULL; + + struct yyguts_t *yyg = (struct yyguts_t *)scanner; + + if (*lexer_state == EXPECT_OWNER) { + *lexer_state = PARSING_OWNER; + } else if (*lexer_state == PARSING_TTL_CLASS_TYPE) { + const char *t; + int token; + uint16_t rrclass; + + /* type */ + token = rrtype_to_token(in_str, &yylval->type); + if (token != 0) { + *lexer_state = PARSING_RDATA; + LEXOUT(("%d[%s] ", token, in_str)); + return token; + } + + /* class */ + rrclass = parser_rrclass_from_string(in_str); + if (rrclass != 0) { + yylval->rclass = rrclass; + LEXOUT(("CLASS ")); + return T_RRCLASS; + } + + /* ttl */ + yylval->ttl = strtottl(in_str, &t); + if (*t == '\0') { + LEXOUT(("TTL ")); + return T_TTL; + } + } + + str = strdup(yytext); + if (str == NULL) { + /* Out of memory */ + ERR_ALLOC_FAILED; + return NO_MEM; + } + len = zoctet(str); + + yylval->data.str = str; + assert(yylval->data.str != NULL); + yylval->data.len = len; + + if (strcmp(yytext, ".") == 0) { + free(str); + yylval->data.str="."; + } else if (strcmp(str, "@") == 0) { + free(str); + yylval->data.str="@"; + } else if (strcmp(str, "\\#") == 0) { + free(str); + yylval->data.str="\\#"; + } + + LEXOUT(("%d[%s] ", token, in_str)); + return token; +} + +/* + * Saves the file specific variables on the include stack. + */ +static void push_parser_state(FILE *input, void *scanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)scanner; + zparser_stack[include_stack_ptr].filename = parser->filename; + zparser_stack[include_stack_ptr].line = parser->line; + zparser_stack[include_stack_ptr].origin = parser->origin; + include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; + yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE, scanner), + scanner); + ++include_stack_ptr; +} + +/* + * Restores the file specific variables from the include stack. + */ +void pop_parser_state(void *scanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)scanner; + --include_stack_ptr; + parser->filename = zparser_stack[include_stack_ptr].filename; + parser->line = zparser_stack[include_stack_ptr].line; + parser->origin = zparser_stack[include_stack_ptr].origin; + yy_delete_buffer(YY_CURRENT_BUFFER, scanner); + yy_switch_to_buffer(include_stack[include_stack_ptr], scanner); +} diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y new file mode 100644 index 0000000..6f081e5 --- /dev/null +++ b/src/zcompile/zparser.y @@ -0,0 +1,1730 @@ +%{ +/*! + * \file zparser.y + * + * \author modifications by Jan Kadlec <jan.kadlec@nic.cz>, + * notable changes: normal allocation, parser is reentrant. + * most of the code by NLnet Labs + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * \brief yacc grammar for (DNS) zone files + * + * \addtogroup zoneparser + * @{ + */ + +/* + * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include "common.h" + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "zcompile/parser-util.h" + +#include "libknot/libknot.h" +#include "zcompile/zcompile.h" +#include "zcompile/parser-descriptor.h" +#include "zcompile/zcompile-error.h" +#include "zparser.h" + +/* these need to be global, otherwise they cannot be used inside yacc */ +zparser_type *parser; + +#ifdef __cplusplus +extern "C" +#endif /* __cplusplus */ +int zp_wrap(void); + +/* this hold the nxt bits */ +static uint8_t nxtbits[16]; +static int dlv_warn = 1; + +/* 256 windows of 256 bits (32 bytes) */ +/* still need to reset the bastard somewhere */ +static uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE]; + +/* hold the highest rcode seen in a NSEC rdata , BUG #106 */ +uint16_t nsec_highest_rcode; + +void zp_error(void *scanner, const char *message); +int zp_lex(YYSTYPE *lvalp, void *scanner); + +/* helper functions */ +void zc_error(const char *fmt, ...); +void zc_warning(const char *fmt, ...); +void zc_error_prev_line(const char *fmt, ...); +void zc_warning_prev_line(const char *fmt, ...); + +#define NSEC3 +#ifdef NSEC3 +/* parse nsec3 parameters and add the (first) rdata elements */ +static void +nsec3_add_params(const char* hash_algo_str, const char* flag_str, + const char* iter_str, const char* salt_str, int salt_len); +#endif /* NSEC3 */ + +knot_dname_t *error_dname; //XXX used to be const +knot_dname_t *error_domain; + +%} +%union { + knot_dname_t *domain; + knot_dname_t *dname; + struct lex_data data; + uint32_t ttl; + uint16_t rclass; + uint16_t type; + uint16_t *unknown; +} + +%pure-parser +%parse-param {void *scanner} +%lex-param {void *scanner} +%name-prefix = "zp_" + +/* + * Tokens to represent the known RR types of DNS. + */ +%token <type> T_A T_NS T_MX T_TXT T_CNAME T_AAAA T_PTR T_NXT T_KEY T_SOA T_SIG +%token <type> T_SRV T_CERT T_LOC T_MD T_MF T_MB T_MG T_MR T_NULL T_WKS T_HINFO +%token <type> T_MINFO T_RP T_AFSDB T_X25 T_ISDN T_RT T_NSAP T_NSAP_PTR T_PX +%token <type> T_GPOS T_EID T_NIMLOC T_ATMA T_NAPTR T_KX T_A6 T_DNAME T_SINK +%token <type> T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR +%token <type> T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY +%token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM + +/* other tokens */ +%token DOLLAR_TTL DOLLAR_ORIGIN NL SP NO_MEM +%token <data> STR PREV BITLAB +%token <ttl> T_TTL +%token <rclass> T_RRCLASS + +/* unknown RRs */ +%token URR +%token <type> T_UTYPE + +%type <type> type_and_rdata +%type <domain> owner dname abs_dname +%type <dname> rel_dname label +%type <data> wire_dname wire_abs_dname wire_rel_dname wire_label +%type <data> concatenated_str_seq str_sp_seq str_dot_seq dotted_str +%type <data> nxt_seq nsec_more +%type <unknown> rdata_unknown + +%% +lines: /* empty file */ + | lines line + ; + +line: NL + | sp NL + | NO_MEM { + zc_error_prev_line("Parser ran out of memory!"); + YYABORT; + } + | PREV NL {} /* Lines containing only whitespace. */ + | ttl_directive + { + parser->error_occurred = 0; + } + | origin_directive + { + parser->error_occurred = 0; + } + | rr + { /* rr should be fully parsed */ + if (!parser->error_occurred) { + /*!< \todo assign error to error occurred */ + /*! \todo Make sure this does not crash */ + if (parser->current_rrset->owner == NULL) { + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + knot_rdata_t *tmp_rdata = knot_rdata_new(); + if (tmp_rdata == NULL) { + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + + if (knot_rdata_set_items(tmp_rdata, + parser->temporary_items, + parser->rdata_count) != 0) { + knot_rdata_free(&tmp_rdata); + knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), 1); + YYABORT; + } + + assert(parser->current_rrset->rdata == NULL); + if (knot_rrset_add_rdata(parser->current_rrset, tmp_rdata) + != 0) { + fprintf(stderr, "Could not add rdata!\n"); + } +// tmp_rdata->next = tmp_rdata; +// parser->current_rrset->rdata = tmp_rdata; + + if (!knot_dname_is_fqdn(parser->current_rrset->owner)) { + knot_dname_t *tmp_dname = + knot_dname_cat(parser->current_rrset->owner, + parser->root_domain); + if (tmp_dname == NULL) { + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } +// knot_rrset_set_owner(parser->current_rrset, tmp_dname); + } + + assert(parser->current_rrset->owner != NULL); + knot_dname_retain(parser->current_rrset->owner); + int ret = 0; + if ((ret = process_rr()) != 0) { + char *name = + knot_dname_to_str(parser->current_rrset->owner); + fprintf(stderr, "Error: could not process RRSet\n" + "owner: %s reason: %s\n", + name, + error_to_str(knot_zcompile_error_msgs, ret)); + free(name); + + /* If the owner is not already in the table, free it. */ +// if (dnslib_dname_table_find_dname(parser->dname_table, +// parser->current_rrset->owner) == NULL) { +// dnslib_dname_free(&parser-> +// current_rrset->owner); +// } /* This would never happen */ + + if (ret == KNOTDZCOMPILE_EBADSOA) { + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } else { + YYABORT; + /* Free rdata, it will not be added + * and hence cannot be + * freed with rest of the zone. */ +/* knot_rdata_deep_free(&tmp_rdata, + parser-> + current_rrset->type, + 0); */ + } + } + } else { + /* Error occured. This could either be lack of memory, or one + * of the converting function was not able to convert. */ + if (parser->error_occurred == KNOTDZCOMPILE_ENOMEM) { + /* Ran out of memory in converting functions. */ + fprintf(stderr, "Parser ran out " + "of memory, aborting!\n"); + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + } + +// printf("Current rrset name: %p (%s)\n", parser->current_rrset->owner->name, +// knot_dname_to_str(parser->current_rrset->owner)); +// getchar(); + +// knot_dname_release(parser->current_rrset->owner); + + parser->current_rrset->type = 0; + parser->rdata_count = 0; + parser->current_rrset->rdata = NULL; + parser->error_occurred = 0; + } + | error NL + ; + +/* needed to cope with ( and ) in arbitary places */ +sp: SP + | sp SP + ; + +trail: NL + | sp NL + ; + +ttl_directive: DOLLAR_TTL sp STR trail + { + parser->default_ttl = zparser_ttl2int($3.str, + &(parser->error_occurred)); + if (parser->error_occurred == 1) { + parser->default_ttl = DEFAULT_TTL; + parser->error_occurred = 0; + } + + free($3.str); + } + ; + + + +origin_directive: DOLLAR_ORIGIN sp abs_dname trail + { + knot_node_t *origin_node = knot_node_new($3 ,NULL, 0); + if (parser->origin != NULL) { +// knot_node_free(&parser->origin, 1); + } + parser->origin = origin_node; + } + | DOLLAR_ORIGIN sp rel_dname trail + { + zc_error_prev_line("$ORIGIN directive requires" + "absolute domain name"); + } + ; + +rr: owner classttl type_and_rdata + { + /* Save the pointer, it might get freed! */ + parser->current_rrset->owner = $1; +// parser->current_rrset->owner = $1; +// printf("new owner assigned: %p\n", $1); + parser->current_rrset->type = $3; + } + ; + +owner: dname sp + { +// char *name = knot_dname_to_str($1); +// printf("Totally new dname: %p %s\n", $1, +// name); +// free(name); + if (parser->prev_dname != NULL) { + // knot_dname_release(parser->prev_dname); + } + parser->prev_dname = $1;//knot_dname_deep_copy($1); +// knot_dname_retain(parser->prev_dname); + $$ = $1; + } + | PREV + { +// printf("Name from prev_dname!: %p %s\n", parser->prev_dname, +// knot_dname_to_str(parser->prev_dname)); + knot_dname_retain(parser->prev_dname); + $$ = parser->prev_dname;//knot_dname_deep_copy(parser->prev_dname); + } + ; + +classttl: /* empty - fill in the default, def. ttl and IN class */ + { + parser->current_rrset->ttl = parser->default_ttl; + parser->current_rrset->rclass = parser->default_class; + } + | T_RRCLASS sp /* no ttl */ + { + parser->current_rrset->ttl = parser->default_ttl; + parser->current_rrset->rclass = $1; + } + | T_TTL sp /* no class */ + { + parser->current_rrset->ttl = $1; + parser->current_rrset->rclass = parser->default_class; + } + | T_TTL sp T_RRCLASS sp /* the lot */ + { + parser->current_rrset->ttl = $1; + parser->current_rrset->rclass = $3; + } + | T_RRCLASS sp T_TTL sp /* the lot - reversed */ + { + parser->current_rrset->ttl = $3; + parser->current_rrset->rclass = $1; + } + ; + +dname: abs_dname + | rel_dname + { + if ($1 == error_dname) { + $$ = error_domain; + } else if ($1->size + parser->origin->owner->size - 1 > + MAXDOMAINLEN) { + zc_error("domain name exceeds %d character limit", + MAXDOMAINLEN); + $$ = error_domain; + } else { + $$ = knot_dname_cat($1, + parser->origin->owner); +// printf("leak: %s\n", knot_dname_to_str($$)); +// getchar(); + } + } + ; + +abs_dname: '.' + { + $$ = parser->root_domain; + /* TODO how about concatenation now? */ + } + | '@' + { + $$ = parser->origin->owner; + } + | rel_dname '.' + { + if ($1 != error_dname) { + $$ = $1; + } else { + $$ = error_domain; + } + } + ; + +label: STR + { + if ($1.len > MAXLABELLEN) { + zc_error("label exceeds %d character limit", MAXLABELLEN); + $$ = error_dname; + } else { +// printf("%s\n", $1.str); + $$ = knot_dname_new_from_str($1.str, $1.len, NULL); +// printf("Creating new (label): %s %p\n", $1.str, $$); +// printf("new: %p %s\n", $$, $1.str); + $$->ref.count = 0; + } + + free($1.str); + + } + | BITLAB + { + zc_error("bitlabels are not supported." + "RFC2673 has status experimental."); + $$ = error_dname; + } + ; + +rel_dname: label + | rel_dname '.' label + { + if ($1 == error_dname || $3 == error_dname) { + $$ = error_dname; + } else if ($1->size + $3->size - 1 > MAXDOMAINLEN) { + zc_error("domain name exceeds %d character limit", + MAXDOMAINLEN); + $$ = error_dname; + } else { + $$ = knot_dname_cat($1, $3); +// knot_dname_release($1); /*!< \todo check! */ + knot_dname_free(&$3); + } + } + ; + +/* + * Some dnames in rdata are handled as opaque blobs + */ + +wire_dname: wire_abs_dname + | wire_rel_dname + ; + +wire_abs_dname: '.' + { + char *result = malloc(2 * sizeof(char)); + if (result == NULL) { + ERR_ALLOC_FAILED; + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + result[0] = 0; + result[1] = '\0'; + $$.str = result; + $$.len = 1; + } + | wire_rel_dname '.' + { + char *result = malloc($1.len + 2 * sizeof(char)); + if (result == NULL) { + ERR_ALLOC_FAILED; + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy(result, $1.str, $1.len); + result[$1.len] = 0; + result[$1.len+1] = '\0'; + $$.str = result; + $$.len = $1.len + 1; + + free($1.str); +; + } + ; + +wire_label: STR + { + char *result = malloc($1.len + sizeof(char)); + if (result == NULL) { + ERR_ALLOC_FAILED; + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + + if ($1.len > MAXLABELLEN) + zc_error("label exceeds %d character limit", MAXLABELLEN); + + /* make label anyway */ + result[0] = $1.len; + memcpy(result+1, $1.str, $1.len); + + $$.str = result; + $$.len = $1.len + 1; + + free($1.str); + } + ; + +wire_rel_dname: wire_label + | wire_rel_dname '.' wire_label + { + if ($1.len + $3.len - 3 > MAXDOMAINLEN) + zc_error("domain name exceeds %d character limit", + MAXDOMAINLEN); + + /* make dname anyway */ + $$.len = $1.len + $3.len; + $$.str = malloc($$.len + sizeof(char)); + if ($$.str == NULL) { + ERR_ALLOC_FAILED; + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy($$.str, $1.str, $1.len); + memcpy($$.str + $1.len, $3.str, $3.len); + $$.str[$$.len] = '\0'; + + free($1.str); + free($3.str); + } + ; + + + +str_seq: STR + { + zadd_rdata_txt_wireformat(zparser_conv_text($1.str, $1.len), 1); + + free($1.str); + } + | str_seq sp STR + { + zadd_rdata_txt_wireformat(zparser_conv_text($3.str, $3.len), 0); +// zc_warning("multiple TXT entries are currently not supported!"); + + free($3.str); + } + ; + +/* + * Generate a single string from multiple STR tokens, separated by + * spaces or dots. + */ +concatenated_str_seq: STR + | '.' + { + $$.len = 1; + $$.str = strdup("."); + } + | concatenated_str_seq sp STR + { + $$.len = $1.len + $3.len + 1; + $$.str = malloc($$.len + 1); + if ($$.str == NULL) { + ERR_ALLOC_FAILED; + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + + memcpy($$.str, $1.str, $1.len); + memcpy($$.str + $1.len, " ", 1); + memcpy($$.str + $1.len + 1, $3.str, $3.len); + $$.str[$$.len] = '\0'; + + free($1.str); + free($3.str); + } + | concatenated_str_seq '.' STR + { + $$.len = $1.len + $3.len + 1; + $$.str = malloc($$.len + 1); + if ($$.str == NULL) { + ERR_ALLOC_FAILED; + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy($$.str, $1.str, $1.len); + memcpy($$.str + $1.len, ".", 1); + memcpy($$.str + $1.len + 1, $3.str, $3.len); + + free($1.str); + free($3.str); + + $$.str[$$.len] = '\0'; + } + ; + +/* used to convert a nxt list of types */ +nxt_seq: STR + { + uint16_t type = knot_rrtype_from_string($1.str); + if (type != 0 && type < 128) { + set_bit(nxtbits, type); + } else { + zc_error("bad type %d in NXT record", (int) type); + } + + free($1.str); + } + | nxt_seq sp STR + { + uint16_t type = knot_rrtype_from_string($3.str); + if (type != 0 && type < 128) { + set_bit(nxtbits, type); + } else { + zc_error("bad type %d in NXT record", (int) type); + } + + free($3.str); + } + ; + +nsec_more: SP nsec_more + { + } + | NL + { + } + | STR nsec_seq + { + uint16_t type = knot_rrtype_from_string($1.str); + if (type != 0) { + if (type > nsec_highest_rcode) { + nsec_highest_rcode = type; + } + set_bitnsec(nsecbits, type); + } else { + zc_error("bad type %d in NSEC record", (int) type); + } + + free($1.str); + } + ; + +nsec_seq: NL + | SP nsec_more + ; + +/* + * Sequence of STR tokens separated by spaces. The spaces are not + * preserved during concatenation. + */ +str_sp_seq: STR + | str_sp_seq sp STR + { + char *result = malloc($1.len + $3.len + 1); + if (result == NULL) { + ERR_ALLOC_FAILED; + fprintf(stderr, "Parser ran out of memory, aborting!\n"); + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy(result, $1.str, $1.len); + memcpy(result + $1.len, $3.str, $3.len); + $$.str = result; + $$.len = $1.len + $3.len; + $$.str[$$.len] = '\0'; + + free($1.str); + free($3.str); + } + ; + +/* + * Sequence of STR tokens separated by dots. The dots are not + * preserved during concatenation. + */ +str_dot_seq: STR + | str_dot_seq '.' STR + { + char *result = malloc($1.len + $3.len + 1); + if (result == NULL) { + ERR_ALLOC_FAILED; + fprintf(stderr, "Parser ran out of memory, aborting!\n"); + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy(result, $1.str, $1.len); + memcpy(result + $1.len, $3.str, $3.len); + $$.str = result; + $$.len = $1.len + $3.len; + $$.str[$$.len] = '\0'; + + free($1.str); + free($3.str); + } + ; + +/* + * A string that can contain dots. + */ +dotted_str: STR + | '.' + { + $$.str = "."; + $$.len = 1; + } + | dotted_str '.' + { + char *result = malloc($1.len + 2); + if (result == NULL) { + ERR_ALLOC_FAILED; + fprintf(stderr, "Parser ran out of memory, aborting!\n"); + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy(result, $1.str, $1.len); + result[$1.len] = '.'; + $$.str = result; + $$.len = $1.len + 1; + $$.str[$$.len] = '\0'; + + free($1.str); + } + | dotted_str '.' STR + { + char *result = malloc($1.len + $3.len + 2); + if (result == NULL) { + ERR_ALLOC_FAILED; + fprintf(stderr, "Parser ran out of memory, aborting!\n"); + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy(result, $1.str, $1.len); + result[$1.len] = '.'; + memcpy(result + $1.len + 1, $3.str, $3.len); + $$.str = result; + $$.len = $1.len + $3.len + 1; + $$.str[$$.len] = '\0'; + + + free($1.str); + free($3.str); + } + ; + +/* define what we can parse */ +type_and_rdata: + /* + * All supported RR types. We don't support NULL and types marked obsolete. + */ + T_A sp rdata_a + | T_A sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_NS sp rdata_domain_name + | T_NS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_MD sp rdata_domain_name { zc_warning_prev_line("MD is obsolete"); } + | T_MD sp rdata_unknown + { + zc_warning_prev_line("MD is obsolete"); + $$ = $1; parse_unknown_rdata($1, $3); + } + | T_MF sp rdata_domain_name { zc_warning_prev_line("MF is obsolete"); } + | T_MF sp rdata_unknown + { + zc_warning_prev_line("MF is obsolete"); + $$ = $1; + parse_unknown_rdata($1, $3); + } + | T_CNAME sp rdata_domain_name + | T_CNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_SOA sp rdata_soa + | T_SOA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_MB sp rdata_domain_name { zc_warning_prev_line("MB is obsolete"); } + | T_MB sp rdata_unknown + { + zc_warning_prev_line("MB is obsolete"); + $$ = $1; + parse_unknown_rdata($1, $3); + } + | T_MG sp rdata_domain_name + | T_MG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_MR sp rdata_domain_name + | T_MR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + /* NULL */ + | T_WKS sp rdata_wks + | T_WKS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_PTR sp rdata_domain_name + | T_PTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_HINFO sp rdata_hinfo + | T_HINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_MINFO sp rdata_minfo /* Experimental */ + | T_MINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_MX sp rdata_mx + | T_MX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_TXT sp rdata_txt + | T_TXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_SPF sp rdata_txt + | T_SPF sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_RP sp rdata_rp /* RFC 1183 */ + | T_RP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_AFSDB sp rdata_afsdb /* RFC 1183 */ + | T_AFSDB sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_X25 sp rdata_x25 /* RFC 1183 */ + | T_X25 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_ISDN sp rdata_isdn /* RFC 1183 */ + | T_ISDN sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_IPSECKEY sp rdata_ipseckey /* RFC 4025 */ + | T_IPSECKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_DHCID sp rdata_dhcid + | T_DHCID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_RT sp rdata_rt /* RFC 1183 */ + | T_RT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_NSAP sp rdata_nsap /* RFC 1706 */ + | T_NSAP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_SIG sp rdata_rrsig + | T_SIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_KEY sp rdata_dnskey + | T_KEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_PX sp rdata_px /* RFC 2163 */ + | T_PX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_AAAA sp rdata_aaaa + | T_AAAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_LOC sp rdata_loc + | T_LOC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_NXT sp rdata_nxt + | T_NXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_SRV sp rdata_srv + | T_SRV sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_NAPTR sp rdata_naptr /* RFC 2915 */ + | T_NAPTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_KX sp rdata_kx /* RFC 2230 */ + | T_KX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_CERT sp rdata_cert /* RFC 2538 */ + | T_CERT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_DNAME sp rdata_domain_name /* RFC 2672 */ + | T_DNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_APL trail /* RFC 3123 */ + | T_APL sp rdata_apl /* RFC 3123 */ + | T_APL sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_DS sp rdata_ds + | T_DS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_DLV sp rdata_dlv + { + if (dlv_warn) { + dlv_warn = 0; + zc_warning_prev_line("DLV is experimental"); + } + } + | T_DLV sp rdata_unknown + { + if (dlv_warn) { + dlv_warn = 0; + zc_warning_prev_line("DLV is experimental"); + } + $$ = $1; + parse_unknown_rdata($1, $3); + } + | T_SSHFP sp rdata_sshfp + | T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_RRSIG sp rdata_rrsig + | T_RRSIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_NSEC sp rdata_nsec + | T_NSEC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_NSEC3 sp rdata_nsec3 + | T_NSEC3 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_NSEC3PARAM sp rdata_nsec3_param + | T_NSEC3PARAM sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_DNSKEY sp rdata_dnskey + | T_DNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + + | STR error NL + { + zc_error_prev_line("unrecognized RR type '%s'", $1.str); + free($1.str); + } + | NO_MEM + { + zc_error_prev_line("parser ran out of memory!"); + YYABORT; + } + ; + +/* + * + * below are all the definition for all the different rdata + * + */ + +rdata_a: dotted_str trail + { + zadd_rdata_wireformat(zparser_conv_a($1.str)); + free($1.str); + } + ; + +rdata_domain_name: dname trail + { + /* convert a single dname record */ + if ($1 != NULL) { + if (!knot_dname_is_fqdn($1)) { + knot_dname_cat($1, parser->root_domain); +// parser->current_rrset->owner = +// knot_dname_cat($1, parser->root_domain); + } + } + zadd_rdata_domain($1); + } + ; + +rdata_soa: dname sp dname sp STR sp STR sp STR sp STR sp STR trail + { + /* convert the soa data */ + if (!knot_dname_is_fqdn($1)) { + knot_dname_cat($1, parser->root_domain); +// parser->current_rrset->owner = +// knot_dname_cat($1, parser->root_domain); + + } + if (!knot_dname_is_fqdn($3)) { + knot_dname_cat($3, parser->root_domain); +// parser->current_rrset->owner = +// knot_dname_cat($3, parser->root_domain); + + } + zadd_rdata_domain($1); /* prim. ns */ + zadd_rdata_domain($3); /* email */ + zadd_rdata_wireformat(zparser_conv_serial($5.str)); /* serial */ + zadd_rdata_wireformat(zparser_conv_period($7.str)); /* refresh */ + zadd_rdata_wireformat(zparser_conv_period($9.str)); /* retry */ + zadd_rdata_wireformat(zparser_conv_period($11.str)); /* expire */ + zadd_rdata_wireformat(zparser_conv_period($13.str)); /* minimum */ + + free($5.str); + free($7.str); + free($9.str); + free($11.str); + free($13.str); + } + ; + +rdata_wks: dotted_str sp STR sp concatenated_str_seq trail + { + zadd_rdata_wireformat(zparser_conv_a($1.str)); /* address */ + zadd_rdata_wireformat(zparser_conv_services($3.str, $5.str)); + /* protocol and services */ + + free($1.str); + free($3.str); + free($5.str); + } + ; + +rdata_hinfo: STR sp STR trail + { + zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len)); /* CPU */ + zadd_rdata_wireformat(zparser_conv_text($3.str, $3.len)); /* OS*/ + + free($1.str); + free($3.str); + } + ; + +rdata_minfo: dname sp dname trail + { + if (!knot_dname_is_fqdn($1)) { + + knot_dname_cat($1, parser->root_domain); + + } + if (!knot_dname_is_fqdn($3)) { + + knot_dname_cat($3, parser->root_domain); + + } + + /* convert a single dname record */ + zadd_rdata_domain($1); + zadd_rdata_domain($3); + } + ; + +rdata_mx: STR sp dname trail + { + if (!knot_dname_is_fqdn($3)) { + knot_dname_cat($3, parser->root_domain); + } + + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* priority */ + zadd_rdata_domain($3); /* MX host */ + + free($1.str); + } + ; + +rdata_txt: str_seq trail + { + ; //zadd_rdata_txt_clean_wireformat(); + } + ; + +/* RFC 1183 */ +rdata_rp: dname sp dname trail + { + if (!knot_dname_is_fqdn($1)) { + knot_dname_cat($1, parser->root_domain); + } + if (!knot_dname_is_fqdn($3)) { + knot_dname_cat($3, parser->root_domain); + } + + zadd_rdata_domain($1); /* mbox d-name */ + zadd_rdata_domain($3); /* txt d-name */ + } + ; + +/* RFC 1183 */ +rdata_afsdb: STR sp dname trail + { + if (!knot_dname_is_fqdn($3)) { + knot_dname_cat($3, parser->root_domain); + } + + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* subtype */ + zadd_rdata_domain($3); /* domain name */ + + free($1.str); + } + ; + +/* RFC 1183 */ +rdata_x25: STR trail + { + zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len)); + /* X.25 address. */ + + free($1.str); + } + ; + +/* RFC 1183 */ +rdata_isdn: STR trail + { + zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len)); + /* address */ + + free($1.str); + } + | STR sp STR trail + { + zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len)); + /* address */ + zadd_rdata_wireformat(zparser_conv_text($3.str, $3.len)); + /* sub-address */ + + free($1.str); + free($3.str); + } + ; + +/* RFC 1183 */ +rdata_rt: STR sp dname trail + { + if (!knot_dname_is_fqdn($3)) { + knot_dname_cat($3, parser->root_domain); + } + + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */ + zadd_rdata_domain($3); /* intermediate host */ + + free($1.str); + } + ; + +/* RFC 1706 */ +rdata_nsap: str_dot_seq trail + { + /* String must start with "0x" or "0X". */ + if (strncasecmp($1.str, "0x", 2) != 0) { + zc_error_prev_line("NSAP rdata must start with '0x'"); + } else { + zadd_rdata_wireformat(zparser_conv_hex($1.str + 2, + $1.len - 2)); + /* NSAP */ + } + + free($1.str); + } + ; + +/* RFC 2163 */ +rdata_px: STR sp dname sp dname trail + { + if (!knot_dname_is_fqdn($3)) { + knot_dname_cat($3, parser->root_domain); + } + if (!knot_dname_is_fqdn($5)) { + knot_dname_cat($5, parser->root_domain); + } + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */ + zadd_rdata_domain($3); /* MAP822 */ + zadd_rdata_domain($5); /* MAPX400 */ + + free($1.str); + } + ; + +rdata_aaaa: dotted_str trail + { + zadd_rdata_wireformat(zparser_conv_aaaa($1.str)); + /* IPv6 address */ + + free($1.str); + } + ; + +rdata_loc: concatenated_str_seq trail + { + zadd_rdata_wireformat(zparser_conv_loc($1.str)); /* Location */ + + free($1.str); + } + ; + +rdata_nxt: dname sp nxt_seq trail + { + if (!knot_dname_is_fqdn($1)) { + knot_dname_cat($1, parser->root_domain); + } + zadd_rdata_domain($1); /* nxt name */ + zadd_rdata_wireformat(zparser_conv_nxt(nxtbits)); /* nxt bitlist */ + memset(nxtbits, 0, sizeof(nxtbits)); + } + ; + +rdata_srv: STR sp STR sp STR sp dname trail + { + if (!knot_dname_is_fqdn($7)) { + knot_dname_cat($7, parser->root_domain); + + } + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* prio */ + zadd_rdata_wireformat(zparser_conv_short($3.str)); /* weight */ + zadd_rdata_wireformat(zparser_conv_short($5.str)); /* port */ + zadd_rdata_domain($7); /* target name */ + + free($1.str); + free($3.str); + free($5.str); + } + ; + +/* RFC 2915 */ +rdata_naptr: STR sp STR sp STR sp STR sp STR sp dname trail + { + if (!knot_dname_is_fqdn($11)) { + knot_dname_cat($11, parser->root_domain); + + } + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* order */ + zadd_rdata_wireformat(zparser_conv_short($3.str)); /* preference */ + zadd_rdata_wireformat(zparser_conv_text($5.str, $5.len)); + /* flags */ + zadd_rdata_wireformat(zparser_conv_text($7.str, $7.len)); + /* service */ + zadd_rdata_wireformat(zparser_conv_text($9.str, $9.len)); + /* regexp */ + zadd_rdata_domain($11); /* target name */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + free($9.str); + } + ; + +/* RFC 2230 */ +rdata_kx: STR sp dname trail + { + if (!knot_dname_is_fqdn($3)) { + knot_dname_cat($3, parser->root_domain); + } + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */ + zadd_rdata_domain($3); /* exchanger */ + + free($1.str); + } + ; + +/* RFC 2538 */ +rdata_cert: STR sp STR sp STR sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_certificate_type($1.str)); + /* type */ + zadd_rdata_wireformat(zparser_conv_short($3.str)); /* key tag */ + zadd_rdata_wireformat(zparser_conv_algorithm($5.str)); + /* algorithm */ + zadd_rdata_wireformat(zparser_conv_b64($7.str)); + /* certificate or CRL */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + } + ; + +/* RFC 3123 */ +rdata_apl: rdata_apl_seq trail + ; + +rdata_apl_seq: dotted_str + { + zadd_rdata_wireformat(zparser_conv_apl_rdata($1.str)); + + free($1.str); + } + | rdata_apl_seq sp dotted_str + { + zadd_rdata_wireformat(zparser_conv_apl_rdata($3.str)); + + free($3.str); + } + ; + +rdata_ds: STR sp STR sp STR sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* keytag */ + zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */ + zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* type */ + zadd_rdata_wireformat(zparser_conv_hex($7.str, $7.len)); /* hash */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + } + ; + +rdata_dlv: STR sp STR sp STR sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* keytag */ + zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */ + zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* type */ + zadd_rdata_wireformat(zparser_conv_hex($7.str, $7.len)); /* hash */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + } + ; + +rdata_sshfp: STR sp STR sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_byte($1.str)); /* alg */ + zadd_rdata_wireformat(zparser_conv_byte($3.str)); /* fp type */ + zadd_rdata_wireformat(zparser_conv_hex($5.str, $5.len)); /* hash */ + + free($1.str); + free($3.str); + free($5.str); + } + ; + +rdata_dhcid: str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_b64($1.str)); /* data blob */ + + free($1.str); + } + ; + +rdata_rrsig: STR sp STR sp STR sp STR sp STR sp STR + sp STR sp wire_dname sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_rrtype($1.str)); + /* rr covered */ + zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */ + zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* # labels */ + zadd_rdata_wireformat(zparser_conv_period($7.str)); + /* # orig TTL */ + zadd_rdata_wireformat(zparser_conv_time($9.str)); /* sig exp */ + zadd_rdata_wireformat(zparser_conv_time($11.str)); /* sig inc */ + zadd_rdata_wireformat(zparser_conv_short($13.str)); /* key id */ +/* zadd_rdata_wireformat(zparser_conv_dns_name((const uint8_t*) + $15.str, + $15.len));*/ + knot_dname_t *dname = + knot_dname_new_from_wire((uint8_t *)$15.str, $15.len, NULL); + if (dname == NULL) { + parser->error_occurred = KNOTDZCOMPILE_ENOMEM; + } else { + knot_dname_cat(dname, parser->root_domain); + } + + zadd_rdata_domain(dname); + /* sig name */ + zadd_rdata_wireformat(zparser_conv_b64($17.str)); /* sig data */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + free($9.str); + free($11.str); + free($13.str); + free($15.str); + free($17.str); + } + ; + +rdata_nsec: wire_dname nsec_seq + { +/* zadd_rdata_wireformat(zparser_conv_dns_name((const uint8_t*) + $1.str, + $1.len));*/ + + knot_dname_t *dname = + knot_dname_new_from_wire((uint8_t *)$1.str, $1.len, NULL); + + free($1.str); + + knot_dname_cat(dname, parser->root_domain); + + zadd_rdata_domain(dname); + /* nsec name */ + zadd_rdata_wireformat(zparser_conv_nsec(nsecbits)); + /* nsec bitlist */ + memset(nsecbits, 0, sizeof(nsecbits)); + nsec_highest_rcode = 0; + } + ; + +rdata_nsec3: STR sp STR sp STR sp STR sp STR nsec_seq + { +#ifdef NSEC3 + nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len); + +/* knot_dname_t *dname = + knot_dname_new_from_str($9.str, $9.len, NULL); + + zadd_rdata_domain(dname); */ + + zadd_rdata_wireformat(zparser_conv_b32($9.str)); + /* next hashed name */ + zadd_rdata_wireformat(zparser_conv_nsec(nsecbits)); + /* nsec bitlist */ + memset(nsecbits, 0, sizeof(nsecbits)); + nsec_highest_rcode = 0; +#else + zc_error_prev_line("nsec3 not supported"); +#endif /* NSEC3 */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + free($9.str); + } + ; + +rdata_nsec3_param: STR sp STR sp STR sp STR trail + { +#ifdef NSEC3 + nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len); +#else + zc_error_prev_line("nsec3 not supported"); +#endif /* NSEC3 */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + } + ; + +rdata_dnskey: STR sp STR sp STR sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_short($1.str)); /* flags */ + zadd_rdata_wireformat(zparser_conv_byte($3.str)); /* proto */ + zadd_rdata_wireformat(zparser_conv_algorithm($5.str)); /* alg */ + zadd_rdata_wireformat(zparser_conv_b64($7.str)); /* hash */ + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + } + ; + +rdata_ipsec_base: STR sp STR sp STR sp dotted_str + { + knot_dname_t* name = 0; + zadd_rdata_wireformat(zparser_conv_byte($1.str)); /* precedence */ + zadd_rdata_wireformat(zparser_conv_byte($3.str)); + /* gateway type */ + zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* algorithm */ + switch(atoi($3.str)) { + case IPSECKEY_NOGATEWAY: + zadd_rdata_wireformat(alloc_rdata_init("", 0)); + break; + case IPSECKEY_IP4: + zadd_rdata_wireformat(zparser_conv_a($7.str)); + break; + case IPSECKEY_IP6: + zadd_rdata_wireformat(zparser_conv_aaaa($7.str)); + break; + case IPSECKEY_DNAME: + /* convert and insert the dname */ + if(strlen($7.str) == 0) + zc_error_prev_line("IPSECKEY must specify" + "gateway name"); + name = knot_dname_new_from_wire((uint8_t*)$7.str + 1, + strlen($7.str + 1), + NULL); + if(!name) { + zc_error_prev_line("IPSECKEY bad gateway" + "dname %s", $7.str); + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + if($7.str[strlen($7.str)-1] != '.') { + knot_dname_t* tmpd = + knot_dname_new_from_wire(name->name, + name->size, + NULL); + if (tmpd == NULL) { + zc_error_prev_line("Could not create dname!"); + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + name = knot_dname_cat(tmpd, + knot_node_parent(parser->origin, 0)->owner); + } + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + + uint8_t* dncpy = malloc(sizeof(uint8_t) * name->size); + if (dncpy == NULL) { + ERR_ALLOC_FAILED; + knot_rrset_deep_free(&(parser->current_rrset), + 0, 0, 0); + knot_zone_deep_free(&(parser->current_zone), + 1); + YYABORT; + } + memcpy(dncpy, name->name, name->size); + zadd_rdata_wireformat((uint16_t *)dncpy); + //knot_dname_free(&name); + break; + default: + zc_error_prev_line("unknown IPSECKEY gateway type"); + } + } + ; + +rdata_ipseckey: rdata_ipsec_base sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_b64($3.str)); /* public key */ + + free($3.str); + } + | rdata_ipsec_base trail + ; + +rdata_unknown: URR sp STR sp str_sp_seq trail + { + /* $2 is the number of octects, currently ignored */ + $$ = zparser_conv_hex($5.str, $5.len); + free($5.str); + free($3.str); + } + | URR sp STR trail + { + $$ = zparser_conv_hex("", 0); + free($3.str); + } + | URR error NL + { + $$ = zparser_conv_hex("", 0); + } + ; +%% + +int zp_wrap(void) +{ + return 1; +} + +/* + * Create the parser. + */ +zparser_type *zparser_create() +{ + zparser_type *result = malloc(sizeof(zparser_type)); + if (result == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + result->temporary_items = malloc(MAXRDATALEN * + sizeof(knot_rdata_item_t)); + if (result->temporary_items == NULL) { + ERR_ALLOC_FAILED; + free(result); + return NULL; + } + + result->current_rrset = knot_rrset_new(NULL, 0, 0, 0); + if (result->current_rrset == NULL) { + ERR_ALLOC_FAILED; + free(result->temporary_items); + free(result); + return NULL; + } + + result->root_domain = knot_dname_new_from_str(".", 1, NULL); +// printf("THE NEW ROOT: %p\n", result->root_domain); + if (result->root_domain == NULL) { + ERR_ALLOC_FAILED; + free(result->temporary_items); + free(result->current_rrset); + free(result); + return NULL; + } + + return result; +} + +/* + * Initialize the parser for a new zone file. + */ +void +zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, + knot_node_t *origin, knot_dname_t *origin_from_config) +{ + memset(nxtbits, 0, sizeof(nxtbits)); + memset(nsecbits, 0, sizeof(nsecbits)); + nsec_highest_rcode = 0; + + parser->current_zone = NULL; + parser->prev_dname = NULL; + + parser->default_ttl = ttl; + parser->default_class = rclass; + + parser->origin = origin; + parser->prev_dname = NULL;//parser->origin->owner; + + parser->default_apex = origin; + parser->error_occurred = 0; + parser->errors = 0; + parser->line = 1; + parser->filename = filename; + parser->rdata_count = 0; + parser->origin_from_config = origin_from_config; + + parser->last_node = origin; +// parser->root_domain = NULL; + + /* Create zone */ + parser->current_zone = knot_zone_new(origin, 0, 1); + + parser->node_rrsigs = NULL; + parser->rrsig_orphans = NULL; + parser->rrsig_orphan_count = 0; + + parser->current_rrset->rclass = parser->default_class; + parser->current_rrset->rdata = NULL; +} + + +void zparser_free() +{ +// knot_dname_release(parser->root_domain); +// knot_dname_release(parser->prev_dname); + knot_dname_free(&parser->origin_from_config); + free(parser->temporary_items); + if (parser->current_rrset != NULL) { + free(parser->current_rrset); + } + free(parser); +} + +void +yyerror(void *scanner, const char *message) +{ + zc_error("%s", message); +} + +static void +error_va_list(unsigned line, const char *fmt, va_list args) +{ + if (parser->filename) { + fprintf(stderr, "%s:%u: ", parser->filename, line); + } + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + + ++parser->errors; + parser->error_occurred = 1; +} + +/* the line counting sux, to say the least + * with this grose hack we try do give sane + * numbers back */ +void +zc_error_prev_line(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + error_va_list(parser->line - 1, fmt, args); + va_end(args); +} + +void +zc_error(const char *fmt, ...) +{ + /* send an error message to stderr */ + va_list args; + va_start(args, fmt); + error_va_list(parser->line, fmt, args); + va_end(args); +} + +static void +warning_va_list(unsigned line, const char *fmt, va_list args) +{ + if (parser->filename) { + fprintf(stderr, "%s:%u: ", parser->filename, line); + } + fprintf(stderr, "warning: "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); +} + +void +zc_warning_prev_line(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + warning_va_list(parser->line - 1, fmt, args); + va_end(args); +} + +void +zc_warning(const char *fmt, ... ) +{ + va_list args; + va_start(args, fmt); + warning_va_list(parser->line, fmt, args); + va_end(args); +} + +#ifdef NSEC3 +static void +nsec3_add_params(const char* hashalgo_str, const char* flag_str, + const char* iter_str, const char* salt_str, int salt_len) +{ + zadd_rdata_wireformat(zparser_conv_byte(hashalgo_str)); + zadd_rdata_wireformat(zparser_conv_byte(flag_str)); + zadd_rdata_wireformat(zparser_conv_short(iter_str)); + + /* salt */ + if(strcmp(salt_str, "-") != 0) + zadd_rdata_wireformat(zparser_conv_hex_length(salt_str, + salt_len)); + else + zadd_rdata_wireformat(alloc_rdata_init("", 1)); + +} +#endif /* NSEC3 */ diff --git a/tests/querytcp.c b/tests/querytcp.c new file mode 100644 index 0000000..7e1418f --- /dev/null +++ b/tests/querytcp.c @@ -0,0 +1,797 @@ +/* +TCP query version of queryperf +querytcp.c + fujiwara@jprs.co.jp + 2009.08.12 + version 0.4 + +queryperf for tcp query + +This program measures DNS server performance of TCP query. + +o Running environment: + Development environment: + Linux + FreeBSD + MacOS X 10.3.4 + +o How to make: + Linux: gcc -D_LINUX -Wall -O2 -g -lm -o querytcp querytcp.c + FreeBSD: gcc -Wall -O2 -g -lm -o querytcp querytcp.c + MacOS X: gcc -Wall -O2 -g -lm -lresolv -o querytcp querytcp.c + +o changes + + 2010/6/7: Linux compatibility + 2009/8/12: Remove use of res_mkquery +*/ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <netdb.h> +#include <errno.h> +#include <math.h> +#include <err.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <math.h> +#ifndef NO_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifdef __APPLE__ +#include <nameser8_compat.h> +#endif + +#ifndef ns_t_soa +#define ns_t_soa T_SOA +#endif +#ifndef ns_t_ns +#define ns_t_ns T_NS +#endif +#ifndef ns_c_in +#define ns_c_in C_IN +#endif + +#ifdef NOINET6 +#undef AF_INET6 +#endif + +#define Global + +#ifndef PACKETSZ +#define PACKETSZ 512 +#endif + +/* debug.c */ +void hexdump(char *title, unsigned char *memory, int len) +{ + printf("[ %s ", title); + while (len-- > 0) + printf("%02x ", *memory++); + printf("]\n"); +} + +#define Xmalloc(size) Xrealloc(NULL, size) + +void *Xrealloc(void *p, int size) +{ + int sz; + + sz = (size > 0) ? size : -size; + if (p == NULL) { + p = malloc(sz); + } else { + p = realloc(p, sz); + } + if (p == NULL) { + char buf[100]; + snprintf(buf, sizeof buf, "size=%d", size); + perror(buf); + exit(1); + } + if (size < 0) + memset(p, 0, sz); + return p; +} + +/* strlcpy() emulation for Linux. */ +#ifdef _LINUX +static inline size_t strlcpy(char *destination, const char *source, size_t size) +{ + if(strncpy(destination, source, size) == NULL) + return 0; + + return size; +} +#endif + +/* + NULL ... returns NULL + */ +char *Xstrdup(char *p) +{ + char *q; + int len; + + if (p == NULL) + return NULL; + len = strlen(p) + 1; + q = Xmalloc(len); + strlcpy(q, p, len); + return q; +} + + +typedef int64_t timediff_t; + +/* packet buffer */ +static struct timeval current; +static struct timeval start, send_finished;; +static fd_set fdset0r, fdset0w; +static int nfds; +static struct sockaddr_storage remote; +static int remote_len = 0; +static int finished = 0; +static timediff_t Timeout = 10*1000000LL; +unsigned short counter = 0; + +#define UpdateCurrentTime gettimeofday(¤t, NULL) + +#define RECVBUFSIZ 65537 +#define SENDBUFSIZ 512 + +struct dnsheader { + unsigned short id; // 2 + unsigned char flag1, flag2; // 2 + unsigned short qdcount, ancount, nscount, arcount; // 8 +}; + +/* + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +*/ + +struct queries { + struct tcpdns { + unsigned short len; + union { + struct dnsheader h; + unsigned char dnsdata[SENDBUFSIZ]; + } u; + } send; + unsigned char recvbuf[RECVBUFSIZ]; + int sendlen; + int sent_flag:1; + int tcpstate:2; + int fd; + int rpos; + int wpos; + int no; + struct timeval sent; /* long tv_sec, long tv_usec */ +}; + +struct queries *Queries; + +#define NQUERY 100 + +#define TCP_NONE 0 +#define TCP_WRITABLE 1 +#define TCP_READABLE 2 + +/* input */ +char *ServerName = "127.0.0.1"; +char *ServerPort = "53"; +int family = PF_UNSPEC; +char *datafile = NULL; +int TimeLimit = 20; +int EDNS0 = 0; +int DNSSEC = 0; +int recursion = 0; +FILE *fp = NULL; +int datafileloop = 0; +int verbose = 0; +int nQueries = 120; +int printrcode = 0; +char *rcodestr[]= { + "NOERROR", "FormatError", "ServerFailure", "NameError", + "NotImplemented", "Reused", "RCODE06", "RCODE07", + "RCODE08", "RCODE09", "RCODE10", "RCODE11", + "RCODE12", "RCODE13", "RCODE14", "RCODE15", +}; + +timediff_t timediff(struct timeval *a, struct timeval *b) /* u sec */ +{ + return (a->tv_sec - b->tv_sec) * 1000000 + (a->tv_usec - b->tv_usec); +} + +#define TIMEOUTERROR -10000 +#define ERROROFFSET -20000 +#define ERRZEROREAD -30000 + +uint64_t countrcode[16]; +uint64_t response_size_sum = 0; +uint64_t response_size_sum2 = 0; +uint64_t countanswers = 0; +uint64_t countqueries = 0; +uint64_t countzeroread = 0; +uint64_t counttimeout = 0; +uint64_t counterror = 0; + +int response_size_min = 0; +int response_size_max = 0; + + + +void register_response(struct queries *q, int timeout, char *note) +{ + u_char *p; + int size; + int rcode; + int id; + + id = ntohs(q->send.u.h.id); + if (note == NULL) + note = ""; + countqueries++; + if (timeout >= 0) { + p = q->recvbuf; + NS_GET16(size, p); + response_size_sum += size; + response_size_sum2 += size * size; + if (response_size_min == 0 || response_size_min > size) + response_size_min = size; + if (response_size_max == 0 || response_size_max < size) + response_size_max = size; + rcode = p[3] & 0x0f; + countrcode[rcode]++; + countanswers++; + if (verbose) + printf("recv response id=%d rcode=%d size=%d rtt=%d\n", id, rcode, size, timeout); + } else if (timeout == ERRZEROREAD) { + countzeroread++; + if (verbose) + printf("recv response id=%d zeroread\n", id); + } else if (timeout == TIMEOUTERROR) { + counttimeout++; + if (verbose) + printf("recv timeout id=%d %lld usec\n", id, timediff(¤t, &q->sent)); + } else { + counterror++; + if (verbose) { + printf("recv error id=%d errno=%d at %s (%s)\n", id, ERROROFFSET - timeout, note, strerror(errno)); + } + } +#ifdef DEBUG + printf("%ld.%03ld no=%d fd=%d %d %s\n", q->sent.tv_sec, q->sent.tv_usec/1000, q->no, q->fd, timeout, note); + fflush(stdout); +#endif +} + +void output() +{ + double response_size_average, response_size_variance, et; + + et = ((double)timediff(¤t, &start))/1000000.0; + + printf("elapsed time: %.3f\n", et); + printf("tcp qps: %.3f\n", (double)countanswers/et); + printf("sent: %lld\n", countqueries); + printf("answer: %lld %3.1f%%\n", countanswers, + (double)((double)countanswers/(double)countqueries*100.0)); + printf("error: %lld %3.1f%%\n", counterror, + (double)((double)counterror/(double)countqueries*100.0)); + printf("zeroread: %lld %3.1f%%\n", countzeroread, + (double)((double)countzeroread/(double)countqueries*100.0)); + printf("timeout: %lld %3.1f%%\n", counttimeout, + (double)((double)counttimeout/(double)countqueries*100.0)); + response_size_average = (double)response_size_sum/countanswers; + response_size_variance = (double)response_size_sum2 / countanswers + - response_size_average * response_size_average; + printf("response size: %d/%.3f/%d/%.3f bytes\n", response_size_min, response_size_average, response_size_max, sqrt(response_size_variance)); + if (printrcode) { + int i; + for (i = 0; i < 16; i++) { + if (countrcode[i] != 0) { + printf("%s %lld %5.1f\n", rcodestr[i], countrcode[i], ((double)countrcode[i])/((double)countanswers)*100.0); + } + } + } +} + +void tcp_close(struct queries *q) +{ + +#ifdef DEBUG +printf("tcp_close no=%d fd=%d\n", q->no, q->fd); +#endif + if (q->fd >= 0) { + close(q->fd); + FD_CLR(q->fd, &fdset0r); + FD_CLR(q->fd, &fdset0w); + } + q->sent_flag = 0; + q->tcpstate = TCP_NONE; + q->fd = -1; +} + +void tcp_send(struct queries *q) +{ + int len; + + len = send(q->fd, &q->send, q->sendlen, MSG_NOSIGNAL); +#ifdef DEBUG +printf("tcp_send no=%d fd=%d %d:%d:%d\n", q->no, q->fd, len, q->wpos, q->sendlen); +#endif + if (len < 0) { + if (errno == ENOTCONN) { +printf("tcp_send no=%d fd=%d ENOTCONN return\n", q->no, q->fd); + return; + } + register_response(q, ERROROFFSET - errno, "tcp_send"); + tcp_close(q); + return; + } + if (len != q->sendlen) { + register_response(q, ERROROFFSET - errno, "tcp_send:sendto"); + tcp_close(q); + return; + } + FD_CLR(q->fd, &fdset0w); + FD_SET(q->fd, &fdset0r); +} + +struct typecodes { + char *name; + int code; +} typecodes[] = { + { "A", ns_t_a }, + { "NS", ns_t_ns }, + { "SOA", ns_t_soa }, + { "PTR", ns_t_ptr }, + { "HINFO", ns_t_hinfo }, + { "MX", ns_t_mx }, + { "TXT", ns_t_txt }, + { "SIG", ns_t_sig }, + { "KEY", ns_t_key }, + { "AAAA", ns_t_aaaa }, + { "NXT", ns_t_nxt }, + { "SRV", ns_t_srv }, + { "NAPTR", ns_t_naptr }, + { NULL, -1 }, +}; + +int stringtodname(unsigned char *qname, unsigned char *buff, unsigned char *lim) +{ + unsigned char *p, *s, *t; + int count, total; + + t = qname; + p = buff; + total = 0; + for ( ;; ) { + s = p++; + count = 0; + if (p >= lim) return -1; + while (*t != 0 && *t != '.') + if (p < lim) { + *p++ = *t++; + count++; + } else + return -1; + *s = count; + if (count == 0) + break; + if (count > 63) + return -1; + total += count + 1; + if (*t == '.') t++; + } + if (total > 250 || !(*t == 0 || (*t == '.' && t[1] == 0))) + return -1; + return p - buff; +} + +void send_query_error(char *mesg) +{ + err(1, "Packet size exceed: %s", mesg); +} + +void send_query(struct queries *q) +{ + u_char *p, *lim; + char *qname; + int qclass; + int qtype; + int tmp; + struct typecodes *t = typecodes; + u_char buff[512]; + static char sep[] = "\n\t "; + static int lineno = 0; + + /* + SEND E[send_packet_pos] + */ + if (q->sent_flag) { + register_response(q, TIMEOUTERROR, "send_query"); + tcp_close(q); + } + if (fp == NULL) { + qname = "version.bind"; + qclass = ns_c_chaos; + qtype = ns_t_txt; + } else { + do { + if (fgets((char*)buff, sizeof(char)*512, fp) == NULL) { + if (datafileloop == 1) { + finished = 1; + fclose(fp); + fp = NULL; + return; + } + if (datafileloop > 0) + datafileloop--; + rewind(fp); + lineno = 0; + if (fgets((char*)buff, sizeof(char)*512, fp) == NULL) + err(1, "cannot rewind input file"); + } + lineno++; + } while(buff[0] == '#'); + qname = strtok((char*)buff, sep); + p = (u_char*) strtok(NULL, sep); + if (p != NULL) { + while(t->name != NULL) { + if (!strcasecmp(t->name, (char*)p)) + break; + t++; + } + qtype = t->code; + } else { + qtype = ns_t_a; + } + if (qname == NULL || qtype < 0) + err(1, "datafile format error at line %d, qname=%s qtype=%d", lineno, qname, qtype); + qclass = ns_c_in; + } + q->send.u.h.id = counter++; + q->send.u.h.flag1 = recursion ? 1 : 0; /* Query,OP=0,AA=0,TC=0,RD=0/1 */ + q->send.u.h.flag2 = 0; + q->send.u.h.qdcount = htons(1); + q->send.u.h.ancount = 0; + q->send.u.h.nscount = 0; + q->send.u.h.arcount = 0; + p = q->send.u.dnsdata + sizeof(q->send.u.h); + lim = p + sizeof(q->send.u.dnsdata); + if ((tmp = stringtodname((u_char*) qname, p, lim)) < 0) + send_query_error(qname); + p += tmp; + *(unsigned short *)p = htons(qtype); + p += sizeof(unsigned short); + *(unsigned short *)p = htons(qclass); + p += sizeof(unsigned short); + q->sendlen = p - q->send.u.dnsdata; + if (EDNS0) { +#define EDNS0size 11 + if (q->sendlen + EDNS0size >= sizeof(q->send.u.dnsdata)) + send_query_error("ENDS0"); + *p++ = 0; /* . */ + *(unsigned short *)p = htons(ns_t_opt); + p += 2; + *(unsigned short *)p = htons(4096); + p += 2; + *p++ = 0; + *p++ = 0; + *p++ = (DNSSEC == 0) ? 0 : 0x80; /* eflag: DO bit */ + *p++ = 0; + *p++ = 0; + *p++ = 0; + q->sendlen += EDNS0size; + p = (u_char*) &q->send.u.dnsdata; + q->send.u.h.ancount = htons(1); + } + q->send.len = htons(q->sendlen); + q->sendlen += sizeof(q->send.len); + q->wpos = 0; + q->rpos = 0; + q->sent = current; + if (verbose > 0) { + int id = ntohs(*(unsigned short *)&q->send.u.dnsdata); + printf("sending query(%s,%d,%d) id=%d %d bytes to %s\n", qname, qclass, qtype, id, q->sendlen, ServerName); + hexdump("sending packet header:", (unsigned char*) &q->send.u.h, 12); + } + if (q->fd > 0) + err(1, "q->fd > 0 but ignored\n"); + + q->fd = socket(remote.ss_family, SOCK_STREAM, 0); + tmp = fcntl(q->fd, F_GETFL, 0); + fcntl(q->fd, F_SETFL, O_NONBLOCK | tmp); + int conn_ret = connect(q->fd, (struct sockaddr *)&remote, remote_len); + if(conn_ret < 0 && errno != EINPROGRESS) { + register_response(q, ERROROFFSET - errno, "send_query:socket+fcntl+connect"); + tcp_close(q); + return; + } +#ifdef DEBUG +printf("send_query no=%d fd=%d socket|connect\n", q->no, q->fd); +#endif + q->tcpstate = TCP_WRITABLE; + FD_SET(q->fd, &fdset0w); + FD_CLR(q->fd, &fdset0r); + if (nfds <= q->fd) { + nfds = q->fd + 1; + } + q->sent = current; + q->sent_flag = 1; +} + +int UpdateQuery() +{ + int i; + timediff_t t, min = Timeout; + struct queries *q; + int free = 0; + + if (!finished && TimeLimit > 0) { + if ((t = timediff(¤t, &start)) > TimeLimit * 1000000LL) { + finished = 1; + send_finished = current; + } + } + for(i = 0; i < nQueries; i++) { + q = &Queries[i]; + if (q->sent_flag) { + if ((t = timediff(¤t, &q->sent)) > Timeout) { + /* timeouted */ + register_response(q, TIMEOUTERROR, "UpdateQuery"); + tcp_close(q); + } else + if (t < min) + min = t; + } + if (!q->sent_flag) { + if (!finished) + send_query(q); + else + free++; + } + } + if (free == nQueries) + min = -1; /* finished */ + return min; +} + +char *skipname(char *p) +{ + while(*p > 0 && *p < 0x40) p += *p + 1; + if (*p == 0) + return p+1; + return p+2; +} + +#define Hexdump(A,B,C) + +void tcp_receive(struct queries *q) +{ + int len, len2; + timediff_t tmp; + unsigned char *recvp; + +/*printf("tcp_receive %s\n", q->nameserverlabel);*/ + + len = read(q->fd, q->recvbuf + q->rpos, len2 = RECVBUFSIZ - q->rpos); + if (len < 0) { + if (errno == EAGAIN) + return; + register_response(q, ERROROFFSET - errno, "tcp_receive:read"); + tcp_close(q); + return; + } + if (len == 0) { + register_response(q, ERRZEROREAD, "tcp_receive:read"); + tcp_close(q); + return; + } + q->rpos += len; + if (q->rpos < 2) + return; + len2 = ntohs(*(unsigned short *)(q->recvbuf)); + if (q->rpos >= len2 + 2) { + /* finished */ + recvp = q->recvbuf + 2; + if (memcmp(recvp, q->send.u.dnsdata, 2) == 0) { + if ((recvp[2] & 1) == 0 /* RA bit */ + || (recvp[3] & 15) != 0 /* RCODE must be 0 */ + ) { +/* + fprintf(stderr, "WRONG AA=%d RCODE=%d\n", + ((recvp[2]>>2) & 1), recvp[3]&15); +*/ + } + tmp = timediff(¤t, &q->sent); + register_response(q, tmp, "tcp_receive"); + tcp_close(q); + return; + } else { +printf("no=%d fd=%d unknown recv %d bytes, len=%d\n", q->no, q->fd, q->rpos, ntohs(*(unsigned short *)(q->recvbuf))); + hexdump("", q->recvbuf, len); + /* + fprintf(stderr, "unknown recv from %s, %d bytes %02x %02x\n", q->nameserverlabel, q->rpos, recvp[0], recvp[1]); + */ + tcp_close(q); + } + } +} + +void query() +{ + fd_set fdsetr, fdsetw; + struct timeval timeout; + int min; + struct queries *q; + int i, n; + struct addrinfo hints, *res0; + int error; + + Queries = Xmalloc(sizeof(Queries[0]) * nQueries); + memset(&remote, 0, sizeof(remote)); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + printf("resolving: %s:%s\n", ServerName, ServerPort); + error = getaddrinfo(ServerName, 0, &hints, &res0); + if (error) { + errx(1, "%s", gai_strerror(error)); + } + + /* Update server port. */ + int port = atoi(ServerPort); + if (res0->ai_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res0->ai_addr; + ipv6->sin6_port = htons(port); + } else { + struct sockaddr_in *ipv4 = (struct sockaddr_in*)res0->ai_addr; + ipv4->sin_port = htons(port); + } + + remote_len = res0->ai_addrlen; + memcpy(&remote, res0->ai_addr, res0->ai_addrlen); + memset(&countrcode, 0, sizeof(countrcode)); + + res_init(); + _res.options ^= ~RES_RECURSE; + _res.options |= RES_AAONLY; + + for (i = 0; i < nQueries; i++) { + Queries[i].sent_flag = 0; + Queries[i].no = i; + } + + FD_ZERO(&fdset0r); + FD_ZERO(&fdset0w); + nfds = 0; + UpdateCurrentTime; + start = current; + finished = 0; + + for (;;) { + UpdateCurrentTime; + if ((min = UpdateQuery()) < 0) + break; + timeout.tv_sec = min / 1000000; + timeout.tv_usec = min % 1000000; + fdsetr = fdset0r; + fdsetw = fdset0w; + n = select(nfds, &fdsetr, &fdsetw, NULL, &timeout); + UpdateCurrentTime; + for(i = 0; i < nQueries; i++) { + q = &Queries[i]; + if (q->fd < 0 || !q->sent_flag) + continue; + if (FD_ISSET(q->fd, &fdsetw)) { + tcp_send(q); + } else if (FD_ISSET(q->fd, &fdsetr)) { + tcp_receive(q); + } + } + } +} + +void usage() +{ + fprintf(stderr, +"querytcp [-d datafile] [-s server_addr] [-p port] [-q num_queries] [-t timeout] [l limit] [-4] [-6] [-h]\n" +" -d specifies the input data file (default: stdin)\n" +" -s sets the server to query (default: 127.0.0.1)\n" +" -p sets the port on which to query the server (default: 53)\n" +" -q specifies the maximum number of queries outstanding (default: 120)\n" +" -t specifies the timeout for query completion in seconds (default: 10)\n" +" -l specifies how a limit for how long to run tests in seconds (no default)\n" +" -e enable EDNS0\n" +" -D set DO bit\n" +" -r set RD bit\n" +"\n" +"\n" +"\n" +" -c print the number of packets with each rcode\n" +" -v verbose: report the RCODE of each response on stdout\n" +" -h print this usage\n" +); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int ch, i; + printf("dnsheader size: %d\n", sizeof(struct dnsheader)); + while ((ch = getopt(argc, argv, "d:s:p:q:t:l:46eDrvh")) != -1) { + switch (ch) { + case 'q': + nQueries = atoi(optarg); + if (nQueries < 1) + err(1, "-q requires natural number"); + break; + case 'p': + ServerPort = Xstrdup(optarg); + break; + case 's': + ServerName = Xstrdup(optarg); + break; + case 'd': + datafile = Xstrdup(optarg); + if ((fp = fopen(datafile, "r")) == NULL) + err(1, "cannot open %s", optarg); + break; + case 't': + i = atoi(optarg); + if (i < 1) + err(1, "-t timeout > 0"); + Timeout = (int64_t)i * 1000000LL; + break; + case 'l': + TimeLimit = atoi(optarg); + break; + case '4': + family = AF_INET; + break; + case '6': + family = AF_INET6; + break; + case 'e': + EDNS0 = 1; + break; + case 'D': + DNSSEC = 1; + break; + case 'r': + recursion = 1; + break; + case 'v': + verbose = 1; + break; + case 'c': + printrcode = 1; + break; + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + query(); + output(); + + return 0; +} @@ -0,0 +1,222 @@ +#! /bin/sh +# ylwrap - wrapper for lex/yacc invocations. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, +# 2007, 2009 Free Software Foundation, Inc. +# +# Written by Tom Tromey <tromey@cygnus.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +case "$1" in + '') + echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 + exit 1 + ;; + --basedir) + basedir=$2 + shift 2 + ;; + -h|--h*) + cat <<\EOF +Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... + +Wrapper for lex/yacc invocations, renaming files as desired. + + INPUT is the input file + OUTPUT is one file PROG generates + DESIRED is the file we actually want instead of OUTPUT + PROGRAM is program to run + ARGS are passed to PROG + +Any number of OUTPUT,DESIRED pairs may be used. + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v|--v*) + echo "ylwrap $scriptversion" + exit $? + ;; +esac + + +# The input. +input="$1" +shift +case "$input" in + [\\/]* | ?:[\\/]*) + # Absolute path; do nothing. + ;; + *) + # Relative path. Make it absolute. + input="`pwd`/$input" + ;; +esac + +pairlist= +while test "$#" -ne 0; do + if test "$1" = "--"; then + shift + break + fi + pairlist="$pairlist $1" + shift +done + +# The program to run. +prog="$1" +shift +# Make any relative path in $prog absolute. +case "$prog" in + [\\/]* | ?:[\\/]*) ;; + *[\\/]*) prog="`pwd`/$prog" ;; +esac + +# FIXME: add hostname here for parallel makes that run commands on +# other machines. But that might take us over the 14-char limit. +dirname=ylwrap$$ +trap "cd '`pwd`'; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 +mkdir $dirname || exit 1 + +cd $dirname + +case $# in + 0) "$prog" "$input" ;; + *) "$prog" "$@" "$input" ;; +esac +ret=$? + +if test $ret -eq 0; then + set X $pairlist + shift + first=yes + # Since DOS filename conventions don't allow two dots, + # the DOS version of Bison writes out y_tab.c instead of y.tab.c + # and y_tab.h instead of y.tab.h. Test to see if this is the case. + y_tab_nodot="no" + if test -f y_tab.c || test -f y_tab.h; then + y_tab_nodot="yes" + fi + + # The directory holding the input. + input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` + # Quote $INPUT_DIR so we can use it in a regexp. + # FIXME: really we should care about more than `.' and `\'. + input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` + + while test "$#" -ne 0; do + from="$1" + # Handle y_tab.c and y_tab.h output by DOS + if test $y_tab_nodot = "yes"; then + if test $from = "y.tab.c"; then + from="y_tab.c" + else + if test $from = "y.tab.h"; then + from="y_tab.h" + fi + fi + fi + if test -f "$from"; then + # If $2 is an absolute path name, then just use that, + # otherwise prepend `../'. + case "$2" in + [\\/]* | ?:[\\/]*) target="$2";; + *) target="../$2";; + esac + + # We do not want to overwrite a header file if it hasn't + # changed. This avoid useless recompilations. However the + # parser itself (the first file) should always be updated, + # because it is the destination of the .y.c rule in the + # Makefile. Divert the output of all other files to a temporary + # file so we can compare them to existing versions. + if test $first = no; then + realtarget="$target" + target="tmp-`echo $target | sed s/.*[\\/]//g`" + fi + # Edit out `#line' or `#' directives. + # + # We don't want the resulting debug information to point at + # an absolute srcdir; it is better for it to just mention the + # .y file with no path. + # + # We want to use the real output file name, not yy.lex.c for + # instance. + # + # We want the include guards to be adjusted too. + FROM=`echo "$from" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + TARGET=`echo "$2" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + + sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \ + -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$? + + # Check whether header files must be updated. + if test $first = no; then + if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then + echo "$2" is unchanged + rm -f "$target" + else + echo updating "$2" + mv -f "$target" "$realtarget" + fi + fi + else + # A missing file is only an error for the first file. This + # is a blatant hack to let us support using "yacc -d". If -d + # is not specified, we don't want an error when the header + # file is "missing". + if test $first = yes; then + ret=1 + fi + fi + shift + shift + first=no + done +else + ret=$? +fi + +# Remove the directory. +cd .. +rm -rf $dirname + +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: |