[Freeswitch-svn] [commit] r3494 - in freeswitch/trunk: conf libs/udns libs/udns/debian src src/include src/mod/applications/mod_bridgecall src/mod/codecs/mod_gsm src/mod/dialplans/mod_dialplan_xml

Freeswitch SVN anthm at freeswitch.org
Thu Nov 30 16:28:33 EST 2006


Author: anthm
Date: Thu Nov 30 16:28:32 2006
New Revision: 3494

Added:
   freeswitch/trunk/libs/udns/
   freeswitch/trunk/libs/udns/COPYING.LGPL
   freeswitch/trunk/libs/udns/Makefile   (contents, props changed)
   freeswitch/trunk/libs/udns/NOTES
   freeswitch/trunk/libs/udns/TODO
   freeswitch/trunk/libs/udns/debian/
   freeswitch/trunk/libs/udns/debian/changelog
   freeswitch/trunk/libs/udns/debian/control
   freeswitch/trunk/libs/udns/debian/copyright
   freeswitch/trunk/libs/udns/debian/rules   (contents, props changed)
   freeswitch/trunk/libs/udns/dnsget.1
   freeswitch/trunk/libs/udns/dnsget.c
   freeswitch/trunk/libs/udns/ex-rdns.c
   freeswitch/trunk/libs/udns/rblcheck.1
   freeswitch/trunk/libs/udns/rblcheck.c
   freeswitch/trunk/libs/udns/udns.3
   freeswitch/trunk/libs/udns/udns.h
   freeswitch/trunk/libs/udns/udns_bl.c
   freeswitch/trunk/libs/udns/udns_codes.c
   freeswitch/trunk/libs/udns/udns_dn.c
   freeswitch/trunk/libs/udns/udns_dntosp.c
   freeswitch/trunk/libs/udns/udns_misc.c
   freeswitch/trunk/libs/udns/udns_parse.c
   freeswitch/trunk/libs/udns/udns_resolver.c
   freeswitch/trunk/libs/udns/udns_rr_a.c
   freeswitch/trunk/libs/udns/udns_rr_mx.c
   freeswitch/trunk/libs/udns/udns_rr_naptr.c
   freeswitch/trunk/libs/udns/udns_rr_ptr.c
   freeswitch/trunk/libs/udns/udns_rr_srv.c
   freeswitch/trunk/libs/udns/udns_rr_txt.c
Modified:
   freeswitch/trunk/conf/freeswitch.xml
   freeswitch/trunk/src/include/switch_types.h
   freeswitch/trunk/src/include/switch_utils.h
   freeswitch/trunk/src/mod/applications/mod_bridgecall/mod_bridgecall.c
   freeswitch/trunk/src/mod/codecs/mod_gsm/mod_gsm.c
   freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c
   freeswitch/trunk/src/switch_ivr.c
   freeswitch/trunk/src/switch_utils.c

Log:
ENUM Support

mod_enum can be used as a dialplan app, an api call from the console or as a dialplan interface.


Dialplan Interface:
put enum as the dialplan parameter in an endpoint module
i.e. instead of "XML" set it to "enum" or "enum,XML" for fall through.

Dialplan App:
This example will do a lookup and set the a variable that is the proper
dialstring to call all of the possible routes in order of preference according to 
the lookup and the order of the routes in the enum.conf section.

<extension name="tollfree">
  <condition field="destination_number" expression="^(18(0{2}|8{2}|7{2}|6{2})\d{7})$">
    <action application="enum" data="$1"/>
    <action application="bridge" data="${enum_auto_route}"/>
  </condition>
</extension>

You can also pick an alrernate root:
<action application="enum" data="$1 myroot.org"/>	


API command:
at the console you can say:
enum <number> [<root>]

The root always defaults to the one in the enum.conf section.




Modified: freeswitch/trunk/conf/freeswitch.xml
==============================================================================
--- freeswitch/trunk/conf/freeswitch.xml	(original)
+++ freeswitch/trunk/conf/freeswitch.xml	Thu Nov 30 16:28:32 2006
@@ -22,6 +22,10 @@
         <load module="mod_console"/>
         <!-- <load module="mod_syslog"/> -->
 
+        <!-- Multi-Faceted -->
+	<!-- mod_enum is a dialplan interface, an application interface and an api command interface -->
+        <load module="mod_enum"/>
+
         <!-- XML Interfaces -->
         <!-- <load module="mod_xml_rpc"/> -->
 
@@ -77,7 +81,6 @@
         <!-- ASR /TTS -->
         <!-- <load module="mod_cepstral"/> -->
         <!-- <load module="mod_rss"/> -->
-
       </modules>
     </configuration>
 
@@ -404,6 +407,19 @@
         </profile>
       </profiles>
     </configuration>
+
+    <configuration name="enum.conf" description="ENUM Module">
+      <settings>
+	<param name="default-root" value="e164.org"/>
+      </settings>
+
+      <routes>
+	<route service="E2U+SIP" regex="sip:(.*)" replace="sofia/test/$1"/>
+	<route service="E2U+IAX2" regex="iax2:(.*)" replace="iax/$1"/>
+	<route service="E2U+XMPP" regex="XMPP:(.*)" replace="dingaling/jingle/$1"/>
+      </routes>
+    </configuration>
+
   </section>
   
   <section name="dialplan" description="Regex/XML Dialplan">
@@ -415,7 +431,8 @@
     <context name="default">
       <extension name="tollfree">
         <condition field="destination_number" expression="^(18(0{2}|8{2}|7{2}|6{2})\d{7})$">
-          <action application="bridge" data="sofia/test/$1-freeswitch at voip.trxtel.com"/>
+	  <action application="enum" data="$1"/>
+	  <action application="bridge" data="${enum_auto_route}"/>
         </condition>
       </extension>
 

Added: freeswitch/trunk/libs/udns/COPYING.LGPL
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/COPYING.LGPL	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+

Added: freeswitch/trunk/libs/udns/Makefile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/Makefile	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,132 @@
+#! /usr/bin/make -rf
+# $Id: Makefile,v 1.42 2006/11/29 21:27:01 mjt Exp $
+# libudns Makefile
+#
+# Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+# This file is part of UDNS library, an async DNS stub resolver.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library, in file named COPYING.LGPL; if not,
+# write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA  02111-1307  USA
+
+VERS   = 0.0.9pre
+SRCS   = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_misc.c \
+	udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \
+	udns_rr_srv.c udns_rr_naptr.c udns_codes.c
+USRCS  = dnsget.c rblcheck.c ex-rdns.c
+DEB    = debian/copyright debian/changelog debian/control debian/rules
+DIST   = COPYING.LGPL udns.h udns.3 dnsget.1 rblcheck.1 $(SRCS) $(USRCS) \
+	Makefile TODO NOTES
+
+OBJS   = $(SRCS:.c=.o) $(GEN:.c=.o)
+LIB    = libudns.a
+
+SOVER  = 0
+SOBJS  = $(OBJS:.o=.lo)
+SOLIB  = libudns.so
+SOLIBV = $(SOLIB).$(SOVER)
+
+LIBS   = $(LIB) $(SOLIBV)
+
+UTILS   = $(USRCS:.c=)
+SOUTILS = $(USRCS:.c=.shared)
+
+NAMEPFX = udns-$(VERS)
+
+CC = gcc
+CFLAGS = -Wall -W -Wmissing-prototypes -O2 -fPIC
+CDEFS = -DHAVE_POLL
+PICFLAGS = -fPIC
+AWK = awk
+
+all: static
+
+.SUFFIXES: .c .o .lo .shared
+
+static: $(LIB) $(UTILS)
+staticlib: $(LIB)
+$(LIB): $(OBJS)
+	-rm -f $@
+	$(AR) rv $@ $(OBJS)
+.c.o:
+	$(CC) $(CFLAGS) $(CDEFS) -c $<
+$(OBJS): udns.h
+
+$(UTILS): udns.h $(LIB)
+.c:
+	$(CC) $(CFLAGS) $(CDEFS) -o $@ $< $(LIB)
+
+shared: $(SOLIBV) $(SOUTILS)
+sharedlib: $(SOLIBV)
+
+$(SOLIBV): $(SOBJS)
+	$(CC) -shared -Wl,--soname,$(SOLIBV) -o $@ $(SOBJS)
+	rm -f $(SOLIB)
+	ln -s $(SOLIBV) $(SOLIB)
+.c.lo:
+	$(CC) $(CFLAGS) $(PICFLAGS) $(CDEFS) -o $@ -c $<
+$(SOBJS): udns.h
+
+$(SOUTILS): udns.h $(SOLIB)
+.c.shared:
+	$(CC) $(CFLAGS) $(CDEFS) -o $@ $< $(SOLIB)
+
+# udns_codes.c is generated from udns.h
+udns_codes.c:	udns.h Makefile
+	@echo Generating $@
+	@set -e; exec >$@.tmp; \
+	set T type C class R rcode; \
+	echo "/* Automatically generated. */"; \
+	echo "#include \"udns.h\""; \
+	while [ "$$1" ]; do \
+	 echo; \
+	 echo "const struct dns_nameval dns_$${2}tab[] = {"; \
+	 $(AWK) "/^  DNS_$${1}_[A-Z0-9_]+[ 	]*=/ \
+	  { printf \" {%s,\\\"%s\\\"},\\n\", \$$1, substr(\$$1,7) }" \
+	  udns.h ; \
+	 echo " {0,0}};"; \
+	 echo "const char *dns_$${2}name(enum dns_$${2} code) {"; \
+	 echo " static char nm[20];"; \
+	 echo " switch(code) {"; \
+	 $(AWK) "BEGIN{i=0} \
+	   /^  DNS_$${1}_[A-Z0-9_]+[ 	]*=/ \
+	   {printf \" case %s: return dns_$${2}tab[%d].name;\\n\",\$$1,i++}\
+	   " udns.h ; \
+	 echo " }"; \
+	 echo " return _dns_format_code(nm,\"$$2\",code);"; \
+	 echo "}"; \
+	 shift 2; \
+	done
+	@mv $@.tmp $@
+
+udns.3.html: udns.3
+	groff -man -Thtml udns.3 > $@.tmp
+	mv $@.tmp $@
+
+dist: $(NAMEPFX).tar.gz
+$(NAMEPFX).tar.gz: $(DIST) $(DEB)
+	mkdir $(NAMEPFX) $(NAMEPFX)/debian
+	ln $(DIST) $(NAMEPFX)
+	ln $(DEB) $(NAMEPFX)/debian
+	tar cvfz $@ $(NAMEPFX)
+	rm -rf $(NAMEPFX)
+subdist:
+	cp -p $(DIST) $(TARGET)/
+
+clean:
+	rm -f $(OBJS) $(SOBJS) build-stamp
+distclean: clean
+	rm -f $(LIBS) libudns.so udns.3.html $(UTILS) $(SOUTILS)
+
+.PHONY: all static staticlib shared sharedlib dist clean distclean subdist

Added: freeswitch/trunk/libs/udns/NOTES
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/NOTES	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,193 @@
+Assorted notes about udns (library).
+
+UDP-only mode
+~~~~~~~~~~~~~
+
+First of all, since udns is (currently) UDP-only, there are some
+shortcomings.
+
+It assumes that a reply will fit into a UDP buffer.  With adoption of EDNS0,
+and general robustness of IP stacks, in most cases it's not an issue.  But
+in some cases there may be problems:
+
+ - if an RRset is "very large" so it does not fit even in buffer of size
+   requested by the library (current default is 4096; some servers limits
+   it further), we will not see the reply, or will only see "damaged"
+   reply (depending on the server)
+
+ - many DNS servers ignores EDNS0 option requests.  In this case, no matter
+   which buffer size udns library will request, such servers reply is limited
+   to 512 bytes (standard pre-EDNS0 DNS packet size).
+
+ - some DNS servers, notable the ones used by Verisign for certain top-level
+   domains, chokes on EDNS0-enabled queries, returning FORMERR.  Such
+   behavior isn't prohibited by DNS standards, but in my opinion it's at
+   least weird - the server can easily ignore EDNS0 options and send a
+   reply, instead of sending error.
+   Currently, udns does nothing in this situation, completely ignoring the
+   error returned by the server, and continue waiting for reply.  It probably
+   should grok that this server does not understand EDNS0 and retry w/o the
+   options, but it does not.  The end result - esp. if your local DNS
+   server or - worse - broken firewall which inspects DNS packets and drops
+   the ones which - from its point of view - are "broken" - is that you
+   see only TEMPFAIL errors from the library trying to resolve ANY names.
+
+Implementing TCP mode (together with non-EDNS0 fall-back as above) isn't
+difficult, but it complicates API significantly.  Currently udns uses only
+single UDP socket (or - maybe in the future - two, see below), but in case of
+TCP, it will need to open and close sockets for TCP connections left and
+right, and that have to be integrated into an application's event loop in
+an easy and efficient way.  Plus all the timeouts - different for connect(),
+write, and several stages of read.
+
+IPv6 vs IPv4 usage
+~~~~~~~~~~~~~~~~~~
+
+This is only relevant for nameservers reachable over IPv6, NOT for IPv6
+queries.  I.e., if you've IPv6 addresses in 'nameservers' line in your
+/etc/resolv.conf file.  Even more: if you have BOTH IPv6 AND IPv4 addresses
+there.  Or pass them to udns initialization routines.
+
+Since udns uses a single UDP socket to communicate with all nameservers,
+it should support both v4 and v6 communications.  Most current platforms
+supports this mode - using PF_INET6 socket and V4MAPPED addresses, i.e,
+"tunnelling" IPv4 inside IPv6.  But not all systems supports this.  And
+more, it has been said that such mode is deprecated.
+
+So, list only IPv4 or only IPv6 addresses, but don't mix them, in your
+/etc/resolv.conf.
+
+An alternative is to use two sockets instead of 1 - one for IPv6 and one
+for IPv4.  For now I'm not sure if it's worth the complexity - again, of
+the API, not the library itself (but this will not simplify library either).
+
+Single socket for all queries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Using single UDP socket for sending queries to all nameservers has obvious
+advantages.  First it's, again, trivial, simple to use API.  And simple
+library too.  Also, after sending queries to all nameservers (in case first
+didn't reply in time), we will be able to receive late reply from first
+nameserver and accept it.
+
+But this mode has disadvantages too.  Most important is that it's much easier
+to send fake reply to us, as the UDP port where we expects the reply to come
+to is constant during the whole lifetime of an application.  More secure
+implementations uses random port for every single query.  While port number
+(16 bits integer) can not hold much randomness, it's still of some help.
+Ok, udns is a stub resolver, so it expects sorta friendly environment, but
+on LAN it's usually much easier to fire an attack, due to the speed of local
+network, where a bad guy can generate alot of packets in a short time.
+
+Choosing of DNS QueryID
+~~~~~~~~~~~~~~~~~~~~~~~
+
+This is more a TODO item really.  Currently, udns uses sequential number for
+query IDs.  Which simplifies attacks even more (c.f. the previous item about
+single UDP port), making them nearly trivial.  The library should use random
+number for query ID.  But there's no portable way to get random numbers, even
+on various flavors of Unix.  It's possible to use low bits from tv_nsec field
+returned by gettimeofday() (current time, nanoseconds), but I wrote the library
+in a way to avoid making system calls where possible, because many syscalls
+means many context switches and slow processes as a result.  Maybe use some
+application-supplied callback to get random values will be a better way,
+defaulting to gettimeofday() method.
+
+Note that a single query - even if (re)sent to different nameservers, several
+times (due to no reply received in time), uses the same qID assigned when it
+was first dispatched.  So we have: single UDP socket (fixed port number),
+sequential (= trivially predictable) qIDs, and long lifetime of those qIDs.
+This all makes (local) attacks against the library really trivial.
+
+Assumptions about RRs returned
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently udns processes records in the reply it received sequentially.
+This means that order of the records is significant.  For example, if
+we asked for foo.bar A, but the server returned that foo.bar is a CNAME
+(alias) for bar.baz, and bar.baz, in turn, has address 1.2.3.4, when
+the CNAME should come first in reply, followed by A.  While DNS specs
+does not say anything about order of records - it's an rrSET - unordered, -
+I think an implementation which returns the records in "wrong" order is
+somewhat insane...  Well ok, to be fair, I don't really remember how
+udns handles this now - need to check this in source... ;)
+
+CNAME recursion
+~~~~~~~~~~~~~~~
+
+Another dark point of udns is the handling of CNAMEs returned as replies
+to non-CNAME queries.  If we asked for foo.bar A, but it's a CNAME, udns
+expects BOTH the CNAME itself and the target DN to be present in the reply.
+In other words, udns DOES NOT RECURSE CNAMES.  If we asked for foo.bar A,
+but only record in reply was that foo.bar is a CNAME for bar.baz, udns will
+return no records to an application (NXDOMAIN).  Strictly speaking, udns
+should repeat the query asking for bar.baz A, and recurse.  But since it's
+stub resolver, recursive resolver should recurse for us instead.
+
+It's not very difficult to implement, however.  Probably with some (global?)
+flag to en/dis-able the feature.  Provided there's some demand for it.
+
+To clarify: udns handles CNAME recursion in a single reply packet just fine.
+
+Error reporting
+~~~~~~~~~~~~~~~
+
+Too many places in the code (various failure paths) sets generic "TEMPFAIL"
+error condition.  For example, if no nameserver replied to our query, an
+application will get generic TEMPFAIL, instead of something like TIMEDOUT.
+This probably should be fixed, but most applications don't care about the
+exact reasons of failure - 4 common cases are already too much:
+  - query returned some valid data
+  - NXDOMAIN
+  - valid domain but no data of requested type - =NXDOMAIN in most cases
+  - temporary error - this one sometimes (incorrectly!) treated as NXDOMAIN
+    by (naive) applications.
+DNS isn't yes/no, it's at least 3 variants, temp err being the 3rd important
+case!  And adding more variations for the temp error case is complicating things
+even more - again, from an application writer standpoint.  For diagnostics,
+such more specific error cases are of good help.
+
+Planned API changes
+~~~~~~~~~~~~~~~~~~~
+
+At least one thing I want to change for 0.1 version is a way how queries are
+submitted.
+
+I want to made dns_query object to be owned by an application.  So that instead
+of udns library allocating it for the lifetime of query, it will be pre-
+allocated by an application.  This simplifies and enhances query submitting
+interface, and complicates it a bit too, in simplest cases.
+
+Currently, we have:
+
+dns_submit_dn(dn, cls, typ, flags, parse, cbck, data)
+dns_submit_p(name, cls, typ, flags, parse, cbck, data)
+dns_submit_a4(ctx, name, flags, cbck, data)
+
+and so on -- with many parameters missed for type-specific cases, but generic
+cases being too complex for most common usage.
+
+Instead, with dns_query being owned by an app, we will be able to separately
+set up various parts of the query - domain name (various forms), type&class,
+parser, flags, callback...  and even change them at runtime.  And we will also
+be able to reuse query structures, instead of allocating/freeing them every
+time.  So the whole thing will look something like:
+
+ q = dns_alloc_query();
+ dns_submit(dns_q_flags(dns_q_a4(q, name, cbck), DNS_F_NOSRCH), data);
+
+The idea is to have a set of functions accepting struct dns_query* and
+returning it (so the calls can be "nested" like the above), to set up
+relevant parts of the query - specific type of callback, conversion from
+(type-specific) query parameters into a domain name (this is for type-
+specific query initializers), and setting various flags and options and
+type&class things.
+
+One example where this is almost essential - if we want to support
+per-query set of nameservers (which isn't at all useless: imagine a
+high-volume mail server, were we want to direct DNSBL queries to a separate
+set of nameservers, and rDNS queries to their own set and so on).  Adding
+another argument (set of nameservers to use) to EVERY query submitting
+routine is.. insane.  Especially since in 99% cases it will be set to
+default NULL.  But with such "nesting" of query initializers, it becomes
+trivial.

Added: freeswitch/trunk/libs/udns/TODO
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/TODO	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,74 @@
+$Id: TODO,v 1.10 2005/04/19 21:48:09 mjt Exp $
+
+The following is mostly an internal, not user-visible stuff.
+
+* rearrange an API to make dns_query object owned by application,
+  so that it'll look like this:
+   struct dns_query *q;
+   q = udns_query_alloc(ctx);
+   udns_query_set(q, options, domain_name, flags, ...);
+   udns_query_submit(ctx, q);
+ or
+   udns_query_resolve(ctx, q);
+
+* allow NULL callbacks?  Or provide separate resolver
+  context list of queries which are done but wich did not
+  have callback, and dns_pick() routine to retrieve results
+  from this query, i.e. allow non-callback usage?  The
+  non-callback usage may be handy sometimes (any *good*
+  example?), but it will be difficult to provide type-safe
+  non-callback interface due to various RR-specific types
+  in use.
+
+* DNS_OPT_FLAGS should be DNS_OPT_ADDFLAGS and DNS_OPT_SETFLAGS.
+  Currently one can't add a single flag bit but preserve
+  existing bits... at least not without retrieving all current
+  flags before, which isn't that bad anyway.
+
+* dns_set_opts() may process flags too (such as aaonly etc)
+
+* a way to disable $NSCACHEIP et al processing?
+
+* initialize/open the context automatically, and be more
+  liberal about initialization in general?
+
+* dns_init(do_open) - make the parameter opposite, aka
+  dns_init(skip_open) ?
+
+* for the above.  Use separate routine for initializing the context
+  from system files, to not link stuff reading resolv.conf if it's
+  not needed.  So that automatic init will not be possible.
+
+* allow TCP queue?
+
+* detect servers which don't understand EDNS0 (returning FORMERR),
+  and fall back to pre-EDNS0 for them.
+
+* for the above to work, we have to be able to find query object by
+  only ID, not ID + qdn.
+
+* And oh, qID should really be random.
+
+* more accurate error reporting.  Currently, udns always returns TEMPFAIL,
+  but don't specify why it happened (ENOMEM, timeout, etc).
+
+* check the error value returned by recvfrom() and
+  sendto() and determine which errors to ignore.
+
+* maybe merge dns_timeouts() and dns_ioevent(), to have
+  only one entry point for everything?  For traditional
+  select-loop-based eventloop it may be easier, but for
+  callback-driven event loops the two should be separate.
+  Provide an option, or a single dns_events() entry point
+  for select-loop approach, or just call dns_ioevent()
+  from within dns_timeouts() (probably after renaming
+  it to be dns_events()) ?
+
+* implement /etc/hosts lookup too, ala [c-]ares??
+
+* sortlist support?
+
+* windows port?  Oh no please!..  At least, I can't do it myself
+  because of the lack of platform.
+  Ok ok, the Windows port is in progress.  Christian Prahauser
+  from cosy.sbg.ac.at is helping with that.

Added: freeswitch/trunk/libs/udns/debian/changelog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/debian/changelog	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,94 @@
+udns (0.0.9pre) unstable; urgency=low
+
+  * s/EOVERFLOW/ENFILE, partly to make win32 happy
+
+  * several win32 fixes
+
+  * don't use `class' in udns.h, to make C++ happy
+    (thanks Markus Koetter for pointing this out)
+
+  * fixed CNAME handling in dnsget tool.  Another Thank You! goes
+    to Markus Koetter.
+
+  * NAPTR (RFC3403) support, thanks to Mikael Magnusson
+    <mikma at users.sourceforge.net> for this.
+
+  * more Win32 fixes from Mikael Magnusson.  I have to admit
+    I never tried to compile it on Win32.
+
+  * added NOTES file
+
+ -- Michael Tokarev <mjt at corpit.ru>  Wed, 29 Nov 2006 04:16:21 +0300
+
+udns (0.0.8) unstable; urgency=low
+
+  * don't compare sockaddr_in's, but individual parts only
+    (on some OSes, there are additional fields in this structure
+    so memcmp() does not quite work)
+
+  * use dnsc_t instead of unsigned char for DNs everywhere
+
+  * SRV records (rfc2782) parsing, thanks to
+    Thadeu Lima de Souza Cascardo.
+
+  * manpage fixes
+
+ -- Michael Tokarev <mjt at corpit.ru>  Mon, 12 Sep 2005 16:06:45 +0400
+
+udns (0.0.7) unstable; urgency=low
+
+  * added dnsget.1 and rblcheck.1 manpages.
+
+  * internal: use generic list implementation in udns_resolver.c
+
+  * don't assume only backward DN pointers in replies, allow forward
+    pointers too.  This is quite large change, involves changing
+    parsing API all over the places.
+
+  * internal: typedef dnsc_t and dnscc_t for [const] unsigned char, to
+    make function prototypes shorter to better fit on a single line.
+
+  * in parsing routines, verify (assert) that the query type
+    is the one we can handle.
+
+  * recognize names (and resolve them) as nameservers in dnsget.
+
+  * when new request is submitted, don't send it immediately, but
+    add it into the head of the active queue with deadline=0.
+    This will allow us to tweak some query settings before it will
+    be processed.
+    Note API change: removed `now' argument from all dns_submit_*()
+    routines.
+
+  * use single per-context user timer, not per-query.
+    Note API change: different user timer callback
+
+  * add dnsc_salen field -- length of the socket address used
+
+  * fix dns_set_opt(DNS_OPT_FLAGS) which didn't work before
+
+  * allow to set some options for a context wich is open but with no
+    active queries
+
+ -- Michael Tokarev <mjt at corpit.ru>  Thu,  5 May 2005 23:14:29 +0400
+
+udns (0.0.6) unstable; urgency=low
+
+  * 0.0.6 release.
+    ALOT of changes all over.  Keep 'em in CVS logs!
+
+ -- Michael Tokarev <mjt at corpit.ru>  Fri,  8 Apr 2005 19:51:38 +0400
+
+udns (0.0.5) unstable; urgency=low
+
+  * Initial Release.
+  * Provides 3 packages:
+     libudns0 - shared library
+     libudns-dev - development files and static library
+     udns-utils - dnsget, rblcheck
+
+ -- Michael Tokarev <mjt at corpit.ru>  Thu,  7 Apr 2005 00:05:24 +0400
+
+Local variables:
+mode: debian-changelog
+End:

Added: freeswitch/trunk/libs/udns/debian/control
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/debian/control	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,33 @@
+Source: udns
+Priority: optional
+Maintainer: Michael Tokarev <mjt at corpit.ru>
+Build-Depends: debhelper (>= 4.0.0)
+Standards-Version: 3.6.1
+
+Package: libudns0
+Section: lib
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: async-capable DNS stub resolver library
+ libudns0 package provides libudns shared library needed
+ to run programs using it
+
+Package: libudns-dev
+Section: libdev
+Architecture: any
+Depends: libudns0 (= ${Source-Version})
+Description: async-capable DNS stub resolver library, development files
+ This package provides development files needed
+ to build programs using udns library
+
+Package: udns-utils
+Section: net
+Architecture: any
+Depends: ${shlibs:Depends}
+Conflicts: rblcheck
+Description: Several DNS-related utilities built on top of udns library
+ This package includes the following utilities:
+  dnsget - a simple DNS query tool, like `host' or `dig' for usage from
+   a command line, and dnsip, dnsname etc for usage in scripts
+  rblcheck - DNSBL (rbl) checker
+ All the utilities are built using udns library

Added: freeswitch/trunk/libs/udns/debian/copyright
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/debian/copyright	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,24 @@
+This is udns, written and maintained by Michael Tokarev <mjt at corpit.ru>
+
+The original source can always be found at:
+	http://www.corpit.ru/mjt/udns.html
+
+Copyright (C) 2005  Michael Tokarev
+
+  This program is free software; you can 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 package; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.

Added: freeswitch/trunk/libs/udns/debian/rules
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/debian/rules	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,91 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+export DH_COMPAT=4
+
+CFLAGS = -Wall -W -Wmissing-prototypes -g
+CDEFS = -DHAVE_POOL
+
+INSTALL = install
+INSTALL_PROGRAM = $(INSTALL) -p
+INSTALL_DATA = $(INSTALL) -p -m0644
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+	INSTALL_PROGRAM += -s
+endif
+ifeq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+#	CDEFS += -DNDEBUG
+endif
+
+SOVER = 0
+
+configure:	# nothing
+	dh_testdir
+
+build:	build-stamp
+build-stamp:
+	dh_testdir
+	$(MAKE) CFLAGS="$(CFLAGS)" CDEFS="$(CDEFS)" SOVER=$(SOVER) \
+		staticlib sharedlib rblcheck.shared dnsget.shared
+	mv -f rblcheck.shared rblcheck
+	mv -f dnsget.shared dnsget
+	touch $@
+
+clean:
+	dh_testdir
+	rm -f build-stamp
+	$(MAKE) distclean
+	dh_clean
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean
+	dh_installdirs
+	dh_installdocs -A NEWS
+
+# libudns
+	dh_install -plibudns$(SOVER) libudns.so.$(SOVER) usr/lib
+
+# libudns-dev
+	dh_install -plibudns-dev libudns.a libudns.so usr/lib
+	dh_install -plibudns-dev udns.h usr/include
+	dh_installman -plibudns-dev udns.3
+	dh_installdocs -plibudns-dev TODO NOTES
+	dh_installexamples -plibudns-dev ex-rdns.c
+
+# udns-utils
+	dh_installdirs -pudns-utils usr/bin
+	dh_install -pudns-utils dnsget rblcheck usr/bin
+	dh_installman -pudns-utils dnsget.1 rblcheck.1
+
+binary-indep: build install
+
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installchangelogs
+	dh_installdocs
+	dh_strip
+	dh_compress
+	dh_fixperms
+	dh_makeshlibs
+	dh_installdeb
+	dh_shlibdeps -L libudns$(SOVER) -l debian/libudns$(SOVER)/usr/lib
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure

Added: freeswitch/trunk/libs/udns/dnsget.1
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/dnsget.1	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,182 @@
+.\" $Id: dnsget.1,v 1.3 2005/04/20 00:55:34 mjt Exp $
+.\" dnsget manpage
+.\"
+.\" Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+.\" This file is part of UDNS library, an async DNS stub resolver.
+.\"
+.\" This library is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU Lesser General Public
+.\" License as published by the Free Software Foundation; either
+.\" version 2.1 of the License, or (at your option) any later version.
+.\"
+.\" This library is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" Lesser General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU Lesser General Public
+.\" License along with this library, in file named COPYING.LGPL; if not,
+.\" write to the Free Software Foundation, Inc., 59 Temple Place,
+.\" Suite 330, Boston, MA  02111-1307  USA
+
+.TH dnsget 1 "Apr 2005" "User Utilities"
+
+.SH NAME
+dnsget \- DNS lookup utility
+
+.SH SYNOPSYS
+.B dnsget
+.RB [\| \-v \||\| \-q \|]
+.RB [\| \-c
+.IR class \|]
+.RB [\| \-t
+.IR type \|]
+.RB [\| \-o
+.IR option : value \]
+.IR name \|.\|.\|.
+
+.SH DESCRIPTION
+.B dnsget
+is a simple command-line to perform DNS lookups, similar to
+.BR host (1)
+and
+.BR dig (1).
+It is useable for both interactive/debugging scenarious and
+in scripts.
+The program is implemented using
+.BR udns (3)
+library.
+
+.PP
+By default,
+.B dnsget
+produces a human-readable output, similar to
+.RS
+.nf
+alias.example.com. CNAME www.example.com.
+www.example.com. A 192.168.1.1
+www.example.com. MX 10 mx.example.com.
+.fi
+.RE
+which is just sufficient to see how a given name resolves.
+Output format is controllable with
+.B \-v
+and
+.B \-q
+options -- the former increases verbosity level up to printing
+the whole DNS contents of all packets sent and received, which
+is suitable for debugging DNS problems, while the latter reduces
+the level, making output more quiet, up to bare result with no
+error messages, which is good for scripts.
+
+.SH OPTIONS
+
+The following options are recognized by
+.BR dnsget :
+
+.TP
+.B \-v
+produce more detailed output.  More
+.BR \-v 's
+means more details will be produced.  With single
+.BR \-v , dnsget
+will print contents of all received DNS packets (in a readable format),
+while with
+.BR \-vv ,
+it will output all outgoing DNS packets too.
+
+.TP
+.B \-q
+the opposite for \fB\-v\fR -- produce less detailed output.
+With single
+.BR \-q , dnsget
+will only show (decoded) data from final DNS resource records (RR),
+while
+.B \-qq
+also suppresses error messages.
+
+.TP
+\fB\-t \fItype\fR
+request record(s) of the given type \fItype\fR.  By default,
+.B dnsget
+will ask for IPv4 address (A) record, or for PTR record if the
+argument in question is an IPv4 or IPv6 address.  Recognized
+types include A, AAAA, MX, TXT, CNAME, PTR, NS, SOA, ANY and
+others.
+
+.TP
+\fB\-c \fIclass\fR
+request DNS record(s) of the given class \fIclass\fR.  By
+default
+.B dnsget
+uses IN class.  Valid classes include IN, CH, HS, ANY.
+
+.TP
+.B \-a
+(compatibility option).  Equivalent to setting query type to
+.B ANY
+and increasing verbosity level
+.RB ( \-v ).
+
+.TP
+.B \-C
+(planned)
+
+.TP
+.B \-x
+(planned)
+
+.TP
+\fB\-o \fIoption\fR:\fIvalue\fR
+Set resolver option \fIoption\fR to the value \fIvalue\fR
+(may be specified several times).  The same as setting
+.RB $ RES_OPTIONS
+environment variable.  The following options are recognized:
+.RS
+.TP
+\fBtimeout\fR:\fIsec\fR
+Set initial query timeout to \fIsec\fR.
+.TP
+\fBattempts\fR:\fInum\fR
+(re)try every query \fInum\fR times before failing.
+.TP
+\fBudpbuf\fR:\fIbytes\fR
+set DNS UDP buffer size to \fIbytes\fR bytes.  Valid values
+are from 512 to 65535.  If \fIbytes\fR is greather than 512,
+EDNS0 (RFC 2671) extensions will be used.
+.TP
+\fBport\fR:\fInum\fR
+Use given UDP port number \fInum\fR instead of the default port 53 (domain).
+.RE
+
+.TP
+\fB\-n \fInameserver\fR
+Use the given nameserver(s) (may be specified more than once)
+instead of the default.  Using this option has the same same effect as 
+.RB $ NSCACHEIP
+or
+.RB $ NAMESERVERS
+environment variables, with the only difference that only IPv4 addresses
+are recognized for now, and it is possible to specify names (which will
+be resolved using default settings) instead of IP addresses.
+
+.TP
+.B \-h
+print short help and exit.
+
+.SH "RETURN VALUE"
+When all names where resovled successefully,
+.B dnsget
+exits with zero exit status.  If at least one name was not found,
+.B dnsget
+will exit with return code 100.  If some other error occured during
+name resolution, it will exit with code 99.  In case of usage or
+initialization error,
+.B dnsget
+will return 1.
+
+.SH "SEE ALSO"
+.BR host (1)
+.BR dig (1)
+.BR resolv.conf (5)
+.BR udns (3).

Added: freeswitch/trunk/libs/udns/dnsget.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/dnsget.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,709 @@
+/* $Id: dnsget.c,v 1.22 2006/11/29 21:28:49 mjt Exp $
+   simple host/dig-like application using UDNS library
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdarg.h>
+#include <errno.h>
+#include "udns.h"
+
+static char *progname;
+static int verbose = 1;
+static int errors;
+static int notfound;
+
+/* verbosity level:
+ * <0 - bare result
+ *  0 - bare result and error messages
+ *  1 - readable result
+ *  2 - received packet contents and `trying ...' stuff
+ *  3 - sent and received packet contents
+ */
+
+static void die(int errnum, const char *fmt, ...) {
+  va_list ap;
+  fprintf(stderr, "%s: ", progname);
+  va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
+  if (errnum) fprintf(stderr, ": %s\n", strerror(errnum));
+  else putc('\n', stderr);
+  fflush(stderr);
+  exit(1);
+}
+
+struct query {
+  const char *name;		/* original query string */
+  unsigned char *dn;		/* the DN being looked up */
+  enum dns_type qtyp;		/* type of the query */
+};
+
+static void query_free(struct query *q) {
+  free(q->dn);
+  free(q);
+}
+
+static struct query *
+query_new(const char *name, const unsigned char *dn, enum dns_type qtyp) {
+  struct query *q = malloc(sizeof(*q));
+  unsigned l = dns_dnlen(dn);
+  unsigned char *cdn = malloc(l);
+  if (!q || !cdn) die(0, "out of memory");
+  memcpy(cdn, dn, l);
+  q->name = name;
+  q->dn = cdn;
+  q->qtyp = qtyp;
+  return q;
+}
+
+static enum dns_class qcls = DNS_C_IN;
+
+static void
+dnserror(struct query *q, int errnum) {
+  if (verbose >= 0)
+    fprintf(stderr, "%s: unable to lookup %s record for %s: %s\n", progname,
+            dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum));
+  if (errnum == DNS_E_NXDOMAIN || errnum == DNS_E_NODATA)
+    ++notfound;
+  else
+    ++errors;
+  query_free(q);
+}
+
+static const unsigned char *
+printtxt(const unsigned char *c) {
+  unsigned n = *c++;
+  const unsigned char *e = c + n;
+  if (verbose > 0) while(c < e) {
+    if (*c < ' ' || *c >= 127) printf("\\%02x", *c);
+    else if (*c == '\\' || *c == '"') printf("\\%c", *c);
+    else putchar(*c);
+    ++c;
+  }
+  else
+   fwrite(c, n, 1, stdout);
+  return e;
+}
+
+static void
+printhex(const unsigned char *c, const unsigned char *e) {
+  while(c < e)
+    printf("%02x", *c++);
+}
+
+static unsigned char to_b64[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static void
+printb64(const unsigned char *c, const unsigned char *e) {
+  while(c < e) {
+    putchar(to_b64[c[0] >> 2]);
+    if (c+1 < e) {
+      putchar(to_b64[(c[0] & 0x3) << 4 | c[1] >> 4]);
+      if (c+2 < e) {
+        putchar(to_b64[(c[1] & 0xf) << 2 | c[2] >> 6]);
+        putchar(to_b64[c[2] & 0x3f]);
+      }
+      else {
+        putchar(to_b64[(c[1] & 0xf) << 2]);
+	putchar('=');
+	break;
+      }
+    }
+    else {
+      putchar(to_b64[(c[0] & 0x3) << 4]);
+      putchar('=');
+      putchar('=');
+      break;
+    }
+    c += 3;
+  }
+}
+
+static void
+printdate(time_t time) {
+  struct tm *tm = gmtime(&time);
+  printf("%04d%02d%02d%02d%02d%02d",
+    tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+    tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+static void
+printrr(const struct dns_parse *p, struct dns_rr *rr) {
+  const unsigned char *pkt = p->dnsp_pkt;
+  const unsigned char *end = p->dnsp_end;
+  const unsigned char *dptr = rr->dnsrr_dptr;
+  const unsigned char *dend = rr->dnsrr_dend;
+  unsigned char *dn = rr->dnsrr_dn;
+  const unsigned char *c;
+  unsigned n;
+
+  if (verbose > 0) {
+    if (verbose > 1) {
+      if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) {
+        printf(";EDNS0 OPT record (UDPsize: %d): %d bytes\n",
+               rr->dnsrr_cls, rr->dnsrr_dsz);
+        return;
+      }
+      n = printf("%s.", dns_dntosp(rr->dnsrr_dn));
+      printf("%s%u\t%s\t%s\t",
+             n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t",
+             rr->dnsrr_ttl,
+             dns_classname(rr->dnsrr_cls),
+             dns_typename(rr->dnsrr_typ));
+    }
+    else
+      printf("%s. %s ", dns_dntosp(rr->dnsrr_dn), dns_typename(rr->dnsrr_typ));
+  }
+
+  switch(rr->dnsrr_typ) {
+
+  case DNS_T_CNAME:
+  case DNS_T_PTR:
+  case DNS_T_NS:
+  case DNS_T_MB:
+  case DNS_T_MD:
+  case DNS_T_MF:
+  case DNS_T_MG:
+  case DNS_T_MR:
+    if (dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto xperr;
+    printf("%s.", dns_dntosp(dn));
+    break;
+
+  case DNS_T_A:
+    if (rr->dnsrr_dsz != 4) goto xperr;
+    printf("%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]);
+    break;
+
+  case DNS_T_AAAA:
+    if (rr->dnsrr_dsz != 16) goto xperr;
+    printf("%s", inet_ntop(AF_INET6, dptr, (char*)dn, DNS_MAXDN));
+    break;
+
+  case DNS_T_MX:
+    c = dptr + 2;
+    if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
+    printf("%d %s.", dns_get16(dptr), dns_dntosp(dn));
+    break;
+
+  case DNS_T_TXT:
+    /* first verify it */
+    for(c = dptr; c < dend; c += n) {
+      n = *c++;
+      if (c + n > dend) goto xperr;
+    }
+    c = dptr; n = 0;
+    while (c < dend) {
+      if (verbose > 0) printf(n++ ? "\" \"":"\"");
+      c = printtxt(c);
+    }
+    if (verbose > 0) putchar('"');
+    break;
+
+  case DNS_T_HINFO:	/* CPU, OS */
+    c = dptr;
+    n = *c++; if ((c += n) >= dend) goto xperr;
+    n = *c++; if ((c += n) != dend) goto xperr;
+    c = dptr;
+    if (verbose > 0) putchar('"');
+    c = printtxt(c);
+    if (verbose > 0) printf("\" \""); else putchar(' ');
+    printtxt(c);
+    if (verbose > 0) putchar('"');
+    break;
+
+  case DNS_T_WKS:
+    c = dptr;
+    if (dptr + 4 + 2 >= end) goto xperr;
+    printf("%s %d", inet_ntoa(*((struct in_addr*)dptr)), dptr[4]);
+    c = dptr + 5;
+    for (n = 0; c < dend; ++c, n += 8) {
+      if (*c) {
+        unsigned b;
+        for (b = 0; b < 8; ++b)
+          if (*c & (1 << (7-b))) printf(" %d", n + b);
+      }
+    }
+    break;
+
+  case DNS_T_SRV:	/* prio weight port targetDN */
+    c = dptr;
+    c += 2 + 2 + 2;
+    if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
+    c = dptr;
+    printf("%d %d %d %s.",
+           dns_get16(c+0), dns_get16(c+2), dns_get16(c+4),
+           dns_dntosp(dn));
+    break;
+
+  case DNS_T_NAPTR:	/* order pref flags serv regexp repl */
+    c = dptr;
+    c += 4;	/* order, pref */
+    for (n = 0; n < 3; ++n)
+      if (c >= dend) goto xperr;
+      else c += *c + 1;
+    if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
+    c = dptr;
+    printf("%u %u", dns_get16(c+0), dns_get16(c+2));
+    c += 4;
+    for(n = 0; n < 3; ++n) {
+      putchar(' ');
+      if (verbose > 0) putchar('"');
+      c = printtxt(c);
+      if (verbose > 0) putchar('"');
+    } 
+    printf(" %s.", dns_dntosp(dn));
+    break;
+
+  case DNS_T_KEY: /* flags(2) proto(1) algo(1) pubkey */
+    c = dptr;
+    if (c + 2 + 1 + 1 > dend) goto xperr;
+    printf("%d %d %d", dns_get16(c), c[2], c[3]);
+    c += 2 + 1 + 1;
+    if (c < dend) {
+      putchar(' ');
+      printb64(c, dend);
+    }
+    break;
+
+  case DNS_T_SIG:
+    /* type(2) algo(1) labels(1) ottl(4) sexp(4) sinc(4) tag(2) sdn sig */
+    c = dptr;
+    c += 2 + 1 + 1 + 4 + 4 + 4 + 2;
+    if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
+    printf("%d %u %u %u ",
+           dns_get16(dptr), dptr[2], dptr[3], dns_get32(dptr+4));
+    printdate(dns_get32(dptr+8));
+    putchar(' ');
+    printdate(dns_get32(dptr+12));
+    printf(" %d %s. ", dns_get16(dptr+10), dns_dntosp(dn));
+    printb64(c, dend);
+    break;
+
+#if 0	/* unused RR types? */
+  case DNS_T_DS:
+    c = dptr;
+    if (c + 2 + 2 >= dend) goto xperr;
+    printf("%u %u %u ", dns_get16(c), c[2], c[3]);
+    printhex(c + 4, dend);
+    break;
+
+  case DNS_T_NSEC:
+    c = dptr;
+    if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
+    printf("%s.", dns_dntosp(dn));
+    unfinished.
+    break;
+#endif
+
+
+  case DNS_T_SOA:
+    c = dptr;
+    if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
+        dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
+        c + 4*5 != dend)
+      goto xperr;
+    dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
+    printf("%s. ", dns_dntosp(dn));
+    dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
+    printf("%s. ", dns_dntosp(dn));
+    printf("%u %u %u %u %u",
+           dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8),
+           dns_get32(dptr+12), dns_get32(dptr+16));
+    break;
+
+  case DNS_T_MINFO:
+    c = dptr;
+    if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
+        dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
+	c != dend)
+      goto xperr;
+    dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
+    printf("%s. ", dns_dntosp(dn));
+    dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
+    printf("%s.", dns_dntosp(dn));
+    break;
+
+  case DNS_T_NULL:
+  default:
+    printhex(dptr, dend);
+    break;
+  }
+  putchar('\n');
+  return;
+
+xperr:
+  printf("<parse error>\n");
+  ++errors;
+}
+
+static int
+printsection(struct dns_parse *p, int nrr, const char *sname) {
+  struct dns_rr rr;
+  int r;
+  if (!nrr) return 0;
+  if (verbose > 1) printf("\n;; %s section (%d):\n", sname, nrr);
+
+  p->dnsp_rrl = nrr;
+  while((r = dns_nextrr(p, &rr)) > 0)
+    printrr(p, &rr);
+  if (r < 0) printf("<<ERROR>>\n");
+  return r;
+}
+
+/* dbgcb will only be called if verbose > 1 */
+static void
+dbgcb(int code, const struct sockaddr *sa, unsigned slen,
+      const unsigned char *pkt, int r,
+      const struct dns_query *unused_q, void *unused_data) {
+  struct dns_parse p;
+  const unsigned char *cur, *end;
+  int numqd;
+
+  if (code > 0)	{
+    printf(";; trying %s.\n", dns_dntosp(dns_payload(pkt)));
+    printf(";; sending %d bytes query to ", r);
+  }
+  else
+    printf(";; received %d bytes response from ", r);
+  if (sa->sa_family == AF_INET && slen >= sizeof(struct sockaddr_in)) {
+    char buf[4*4];
+    printf("%s port %d\n",
+           inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr,
+                     buf, sizeof(buf)),
+           htons(((struct sockaddr_in*)sa)->sin_port));
+  }
+#ifdef AF_INET6
+  else if (sa->sa_family == AF_INET6 && slen >= sizeof(struct sockaddr_in6)) {
+    char buf[6*5+4*4];
+    printf("%s port %d\n",
+           inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr,
+                     buf, sizeof(buf)),
+           htons(((struct sockaddr_in6*)sa)->sin6_port));
+  }
+#endif
+  else
+    printf("<<unknown socket type %d>>\n", sa->sa_family);
+  if (code > 0 && verbose < 3) {
+    putchar('\n');
+    return;
+  }
+
+  if (code == -2) printf(";; reply from unexpected source\n");
+  if (code == -5) printf(";; reply to a query we didn't sent (or old)\n");
+  if (r < DNS_HSIZE) {
+    printf(";; short packet (%d bytes)\n", r);
+    return;
+  }
+  if (dns_opcode(pkt) != 0)
+    printf(";; unexpected opcode %d\n", dns_opcode(pkt));
+  if (dns_tc(pkt) != 0)
+    printf(";; warning: TC bit set, probably incomplete reply\n");
+
+  printf(";; ->>HEADER<<- opcode: ");
+  switch(dns_opcode(pkt)) {
+  case 0: printf("QUERY"); break;
+  case 1: printf("IQUERY"); break;
+  case 2: printf("STATUS"); break;
+  default: printf("UNKNOWN(%u)", dns_opcode(pkt)); break;
+  }
+  printf(", status: %s, id: %d, size: %d\n;; flags:",
+         dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r);
+  if (dns_qr(pkt)) printf(" qr");
+  if (dns_rd(pkt)) printf(" rd");
+  if (dns_ra(pkt)) printf(" ra");
+  if (dns_aa(pkt)) printf(" aa");
+  if (dns_tc(pkt)) printf(" tc");
+  numqd = dns_numqd(pkt);
+  printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n",
+         numqd, dns_numan(pkt), dns_numns(pkt), dns_numar(pkt));
+  if (numqd != 1)
+    printf(";; unexpected number of entries in QUERY section: %d\n",
+           numqd);
+  printf("\n;; QUERY SECTION (%d):\n", numqd);
+  cur = dns_payload(pkt);
+  end = pkt + r;
+  while(numqd--) {
+    if (dns_getdn(pkt, &cur, end, p.dnsp_dnbuf, DNS_MAXDN) <= 0 ||
+        cur + 4 > end) {
+      printf("; invalid query section\n");
+      return;
+    }
+    r = printf(";%s.", dns_dntosp(p.dnsp_dnbuf));
+    printf("%s%s\t%s\n",
+           r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t",
+           dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur)));
+    cur += 4;
+  }
+
+  p.dnsp_pkt = pkt;
+  p.dnsp_cur = p.dnsp_ans = cur;
+  p.dnsp_end = end;
+  p.dnsp_qdn = NULL;
+  p.dnsp_qcls = p.dnsp_qtyp = 0;
+  p.dnsp_ttl = 0xffffffffu;
+  p.dnsp_nrr = 0;
+
+  r = printsection(&p, dns_numan(pkt), "ANSWER");
+  if (r == 0)
+    r = printsection(&p, dns_numns(pkt), "AUTHORITY");
+  if (r == 0)
+    r = printsection(&p, dns_numar(pkt), "ADDITIONAL");
+  putchar('\n');
+}
+
+static void dnscb(struct dns_ctx *ctx, void *result, void *data) {
+  int r = dns_status(ctx);
+  struct query *q = data;
+  struct dns_parse p;
+  struct dns_rr rr;
+  unsigned nrr;
+  unsigned char dn[DNS_MAXDN];
+  const unsigned char *pkt, *cur, *end;
+  if (!result) {
+    dnserror(q, r);
+    return;
+  }
+  pkt = result; end = pkt + r; cur = dns_payload(pkt);
+  dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+  dns_initparse(&p, NULL, pkt, cur, end);
+  p.dnsp_qcls = p.dnsp_qtyp = 0;
+  nrr = 0;
+  while((r = dns_nextrr(&p, &rr)) > 0) {
+    if (!dns_dnequal(dn, rr.dnsrr_dn)) continue;
+    if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) &&
+        (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
+      ++nrr;
+    else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
+      if (dns_getdn(pkt, &rr.dnsrr_dptr, end,
+                    p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 ||
+          rr.dnsrr_dptr != rr.dnsrr_dend) {
+        r = DNS_E_PROTOCOL;
+        break;
+      }
+      else {
+        if (verbose == 1) {
+          printf("%s.", dns_dntosp(dn));
+          printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf));
+        }
+	dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn));
+      }
+    }
+  }
+  if (!r && !nrr)
+    r = DNS_E_NODATA;
+  if (r < 0) {
+    dnserror(q, r);
+    free(result);
+    return;
+  }
+  if (verbose < 2) {	/* else it is already printed by dbgfn */
+    dns_rewind(&p, NULL);
+    p.dnsp_qtyp = q->qtyp;
+    p.dnsp_qcls = qcls;
+    while(dns_nextrr(&p, &rr))
+      printrr(&p, &rr);
+  }
+  free(result);
+  query_free(q);
+}
+
+int main(int argc, char **argv) {
+  int i;
+  int fd;
+  fd_set fds;
+  struct timeval tv;
+  time_t now;
+  char *ns[DNS_MAXSERV];
+  int nns = 0;
+  struct query *q;
+  enum dns_type qtyp = 0;
+  struct dns_ctx *nctx = NULL;
+
+  if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
+  else argv[0] = ++progname;
+
+  if (argc <= 1)
+    die(0, "try `%s -h' for help", progname);
+
+  if (dns_init(0) < 0 || !(nctx = dns_new(NULL)))
+    die(errno, "unable to initialize dns library");
+  /* we keep two dns contexts: one may be needed to resolve
+   * nameservers if given as names, using default options.
+   */
+
+  while((i = getopt(argc, argv, "vqt:c:an:o:h")) != EOF) switch(i) {
+  case 'v': ++verbose; break;
+  case 'q': --verbose; break;
+  case 't':
+    if (optarg[0] == '*' && !optarg[1])
+      i = DNS_T_ANY;
+    else if ((i = dns_findtypename(optarg)) <= 0)
+      die(0, "unrecognized query type `%s'", optarg);
+    qtyp = i;
+    break;
+  case 'c':
+    if (optarg[0] == '*' && !optarg[1])
+      i = DNS_C_ANY;
+    else if ((i = dns_findclassname(optarg)) < 0)
+      die(0, "unrecognized query class `%s'", optarg);
+    qcls = i;
+    break;
+  case 'a':
+    qtyp = DNS_T_ANY;
+    ++verbose;
+    break;
+  case 'n':
+    if (nns >= DNS_MAXSERV)
+      die(0, "too many nameservers, %d max", DNS_MAXSERV);
+    ns[nns++] = optarg;
+    break;
+  case 'o':
+    if (dns_set_opts(NULL, optarg) != 0)
+      die(0, "invalid option string: `%s'", optarg);
+    break;
+  case 'h':
+    printf(
+"%s: simple DNS query tool (using udns version %s)\n"
+"Usage: %s [options] domain-name...\n"
+"where options are:\n"
+" -h - print this help and exit\n"
+" -v - be more verbose\n"
+" -q - be less verbose\n"
+" -t type - set query type (A, AA, PTR etc)\n"
+" -c class - set query class (IN (default), CH, HS, *)\n"
+" -a - equivalent to -t ANY -v\n"
+" -n ns - use given nameserver(s) instead of default\n"
+"  (may be specified multiple times)\n"
+" -o option:value - set resovler option (the same as setting $RES_OPTIONS):\n"
+"  timeout:sec  - initial query timeout\n"
+"  attempts:num - number of attempt to resovle a query\n"
+"  ndots:num    - if name has more than num dots, lookup it before search\n"
+"  port:num     - port number for queries instead of default 53\n"
+"  udpbuf:num   - size of UDP buffer (use EDNS0 if >512)\n"
+"  (may be specified more than once)\n"
+      , progname, dns_version(), progname);
+    return 0;
+  default:
+    die(0, "try `%s -h' for help", progname);
+  }
+
+  argc -= optind; argv += optind;
+  if (!argc)
+    die(0, "no name(s) to query specified");
+
+  if (nns) {
+    /* if nameservers given as names, resolve them.
+     * We only allow IPv4 nameservers as names for now.
+     * Ok, it is easy enouth to try both AAAA and A,
+     * but the question is what to do by default.
+     */
+    struct sockaddr_in sin;
+    int j, r = 0, opened = 0;
+    memset(&sin, 0, sizeof(sin));
+    sin.sin_family = AF_INET;
+    sin.sin_port = htons(dns_set_opt(NULL, DNS_OPT_PORT, -1));
+    dns_add_serv(NULL, NULL);
+    for(i = 0; i < nns; ++i) {
+      if (!inet_aton(ns[i], &sin.sin_addr)) {
+        struct dns_rr_a4 *rr;
+        if (!opened) {
+          if (dns_open(nctx) < 0)
+            die(errno, "unable to initialize dns context");
+          opened = 1;
+        }
+        rr = dns_resolve_a4(nctx, ns[i], 0);
+        if (!rr)
+          die(0, "unable to resolve nameserver %s: %s",
+              ns[i], dns_strerror(dns_status(nctx)));
+        for(j = 0; j < rr->dnsa4_nrr; ++j) {
+          sin.sin_addr = rr->dnsa4_addr[j];
+          if ((r = dns_add_serv_s(NULL, (struct sockaddr *)&sin)) < 0)
+            break;
+        }
+        free(rr);
+      }
+      else
+        r = dns_add_serv_s(NULL, (struct sockaddr *)&sin);
+      if (r < 0)
+        die(errno, "unable to add nameserver %s", inet_ntoa(sin.sin_addr));
+    }
+  }
+  dns_free(nctx);
+
+  fd = dns_open(NULL);
+  if (fd < 0)
+    die(errno, "unable to initialize dns context");
+
+  if (verbose > 1)
+    dns_set_dbgfn(NULL, dbgcb);
+
+  for (i = 0; i < argc; ++i) {
+    char *name = argv[i];
+    union {
+      struct in_addr addr;
+      struct in6_addr addr6;
+    } a;
+    unsigned char dn[DNS_MAXDN];
+    enum dns_type l_qtyp = 0;
+    int abs;
+    if (inet_pton(AF_INET, name, &a.addr) > 0) {
+      dns_a4todn(&a.addr, 0, dn, sizeof(dn));
+      l_qtyp = DNS_T_PTR;
+      abs = 1;
+    }
+    else if (inet_pton(AF_INET6, name, &a.addr6) > 0) {
+      dns_a6todn(&a.addr6, 0, dn, sizeof(dn));
+      l_qtyp = DNS_T_PTR;
+      abs = 1;
+    }
+    else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs))
+      die(0, "invalid name `%s'\n", name);
+    else
+      l_qtyp = DNS_T_A;
+    if (qtyp) l_qtyp = qtyp;
+    q = query_new(name, dn, l_qtyp);
+    if (abs) abs = DNS_NOSRCH;
+    if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q))
+      dnserror(q, dns_status(NULL));
+  }
+
+  FD_ZERO(&fds);
+  now = 0;
+  while((i = dns_timeouts(NULL, -1, now)) > 0) {
+    FD_SET(fd, &fds);
+    tv.tv_sec = i;
+    tv.tv_usec = 0;
+    i = select(fd+1, &fds, 0, 0, &tv);
+    now = time(NULL);
+    if (i > 0) dns_ioevent(NULL, now);
+  }
+
+  return errors ? 1 : notfound ? 100 : 0;
+}

Added: freeswitch/trunk/libs/udns/ex-rdns.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/ex-rdns.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,111 @@
+/* $Id: ex-rdns.c,v 1.6 2005/05/07 12:21:42 mjt Exp $
+   parallel rDNS resolver example - read IP addresses from stdin,
+   write domain names to stdout
+ 
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include "udns.h"
+
+static int curq;
+
+static const char *n2ip(const unsigned char *c) {
+  static char b[sizeof("255.255.255.255")];
+  sprintf(b, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]);
+  return b;
+}
+static void dnscb(struct dns_ctx *ctx, struct dns_rr_ptr *rr, void *data) {
+  const char *ip = n2ip((unsigned char *)&data);
+  int i;
+  --curq;
+  if (rr) {
+    printf("%s", ip);
+    for(i = 0; i < rr->dnsptr_nrr; ++i)
+      printf(" %s", rr->dnsptr_ptr[i]);
+    putchar('\n');
+    free(rr);
+  }
+  else
+    fprintf(stderr, "%s: %s\n", ip, dns_strerror(dns_status(ctx)));
+}
+
+int main(int argc, char **argv) {
+  int c, t;
+  time_t now;
+  int maxq = 10;
+  struct pollfd pfd;
+  char linebuf[1024];
+  char *eol;
+  int eof;
+
+  if (dns_init(1) < 0) return 1;
+  while((c = getopt(argc, argv, "m:r")) != EOF) switch(c) {
+  case 'm': maxq = atoi(optarg); break;
+  case 'r':
+     dns_set_opt(0, DNS_OPT_FLAGS,
+                 dns_set_opt(0, DNS_OPT_FLAGS, -1) | DNS_NORD);
+     break;
+  default: return 1;
+  }
+  if (argc != optind) return 1;
+
+  pfd.fd = dns_sock(0);
+  pfd.events = POLLIN;
+  now = time(NULL);
+  c = optind;
+  eof = 0;
+  while(curq || !eof) {
+    if (!eof && curq < maxq) {
+      union { struct in_addr a; void *p; } pa;
+      if (!fgets(linebuf, sizeof(linebuf), stdin)) {
+        eof = 1;
+        continue;
+      }
+      eol = strchr(linebuf, '\n');
+      if (eol) *eol = '\0';
+      if (!linebuf[0]) continue;
+      if (!inet_aton(linebuf, &pa.a))
+        fprintf(stderr, "%s: invalid address\n", linebuf);
+      else if (dns_submit_a4ptr(0, &pa.a, dnscb, pa.p) == 0)
+        fprintf(stderr, "%s: unable to submit query: %s\n",
+                linebuf, dns_strerror(dns_status(0)));
+      else
+        ++curq;
+      continue;
+    }
+    if (curq) {
+      t = dns_timeouts(0, -1, now);
+      t = poll(&pfd, 1, c * 1000);
+      now = time(NULL);
+      if (t) dns_ioevent(0, now);
+    }
+  }
+  return 0;
+}

Added: freeswitch/trunk/libs/udns/rblcheck.1
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/rblcheck.1	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,151 @@
+.\" $Id: rblcheck.1,v 1.1 2005/04/24 23:14:23 mjt Exp $
+.\" rblckeck manpage
+.\"
+.\" Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+.\" This file is part of UDNS library, an async DNS stub resolver.
+.\"
+.\" This library is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU Lesser General Public
+.\" License as published by the Free Software Foundation; either
+.\" version 2.1 of the License, or (at your option) any later version.
+.\"
+.\" This library is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" Lesser General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU Lesser General Public
+.\" License along with this library, in file named COPYING.LGPL; if not,
+.\" write to the Free Software Foundation, Inc., 59 Temple Place,
+.\" Suite 330, Boston, MA  02111-1307  USA
+
+.TH rblckeck 1 "Apr 2005" "User Utilities"
+
+.SH NAME
+rblckeck \- DNSBL lookup utility
+
+.SH SYNOPSYS
+.B rblcheck
+.RB [\| \-s
+.IR zone \|]
+.RB [\| \-S
+.IR zone\-file \|]
+.RB [\| \-c \|]
+.RB [\| \-tmvq \|]
+.RB [\| \-n
+.IR nsaddr \|]
+.IR address \|.\|.\|.
+
+.SH DESCRIPTION
+.B rblcheck
+is a simple command-line to perform DNSBL (DNS-based blocklists) lookups.
+For every IP address (or a name, in which case it will be resolved to an
+address first), the utility verifies whenever it is listed in a (list of)
+DNS blocklists specified with
+.B \-s
+or
+.B \-S
+options, optionally obtains text assotiated with the listing (usually it
+is either some description about the reason of the listing or an URL
+referring to such a description), and displays results on standard output.
+.PP
+The program is implemented on top of
+.BR udns (3)
+library.
+
+.SH OPTIONS
+
+The following options are recognized by
+.BR rblcheck :
+
+.TP
+.B \-s \fIzone\fR
+add the given \fIzone\fR DNSBL name to the list of active zones.
+.TP
+.B \-S \fIzone-file\fR
+add list of zones from the named \fIzone-file\fR to the list of
+active zones (the file specifies one zone as the first word on a
+line, empty lines and lines starting with `#' character are ignored).
+.TP
+.B \-c
+reset active zone list.
+.TP
+.B \-v
+be more verbose, produce more detailed output.
+.TP
+.B \-q
+the opposite for \fB\-v\fR -- produce less detailed output.
+.TP
+.B \-t
+obtain text for listed addresses.
+.TP
+.B \-n \fInsaddr\fR
+Use the given nameserver (given as IPv4 or IPv6 address) instead of the
+default.  The same effect may be achieved by setting $NSCACHEIP environment
+variable.
+.TP
+.B \-m
+stop after first hit, ie after the first address which is found to be
+listed.
+
+.TP
+.B \-h
+print short help and exit.
+
+.PP
+If no
+.BR \-s ,
+.BR \-S
+and
+.B \-c
+options are given,
+.B rblcheck
+will try to obtain list of zones using $RBLCHECK_ZONES environment variable,
+or ~/.rblcheckrc, or /etc/rblckechrc files, in that order.  If no zones are
+found, it will exit unsuccessefully.
+
+.SH "RETURN VALUE"
+When no addresses given are listed and no errors occured,
+.B rblcheck
+exits with code 0.  If at least one address is listed,
+.B rblcheck
+returns 100.  In case of DNS errors,
+.B rblcheck
+returns 2.
+
+.SH ENVIRONMENT
+
+.TP
+.B $RBLCHECK_ZONES
+if no
+.BR \-s ,
+.B \-S
+or
+.B \-c
+option is given,
+.B rblcheck
+tries this variable to obtain list of DNSBL zones to check against.
+
+.SH FILES
+
+.TP
+$HOME/.rblcheckrc and /etc/rblcheckrc
+if no
+.BR \-s ,
+.B \-S
+or
+.B \-c
+option is given, and no $RBLCHECK_ZONES environment variable is set,
+.B rblcheck
+will try the two files (the first one that exists) to obtain list of
+DNSBL zones to check against.
+Each line specifies one zone (only first word in each line is used).
+Empty lines and lines starting with `#' character are ignored.
+
+.SH "SEE ALSO"
+.BR dnsget (1)
+.BR resolv.conf (5)
+.BR udns (3).
+
+.SH AUTHOR
+This program and manual pages are written by Michael Tokarev.

Added: freeswitch/trunk/libs/udns/rblcheck.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/rblcheck.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,364 @@
+/* $Id: rblcheck.c,v 1.9 2005/04/24 22:49:10 mjt Exp $
+   dnsbl (rbl) checker application
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+#include "udns.h"
+
+static const char *version = "udns-rblcheck 0.1";
+static char *progname;
+
+struct rblookup {
+  struct ipcheck *parent;
+  struct in_addr key;
+  const char *zone;
+  struct dns_rr_a4  *addr;
+  struct dns_rr_txt *txt;
+};
+
+struct ipcheck {
+  const char *name;
+  int naddr;
+  int listed;
+  struct rblookup *lookup;
+};
+
+#define notlisted ((void*)1)
+
+static int nzones, nzalloc;
+static const char **zones;
+
+static int do_txt;
+static int stopfirst;
+static int verbose = 1;
+/* verbosity level:
+ * <0 - only bare As/TXTs
+ * 0 - what RBL result
+ * 1(default) - what is listed by RBL: result
+ * 2          - what is[not ]listed by RBL: result, name lookups
+ */
+
+static int listed;
+static int failures;
+
+static void *ecalloc(int size, int cnt) {
+  void *t = calloc(size, cnt);
+  if (!t) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    exit(1);
+  }
+  return t;
+}
+
+static void addzone(const char *zone) {
+  if (nzones >= nzalloc) {
+    const char **zs = (const char**)ecalloc(sizeof(char*), (nzalloc += 16));
+    if (zones) {
+      memcpy(zs, zones, nzones * sizeof(char*));
+      free(zones);
+    }
+    zones = zs;
+  }
+  zones[nzones++] = zone;
+}
+
+static int addzonefile(const char *fname) {
+  FILE *f = fopen(fname, "r");
+  char linebuf[2048];
+  if (!f)
+    return 0;
+  while(fgets(linebuf, sizeof(linebuf), f)) {
+    char *p = linebuf, *e;
+    while(*p == ' ' || *p == '\t') ++p;
+    if (*p == '#' || *p == '\n') continue;
+    e = p;
+    while(*e && *e != ' ' && *e != '\t' && *e != '\n')
+      ++e;
+    *e = '\0';
+    addzone(p);
+  }
+  fclose(f);
+  return 1;
+}
+
+static void dnserror(struct rblookup *ipl, const char *what) {
+  fprintf(stderr, "%s: unable to %s for %s (%s): %s\n",
+          progname, what, inet_ntoa(ipl->key), ipl->zone,
+          dns_strerror(dns_status(0)));
+  ++failures;
+}
+
+static void display_result(struct ipcheck *ipc) {
+  int j;
+  struct rblookup *l, *le;
+  if (!ipc->naddr) return;
+  for (l = ipc->lookup, le = l + nzones * ipc->naddr; l < le; ++l) {
+    if (!l->addr) continue;
+    if (verbose < 2 && l->addr == notlisted) continue;
+    if (verbose >= 0) {
+      if (ipc->name) printf("%s[%s]", ipc->name, inet_ntoa(l->key));
+      else printf("%s", inet_ntoa(l->key));
+    }
+    if (l->addr == notlisted) {
+      printf(" is NOT listed by %s\n", l->zone);
+      continue;
+    }
+    else if (verbose >= 1)
+      printf(" is listed by %s: ", l->zone);
+    else if (verbose >= 0)
+      printf(" %s ", l->zone);
+    if (verbose >= 1 || !do_txt)
+      for (j = 0; j < l->addr->dnsa4_nrr; ++j)
+        printf("%s%s", j ? " " : "", inet_ntoa(l->addr->dnsa4_addr[j]));
+    if (!do_txt) ;
+    else if (l->txt) {
+      for(j = 0; j < l->txt->dnstxt_nrr; ++j) {
+        unsigned char *t = l->txt->dnstxt_txt[j].txt;
+        unsigned char *e = t + l->txt->dnstxt_txt[j].len;
+        printf("%s\"", verbose > 0 ? "\n\t" : j ? " " : "");
+        while(t < e) {
+          if (*t < ' ' || *t >= 127) printf("\\x%02x", *t);
+          else if (*t == '\\' || *t == '"') printf("\\%c", *t);
+          else putchar(*t);
+          ++t;
+        }
+        putchar('"');
+      }
+      free(l->txt);
+    }
+    else
+      printf("%s<no text available>", verbose > 0 ? "\n\t" : "");
+    free(l->addr);
+    putchar('\n');
+  }
+  free(ipc->lookup);
+}
+
+static void txtcb(struct dns_ctx *ctx, struct dns_rr_txt *r, void *data) {
+  struct rblookup *ipl = data;
+  if (r) {
+    ipl->txt = r;
+    ++ipl->parent->listed;
+  }
+  else if (dns_status(ctx) != DNS_E_NXDOMAIN)
+    dnserror(ipl, "lookup DNSBL TXT record");
+}
+
+static void a4cb(struct dns_ctx *ctx, struct dns_rr_a4 *r, void *data) {
+  struct rblookup *ipl = data;
+  if (r) {
+    ipl->addr = r;
+    ++listed;
+    if (do_txt) {
+      if (dns_submit_a4dnsbl_txt(0, &ipl->key, ipl->zone, txtcb, ipl))
+        return;
+      dnserror(ipl, "submit DNSBL TXT record");
+    }
+    ++ipl->parent->listed;
+  }
+  else if (dns_status(ctx) != DNS_E_NXDOMAIN)
+    dnserror(ipl, "lookup DNSBL A record");
+  else
+    ipl->addr = notlisted;
+}
+
+static int
+submit_a_queries(struct ipcheck *ipc,
+                 int naddr, const struct in_addr *addr) {
+  int z, a;
+  struct rblookup *rl = ecalloc(sizeof(*rl), nzones * naddr);
+  ipc->lookup = rl;
+  ipc->naddr = naddr;
+  for(a = 0; a < naddr; ++a) {
+    for(z = 0; z < nzones; ++z) {
+      rl->key = addr[a];
+      rl->zone = zones[z];
+      rl->parent = ipc;
+      if (!dns_submit_a4dnsbl(0, &rl->key, rl->zone, a4cb, rl))
+        dnserror(rl, "submit DNSBL A query");
+      ++rl;
+    }
+  }
+  return 0;
+}
+
+static void namecb(struct dns_ctx *ctx, struct dns_rr_a4 *rr, void *data) {
+  struct ipcheck *ipc = data;
+  if (rr) {
+    submit_a_queries(ipc, rr->dnsa4_nrr, rr->dnsa4_addr);
+    free(rr);
+  }
+  else
+    fprintf(stderr, "%s: unable to lookup %s: %s\n",
+            progname, ipc->name, dns_strerror(dns_status(ctx)));
+}
+
+static int submit(struct ipcheck *ipc) {
+  struct in_addr addr;
+  if (inet_aton(ipc->name, &addr)) {
+    submit_a_queries(ipc, 1, &addr);
+    ipc->name = NULL;
+  }
+  else if (!dns_submit_a4(0, ipc->name, 0, namecb, ipc))
+    fprintf(stderr, "%s: unable to submit name query for %s: %s\n",
+            progname, ipc->name, dns_strerror(dns_status(0)));
+  return 0;
+}
+
+static void waitdns(struct ipcheck *ipc) {
+  struct timeval tv;
+  fd_set fds;
+  int c;
+  int fd = dns_sock(NULL);
+  time_t now = 0;
+  FD_ZERO(&fds);
+  while((c = dns_timeouts(NULL, -1, now)) > 0) {
+    FD_SET(fd, &fds);
+    tv.tv_sec = c;
+    tv.tv_usec = 0;
+    c = select(fd+1, &fds, NULL, NULL, &tv);
+    now = time(NULL);
+    if (c > 0)
+      dns_ioevent(NULL, now);
+    if (stopfirst && ipc->listed)
+      break;
+  }
+}
+
+int main(int argc, char **argv) {
+  int c;
+  struct ipcheck ipc;
+  char *nameserver = NULL;
+  int zgiven = 0;
+
+  if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
+  else argv[0] = ++progname;
+
+  while((c = getopt(argc, argv, "hqtvms:S:cn:")) != EOF) switch(c) {
+  case 's': ++zgiven; addzone(optarg); break;
+  case 'S':
+    ++zgiven;
+    if (addzonefile(optarg)) break;
+    fprintf(stderr, "%s: unable to read %s\n", progname, optarg);
+    return 1;
+  case 'c': ++zgiven; nzones = 0; break;
+  case 'q': --verbose; break;
+  case 'v': ++verbose; break;
+  case 't': do_txt = 1; break;
+  case 'n': nameserver = optarg; break;
+  case 'm': ++stopfirst; break;
+  case 'h':
+    printf("%s: %s.\n", progname, version);
+    printf("Usage is: %s [options] address..\n", progname);
+    printf(
+"Where options are:\n"
+" -h - print this help and exit\n"
+" -s service - add the service (DNSBL zone) to the serice list\n"
+" -S service-file - add the DNSBL zone(s) read from the given file\n"
+" -c - clear service list\n"
+" -v - increase verbosity level (more -vs => more verbose)\n"
+" -q - decrease verbosity level (opposite of -v)\n"
+" -t - obtain and print TXT records if any\n"
+" -m - stop checking after first address match in any list\n"
+" -n ipaddr - use the given nameserver instead of the default\n"
+"(if no -s or -S option is given, use $RBLCHECK_ZONES, ~/.rblcheckrc\n"
+"or /etc/rblcheckrc in that order)\n"
+    );
+    return 0;
+  default:
+    fprintf(stderr, "%s: use `%s -h' for help\n", progname, progname);
+    return 1;
+  }
+
+  if (!zgiven) {
+    char *s = getenv("RBLCHECK_ZONES");
+    if (s) {
+      char *k;
+      s = strdup(s);
+      k = strtok(s, " \t");
+      while(k) {
+        addzone(k);
+        k = strtok(NULL, " \t");
+      }
+      free(s);
+    }
+    else {
+      char *path;
+      char *home = getenv("HOME");
+      if (!home) home = ".";
+      path = malloc(strlen(home) + 1 + sizeof(".rblcheckrc"));
+      sprintf(path, "%s/.rblcheckrc", home);
+      if (!addzonefile(path))
+        addzonefile("/etc/rblcheckrc");
+      free(path);
+    }
+  }
+  if (!nzones) {
+    fprintf(stderr, "%s: no service (zone) list specified (-s or -S option)\n",
+            progname);
+    return 1;
+  }
+
+  argv += optind;
+  argc -= optind;
+
+  if (!argc)
+    return 0;
+
+  if (dns_init(0) < 0) {
+    fprintf(stderr, "%s: unable to initialize DNS library: %s\n",
+            progname, strerror(errno));
+    return 1;
+  }
+  if (nameserver) {
+    dns_add_serv(NULL, NULL);
+    if (dns_add_serv(NULL, nameserver) < 0)
+      fprintf(stderr, "%s: unable to use nameserver %s: %s\n",
+              progname, nameserver, strerror(errno));
+  }
+  if (dns_open(NULL) < 0) {
+    fprintf(stderr, "%s: unable to initialize DNS library: %s\n",
+            progname, strerror(errno));
+    return 1;
+  }
+
+  for (c = 0; c < argc; ++c) {
+    if (c && (verbose > 1 || (verbose == 1 && do_txt))) putchar('\n');
+    ipc.name = argv[c];
+    submit(&ipc);
+    waitdns(&ipc);
+    display_result(&ipc);
+    if (stopfirst > 1 && listed) break;
+  }
+
+  return listed ? 100 : failures ? 2 : 0;
+}

Added: freeswitch/trunk/libs/udns/udns.3
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns.3	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,1284 @@
+.\" $Id: udns.3,v 1.26 2006/11/28 22:58:04 mjt Exp $
+.\" udns library manpage
+.\"
+.\" Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+.\" This file is part of UDNS library, an async DNS stub resolver.
+.\"
+.\" This library is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU Lesser General Public
+.\" License as published by the Free Software Foundation; either
+.\" version 2.1 of the License, or (at your option) any later version.
+.\"
+.\" This library is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" Lesser General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU Lesser General Public
+.\" License along with this library, in file named COPYING.LGPL; if not,
+.\" write to the Free Software Foundation, Inc., 59 Temple Place,
+.\" Suite 330, Boston, MA  02111-1307  USA
+
+.TH udns 3 "Apr 2005" "Library Functions"
+
+.SH NAME
+udns \- stub DNS resolver library
+
+.SH SYNOPSYS
+.nf
+#include <udns.h>
+struct \fBdns_ctx\fR;
+struct \fBdns_query\fR;
+extern struct dns_ctx \fBdns_defctx\fR;
+struct dns_ctx *\fIctx\fR;
+typedef void \fBdns_query_fn\fR(\fIctx\fR, void *\fIresult\fR, void *\fIdata\fR);
+typedef int
+\fBdns_parse_fn\fR(const unsigned char *\fIqnd\fR,
+       const unsigned char *\fIpkt\fR,
+       const unsigned char *\fIcur\fR,
+       const unsigned char *\fIend\fR,
+       void **\fIresultp\fR);
+
+\fBcc\fR ... -l\fBudns\fR
+.fi
+
+.SH DESCRIPTION
+
+.PP
+The DNS library, \fBudns\fR, implements thread-safe stub DNS resolver
+functionality, which may be used both traditional, syncronous way
+and asyncronously, with application-supplied event loop.
+
+.PP
+While DNS works with both TCP and UDP, performing UDP query first and
+if the result does not fit in UDP buffer (512 bytes max for original
+DNS protocol), retrying the query over TCP, the library uses UDP only,
+but uses EDNS0 (RFC2671) extensions which allows larger UDP buffers.
+
+.PP
+The library uses single UDP socket to perform all operations even when
+asking multiple nameservers.  This way, it is very simple to use the
+library in asyncronous event-loop applications: an application should
+add only single socket to the set of filedescriptors it monitors for I/O.
+
+.PP
+The library uses two main objects, \fIresolver context\fR of type
+\fBstruct\ dns_ctx\fR, and \fIquery structure\fR of type
+\fBstruct\ dns_query\fR, both are opaque for an application.
+Resolver context holds global information about the resolver,
+such as list of nameservers to use, list of active requests and the like.
+Query objects holds information about a single DNS query in progress and
+are allocated/processed/freed by the library.   Pointer to query structure
+may be treated as an identifier of an in-progress query and may be used
+to cancel the asyncronous query or to wait for it to complete.
+
+.PP
+Asyncronous interface works as follows.  An application initializes
+resolver context, submits any number of queries for it using one of
+supplied \fBdns_submit_\fIXXX\fR() routines (each return the query
+identifier as pointer to query structure), waits for input on the
+UDP socket used by the library, and gives some control to the library
+by calling \fBdns_ioevent\fR() and \fBdns_timeouts\fR() routines when
+appropriate.  The library performs all necessary processing and executes
+application supplied callback routine when a query completes (either
+successefully or not), giving it the result if any, pointer to the
+resolver context (from which completion status may be obtained), and
+the data pointer supplied by an application when the query has been
+submitted.  When submitting a query, an application requests how to
+handle the reply -- to either return raw DNS reply packet for its
+own low-level processing, or it may provide an address of \fIparsing
+routine\fR of type \fBdns_parse_fn\fR to perform conversion of on-wire
+format into easy to use data structure (the library provides parsing
+routines for several commonly used resource record types, as well as
+type-safe higher-level inteface that requests parsing automatically).
+The I/O monitoring and timeout handling may be either traditional
+select() or poll() based, or any callback-driven technique may be
+used.
+
+.PP
+Additionally, the library provides traditional syncronous interface,
+which may be intermixed with asyncronous calls (during syncronous
+query processing, other asyncronous queries for the same resolver
+context continued to be processed as usual).  An application uses
+one of numerous \fBdns_resolve_\fIXXX\fR() routines provided by the
+library to perform a query.  As with asyncronous interface, an
+application may either request to return raw DNS packet or type-specific
+data structure by providing the parsing routine to handle the reply.
+Every routine from \fBdns_resolve_\fIXXX\fR() series return pointer
+to result or NULL in case of any error.  Query completion status
+(or length of the raw DNS packet) is available from the resolver
+context using \fBdns_status\fR() routine, the same way as for the
+asyncronous interface.
+
+.PP
+Internally, library uses on-wire format of domain names, referred
+to as \fIDN format\fR in this manual page.  This is a series of domain
+\fIlabels\fR whith preceeding length byte, terminated by zero-length
+label wich is integral part of the DN format.  There are several routines
+provided to convert from traditional asciiz string to DN and back.
+Higher-level type-specific query interface hides the DN format from
+an application.
+
+.SH "COMMON DEFINITIONS"
+
+.PP
+Every DNS Resource Record (RR) has a \fItype\fR and a \fIclass\fR.
+The library defines several integer constants, \fBDNS_C_\fIXXX\fR and
+\fBDNS_T_\fIXXX\fR, to use as symbolic names for RR classes and types,
+such as \fBDNS_C_IN\fR for Internet class, \fBDNS_T_A\fR for IPv4
+address record type and so on.  See udns.h header file for complete list
+of all such constants.
+
+.PP
+The following constants are defined in dns.h header file:
+.IP "\fBDNS_MAXDN\fR (255 bytes)"
+Maximum length of the domain name in internal (on-wire) DN format.
+.IP "\fBDNS_MAXLABEL\fR (63 bytes)"
+Maximum length of a single label in DN format.
+.IP "\fBDNS_MAXNAME\fR (1024 bytes)"
+Maximum length of asciiz format of a domain name.
+.IP "\fBDNS_HSIZE\fR (12 bytes)"
+Size of header in DNS packet.
+.IP "\fBDNS_PORT\fR (53)"
+Default port to use when contacting a DNS server.
+.IP "\fBDNS_MAXSERV\fR (6 servers)"
+Maximum number of DNS servers to use.
+.IP "\fBDNS_MAXSRCH\fR (5 search list entries)"
+Maximum number of domain search list
+.IP "\fBDNS_MAXPACKET\fR (512 bytes)"
+Maximum length of DNS UDP packet as specified by original DNS protocol
+.IP "\fBDNS_EDNS0PACKET\fR (4096 bytes)"
+Default length of DNS UDP packet (with EDNS0 extensions) the library uses.
+Note that recursive nameservers usually resides near the client asking them
+to resolve names, e.g. on the same LAN segment or even on the same host, so
+UDP packet fragmentation isn't a problem in most cases.  Note also that
+the size of actual packets will be as many bytes as actual reply size requires,
+which is smaller than this value in almost all cases.
+
+.PP
+Additionally, several constants are defined to simplify work with raw DNS
+packets, such as DNS response codes (\fBDNS_R_\fIXXX\fR), DNS header layout
+(\fBDNS_H_\fIXXX\fR) and others.  Again, see udns.h for complete list.
+Library error codes (\fBDNS_E_\fIXXX\fR) are described later in this
+manual page.
+
+.SH "RESOLVER CONTEXT"
+
+.PP
+Resolver context, of type \fBstruct\ dns_ctx\fR, is an object which is
+opaque to an application.  Several routines provided by the library
+to initialize, copy and free resolver contexts.  Most other high-level
+routines in this library expects a pointer to resolver context, \fIctx\fR,
+as the first argument.  There is a default resolver context available,
+named \fBdns_defctx\fR.  When the context pointer \fIctx\fR passed to
+a routine is NULL, \fBdns_defctx\fR is used.  Several resolver contexts
+may be active at the same time, for example, when an application is
+multi-threaded and each thread uses resolver.
+.PP
+When initializing resolver context, the library uses information from
+system file /etc/resolv.conf (see \fBresolv.conf\fR(5)), consults
+environment variables \fB$LOCALDOMAIN\fR, \fB$DNSCACHEIP\fR,
+\fB$NAMESERVERS\fR and \fB$RES_OPTIONS\fR, and local host name to obtain
+list of local nameservers, domain name search list and various resolver
+options.
+.PP
+The following routines to initialize resolver context are available:
+.PP
+.nf
+int \fBdns_init\fR(int \fIdo_open\fR)
+struct dns_ctx *\fBdns_new\fR(struct dns_ctx *\fIcopy\fR)
+void \fBdns_free\fR(\fIctx\fR)
+.fi
+.RS
+\fBdns_init\fR() initializes default resolver context, \fBdns_defctx\fR,
+and optionally opens it (if \fIdo_open\fR is true) using \fBdns_open\fR(),
+returning negative value on error.
+\fBdns_new\fR() makes a copy of a given resolver context \fIcopy\fR, or
+default context if \fIcopy\fR is NULL, and returns pointer to it.
+\fBdns_new\fR() may fail if there's no memory available to make a copy
+of \fIcopy\fR, in which case the routine will return NULL pointer.
+\fBdns_free\fR() is used to close assotiated socket and free resolver
+context resources and cancelling (abandoming) all active queries
+assotiated with it.  It's ok to free \fBdns_defctx\fR as well as
+dynamically allocated contexts returned by \fBdns_new\fR().
+.RE
+.PP
+.nf
+int \fBdns_add_serv\fR(\fIctx\fR, const char *\fIserv\fR)
+int \fBdns_add_serv_s\fR(\fIctx\fR, const struct sockaddr *\fIsa\fR)
+int \fBdns_add_srch\fR(\fIctx\fR, const char *\fIsrch\fR)
+.fi
+.RS
+Add an element to list of nameservers (\fBdns_add_serv\fR(), as
+asciiz-string \fIserv\fR with an IP address of the nameserver,
+and \fBdns_add_serv_s\fR(), as initialized socket address \fIsa\fR),
+or search list (\fBdns_add_srch\fR(), as a pointer to domain name)
+for the given context \fIctx\fR.  If the last argument is a NULL
+pointer, the corresponding list (search or nameserver) is reset
+instead.  Upon successeful completion, each routine returns new
+number of elements in the list in question.  On error, negative
+value is returned and global variable \fBerrno\fR is set appropriately.
+It is an error to call any of this functions if the context is
+opened (after \fBdns_open\fR() or \fBdns_init\fR() with non-zero argument).
+.RE
+.PP
+.nf
+int \fBdns_set_opts\fR(\fIctx\fR, const char *\fIopts\fR)
+.fi
+.RS
+set resolver context options from \fIopts\fR string, in the same way as
+processing \fBoptions\fR statement in resolv.conf and \fB$RES_OPTIONS\fR
+environment variable.
+.RE
+.PP
+.nf
+void \fBdns_set_opt\fR(\fIctx\fR, int \fIopt\fR, \fIval\fR)
+.fi
+.RS
+.B TODO
+The \fIflags\fR argument is a bitmask with the following bits defined:
+.IP \fBDNS_NOSRCH\fR
+do not perform domain name search in search list.
+.IP \fBDNS_NORD\fR
+do not request recursion when performing queries
+(i.e. don't set RD flag in querues).
+.IP \fBDNS_AAONLY\fR
+request authoritative answers only (i.e. set AA
+flag in queries).
+.RE
+
+.PP
+.nf
+int \fBdns_open\fR(\fIctx\fR)
+int \fBdns_sock\fR(const \fIctx\fR)
+void \fBdns_close\fR(\fIctx\fR)
+.fi
+.RS
+\fBdns_open\fR() opens the UDP socket used for queries if not already
+open, and return assotiated filedescriptor (or negative value in case
+of error).
+\fBdns_sock\fR() return the UDP socket if open, or -1 if not.
+\fBdns_close\fR() closes the UDP socket if it was open.
+.RE
+
+.PP
+.nf
+int \fBdns_active\fR(const \fIctx\fR)
+.fi
+.RS
+return number of active queries queued for the given context
+\fIctx\fR, or zero if none.
+.RE
+
+.PP
+.nf
+int \fBdns_status\fR(const \fIctx\fR)
+.fi
+.RS
+return status code from last operation.  When using syncronous
+interface, this is the query completion status of the last query.
+With asyncronous interface, from within the callback routine,
+this is the query completion status of the query for which the
+callback is being called.  When query submission fails, this
+is the error code indicating failure reason.  All error codes
+are negative and are represented by \fBDNS_E_\fIXXX\fR constants
+described below.
+.RE
+
+.PP
+.nf
+void \fBdns_ioevent\fR(\fIctx\fR, time_t \fInow\fR)
+.fi
+.RS
+this routine may be called by an application to process I/O
+events on the UDP socket used by the library, as returned
+by \fBdns_sock\fR().  The routine tries to receive incoming
+UDP datagram from the socket and process it.  The socket is
+set up to be non-blocking, so it is safe to call the routine
+even if there's no data to read.  The routine will process
+as many datagrams as are queued for the socket, so it is
+safe to use it with either level-triggered or edge-triggered
+I/O monitoring model.  The \fInow\fR argument is either a
+current time as returned by \fBtime\fR(), or 0, in which
+case the routine will obtain current time by it's own.
+.RE
+
+.PP
+.nf
+int \fBdns_timeouts\fR(\fIctx\fR, int \fImaxwait\fR, time_t \fInow\fR)
+.fi
+.RS
+process any pending timeouts and return number of secounds
+from current time (\fInow\fR if it is not 0) to the time when
+the library wants the application to pass it control to process
+more queued requests.  In case when there are no requests pending,
+this time is -1.  The routine will not request a time larger than
+\fImaxwait\fR secounds if it is greather or equal to zero.  If
+\fInow\fR is 0, the routine will obtain current time by it's own;
+when it is not 0, it should contain current time as returned by
+\fBtime\fR().
+.RE
+
+.PP
+.nf
+typedef void \fBdns_utm_fn\fR(\fIctx\fR, int \fItimeout\fR, void *\fIdata\fR)
+void \fBdns_set_cbck\fR(\fIctx\fR, dns_utm_fn *\fIutmfn\fR, void *\fIdata\fR)
+.fi
+.RS
+An application may use custom callback-based I/O multiplexing mechanism.
+Usually such a mechanism have concept of a \fItimer\fR, and an ability
+to register a timer event in a form of a callback routine which will
+be executed after certain amount of time.  In order to use such an
+event mechanism, udns provides an ability to register and de-register
+timer events necessary for internal processing using whatever event
+mechanism an application uses.  For this to work, it is possible to
+assotiate a pointer to a routine that will perform necessary work for
+(de)registering timer events with a given resolver context, and
+udns will call that routine at appropriate times.  Prototype of
+such a routine is shown by \fBdns_utm_fn\fR typedef above.  Libudns
+assotiates single timer with resolver context.  User-supplied \fIutmfn\fR
+routine will be called by the library with the following arguments:
+.IP "\fIctx\fR == NULL"
+delete user timer, at context free time or when an application changes
+user timer request routine using \fBdns_set_cbck\fR();
+.IP "\fIctx\fR != NULL, \fItimeout\fR < 0"
+don't fire timer anymore, when there are no active requests;
+.IP "\fIctx\fR != NULL, \fItimeout\fR == 0"
+fire timer at the next possibility, but not immediately;
+.IP "\fIctx\fR != NULL, \fItimeout\fR > 0"
+fire timer after \fItimeout\fR seconds after now.
+.PP
+The \fIdata\fR argument passed to the routine will be the same
+as passed to \fBdns_set_cbck\fR().
+.PP
+When a timer expires, an application should call \fBdns_tmeouts\fR()
+routine (see below).  Non-callback timer usage is provided too.
+.RE
+
+.PP
+.B XXXX TODO: some more resolver context routines, like dns_set_dbgfn() etc.
+
+.SH "QUERY INTERFACE"
+
+.PP
+There are two ways to perform DNS queries: traditional syncronous
+way, when udns performs all the necessary processing and return
+control to the application only when the query completes, and
+asyncronous way, when an application submits one or more queries
+to the library using given resolver context, and waits for completion
+by monitoring filedescriptor used by library and calling library
+routines to process input on that filedescriptor.  Asyncronous mode
+works with callback routines: an application supplies an address of
+a routine to execute when the query completes, and a data pointer,
+which is passed to the callback routine.
+
+.PP
+Queries are submitted to the library in a form of \fBstruct\ dns_query\fR.
+To perform asyncronous query, an application allocates memory for the
+\fIquery structure\fR and passes it to the library using \fBdns_submit\fR()
+routines, together with all the query parameters.  When the query completes,
+library will call application-supplied callback routine, giving it the
+resolver context (wich holds query completion status), dynamically allocated
+result (which will be either raw DNS packet or, if applicatin requested parsing
+the result by specifying non-NULL parse routine, ready-to-use type-specific
+structure), and a data pointer provided by an application when it submitted the
+query.  It is the application who's responsible for freeing the result memory.
+.PP
+Generic query callback routine looks like this:
+.nf
+typedef void
+\fBdns_query_fn\fR(\fIctx\fR, void *\fIresult\fR, void *\fIdata\fR)
+.fi
+Type-specific query interface expects similar form of callback
+routine with the only difference in type of \fBresult\fR argument,
+which will be pointer to specific data structure (decoded reply)
+instead of this void pointer to raw DNS packet data.
+
+.PP
+Result parsing routine looks like this:
+.nf
+typedef int
+\fBdns_parse_fn\fR(const unsigned char *\fIqdn\fR,
+      const unsigned char *\fIpkt\fR,
+      const unsigned char *\fIcur\fR,
+      const unsigned char *\fIend\fR,
+      void **\fIresultp\fR);
+.fi
+When called by the library, the arguments are as follows:
+\fIpkt\fR points to the start of the packet received;
+\fIend\fR points past the end of the packet received;
+\fIcur\fR points past the query DN in the query section of the
+packet;
+\fIqdn\fR points to the original query DN.
+The routine should allocate a single buffer to hold the result,
+parse the reply filling in the buffer, and return the buffer
+using \fIresultp\fR argument.  It returns 0 in case of error,
+or udns error code (\fBDNS_E_\fIXXX\fR constants) in case of
+error.
+Note that by the time when the parse routine is called by the
+library, packet is already verified to be a reply to the
+original query, by matching query DN, query class and query type.
+
+.PP
+Type-specific query inteface supplies necessary parsing routines
+automatically.
+
+.PP
+In case of error, query completion status as returned by
+\fBdns_status\fR(\fIctx\fR), will contain one of the following values:
+.IP "positive value"
+length of raw DNS packet if parsing is not requested.
+.IP 0
+the query was successeful and the \fIreply\fR points to type-specific
+data structure.
+.IP \fBDNS_E_TEMPFAIL\fR
+temporary error, the resolver nameserver was not able to
+process our query or timed out.
+.IP \fBDNS_E_PROTOCOL\fR
+protocol error, a nameserver returned malformed reply.
+.IP \fBDNS_E_NXDOMAIN\fR
+the domain name does not exist.
+.IP \fBDNS_E_NODATA\fR
+there is no data of requested type found.
+.IP \fBDNS_E_NOMEM\fR
+out of memory while processing request.
+.IP \fBDNS_E_BADQUERY\fR
+some aspect of the query (most common is the domain name in question)
+is invalid, and the library can't even start a query.
+
+.PP
+Library provides two series of routines which uses similar interface --
+one for asyncronous queries and another for syncronous queries.  There
+are two general low-level routines in each series to submit (asyncronous
+interface) and resolve (syncronous interface) queries, as well as several
+type-specific routines with more easy-to-use interfaces.  To submit
+an asyncronous query, use one of \fBdns_submit_\fIXXX\fR() routine, each
+of which accepts query parameters, pointers to callback routine and to
+callback data, and optional current time hint.  Note type-specific
+\fBdns_submit_\fIXXX\fR() routines expects specific type of the callback
+routine as well, which accepts reply as a pointer to corresponding
+structure, not a void pointer).  Every \fBdns_submit_\fIXXX\fR() routine
+return pointer to internal query structure of type struct\ dns_query,
+used as an identifier for the given query.
+
+.PP
+To resolve a query syncronously, use one of \fBdns_resolve_\fIXXX\fR()
+routines, which accepts the same query parameters (but not the
+callback pointers) as corresponding \fBdns_submit_\fIXXX\fR(), and
+return the query result, which is the same as passed to the callback
+routine in case of asyncronous interface.
+
+.PP
+In either case, the result memory (if the query completed successefully)
+is dynamically allocated and should be freed by an application.  If
+the query failed for any reason, the result will be NULL, and error
+status will be available from \fBdns_status\fR(\fIctx\fR) routine
+as shown above.
+
+.PP
+.nf
+struct dns_query *
+\fBdns_submit_dn\fR(\fIctx\fR,
+     const unsigned char *\fIdn\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR,
+     \fIparse\fR, \fIcbck\fR, \fIdata\fR)
+struct dns_query *
+\fBdns_submit_p\fR(\fIctx\fR,
+     const char *\fIname\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR,
+     \fIparse\fR, \fIcbck\fR, \fIdata\fR)
+   enum dns_class \fIqcls\fR;
+   enum dns_type \fIqtyp\fR;
+   int \fIflags\fR;
+   dns_parse_fn *\fIparse\fR;
+   dns_query_fn *\fIcbck\fR;
+   void *\fIdata\fR;
+.fi
+.RS
+submit a query for processing for the given resolver context \fIctx\fR.
+Two routines differs only in 3rd argument, which is domain name in
+DN format (\fIdn\fR) or asciiz string (\fIname\fR).  The query will be
+performed for the given domain name, with type \fIqtyp\fR in class \fIqcls\fR,
+using option bits in \fIflags\fR, using RR parsing routine pointed by
+\fIparse\fR if not-NULL, and upon completion, \fIcbck\fR function will
+be called with the \fIdata\fR argument.
+In case of successeful query submission,
+the routine return pointer to internal query structure which may be treated
+as an identifier of the query as used by the library, and may be used as an
+argument for \fBdns_cancel\fR() routine.  In case of error, NULL will be
+returned, and context error status (available using \fIdns_status\fR() routine)
+will be set to corresponding error code, which in this case may be
+DNS_E_BADQUERY if the \fIname\fR of \fIdn\fR is invalid, DNS_E_NOMEM if
+there's no memory available to allocate query structure, or DNS_E_TEMPFAIL
+if an internal error occured.
+.RE
+
+.PP
+.nf
+void *\fBdns_resolve_dn\fR(\fIctx\fR,
+     const unsigned char *\fIdn\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, \fIparse\fR);
+void *\fBdns_resolve_p\fR(\fIctx\fR,
+     const char *\fIname\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, \fIparse\fR)
+   enum dns_class \fIqcls\fR;
+   enum dns_type \fIqtyp\fR;
+   int \fIflags\fR;
+   dns_parse_fn *\fIparse\fR;  
+.fi
+.RS
+syncronous interface.  The routines perform all the steps necessary to resolve
+the given query and return the result.  If there's no positive result for any
+reason, all the routines return NULL, and set context error status (available 
+using \fBdns_status\fR() routine) to indicate the error code.  If the query
+was successeful, context status code will contain either the length of the
+raw DNS reply packet if \fIparse\fR argument was NULL (in which case the return
+value is pointer to the reply DNS packet), or 0 (in which case the return value
+is the result of \fIparse\fR routine).  If the query successeful (return value
+is not NULL), the memory returned was dynamically allocated by the library
+and should be free()d by application after use.
+.RE
+
+.PP
+.nf
+void *\fBdns_resolve\fR(\fIctx\fR, struct dns_query *\fIq\fR)
+.fi
+.RS
+wait for the given query \fIq\fR, as returned by one of
+\fBdns_submit_\fIXXX\fR() routines, for completion, and
+return the result.  The callback routine will not be called
+for this query.  After completion, the query identifier \fIq\fI
+is not valid. Both \fBdns_resolve_dn\fR() and \fBdns_resolve_p\fR()
+are just wrappers around corresponding submit routines and this
+\fBdns_resolve\fR() routine.
+.RE
+
+.PP
+.nf
+void \fBdns_cancel\fR(\fIctx\fR, struct dns_query *\fIq\fR)
+.fi
+.RS
+cancel an active query \fIq\fR, without calling a callback routine.
+After completion, the query identifier \fIq\fR is not valid.
+.RE
+
+.SH "TYPE-SPECIFIC QUERIES"
+
+.PP
+In addition to the generic low-level query interface, the library provides
+a set of routines to perform specific queries in a type-safe manner, as
+well as parsers for several well-known resource record types.  The library
+implements high-level interface for A, AAAA, PTR, MX and TXT records
+and DNSBL and RHSBL functionality.  These routines returns specific types
+as result of a query, instead of raw DNS packets.  The following types
+and routines are available.
+
+.PP
+.nf
+struct \fBdns_rr_null\fR {
+  char *\fBdnsn_qname\fR;     /* original query name */
+  char *\fBdnsn_cname\fR;     /* canonical name */
+  unsigned \fBdnsn_ttl\fR;    /* Time-To-Live (TTL) value */
+  int \fBdnsn_nrr\fR;         /* number of records in the set */
+};
+.fi
+.PP
+NULL RR set, used as a base for all other RR type structures.
+Every RR structure as used by the library have four standard
+fields as in struct\ \fBdns_rr_null\fR.
+
+.SS "IN A Queries"
+.PP
+.nf
+struct \fBdns_rr_a4\fR {       /* IN A RRset */
+  char *\fBdnsa4_qname\fR;     /* original query name */
+  char *\fBdnsa4_cname\fR;     /* canonical name */
+  unsigned \fBdnsa4_ttl\fR;    /* Time-To-Live (TTL) value */
+  int \fBdnsa4_nrr\fR;         /* number of addresses in the set */
+  struct in_addr \fBdnsa4_addr\fR[]; /* array of addresses */
+};
+typedef void
+  \fBdns_query_a4_fn\fR(\fIctx\fR, struct dns_rr_a4 *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_a4\fB;
+struct dns_query *
+\fBdns_submit_a4\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR,
+   dns_query_a4_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_a4 *
+\fBdns_resolve_a4\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_a4\fR structure holds a result of an \fBIN A\fR query,
+which is an array of IPv4 addresses.  Callback routine for IN A queries
+expected to be of type \fBdns_query_a4_fn\fR, which expects pointer to
+\fBdns_rr_a4\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_a4\fR() is used to convert raw DNS reply packet into
+\fBdns_rr_a4\fR structure (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_a4\fR() and
+\fBdns_resolve_a4\fR() are used to perform A IN queries in a type-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).
+
+.SS "IN AAAA Queries"
+.PP
+.nf
+struct \fBdns_rr_a6\fR {       /* IN AAAA RRset */
+  char *\fBdnsa6_qname\fR;     /* original query name */
+  char *\fBdnsa6_cname\fR;     /* canonical name */
+  unsigned \fBdnsa6_ttl\fR;    /* Time-To-Live (TTL) value */
+  int \fBdnsa6_nrr\fR;         /* number of addresses in the set */
+  struct in6_addr \fBdnsa6_addr\fR[]; /* array of addresses */
+};
+typedef void
+  \fBdns_query_a6_fn\fR(\fIctx\fR, struct dns_rr_a6 *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_a6\fB;
+struct dns_query *
+\fBdns_submit_a6\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR,
+   dns_query_a6_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_a6 *
+\fBdns_resolve_a6\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_a6\fR structure holds a result of an \fBIN AAAA\fR query,
+which is an array of IPv6 addresses.  Callback routine for IN AAAA queries
+expected to be of type \fBdns_query_a6_fn\fR, which expects pointer to
+\fBdns_rr_a6\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_a6\fR() is used to convert raw DNS reply packet into
+\fBdns_rr_a6\fR structure (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_a6\fR() and
+\fBdns_resolve_a6\fR() are used to perform AAAA IN queries in a type-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).
+
+.SS "IN PTR Queries"
+.PP
+.nf
+struct \fBdns_rr_ptr\fR {       /* IN PTR RRset */
+  char *\fBdnsptr_qname\fR;     /* original query name */
+  char *\fBdnsptr_cname\fR;     /* canonical name */
+  unsigned \fBdnsptr_ttl\fR;    /* Time-To-Live (TTL) value */
+  int \fBdnsptr_nrr\fR;         /* number of domain name pointers */
+  char *\fBdnsptr_ptr\fR[];     /* array of domain name pointers */
+};
+typedef void
+  \fBdns_query_ptr_fn\fR(\fIctx\fR, struct dns_rr_ptr *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_ptr\fB;
+struct dns_query *
+\fBdns_submit_a4ptr\fB(\fIctx\fR, const struct in_addr *\fBaddr\fR,
+   dns_query_ptr_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_ptr *
+\fBdns_resolve_a4ptr\fB(\fIctx\fR, const struct in_addr *\fBaddr\fR);
+struct dns_query *
+\fBdns_submit_a6ptr\fB(\fIctx\fR, const struct in6_addr *\fBaddr\fR,
+   dns_query_ptr_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_ptr *
+\fBdns_resolve_a6ptr\fB(\fIctx\fR, const struct in6_addr *\fBaddr\fR);
+.fi
+.PP
+The \fBdns_rr_ptr\fR structure holds a result of an IN PTR query, which
+is an array of domain name pointers for a given IPv4 or IPv6 address.
+Callback routine for IN PTR queries expected to be of type
+\fBdns_query_ptr_fn\fR, which expects pointer to \fBdns_rr_ptr\fR
+structure as query result instead of raw DNS packet.  The \fBdns_parse_ptr\fR()
+is used to convert raw DNS reply packet into \fBdns_rr_ptr\fR structure
+(it is used internally and may be used directly too with generic query
+interface).  Routines \fBdns_submit_a4ptr\fR() and \fBdns_resolve_a4ptr\fR()
+are used to perform IN PTR queries for IPv4 addresses in a type-safe
+manner. Routines \fBdns_submit_a6ptr\fR() and \fBdns_resolve_a6ptr\fR()
+are used to perform IN PTR queries for IPv6 addresses.
+
+.SS "IN MX Queries"
+.PP
+.nf
+struct \fBdns_mx\fR {          /* single MX record */
+  int \fBpriority\fR;          /* priority value of this MX */
+  char *\fBname\fR;            /* domain name of this MX */
+};
+struct \fBdns_rr_mx\fR {       /* IN MX RRset */
+  char *\fBdnsmx_qname\fR;     /* original query name */
+  char *\fBdnsmx_cname\fR;     /* canonical name */
+  unsigned \fBdnsmx_ttl\fR;    /* Time-To-Live (TTL) value */
+  int \fBdnsmx_nrr\fR;         /* number of mail exchangers in the set */
+  struct dns_mx \fBdnsmx_mx\fR[]; /* array of mail exchangers */
+};
+typedef void
+  \fBdns_query_mx_fn\fR(\fIctx\fR, struct dns_rr_mx *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_mx\fB;
+struct dns_query *
+\fBdns_submit_mx\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR,
+   dns_query_mx_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_mx *
+\fBdns_resolve_mx\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_mx\fR structure holds a result of an IN MX query, which
+is an array of mail exchangers for a given domain.  Callback routine for IN MX
+queries expected to be of type \fBdns_query_mx_fn\fR, which expects pointer to
+\fBdns_rr_mx\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_mx\fR() is used to convert raw DNS reply packet into
+\fBdns_rr_mx\fR structure (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_mx\fR() and
+\fBdns_resolve_mx\fR() are used to perform IN MX queries in a type-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).
+
+.SS "TXT Queries"
+.PP
+.nf
+struct \fBdns_txt\fR {          /* single TXT record */
+  int \fBlen\fR;                /* length of the text */
+  unsigned char *\fBtxt\fR;     /* pointer to the text */
+};
+struct \fBdns_rr_txt\fR {       /* TXT RRset */
+  char *\fBdnstxt_qname\fR;     /* original query name */
+  char *\fBdnstxt_cname\fR;     /* canonical name */
+  unsigned \fBdnstxt_ttl\fR;    /* Time-To-Live (TTL) value */
+  int \fBdnstxt_nrr\fR;         /* number of text records in the set */
+  struct dns_txt \fBdnstxt_txt\fR[]; /* array of TXT records */
+};
+typedef void
+  \fBdns_query_txt_fn\fR(\fIctx\fR, struct dns_rr_txt *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_txt\fB;
+struct dns_query *
+\fBdns_submit_txt\fB(\fIctx\fR, const char *\fIname\fR, enum dns_class \fIqcls\fR,
+   int \fIflags\fR, dns_query_txt_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_txt *
+\fBdns_resolve_txt\fB(\fIctx\fR, const char *\fIname\fR,
+             enum dns_class \fIqcls\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_txt\fR structure holds a result of a TXT query, which is an
+array of text records for a given domain name.  Callback routine for TXT
+queries expected to be of type \fBdns_query_txt_fn\fR, which expects pointer
+to \fBdns_rr_txt\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_txt\fR() is used to convert raw DNS reply packet into
+\fBdns_rr_txt\fR structure (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_txt\fR() and
+\fBdns_resolve_txt\fR() are used to perform IN MX queries in a type-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).  Note that each TXT string
+is represented by \fBstruct\ dns_txt\fR, while zero-terminated (and the
+len field of the structure does not include the terminator), may contain
+embedded null characters -- content of TXT records is not interpreted
+by the library in any way.
+
+.SS "SRV Queries"
+.PP
+.nf
+struct \fBdns_srv\fR {          /* single SRV record */
+  int \fBpriority\fR;           /* priority of the record */
+  int \fBweight\fR;             /* weight of the record */
+  int \fBport\fR;               /* the port number to connect to */
+  char *\fBname\fR;             /* target host name */
+};
+struct \fBdns_rr_srv\fR {       /* SRV RRset */
+  char *\fBdnssrv_qname\fR;     /* original query name */
+  char *\fBdnssrv_cname\fR;     /* canonical name */
+  unsigned \fBdnssrv_ttl\fR;    /* Time-To-Live (TTL) value */
+  int \fBdnssrv_nrr\fR;         /* number of text records in the set */
+  struct dns_srv \fBdnssrv_srv\fR[]; /* array of SRV records */
+};
+typedef void
+  \fBdns_query_srv_fn\fR(\fIctx\fR, struct dns_rr_srv *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_srv\fB;
+struct dns_query *
+\fBdns_submit_srv\fB(\fIctx\fR, const char *\fIname\fR, const char *\fIservice\fR, const char *\fIprotocol\fR,
+   int \fIflags\fR, dns_query_txt_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_srv *
+\fBdns_resolve_srv\fB(\fIctx\fR, const char *\fIname\fR, const char *\fIservice\fR, const char *\fIprotocol\fR,
+             int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_srv\fR structure holds a result of an IN SRV (rfc2782) query,
+which is an array of servers (together with port numbers) which are performing
+operations for a given \fIservice\fR using given \fIprotocol\fR on a target
+domain \fIname\fR.  Callback routine for IN SRV queries expected to be of type
+\fBdns_query_srv_fn\fR, which expects pointer to \fBdns_rr_srv\fR structure as
+query result instead of raw DNS packet.  The \fBdns_parse_srv\fR() is used to
+convert raw DNS reply packet into \fBdns_rr_srv\fR structure (it is used
+internally and may be used directly too with generic query interface).
+Routines \fBdns_submit_srv\fR() and \fBdns_resolve_srv\fR() are used to
+perform IN SRV queries in a type-safe manner.  The \fIname\fR parameter
+is the domain name in question, \fIservice\fR and \fRprotocl\fR specifies the
+service and the protocol in question (the library will construct query DN
+according to rfc2782 rules) and may be NULL (in this case the library
+assumes \fIname\fR parameter holds the complete SRV query), and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).
+
+.SS "NAPTR Queries"
+.PP
+.nf
+struct \fBdns_naptr\fR {        /* single NAPTR record */
+  int \fBorder\fR;              /* record order */
+  int \fBpreference\fR;         /* preference of this record */
+  char *\fBflags\fR;            /* application-specific flags */
+  char *\fBservices\fR;         /* service parameters */
+  char *\fBregexp\fR;           /* substitutional regular expression */
+  char *\fBreplacement\fR;      /* replacement string */
+};
+struct \fBdns_rr_naptr\fR {     /* NAPTR RRset */
+  char *\fBdnsnaptr_qname\fR;   /* original query name */
+  char *\fBdnsnaptr_cname\fR;   /* canonical name */
+  unsigned \fBdnsnaptr_ttl\fR;  /* Time-To-Live (TTL) value */
+  int \fBdnsnaptr_nrr\fR;       /* number of text records in the set */
+  struct dns_naptr \fBdnsnaptr_naptr\fR[]; /* array of NAPTR records */
+};
+typedef void
+  \fBdns_query_naptr_fn\fR(\fIctx\fR, struct dns_rr_naptr *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_naptr\fB;
+struct dns_query *
+\fBdns_submit_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR,
+   dns_query_txt_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_naptr *
+\fBdns_resolve_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_naptr\fR structure holds a result of an IN NAPTR (rfc3403) query.
+Callback routine for IN NAPTR queries expected to be of type
+\fBdns_query_naptr_fn\fR, expects pointer to \fBdns_rr_naptr\fR
+structure as query result instead of raw DNS packet.
+The \fBdns_parse_naptr\fR() is used to convert raw DNS reply packet into
+\fBdns_rr_naptr\fR structure (it is used
+internally and may be used directly too with generic query interface).
+Routines \fBdns_submit_naptr\fR() and \fBdns_resolve_naptr\fR() are used to
+perform IN NAPTR queries in a type-safe manner.  The \fIname\fR parameter
+is the domain name in question, and \fIflags\fR is query flags bitmask,
+with one bit, DNS_NOSRCH, of practical interest (if the \fIname\fR is
+absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set
+automatically).
+
+.SS "DNSBL Interface"
+.PP
+A DNS-based blocklists, or a DNSBLs, are in wide use nowadays, especially
+to protect mailservers from spammers.  The library provides DNSBL interface,
+a set of routines to perform queries against DNSBLs.  Routines accepts an
+IP address (IPv4 and IPv6 are both supported) and a base DNSBL zone as
+query parameters, and returns either \fBdns_rr_a4\fR or \fBdns_rr_txt\fR
+structure.  Note that IPv6 interface return IPv4 RRset.
+.PP
+.nf
+struct dns_query *
+\fBdns_submit_a4dnsbl\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR);
+struct dns_query *
+\fBdns_submit_a4dnsbl_txt\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR);
+struct dns_query *
+\fBdns_submit_a6dnsbl\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR);
+struct dns_query *
+\fBdns_submit_a6dnsbl_txt\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR);
+struct dns_rr_a4 *\fBdns_resolve_a4dnsbl\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+struct dns_rr_txt *\fBdns_resolve_a4dnsbl_txt\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+struct dns_rr_a4 *\fBdns_resolve_a6dnsbl\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+struct dns_rr_txt *\fBdns_resolve_a6dnsbl_txt\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+.fi
+Perform (submit or resolve) a DNSBL query for the given \fIdnsbl\fR
+domain and an IP \fIaddr\fR in question, requesting either A or TXT
+records.
+
+.SS "RHSBL Interface"
+.PP
+RHSBL is similar to DNSBL, but instead of an IP address, the
+parameter is a domain name.
+.PP
+.nf
+struct dns_query *
+\fBdns_submit_rhsbl\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR,
+  dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR);
+struct dns_query *
+\fBdns_submit_rhsbl_txt\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR,
+  dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR);
+struct dns_rr_a4 *
+\fBdns_resolve_rhsbl\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR);
+struct dns_rr_txt *
+\fBdns_resolve_rhsbl_txt\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR);
+.fi
+Perform (submit or resolve) a RHSBL query for the given \fIrhsbl\fR
+domain and \fIname\fR in question, requesting either A or TXT records.
+
+
+.SH "LOW-LEVEL INTERFACE"
+
+.SS "Domain Names (DNs)"
+
+.PP
+A DN is a series of domain name labels each starts with length byte,
+followed by empty label (label with zero length).  The following
+routines to work with DNs are provided.
+
+.PP
+.nf
+unsigned \fBdns_dnlen\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+return length of the domain name \fIdn\fR, including the terminating label.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dnlabels\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+return number of non-zero labels in domain name \fIdn\fR.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dnequal\fR(\fIdn1\fR, \fIdn2\fR)
+  const unsigned char *\fIdn1\fR, *\fIdn2\fR;
+.fi
+.RS
+test whenever the two domain names, \fIdn1\fR and \fIdn2\fR, are
+equal (case-insensitive).  Return domain name length if equal
+or 0 if not.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dntodn\fR(\fIsdn\fR, \fIddn\fR, \fIdnsiz\fR)
+  const unsigned char *\fIsdn\fR;
+  unsigned char *\fIddn\fR;
+  unsigned \fIdnsiz\fR;
+.fi
+.RS
+copies the source domain name \fIsdn\fR to destination buffer \fIddn\fR
+of size \fIdnsiz\fR.  Return domain name length or 0 if \fIddn\fR is
+too small.
+.RE
+
+.PP
+.nf
+int \fBdns_ptodn\fR(\fIname\fR, \fInamelen\fR, \fIdn\fR, \fIdnsiz\fR, \fIisabs\fR)
+int \fBdns_sptodn\fR(\fIname\fR, \fIdn\fR, \fIdnsiz\fR)
+  const char *\fIname\fR; unsigned \fInamelen\fR;
+  unsigned char *\fIdn\fR; unsigned \fIdnsiz\fR;
+  int *\fIisabs\fR;
+.fi
+.RS
+convert asciiz name \fIname\fR of length \fInamelen\fR to DN format,
+placing result into buffer \fIdn\fR of size \fIdnsiz\fR.  Return
+length of the DN if successeful, 0 if the \fIdn\fR buffer supplied is
+too small, or negative value if \fIname\fR is invalid.  If \fIisabs\fR
+is non-NULL and conversion was successeful, *\fIisabs\fR will be set to
+either 1 or 0 depending whenever \fIname\fR was absolute (i.e. ending with
+a dot) or not.  Name length, \fInamelength\fR, may be zero, in which case
+strlen(\fIname\fR) will be used.  Second form, \fBdns_sptodn\fR(), is a
+simplified form of \fBdns_ptodn\fR(), equivalent to
+.br
+.nf
+\fBdns_ptodn\fR(\fIname\fR, 0, \fIdn\fR, \fIdnlen\fR, 0).
+.fi
+.RE
+
+.PP
+.nf
+extern const unsigned char \fBdns_inaddr_arpa_dn\fR[]
+int \fBdns_a4todn\fR(const struct in_addr *\fIaddr\fR, const unsigned char *\fItdn\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+int \fBdns_a4ptodn\fR(const struct in_addr *\fIaddr\fR, const char *\fItname\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+extern const unsigned char \fBdns_ip6_arpa_dn\fR[]
+int \fBdns_a6todn\fR(const struct in6_addr *\fIaddr\fR, const unsigned char *\fItdn\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+int \fBdns_a6ptodn\fR(const struct in6_addr *\fIaddr\fR, const char *\fItname\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+.fi
+.RS
+several variants of routines to convert IPv4 and IPv6 address \fIaddr\fR
+into reverseDNS-like domain name in DN format, storing result in \fIdn\fR
+of size \fIdnsiz\fR.  \fItdn\fR (or \fItname\fR) is the base zone name,
+like in-addr.arpa for IPv4 or in6.arpa for IPv6.  If \fItdn\fR (or \fItname\fR)
+is NULL, \fBdns_inaddr_arpa_dn\fR (or \fBdns_ip6_arpa_dn\fR) will be used.
+The routines may be used to construct a DN for a DNSBL lookup for example.
+All routines return length of the resulting DN on success, -1 if resulting
+DN is invalid, or 0 if the \fIdn\fR buffer (\fIdnsiz\fR) is too small.
+To hold standard rDNS DN, a buffer of size \fBDNS_A4RSIZE\fR (30 bytes) for
+IPv4 address, or \fBDNS_A6RSIZE\fR (74 bytes) for IPv6 address, is sufficient.
+.RE
+
+.PP
+.nf
+int \fBdns_dntop\fR(\fIdn\fR, \fIname\fR, \fInamesiz\fR)
+   const unsigned char *\fIdn\fR;
+   const char *\fIname\fR; unsigned \fInamesiz\fR;
+.fi
+.RS
+convert domain name \fIdn\fR in DN format to asciiz string, placing result
+into \fIname\fR buffer of size \fInamesiz\fR.  Maximum length of asciiz
+representation of domain name is \fBDNS_MAXNAME\fR (1024) bytes.  Root
+domain is represented as empty string.  Return length of the resulting name
+(including terminating character, i.e. strlen(name)+1) on success, 0 if the
+\fIname\fR buffer is too small, or negative value if \fIdn\fR is invalid
+(last case should never happen since all routines in this library which
+produce domain names ensure the DNs generated are valid).
+.RE
+
+.PP
+.nf
+const char *\fBdns_dntosp\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+convert domain name \fIdn\fR in DN format to asciiz string using static
+buffer.  Return the resulting asciiz string on success or NULL on failure.
+Note since this routine uses static buffer, it is not thread-safe.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dntop_size\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+return the buffer size needed to convert the \fIdn\fR domain name
+in DN format to asciiz string, for \fBdns_dntop\fR().  The routine
+return either the size of buffer required, including the trailing
+zero byte, or 0 if \fIdn\fR is invalid.
+.RE
+
+.SS "Working with DNS Packets"
+
+.PP
+The following routines are provided to encode and decode DNS on-wire
+packets.  This is low-level interface.
+
+.PP
+DNS response codes (returned by \fBdns_rcode\fR() routine) are
+defined as constants prefixed with \fBDNS_R_\fR.  See dns.h
+header file for the complete list.  In particular, constants
+\fBDNS_R_NOERROR\fR (0), \fBDNS_R_SERVFAIL\fR, \fBDNS_R_NXDOMAIN\fR
+may be of interest to an application.
+
+.PP
+.nf
+unsigned \fBdns_get16\fR(const unsigned char *\fIp\fR)
+unsigned \fBdns_get32\fR(const unsigned char *\fIp\fR)
+.fi
+.RS
+helper routines, convert 16-bit or 32-bit integer in on-wire
+format pointed to by \fIp\fR to unsigned.
+.RE
+
+.PP
+.nf
+unsigned char *\fBdns_put16\fR(unsigned char *\fId\fR, unsigned \fIn\fR)
+unsigned char *\fBdns_put32\fR(unsigned char *\fId\fR, unsigned \fIn\fR)
+.fi
+.RS
+helper routine, convert unsigned 16-bit or 32-bit integer \fIn\fR to
+on-wire format to buffer pointed to by \fId\fR, return \fId\fR+2 or
+\fId\fR+4.
+.RE
+
+.PP
+.nf
+\fBDNS_HSIZE\fR (12)
+.fi
+.RS
+defines size of DNS header.  Data section
+in the DNS packet immediately follows the header.  In the header,
+there are query identifier (id), various flags and codes,
+and number of resource records in various data sections.
+See dns.h header file for complete list of DNS header definitions.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_qid\fR(const unsigned char *\fIpkt\fR)
+int \fBdns_rd\fR(const unsigned char *\fIpkt\fR)
+int \fBdns_tc\fR(const unsigned char *\fIpkt\fR)
+int \fBdns_aa\fR(const unsigned char *\fIpkt\fR)
+int \fBdns_qr\fR(const unsigned char *\fIpkt\fR)
+int \fBdns_ra\fR(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_opcode\fR(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_rcode\fR(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numqd\fR(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numan\fR(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numns\fR(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numar\fR(const unsigned char *\fIpkt\fR)
+const unsigned char *\fBdns_payload\fR(const unsigned char *\fIpkt\fR)
+.fi
+.RS
+return various parts from the DNS packet header \fIpkt\fR:
+query identifier (qid),
+recursion desired (rd) flag,
+truncation occured (tc) flag,
+authoritative answer (aa) flag,
+query response (qr) flag,
+recursion available (ra) flag,
+operation code (opcode),
+result code (rcode),
+number of entries in question section (numqd),
+number of answers (numan),
+number of authority records (numns),
+number of additional records (numar),
+and the pointer to the packet data (payload).
+.RE
+
+.PP
+.nf
+int \fBdns_getdn\fR(\fIpkt\fR, \fIcurp\fR, \fIpkte\fR, \fIdn\fR, \fIdnsiz\fR)
+const unsigned char *\fBdns_skipdn\fR(\fIcur\fR, \fIpkte\fR)
+   const unsigned char *\fIpkt\fR, *\fIpkte\fR, **\fIcurp\fR, *\fIcur\fR;
+   unsigned char *\fIdn\fR; unsigned \fIdnsiz\fR;
+.fi
+.RS
+\fBdns_getdn\fR() extract DN from DNS packet \fIpkt\fR which ends before
+\fIpkte\fR starting at position *\fIcurp\fR into buffer pointed to by
+\fIdn\fR of size \fIdnsiz\fR.  Upon successeful completion, *\fIcurp\fR
+will point to the next byte in the packet after the extracted domain name.
+It return positive number (length of the DN if \fIdn\fR) upon successeful
+completion, negative value on error (when the packet contains invalid data),
+or zero if the \fIdnsiz\fR is too small (maximum length of a domain name is
+\fBDNS_MAXDN\fR).  \fBdns_skipdn\fR() return pointer to the next byte in
+DNS packet which ends up before \fIpkte\fR after a domain name which starts
+at the \fIcur\fP byte, or NULL if the packet is invalid.  \fBdns_skipdn\fR()
+is more or less equivalent to what \fBdns_getdn\fR() does, except it does not
+actually extract the domain name in question, and uses simpler interface.
+.RE
+
+.PP
+.nf
+struct \fBdns_rr\fR {
+  unsigned char \fBdnsrr_dn\fR[DNS_MAXDN]; /* the RR DN name */
+  enum dns_class \fBdnsrr_cls\fR;          /* class of the RR */
+  enum dns_type  \fBdnsrr_typ\fR;          /* type of the RR */
+  unsigned \fBdnsrr_ttl\fR;                /* TTL value */
+  unsigned \fBdnsrr_dsz\fR;                /* size of data in bytes */
+  const unsigned char *\fBdnsrr_dptr\fR;   /* pointer to the first data byte */
+  const unsigned char *\fBdnsrr_dend\fR;   /* next byte after RR */
+};
+.fi
+.RS
+The \fBdns_rr\fR structure is used to hold information about
+single DNS Resource Record (RR) in an easy to use form.
+.RE
+
+.PP
+.nf
+struct \fBdns_parse\fR {
+  const unsigned char *\fBdnsp_pkt\fR; /* pointer to the packet being parsed */
+  const unsigned char *\fBdnsp_end\fR; /* end of the packet pointer */
+  const unsigned char *\fBdnsp_cur\fR; /* current packet positionn */
+  const unsigned char *\fBdnsp_ans\fR; /* pointer to the answer section */
+  int \fBdnsp_rrl\fR;                  /* number of RRs left */
+  int \fBdnsp_nrr\fR;                  /* number of relevant RRs seen so far */
+  unsigned \fBdnsp_ttl\fR;             /* TTL value so far */
+  const unsigned char *\fBdnsp_qdn\fR; /* the domain of interest or NULL */
+  enum dns_class \fBdnsp_qcls\fR;      /* class of interest or 0 for any */
+  enum dns_type  \fBdnsp_qtyp\fR;      /* type of interest or 0 for any */
+  unsigned char \fBdnsp_dnbuf\fR[DNS_MAXDN]; /* domain name buffer */
+};
+.fi
+.RS
+The \fBdns_parse\fR structure is used to parse DNS reply packet.
+It holds information about the packet being parsed (dnsp_pkt, dnsp_end and
+dnsp_cur fields), number of RRs in the current section left to do, and
+the information about specific RR which we're looking for (dnsp_qdn,
+dnsp_qcls and dnsp_qtyp fields).
+.RE
+
+.PP
+.nf
+int \fBdns_initparse\fR(struct dns_parse *\fIp\fR,
+  const unsigned char *\fIqdn\fR,
+  const unsigned char *\fIpkt\fR,
+  const unsigned char *\fIcur\fR,
+  const unsigned char *\fIend\fR)
+.fi
+.RS
+initializes the RR parsing structure \fIp\fR.  Arguments \fIpkt\fR, \fIcur\fR
+and \fIend\fR should describe the received packet: \fIpkt\fR is the start of
+the packet, \fIend\fR points to the next byte after the end of the packet,
+and \fIcur\fR points past the query DN in query section (to query class+type
+information).  And \fIqdn\fR points to the query DN.  This is the arguments
+passed to \fBdns_parse_fn\fR() routine. \fBdns_initparse\fR() initializes
+\fBdnsp_pkt\fR, \fBdnsp_end\fR and \fBdnsp_qdn\fR fields to the corresponding
+arguments, extracts and initializes \fBdnsp_qcls\fR and \fBdnsp_qtyp\fR
+fields to the values found at \fIcur\fR pointer, initializes
+\fBdnsp_cur\fR and \fBdnsp_ans\fR fields to be \fIcur\fR+4 (to the start of
+answer section), and initializes \fBdnsp_rrl\fR field to be number of entries
+in answer section. \fBdnsp_ttl\fR will be set to max TTL value, 0xffffffff,
+and \fBdnsp_nrr\fR to 0.
+.RE
+
+.PP
+.nf
+int \fBdns_nextrr\fR(struct dns_parse *\fIp\fR, struct dns_rr *\fIrr\fR);
+.fi
+.RS
+searches for next RR in the packet based on the criteria provided in
+the \fIp\fR structure, filling in the \fIrr\fR structure and
+advancing \fIp\fR->\fBdnsp_cur\fR to the next RR in the packet.
+RR selection is based on dnsp_qdn, dnsp_qcls and dnsp_qtyp fields in
+the dns_parse structure.  Any (or all) of the 3 fields may be 0,
+which means any actual value from the packet is acceptable.  In case
+the field isn't 0 (or NULL for dnsp_qdn), only RRs with corresponding
+characteristics are acceptable.  Additionally, when dnsp_qdn is non-NULL,
+\fBdns_nextrr\fR() performs automatic CNAME expansion.
+Routine will return positive value on success, 0 in case it reached the end
+of current section in the packet (\fIp\fR->\fBdnsp_rrl\fR is zero), or
+negative value if next RR can not be decoded (packet format is invalid).
+The routine updates \fIp\fR->\fBdnsp_qdn\fR automatically when this
+field is non-NULL and it encounters appropriate CNAME RRs (saving CNAME
+target in \fIp\fR->\fBdnsp_dnbuf\fR), so after end of the process,
+\fIp\fR->\fBdnsp_qdn\fR will point to canonical name of the domain
+in question.  The routine updates \fIp\fR->\fBdnsp_ttl\fR value to
+be the minimum TTL of all RRs found.
+.RE
+
+.PP
+.nf
+void \fBdns_rewind\fR(struct dns_parse *\fIp\fR, const unsigned char *\fIqdn\fR)
+.fi
+.RS
+this routine "rewinds" the packet parse state structure to be at the
+same state as after a call to \fBdns_initparse\fR(), i.e. reposition
+the parse structure \fIp\fR to the start of answer section and
+initialize \fIp\fR->\fBdnsp_rrl\fR to the number of entries in
+answer section.
+.RE
+
+.PP
+.nf
+int \fBdns_stdrr_size\fR(const struct dns_parse *\fIp\fR);
+.fi
+.RS
+return size to hold standard RRset structure information, as shown
+in \fBdns_rr_null\fR structure (for the query and canonical
+names).  Used to calculate amount of memory to allocate for common
+part of type-specific RR structures in parsing routines.
+.RE
+
+.PP
+.nf
+void *\fBdns_stdrr_finish\fR(struct dns_rr_null *\fIret\fR, char *\fIcp\fR,
+  const struct dns_parse *\fIp\fR);
+.fi
+.RS
+initializes standard RRset fields in \fIret\fR structure using buffer
+pointed to by \fIcp\fR, which should have at least as many bytes
+as \fBdns_stdrr_size\fR(\fIp\fR) returned.  Used to finalize common
+part of type-specific RR structures in parsing routines.
+.RE
+
+.PP
+See library source for usage examples of all the above low-level routines,
+especially source of the parsing routines.
+
+.SH AUTHOR
+.PP
+The \fBudns\fR library has been written by Michael Tokarev, mjt at corpit.ru.

Added: freeswitch/trunk/libs/udns/udns.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns.h	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,736 @@
+/* $Id: udns.h,v 1.41 2006/11/29 01:20:30 mjt Exp $
+   header file for the UDNS library.
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#ifndef UDNS_VERSION	/* include guard */
+
+#define UDNS_VERSION "0.0.9pre"
+
+#ifdef WIN32
+# ifdef UDNS_DYNAMIC_LIBRARY
+#  ifdef DNS_LIBRARY_BUILD
+#   define UDNS_API __declspec(dllexport)
+#   define UDNS_DATA_API __declspec(dllexport)
+#  else
+#   define UDNS_API __declspec(dllimport)
+#   define UDNS_DATA_API __declspec(dllimport)
+#  endif
+# endif
+#endif
+
+#ifndef UDNS_API
+# define UDNS_API
+#endif
+#ifndef UDNS_DATA_API
+# define UDNS_DATA_API
+#endif
+
+#include <sys/types.h>		/* for time_t */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* forward declarations if sockets stuff isn't #include'd */
+struct in_addr;
+struct in6_addr;
+struct sockaddr;
+
+/**************************************************************************/
+/**************** Common definitions **************************************/
+
+UDNS_API const char *
+dns_version(void);
+
+struct dns_ctx;
+struct dns_query;
+
+/* shorthand for [const] unsigned char */
+typedef unsigned char dnsc_t;
+typedef const unsigned char dnscc_t;
+
+#define DNS_MAXDN	255	/* max DN length */
+#define DNS_MAXLABEL	63	/* max DN label length */
+#define DNS_MAXNAME	1024	/* max asciiz domain name length */
+#define DNS_HSIZE	12	/* DNS packet header size */
+#define DNS_PORT	53	/* default domain port */
+#define DNS_MAXSERV	6	/* max servers to consult */
+#define DNS_MAXSRCH	5	/* max searchlist entries */
+#define DNS_MAXPACKET	512	/* max traditional-DNS UDP packet size */
+#define DNS_EDNS0PACKET	4096	/* EDNS0 packet size to use */
+
+enum dns_class {	/* DNS RR Classes */
+  DNS_C_INVALID	= 0,	/* invalid class */
+  DNS_C_IN	= 1,	/* Internet */
+  DNS_C_CH	= 3,	/* CHAOS */
+  DNS_C_HS	= 4,	/* HESIOD */
+  DNS_C_ANY	= 255	/* wildcard */
+};
+
+enum dns_type {		/* DNS RR Types */
+  DNS_T_INVALID		= 0,	/* Cookie. */
+  DNS_T_A		= 1,	/* Host address. */
+  DNS_T_NS		= 2,	/* Authoritative server. */
+  DNS_T_MD		= 3,	/* Mail destination. */
+  DNS_T_MF		= 4,	/* Mail forwarder. */
+  DNS_T_CNAME		= 5,	/* Canonical name. */
+  DNS_T_SOA		= 6,	/* Start of authority zone. */
+  DNS_T_MB		= 7,	/* Mailbox domain name. */
+  DNS_T_MG		= 8,	/* Mail group member. */
+  DNS_T_MR		= 9,	/* Mail rename name. */
+  DNS_T_NULL		= 10,	/* Null resource record. */
+  DNS_T_WKS		= 11,	/* Well known service. */
+  DNS_T_PTR		= 12,	/* Domain name pointer. */
+  DNS_T_HINFO		= 13,	/* Host information. */
+  DNS_T_MINFO		= 14,	/* Mailbox information. */
+  DNS_T_MX		= 15,	/* Mail routing information. */
+  DNS_T_TXT		= 16,	/* Text strings. */
+  DNS_T_RP		= 17,	/* Responsible person. */
+  DNS_T_AFSDB		= 18,	/* AFS cell database. */
+  DNS_T_X25		= 19,	/* X_25 calling address. */
+  DNS_T_ISDN		= 20,	/* ISDN calling address. */
+  DNS_T_RT		= 21,	/* Router. */
+  DNS_T_NSAP		= 22,	/* NSAP address. */
+  DNS_T_NSAP_PTR	= 23,	/* Reverse NSAP lookup (deprecated). */
+  DNS_T_SIG		= 24,	/* Security signature. */
+  DNS_T_KEY		= 25,	/* Security key. */
+  DNS_T_PX		= 26,	/* X.400 mail mapping. */
+  DNS_T_GPOS		= 27,	/* Geographical position (withdrawn). */
+  DNS_T_AAAA		= 28,	/* Ip6 Address. */
+  DNS_T_LOC		= 29,	/* Location Information. */
+  DNS_T_NXT		= 30,	/* Next domain (security). */
+  DNS_T_EID		= 31,	/* Endpoint identifier. */
+  DNS_T_NIMLOC		= 32,	/* Nimrod Locator. */
+  DNS_T_SRV		= 33,	/* Server Selection. */
+  DNS_T_ATMA		= 34,	/* ATM Address */
+  DNS_T_NAPTR		= 35,	/* Naming Authority PoinTeR */
+  DNS_T_KX		= 36,	/* Key Exchange */
+  DNS_T_CERT		= 37,	/* Certification record */
+  DNS_T_A6		= 38,	/* IPv6 address (deprecates AAAA) */
+  DNS_T_DNAME		= 39,	/* Non-terminal DNAME (for IPv6) */
+  DNS_T_SINK		= 40,	/* Kitchen sink (experimentatl) */
+  DNS_T_OPT		= 41,	/* EDNS0 option (meta-RR) */
+  DNS_T_DS		= 43,	/* DNSSEC */
+  DNS_T_NSEC		= 47,	/* DNSSEC */
+  DNS_T_TSIG		= 250,	/* Transaction signature. */
+  DNS_T_IXFR		= 251,	/* Incremental zone transfer. */
+  DNS_T_AXFR		= 252,	/* Transfer zone of authority. */
+  DNS_T_MAILB		= 253,	/* Transfer mailbox records. */
+  DNS_T_MAILA		= 254,	/* Transfer mail agent records. */
+  DNS_T_ANY		= 255,	/* Wildcard match. */
+  DNS_T_ZXFR		= 256,	/* BIND-specific, nonstandard. */
+  DNS_T_MAX		= 65536
+};
+
+/**************************************************************************/
+/**************** Domain Names (DNs) **************************************/
+
+/* return length of the DN */
+UDNS_API unsigned
+dns_dnlen(dnscc_t *dn);
+
+/* return #of labels in a DN */
+UDNS_API unsigned
+dns_dnlabels(dnscc_t *dn);
+
+/* lower- and uppercase single DN char */
+#define DNS_DNLC(c) ((c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 'a' : (c))
+#define DNS_DNUC(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
+
+/* compare the DNs, return dnlen of equal or 0 if not */
+UDNS_API unsigned
+dns_dnequal(dnscc_t *dn1, dnscc_t *dn2);
+
+/* copy one DN to another, size checking */
+UDNS_API unsigned
+dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz);
+
+/* convert asciiz string of length namelen (0 to use strlen) to DN */
+UDNS_API int
+dns_ptodn(const char *name, unsigned namelen,
+          dnsc_t *dn, unsigned dnsiz, int *isabs);
+
+/* simpler form of dns_ptodn() */
+#define dns_sptodn(name,dn,dnsiz) dns_ptodn((name),0,(dn),(dnsiz),0)
+
+UDNS_DATA_API extern dnscc_t dns_inaddr_arpa_dn[14];
+#define DNS_A4RSIZE	30
+UDNS_API int
+dns_a4todn(const struct in_addr *addr, dnscc_t *tdn,
+           dnsc_t *dn, unsigned dnsiz);
+UDNS_API int
+dns_a4ptodn(const struct in_addr *addr, const char *tname,
+            dnsc_t *dn, unsigned dnsiz);
+UDNS_API dnsc_t *
+dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne);
+
+UDNS_DATA_API extern dnscc_t dns_ip6_arpa_dn[10];
+#define DNS_A6RSIZE	74
+UDNS_API int
+dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn,
+           dnsc_t *dn, unsigned dnsiz);
+UDNS_API int
+dns_a6ptodn(const struct in6_addr *addr, const char *tname,
+            dnsc_t *dn, unsigned dnsiz);
+UDNS_API dnsc_t *
+dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne);
+
+/* convert DN into asciiz string */
+UDNS_API int
+dns_dntop(dnscc_t *dn, char *name, unsigned namesiz);
+
+/* convert DN into asciiz string, using static buffer (NOT thread-safe!) */
+UDNS_API const char *
+dns_dntosp(dnscc_t *dn);
+
+/* return buffer size (incl. null byte) required for asciiz form of a DN */
+UDNS_API unsigned
+dns_dntop_size(dnscc_t *dn);
+
+/**************************************************************************/
+/**************** DNS raw packet layout ***********************************/
+
+enum dns_rcode {	/* reply codes */
+  DNS_R_NOERROR		= 0,	/* ok, no error */
+  DNS_R_FORMERR		= 1,	/* format error */
+  DNS_R_SERVFAIL	= 2,	/* server failed */
+  DNS_R_NXDOMAIN	= 3,	/* domain does not exists */
+  DNS_R_NOTIMPL		= 4,	/* not implemented */
+  DNS_R_REFUSED		= 5,	/* query refused */
+  /* these are for BIND_UPDATE */
+  DNS_R_YXDOMAIN	= 6,	/* Name exists */
+  DNS_R_YXRRSET		= 7,	/* RRset exists */
+  DNS_R_NXRRSET		= 8,	/* RRset does not exist */
+  DNS_R_NOTAUTH		= 9,	/* Not authoritative for zone */
+  DNS_R_NOTZONE		= 10,	/* Zone of record different from zone section */
+  /*ns_r_max = 11,*/
+  /* The following are TSIG extended errors */
+  DNS_R_BADSIG		= 16,
+  DNS_R_BADKEY		= 17,
+  DNS_R_BADTIME		= 18
+};
+
+static __inline unsigned dns_get16(dnscc_t *s) {
+  return ((unsigned)s[0]<<8) | s[1];
+}
+static __inline unsigned dns_get32(dnscc_t *s) {
+  return ((unsigned)s[0]<<24) | ((unsigned)s[1]<<16)
+        | ((unsigned)s[2]<<8) | s[3];
+}
+static __inline dnsc_t *dns_put16(dnsc_t *d, unsigned n) {
+  *d++ = (n >> 8) & 255; *d++ = n & 255; return d;
+}
+static __inline dnsc_t *dns_put32(dnsc_t *d, unsigned n) {
+  *d++ = (n >> 24) & 255; *d++ = (n >> 16) & 255;
+  *d++ = (n >>  8) & 255; *d++ = n & 255;
+  return d;
+}
+
+/* DNS Header layout */
+enum {
+ /* bytes 0:1 - query ID */
+  DNS_H_QID1	= 0,
+  DNS_H_QID2	= 1,
+  DNS_H_QID	= DNS_H_QID1,
+#define dns_qid(pkt)	dns_get16((pkt)+DNS_H_QID)
+ /* byte 2: flags1 */
+  DNS_H_F1	= 2,
+  DNS_HF1_QR	= 0x80,	/* query response flag */
+#define dns_qr(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_QR)
+  DNS_HF1_OPCODE = 0x78, /* opcode, 0 = query */
+#define dns_opcode(pkt)	(((pkt)[DNS_H_F1]&DNS_HF1_OPCODE)>>3)
+  DNS_HF1_AA	= 0x04,	/* auth answer */
+#define dns_aa(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_AA)
+  DNS_HF1_TC	= 0x02,	/* truncation flag */
+#define dns_tc(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_TC)
+  DNS_HF1_RD	= 0x01,	/* recursion desired (may be set in query) */
+#define dns_rd(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_RD)
+ /* byte 3: flags2 */
+  DNS_H_F2	= 3,
+  DNS_HF2_RA	= 0x80,	/* recursion available */
+#define dns_ra(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_RA)
+  DNS_HF2_Z	= 0x70,	/* reserved */
+  DNS_HF2_RCODE	= 0x0f,	/* response code, DNS_R_XXX above */
+#define dns_rcode(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_RCODE)
+ /* bytes 4:5: qdcount, numqueries */
+  DNS_H_QDCNT1	= 4,
+  DNS_H_QDCNT2	= 5,
+  DNS_H_QDCNT	= DNS_H_QDCNT1,
+#define dns_numqd(pkt)	dns_get16((pkt)+4)
+ /* bytes 6:7: ancount, numanswers */
+  DNS_H_ANCNT1	= 6,
+  DNS_H_ANCNT2	= 7,
+  DNS_H_ANCNT	= DNS_H_ANCNT1,
+#define dns_numan(pkt)	dns_get16((pkt)+6)
+ /* bytes 8:9: nscount, numauthority */
+  DNS_H_NSCNT1	= 8,
+  DNS_H_NSCNT2	= 9,
+  DNS_H_NSCNT	= DNS_H_NSCNT1,
+#define dns_numns(pkt)	dns_get16((pkt)+8)
+ /* bytes 10:11: arcount, numadditional */
+  DNS_H_ARCNT1	= 10,
+  DNS_H_ARCNT2	= 11,
+  DNS_H_ARCNT	= DNS_H_ARCNT1,
+#define dns_numar(pkt)	dns_get16((pkt)+10)
+#define dns_payload(pkt) ((pkt)+DNS_HSIZE)
+};
+
+/* packet buffer: start at pkt, end before pkte, current pos *curp.
+ * extract a DN and set *curp to the next byte after DN in packet.
+ * return -1 on error, 0 if dnsiz is too small, or dnlen on ok.
+ */
+UDNS_API int
+dns_getdn(dnscc_t *pkt, dnscc_t **curp, dnscc_t *end,
+          dnsc_t *dn, unsigned dnsiz);
+
+/* skip the DN at position cur in packet ending before pkte,
+ * return pointer to the next byte after the DN or NULL on error */
+UDNS_API dnscc_t *
+dns_skipdn(dnscc_t *end, dnscc_t *cur);
+
+struct dns_rr {		/* DNS Resource Record */
+  dnsc_t dnsrr_dn[DNS_MAXDN];	/* the DN of the RR */
+  enum dns_class dnsrr_cls;	/* Class */
+  enum dns_type  dnsrr_typ;	/* Type */
+  unsigned dnsrr_ttl;		/* Time-To-Live (TTL) */
+  unsigned dnsrr_dsz;		/* data size */
+  dnscc_t *dnsrr_dptr;		/* pointer to start of data */
+  dnscc_t *dnsrr_dend;		/* past end of data */
+};
+
+struct dns_parse {	/* RR/packet parsing state */
+  dnscc_t *dnsp_pkt;		/* start of the packet */
+  dnscc_t *dnsp_end;		/* end of the packet */
+  dnscc_t *dnsp_cur;		/* current packet position */
+  dnscc_t *dnsp_ans;		/* start of answer section */
+  int dnsp_rrl;			/* number of RRs left to go */
+  int dnsp_nrr;			/* RR count so far */
+  unsigned dnsp_ttl;		/* TTL value so far */
+  dnscc_t *dnsp_qdn;		/* the RR DN we're looking for */
+  enum dns_class dnsp_qcls;	/* RR class we're looking for or 0 */
+  enum dns_type  dnsp_qtyp;	/* RR type we're looking for or 0 */
+  dnsc_t dnsp_dnbuf[DNS_MAXDN];	/* domain buffer */
+};
+
+/* initialize the parse structure */
+UDNS_API void
+dns_initparse(struct dns_parse *p, dnscc_t *qdn,
+              dnscc_t *pkt, dnscc_t *cur, dnscc_t *end);
+
+/* search next RR, <0=error, 0=no more RRs, >0 = found. */
+UDNS_API int
+dns_nextrr(struct dns_parse *p, struct dns_rr *rr);
+
+UDNS_API void
+dns_rewind(struct dns_parse *p, dnscc_t *qdn);
+
+
+/**************************************************************************/
+/**************** Resolver Context ****************************************/
+
+/* default resolver context */
+UDNS_DATA_API extern struct dns_ctx dns_defctx;
+
+/* initialize default resolver context and open it if do_open is true.
+ * <0 on failure. */
+UDNS_API int
+dns_init(int do_open);
+
+/* return new resolver context with the same settings as copy */
+UDNS_API struct dns_ctx *
+dns_new(const struct dns_ctx *copy);
+
+/* free resolver context; all queries are dropped */
+UDNS_API void
+dns_free(struct dns_ctx *ctx);
+
+/* add nameserver for a resolver context (or reset nslist if serv==NULL) */
+UDNS_API int
+dns_add_serv(struct dns_ctx *ctx, const char *serv);
+
+/* add nameserver using struct sockaddr array (with ports etc) */
+UDNS_API int
+dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa);
+
+/* add search list element for a resolver context (or reset it if srch==NULL) */
+UDNS_API int
+dns_add_srch(struct dns_ctx *ctx, const char *srch);
+
+/* set options for a resolver context */
+UDNS_API int
+dns_set_opts(struct dns_ctx *ctx, const char *opts);
+
+enum dns_opt {		/* options */
+  DNS_OPT_FLAGS,	/* flags, DNS_F_XXX */
+  DNS_OPT_TIMEOUT,	/* timeout in secounds */
+  DNS_OPT_NTRIES,	/* number of retries */
+  DNS_OPT_NDOTS,	/* ndots */
+  DNS_OPT_UDPSIZE,	/* EDNS0 UDP size */
+  DNS_OPT_PORT,		/* port to use */
+};
+
+/* set or get (if val<0) an option */
+UDNS_API int
+dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val);
+
+enum dns_flags {
+  DNS_NOSRCH	= 0x00010000,	/* do not perform search */
+  DNS_NORD	= 0x00020000,	/* request no recursion */
+  DNS_AAONLY	= 0x00040000,	/* set AA flag in queries */
+  DNS_PASSALL	= 0x00080000,	/* pass all replies to application */
+};
+
+/* set the debug function pointer */
+typedef void
+(dns_dbgfn)(int code, const struct sockaddr *sa, unsigned salen,
+            dnscc_t *pkt, int plen,
+            const struct dns_query *q, void *data);
+UDNS_API void
+dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn);
+
+/* open and return UDP socket */
+UDNS_API int
+dns_open(struct dns_ctx *ctx);
+
+/* return UDP socket or -1 if not open */
+UDNS_API int
+dns_sock(const struct dns_ctx *ctx);
+
+/* close the UDP socket */
+UDNS_API void
+dns_close(struct dns_ctx *ctx);
+
+/* return number of requests queued */
+UDNS_API int
+dns_active(const struct dns_ctx *ctx);
+
+/* return status of the last operation */
+UDNS_API int
+dns_status(const struct dns_ctx *ctx);
+UDNS_API void
+dns_setstatus(struct dns_ctx *ctx, int status);
+
+/* handle I/O event on UDP socket */
+UDNS_API void
+dns_ioevent(struct dns_ctx *ctx, time_t now);
+
+/* process any timeouts, return time in secounds to the
+ * next timeout (or -1 if none) but not greather than maxwait */
+UDNS_API int
+dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now);
+
+/* define timer requesting routine to use */
+typedef void dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data);
+UDNS_API void
+dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data);
+
+/**************************************************************************/
+/**************** Making Queries ******************************************/
+
+/* query callback routine */
+typedef void dns_query_fn(struct dns_ctx *ctx, void *result, void *data);
+
+/* query parse routine: raw DNS => application structure */
+typedef int
+dns_parse_fn(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+             void **res);
+
+enum dns_status {
+  DNS_E_NOERROR		= 0,	/* ok, not an error */
+  DNS_E_TEMPFAIL	= -1,	/* timeout, SERVFAIL or similar */
+  DNS_E_PROTOCOL	= -2,	/* got garbled reply */
+  DNS_E_NXDOMAIN	= -3,	/* domain does not exists */
+  DNS_E_NODATA		= -4,	/* domain exists but no data of reqd type */
+  DNS_E_NOMEM		= -5,	/* out of memory while processing */
+  DNS_E_BADQUERY	= -6	/* the query is malformed */
+};
+
+/* submit generic DN query */
+UDNS_API struct dns_query *
+dns_submit_dn(struct dns_ctx *ctx,
+              dnscc_t *dn, int qcls, int qtyp, int flags,
+              dns_parse_fn *parse, dns_query_fn *cbck, void *data);
+/* submit generic name query */
+UDNS_API struct dns_query *
+dns_submit_p(struct dns_ctx *ctx,
+             const char *name, int qcls, int qtyp, int flags,
+             dns_parse_fn *parse, dns_query_fn *cbck, void *data);
+
+/* cancel the given async query in progress */
+UDNS_API int
+dns_cancel(struct dns_ctx *ctx, struct dns_query *q);
+
+/* resolve a generic query, return the answer */
+UDNS_API void *
+dns_resolve_dn(struct dns_ctx *ctx,
+               dnscc_t *qdn, int qcls, int qtyp, int flags,
+               dns_parse_fn *parse);
+UDNS_API void *
+dns_resolve_p(struct dns_ctx *ctx,
+              const char *qname, int qcls, int qtyp, int flags,
+              dns_parse_fn *parse);
+UDNS_API void *
+dns_resolve(struct dns_ctx *ctx, struct dns_query *q);
+
+
+/* Specific RR handlers */
+
+#define dns_rr_common(prefix)						\
+  char *prefix##_cname;		/* canonical name */			\
+  char *prefix##_qname;		/* original query name */		\
+  unsigned prefix##_ttl;	/* TTL value */				\
+  int prefix##_nrr		/* number of records */
+
+struct dns_rr_null {		/* NULL RRset, aka RRset template */
+  dns_rr_common(dnsn);
+};
+
+UDNS_API int
+dns_stdrr_size(const struct dns_parse *p);
+UDNS_API void *
+dns_stdrr_finish(struct dns_rr_null *ret, char *cp, const struct dns_parse *p);
+
+struct dns_rr_a4 {		/* the A RRset */
+  dns_rr_common(dnsa4);
+  struct in_addr *dnsa4_addr;	/* array of addresses, naddr elements */
+};
+
+UDNS_API dns_parse_fn dns_parse_a4;	/* A RR parsing routine */
+typedef void				/* A query callback routine */
+dns_query_a4_fn(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data);
+
+/* submit A IN query */
+UDNS_API struct dns_query *
+dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_a4_fn *cbck, void *data);
+
+/* resolve A IN query */
+UDNS_API struct dns_rr_a4 *
+dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags);
+
+
+struct dns_rr_a6 {		/* the AAAA RRset */
+  dns_rr_common(dnsa6);
+  struct in6_addr *dnsa6_addr;	/* array of addresses, naddr elements */
+};
+
+UDNS_API dns_parse_fn dns_parse_a6;	/* A RR parsing routine */
+typedef void				/* A query callback routine */
+dns_query_a6_fn(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data);
+
+/* submit AAAA IN query */
+UDNS_API struct dns_query *
+dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_a6_fn *cbck, void *data);
+
+/* resolve AAAA IN query */
+UDNS_API struct dns_rr_a6 *
+dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags);
+
+
+struct dns_rr_ptr {		/* the PTR RRset */
+  dns_rr_common(dnsptr);
+  char **dnsptr_ptr;		/* array of PTRs */
+};
+
+UDNS_API dns_parse_fn dns_parse_ptr;	/* PTR RR parsing routine */
+typedef void				/* PTR query callback */
+dns_query_ptr_fn(struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data);
+/* submit PTR IN in-addr.arpa query */
+UDNS_API struct dns_query *
+dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr,
+                 dns_query_ptr_fn *cbck, void *data);
+/* resolve PTR IN in-addr.arpa query */
+UDNS_API struct dns_rr_ptr *
+dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr);
+
+/* the same as above, but for ip6.arpa */
+UDNS_API struct dns_query *
+dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr,
+                 dns_query_ptr_fn *cbck, void *data);
+UDNS_API struct dns_rr_ptr *
+dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr);
+
+
+struct dns_mx {		/* single MX RR */
+  int priority;		/* MX priority */
+  char *name;		/* MX name */
+};
+struct dns_rr_mx {		/* the MX RRset */
+  dns_rr_common(dnsmx);
+  struct dns_mx *dnsmx_mx;	/* array of MXes */
+};
+UDNS_API dns_parse_fn dns_parse_mx;	/* MX RR parsing routine */
+typedef void				/* MX RR callback */
+dns_query_mx_fn(struct dns_ctx *ctx, struct dns_rr_mx *result, void *data);
+/* submit MX IN query */
+UDNS_API struct dns_query *
+dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_mx_fn *cbck, void *data);
+/* resolve MX IN query */
+UDNS_API struct dns_rr_mx *
+dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags);
+
+
+struct dns_txt {	/* single TXT record */
+  int len;		/* length of the text */
+  dnsc_t *txt;	/* pointer to text buffer. May contain nulls. */
+};
+struct dns_rr_txt {		/* the TXT RRset */
+  dns_rr_common(dnstxt);
+  struct dns_txt *dnstxt_txt;	/* array of TXT records */
+};
+UDNS_API dns_parse_fn dns_parse_txt;	/* TXT RR parsing routine */
+typedef void				/* TXT RR callback */
+dns_query_txt_fn(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data);
+/* submit TXT query */
+UDNS_API struct dns_query *
+dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags,
+               dns_query_txt_fn *cbck, void *data);
+/* resolve TXT query */
+UDNS_API struct dns_rr_txt *
+dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags);
+
+
+struct dns_srv {	/* single SRV RR */
+  int priority;		/* SRV priority */
+  int weight;		/* SRV weight */
+  int port;		/* SRV port */
+  char *name;		/* SRV name */
+};
+struct dns_rr_srv {		/* the SRV RRset */
+  dns_rr_common(dnssrv);
+  struct dns_srv *dnssrv_srv;	/* array of SRVes */
+};
+UDNS_API dns_parse_fn dns_parse_srv;	/* SRV RR parsing routine */
+typedef void				/* SRV RR callback */
+dns_query_srv_fn(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data);
+/* submit SRV IN query */
+UDNS_API struct dns_query *
+dns_submit_srv(struct dns_ctx *ctx,
+               const char *name, const char *srv, const char *proto,
+               int flags, dns_query_srv_fn *cbck, void *data);
+/* resolve SRV IN query */
+UDNS_API struct dns_rr_srv *
+dns_resolve_srv(struct dns_ctx *ctx,
+                const char *name, const char *srv, const char *proto,
+                int flags);
+
+/* NAPTR (RFC3403) RR type */
+struct dns_naptr {	/* single NAPTR RR */
+  int order;		/* NAPTR order */
+  int preference;	/* NAPTR preference */
+  char *flags;		/* NAPTR flags */
+  char *service;	/* NAPTR service */
+  char *regexp;		/* NAPTR regexp */
+  char *replacement;	/* NAPTR replacement */
+};
+
+struct dns_rr_naptr {		/* the NAPTR RRset */
+  dns_rr_common(dnsnaptr);
+  struct dns_naptr *dnsnaptr_naptr;	/* array of NAPTRes */
+};
+UDNS_API dns_parse_fn dns_parse_naptr;	/* NAPTR RR parsing routine */
+typedef void				/* NAPTR RR callback */
+dns_query_naptr_fn(struct dns_ctx *ctx,
+                   struct dns_rr_naptr *result, void *data);
+/* submit NAPTR IN query */
+UDNS_API struct dns_query *
+dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
+                 dns_query_naptr_fn *cbck, void *data);
+/* resolve NAPTR IN query */
+UDNS_API struct dns_rr_naptr *
+dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags);
+
+
+UDNS_API struct dns_query *
+dns_submit_a4dnsbl(struct dns_ctx *ctx,
+                   const struct in_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data);
+UDNS_API struct dns_query *
+dns_submit_a4dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data);
+UDNS_API struct dns_rr_a4 *
+dns_resolve_a4dnsbl(struct dns_ctx *ctx,
+                    const struct in_addr *addr, const char *dnsbl);
+UDNS_API struct dns_rr_txt *
+dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in_addr *addr, const char *dnsbl);
+
+UDNS_API struct dns_query *
+dns_submit_a6dnsbl(struct dns_ctx *ctx,
+                   const struct in6_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data);
+UDNS_API struct dns_query *
+dns_submit_a6dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in6_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data);
+UDNS_API struct dns_rr_a4 *
+dns_resolve_a6dnsbl(struct dns_ctx *ctx,
+                    const struct in6_addr *addr, const char *dnsbl);
+UDNS_API struct dns_rr_txt *
+dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in6_addr *addr, const char *dnsbl);
+
+UDNS_API struct dns_query *
+dns_submit_rhsbl(struct dns_ctx *ctx,
+                 const char *name, const char *rhsbl,
+                 dns_query_a4_fn *cbck, void *data);
+UDNS_API struct dns_query *
+dns_submit_rhsbl_txt(struct dns_ctx *ctx,
+                     const char *name, const char *rhsbl,
+                     dns_query_txt_fn *cbck, void *data);
+UDNS_API struct dns_rr_a4 *
+dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl);
+UDNS_API struct dns_rr_txt *
+dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl);
+
+/**************************************************************************/
+/**************** Names, Names ********************************************/
+
+struct dns_nameval {
+  int val;
+  const char *name;
+};
+
+UDNS_DATA_API extern const struct dns_nameval dns_classtab[];
+UDNS_DATA_API extern const struct dns_nameval dns_typetab[];
+UDNS_DATA_API extern const struct dns_nameval dns_rcodetab[];
+UDNS_API int
+dns_findname(const struct dns_nameval *nv, const char *name);
+#define dns_findclassname(cls) dns_findname(dns_classtab, (cls))
+#define dns_findtypename(type) dns_findname(dns_typetab, (type))
+#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode))
+
+UDNS_API const char *dns_classname(enum dns_class cls);
+UDNS_API const char *dns_typename(enum dns_type type);
+UDNS_API const char *dns_rcodename(enum dns_rcode rcode);
+const char *_dns_format_code(char *buf, const char *prefix, int code);
+
+UDNS_API const char *dns_strerror(int errnum);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif	/* include guard */

Added: freeswitch/trunk/libs/udns/udns_bl.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_bl.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,160 @@
+/* $Id: udns_bl.c,v 1.10 2005/09/12 10:55:21 mjt Exp $
+   DNSBL stuff
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include "udns.h"
+#ifndef NULL
+# define NULL 0
+#endif
+
+struct dns_query *
+dns_submit_a4dnsbl(struct dns_ctx *ctx,
+                   const struct in_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data) {
+  dnsc_t dn[DNS_MAXDN];
+  if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
+                  dns_parse_a4, (dns_query_fn*)cbck, data);
+}
+
+struct dns_query *
+dns_submit_a4dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data) {
+  dnsc_t dn[DNS_MAXDN];
+  if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
+                  dns_parse_txt, (dns_query_fn*)cbck, data);
+}
+
+struct dns_rr_a4 *
+dns_resolve_a4dnsbl(struct dns_ctx *ctx,
+                    const struct in_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_a4 *)
+    dns_resolve(ctx, dns_submit_a4dnsbl(ctx, addr, dnsbl, 0, 0));
+}
+
+struct dns_rr_txt *
+dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_txt *)
+    dns_resolve(ctx, dns_submit_a4dnsbl_txt(ctx, addr, dnsbl, 0, 0));
+}
+
+
+struct dns_query *
+dns_submit_a6dnsbl(struct dns_ctx *ctx,
+                   const struct in6_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data) {
+  dnsc_t dn[DNS_MAXDN];
+  if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
+                  dns_parse_a4, (dns_query_fn*)cbck, data);
+}
+
+struct dns_query *
+dns_submit_a6dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in6_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data) {
+  dnsc_t dn[DNS_MAXDN];
+  if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
+                  dns_parse_txt, (dns_query_fn*)cbck, data);
+}
+
+struct dns_rr_a4 *
+dns_resolve_a6dnsbl(struct dns_ctx *ctx,
+                    const struct in6_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_a4 *)
+    dns_resolve(ctx, dns_submit_a6dnsbl(ctx, addr, dnsbl, 0, 0));
+}
+
+struct dns_rr_txt *
+dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in6_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_txt *)
+    dns_resolve(ctx, dns_submit_a6dnsbl_txt(ctx, addr, dnsbl, 0, 0));
+}
+
+static int
+dns_rhsbltodn(const char *name, const char *rhsbl, dnsc_t dn[DNS_MAXDN])
+{
+  int l = dns_sptodn(name, dn, DNS_MAXDN);
+  if (l <= 0) return 0;
+  l = dns_sptodn(rhsbl, dn+l-1, DNS_MAXDN-l+1);
+  if (l <= 0) return 0;
+  return 1;
+}
+
+struct dns_query *
+dns_submit_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl,
+                 dns_query_a4_fn *cbck, void *data) {
+  dnsc_t dn[DNS_MAXDN];
+  if (!dns_rhsbltodn(name, rhsbl, dn)) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
+                  dns_parse_a4, (dns_query_fn*)cbck, data);
+}
+struct dns_query *
+dns_submit_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl,
+                     dns_query_txt_fn *cbck, void *data) {
+  dnsc_t dn[DNS_MAXDN];
+  if (!dns_rhsbltodn(name, rhsbl, dn)) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
+                  dns_parse_txt, (dns_query_fn*)cbck, data);
+}
+
+struct dns_rr_a4 *
+dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl) {
+  return (struct dns_rr_a4*)
+    dns_resolve(ctx, dns_submit_rhsbl(ctx, name, rhsbl, 0, 0));
+}
+
+struct dns_rr_txt *
+dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl)
+{
+  return (struct dns_rr_txt*)
+    dns_resolve(ctx, dns_submit_rhsbl_txt(ctx, name, rhsbl, 0, 0));
+}

Added: freeswitch/trunk/libs/udns/udns_codes.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_codes.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,171 @@
+/* Automatically generated. */
+#include "udns.h"
+
+const struct dns_nameval dns_typetab[] = {
+ {DNS_T_INVALID,"INVALID"},
+ {DNS_T_A,"A"},
+ {DNS_T_NS,"NS"},
+ {DNS_T_MD,"MD"},
+ {DNS_T_MF,"MF"},
+ {DNS_T_CNAME,"CNAME"},
+ {DNS_T_SOA,"SOA"},
+ {DNS_T_MB,"MB"},
+ {DNS_T_MG,"MG"},
+ {DNS_T_MR,"MR"},
+ {DNS_T_NULL,"NULL"},
+ {DNS_T_WKS,"WKS"},
+ {DNS_T_PTR,"PTR"},
+ {DNS_T_HINFO,"HINFO"},
+ {DNS_T_MINFO,"MINFO"},
+ {DNS_T_MX,"MX"},
+ {DNS_T_TXT,"TXT"},
+ {DNS_T_RP,"RP"},
+ {DNS_T_AFSDB,"AFSDB"},
+ {DNS_T_X25,"X25"},
+ {DNS_T_ISDN,"ISDN"},
+ {DNS_T_RT,"RT"},
+ {DNS_T_NSAP,"NSAP"},
+ {DNS_T_NSAP_PTR,"NSAP_PTR"},
+ {DNS_T_SIG,"SIG"},
+ {DNS_T_KEY,"KEY"},
+ {DNS_T_PX,"PX"},
+ {DNS_T_GPOS,"GPOS"},
+ {DNS_T_AAAA,"AAAA"},
+ {DNS_T_LOC,"LOC"},
+ {DNS_T_NXT,"NXT"},
+ {DNS_T_EID,"EID"},
+ {DNS_T_NIMLOC,"NIMLOC"},
+ {DNS_T_SRV,"SRV"},
+ {DNS_T_ATMA,"ATMA"},
+ {DNS_T_NAPTR,"NAPTR"},
+ {DNS_T_KX,"KX"},
+ {DNS_T_CERT,"CERT"},
+ {DNS_T_A6,"A6"},
+ {DNS_T_DNAME,"DNAME"},
+ {DNS_T_SINK,"SINK"},
+ {DNS_T_OPT,"OPT"},
+ {DNS_T_DS,"DS"},
+ {DNS_T_NSEC,"NSEC"},
+ {DNS_T_TSIG,"TSIG"},
+ {DNS_T_IXFR,"IXFR"},
+ {DNS_T_AXFR,"AXFR"},
+ {DNS_T_MAILB,"MAILB"},
+ {DNS_T_MAILA,"MAILA"},
+ {DNS_T_ANY,"ANY"},
+ {DNS_T_ZXFR,"ZXFR"},
+ {DNS_T_MAX,"MAX"},
+ {0,0}};
+const char *dns_typename(enum dns_type code) {
+ static char nm[20];
+ switch(code) {
+ case DNS_T_INVALID: return dns_typetab[0].name;
+ case DNS_T_A: return dns_typetab[1].name;
+ case DNS_T_NS: return dns_typetab[2].name;
+ case DNS_T_MD: return dns_typetab[3].name;
+ case DNS_T_MF: return dns_typetab[4].name;
+ case DNS_T_CNAME: return dns_typetab[5].name;
+ case DNS_T_SOA: return dns_typetab[6].name;
+ case DNS_T_MB: return dns_typetab[7].name;
+ case DNS_T_MG: return dns_typetab[8].name;
+ case DNS_T_MR: return dns_typetab[9].name;
+ case DNS_T_NULL: return dns_typetab[10].name;
+ case DNS_T_WKS: return dns_typetab[11].name;
+ case DNS_T_PTR: return dns_typetab[12].name;
+ case DNS_T_HINFO: return dns_typetab[13].name;
+ case DNS_T_MINFO: return dns_typetab[14].name;
+ case DNS_T_MX: return dns_typetab[15].name;
+ case DNS_T_TXT: return dns_typetab[16].name;
+ case DNS_T_RP: return dns_typetab[17].name;
+ case DNS_T_AFSDB: return dns_typetab[18].name;
+ case DNS_T_X25: return dns_typetab[19].name;
+ case DNS_T_ISDN: return dns_typetab[20].name;
+ case DNS_T_RT: return dns_typetab[21].name;
+ case DNS_T_NSAP: return dns_typetab[22].name;
+ case DNS_T_NSAP_PTR: return dns_typetab[23].name;
+ case DNS_T_SIG: return dns_typetab[24].name;
+ case DNS_T_KEY: return dns_typetab[25].name;
+ case DNS_T_PX: return dns_typetab[26].name;
+ case DNS_T_GPOS: return dns_typetab[27].name;
+ case DNS_T_AAAA: return dns_typetab[28].name;
+ case DNS_T_LOC: return dns_typetab[29].name;
+ case DNS_T_NXT: return dns_typetab[30].name;
+ case DNS_T_EID: return dns_typetab[31].name;
+ case DNS_T_NIMLOC: return dns_typetab[32].name;
+ case DNS_T_SRV: return dns_typetab[33].name;
+ case DNS_T_ATMA: return dns_typetab[34].name;
+ case DNS_T_NAPTR: return dns_typetab[35].name;
+ case DNS_T_KX: return dns_typetab[36].name;
+ case DNS_T_CERT: return dns_typetab[37].name;
+ case DNS_T_A6: return dns_typetab[38].name;
+ case DNS_T_DNAME: return dns_typetab[39].name;
+ case DNS_T_SINK: return dns_typetab[40].name;
+ case DNS_T_OPT: return dns_typetab[41].name;
+ case DNS_T_DS: return dns_typetab[42].name;
+ case DNS_T_NSEC: return dns_typetab[43].name;
+ case DNS_T_TSIG: return dns_typetab[44].name;
+ case DNS_T_IXFR: return dns_typetab[45].name;
+ case DNS_T_AXFR: return dns_typetab[46].name;
+ case DNS_T_MAILB: return dns_typetab[47].name;
+ case DNS_T_MAILA: return dns_typetab[48].name;
+ case DNS_T_ANY: return dns_typetab[49].name;
+ case DNS_T_ZXFR: return dns_typetab[50].name;
+ case DNS_T_MAX: return dns_typetab[51].name;
+ }
+ return _dns_format_code(nm,"type",code);
+}
+
+const struct dns_nameval dns_classtab[] = {
+ {DNS_C_INVALID,"INVALID"},
+ {DNS_C_IN,"IN"},
+ {DNS_C_CH,"CH"},
+ {DNS_C_HS,"HS"},
+ {DNS_C_ANY,"ANY"},
+ {0,0}};
+const char *dns_classname(enum dns_class code) {
+ static char nm[20];
+ switch(code) {
+ case DNS_C_INVALID: return dns_classtab[0].name;
+ case DNS_C_IN: return dns_classtab[1].name;
+ case DNS_C_CH: return dns_classtab[2].name;
+ case DNS_C_HS: return dns_classtab[3].name;
+ case DNS_C_ANY: return dns_classtab[4].name;
+ }
+ return _dns_format_code(nm,"class",code);
+}
+
+const struct dns_nameval dns_rcodetab[] = {
+ {DNS_R_NOERROR,"NOERROR"},
+ {DNS_R_FORMERR,"FORMERR"},
+ {DNS_R_SERVFAIL,"SERVFAIL"},
+ {DNS_R_NXDOMAIN,"NXDOMAIN"},
+ {DNS_R_NOTIMPL,"NOTIMPL"},
+ {DNS_R_REFUSED,"REFUSED"},
+ {DNS_R_YXDOMAIN,"YXDOMAIN"},
+ {DNS_R_YXRRSET,"YXRRSET"},
+ {DNS_R_NXRRSET,"NXRRSET"},
+ {DNS_R_NOTAUTH,"NOTAUTH"},
+ {DNS_R_NOTZONE,"NOTZONE"},
+ {DNS_R_BADSIG,"BADSIG"},
+ {DNS_R_BADKEY,"BADKEY"},
+ {DNS_R_BADTIME,"BADTIME"},
+ {0,0}};
+const char *dns_rcodename(enum dns_rcode code) {
+ static char nm[20];
+ switch(code) {
+ case DNS_R_NOERROR: return dns_rcodetab[0].name;
+ case DNS_R_FORMERR: return dns_rcodetab[1].name;
+ case DNS_R_SERVFAIL: return dns_rcodetab[2].name;
+ case DNS_R_NXDOMAIN: return dns_rcodetab[3].name;
+ case DNS_R_NOTIMPL: return dns_rcodetab[4].name;
+ case DNS_R_REFUSED: return dns_rcodetab[5].name;
+ case DNS_R_YXDOMAIN: return dns_rcodetab[6].name;
+ case DNS_R_YXRRSET: return dns_rcodetab[7].name;
+ case DNS_R_NXRRSET: return dns_rcodetab[8].name;
+ case DNS_R_NOTAUTH: return dns_rcodetab[9].name;
+ case DNS_R_NOTZONE: return dns_rcodetab[10].name;
+ case DNS_R_BADSIG: return dns_rcodetab[11].name;
+ case DNS_R_BADKEY: return dns_rcodetab[12].name;
+ case DNS_R_BADTIME: return dns_rcodetab[13].name;
+ }
+ return _dns_format_code(nm,"rcode",code);
+}

Added: freeswitch/trunk/libs/udns/udns_dn.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_dn.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,382 @@
+/* $Id: udns_dn.c,v 1.7 2006/11/28 22:45:20 mjt Exp $
+   domain names manipulation routines
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <string.h>
+#include "udns.h"
+
+unsigned dns_dnlen(dnscc_t *dn) {
+  register dnscc_t *d = dn;
+  while(*d)
+    d += 1 + *d;
+  return (unsigned)(d - dn) + 1;
+}
+
+unsigned dns_dnlabels(register dnscc_t *dn) {
+  register unsigned l = 0;
+  while(*dn)
+    ++l, dn += 1 + *dn;
+  return l;
+}
+
+unsigned dns_dnequal(register dnscc_t *dn1, register dnscc_t *dn2) {
+  register unsigned c;
+  dnscc_t *dn = dn1;
+  for(;;) {
+    if ((c = *dn1++) != *dn2++)
+      return 0;
+    if (!c)
+      return (unsigned)(dn1 - dn);
+    while(c--) {
+      if (DNS_DNLC(*dn1) != DNS_DNLC(*dn2))
+        return 0;
+      ++dn1; ++dn2;
+    }
+  }
+}
+
+unsigned
+dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz) {
+  unsigned sdnlen = dns_dnlen(sdn);
+  if (ddnsiz < sdnlen)
+    return 0;
+  memcpy(ddn, sdn, sdnlen);
+  return sdnlen;
+}
+
+int
+dns_ptodn(const char *name, unsigned namelen,
+          dnsc_t *dn, unsigned dnsiz, int *isabs)
+{
+  dnsc_t *dp;		/* current position in dn (len byte first) */
+  dnsc_t *const de	/* end of dn: last byte that can be filled up */
+      = dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1;
+  dnscc_t *np = (dnscc_t *)name;
+  dnscc_t *ne = np + (namelen ? namelen : strlen((char*)np));
+  dnsc_t *llab;		/* start of last label (llab[-1] will be length) */
+  unsigned c;		/* next input character, or length of last label */
+
+  if (!dnsiz)
+    return 0;
+  dp = llab = dn + 1;
+
+  while(np < ne) {
+
+    if (*np == '.') {	/* label delimiter */
+      c = dp - llab;		/* length of the label */
+      if (!c) {			/* empty label */
+        if (np == (dnscc_t *)name && np + 1 == ne) {
+          /* special case for root dn, aka `.' */
+          ++np;
+          break;
+        }
+        return -1;		/* zero label */
+      }
+      if (c > DNS_MAXLABEL)
+        return -1;		/* label too long */
+      llab[-1] = (dnsc_t)c;	/* update len of last label */
+      llab = ++dp; /* start new label, llab[-1] will be len of it */
+      ++np;
+      continue;
+    }
+
+    /* check whenever we may put out one more byte */
+    if (dp >= de) /* too long? */
+      return dnsiz >= DNS_MAXDN ? -1 : 0;
+    if (*np != '\\') { /* non-escape, simple case */
+      *dp++ = *np++;
+      continue;
+    }
+    /* handle \-style escape */
+    /* note that traditionally, domain names (gethostbyname etc)
+     * used decimal \dd notation, not octal \ooo (RFC1035), so
+     * we're following this tradition here.
+     */
+    if (++np == ne)
+      return -1;			/* bad escape */
+    else if (*np >= '0' && *np <= '9') { /* decimal number */
+      /* we allow not only exactly 3 digits as per RFC1035,
+       * but also 2 or 1, for better usability. */
+      c = *np++ - '0';
+      if (np < ne && *np >= '0' && *np <= '9') { /* 2digits */
+        c = c * 10 + *np++ - '0';
+        if (np < ne && *np >= '0' && *np <= '9') {
+          c = c * 10 + *np++ - '0';
+          if (c > 255)
+            return -1;			/* bad escape */
+        }
+      }
+    }
+    else
+      c = *np++;
+    *dp++ = (dnsc_t)c;	/* place next out byte */
+  }
+
+  if ((c = dp - llab) > DNS_MAXLABEL)
+    return -1;				/* label too long */
+  if ((llab[-1] = (dnsc_t)c) != 0) {
+    *dp++ = 0;
+    if (isabs)
+      *isabs = 0;
+  }
+  else if (isabs)
+    *isabs = 1;
+
+  return dp - dn;
+}
+
+dnscc_t dns_inaddr_arpa_dn[14] = "\07in-addr\04arpa";
+
+dnsc_t *
+dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne) {
+  dnsc_t *p;
+  unsigned n;
+  dnscc_t *s = ((dnscc_t *)addr) + 4;
+  while(--s >= (dnscc_t *)addr) {
+    n = *s;
+    p = dn + 1;
+    if (n > 99) {
+      if (p + 2 > dne) return 0;
+      *p++ = n / 100 + '0';
+      *p++ = (n % 100 / 10) + '0';
+      *p = n % 10 + '0';
+    }
+    else if (n > 9) {
+      if (p + 1 > dne) return 0;
+      *p++ = n / 10 + '0';
+      *p = n % 10 + '0';
+    }
+    else {
+      if (p > dne) return 0;
+      *p = n + '0';
+    }
+    *dn = p - dn;
+    dn = p + 1;
+  }
+  return dn;
+}
+
+int dns_a4todn(const struct in_addr *addr, dnscc_t *tdn,
+               dnsc_t *dn, unsigned dnsiz) {
+  dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
+  dnsc_t *p;
+  unsigned l;
+  p = dns_a4todn_(addr, dn, dne);
+  if (!p) return 0;
+  if (!tdn)
+    tdn = dns_inaddr_arpa_dn;
+  l = dns_dnlen(tdn);
+  if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
+  memcpy(p, tdn, l);
+  return (p + l) - dn;
+}
+
+int dns_a4ptodn(const struct in_addr *addr, const char *tname,
+                dnsc_t *dn, unsigned dnsiz) {
+  dnsc_t *p;
+  int r;
+  if (!tname)
+    return dns_a4todn(addr, NULL, dn, dnsiz);
+  p = dns_a4todn_(addr, dn, dn + dnsiz);
+  if (!p) return 0;
+  r = dns_sptodn(tname, p, dnsiz - (p - dn));
+  return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
+}
+
+dnscc_t dns_ip6_arpa_dn[10] = "\03ip6\04arpa";
+
+dnsc_t *
+dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne) {
+  unsigned n;
+  dnscc_t *s = ((dnscc_t *)addr) + 16;
+  if (dn + 64 > dne) return 0;
+  while(--s >= (dnscc_t *)addr) {
+    *dn++ = 1;
+    n = *s & 0x0f;
+    *dn++ = n > 9 ? n + 'a' - 10 : n + '0';
+    *dn++ = 1;
+    n = *s >> 4;
+    *dn++ = n > 9 ? n + 'a' - 10 : n + '0';
+  }
+  return dn;
+}
+
+int dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn,
+               dnsc_t *dn, unsigned dnsiz) {
+  dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
+  dnsc_t *p;
+  unsigned l;
+  p = dns_a6todn_(addr, dn, dne);
+  if (!p) return 0;
+  if (!tdn)
+    tdn = dns_ip6_arpa_dn;
+  l = dns_dnlen(tdn);
+  if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
+  memcpy(p, tdn, l);
+  return (p + l) - dn;
+}
+
+int dns_a6ptodn(const struct in6_addr *addr, const char *tname,
+                dnsc_t *dn, unsigned dnsiz) {
+  dnsc_t *p;
+  int r;
+  if (!tname)
+    return dns_a6todn(addr, NULL, dn, dnsiz);
+  p = dns_a6todn_(addr, dn, dn + dnsiz);
+  if (!p) return 0;
+  r = dns_sptodn(tname, p, dnsiz - (p - dn));
+  return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
+}
+
+/* return size of buffer required to convert the dn into asciiz string.
+ * Keep in sync with dns_dntop() below.
+ */
+unsigned dns_dntop_size(dnscc_t *dn) {
+  unsigned size = 0;		/* the size reqd */
+  dnscc_t *le;			/* label end */
+
+  while(*dn) {
+    /* *dn is the length of the next label, non-zero */
+    if (size)
+      ++size;		/* for the dot */
+    le = dn + *dn + 1;
+    ++dn;
+    do {
+      switch(*dn) {
+      case '.':
+      case '\\':
+      /* Special modifiers in zone files. */
+      case '"':
+      case ';':
+      case '@':
+      case '$':
+        size += 2;
+        break;
+      default:
+        if (*dn <= 0x20 || *dn >= 0x7f)
+          /* \ddd decimal notation */
+          size += 4;
+        else
+          size += 1;
+      }
+    } while(++dn < le);
+  }
+  size += 1;	/* zero byte at the end - string terminator */
+  return size > DNS_MAXNAME ? 0 : size;
+}
+
+/* Convert the dn into asciiz string.
+ * Keep in sync with dns_dntop_size() above.
+ */
+int dns_dntop(dnscc_t *dn, char *name, unsigned namesiz) {
+  char *np = name;			/* current name ptr */
+  char *const ne = name + namesiz;	/* end of name */
+  dnscc_t *le;		/* label end */
+
+  while(*dn) {
+    /* *dn is the length of the next label, non-zero */
+    if (np != name) {
+      if (np >= ne) goto toolong;
+      *np++ = '.';
+    }
+    le = dn + *dn + 1;
+    ++dn;
+    do {
+      switch(*dn) {
+      case '.':
+      case '\\':
+      /* Special modifiers in zone files. */
+      case '"':
+      case ';':
+      case '@':
+      case '$':
+        if (np + 2 > ne) goto toolong;
+        *np++ = '\\';
+        *np++ = *dn;
+        break;
+      default:
+        if (*dn <= 0x20 || *dn >= 0x7f) {
+          /* \ddd decimal notation */
+          if (np + 4 >= ne) goto toolong;
+          *np++ = '\\';
+          *np++ = '0' + (*dn / 100);
+          *np++ = '0' + ((*dn % 100) / 10);
+          *np++ = '0' + (*dn % 10);
+        }
+        else {
+          if (np >= ne) goto toolong;
+          *np++ = *dn;
+        }
+      }
+    } while(++dn < le);
+  }
+  if (np >= ne) goto toolong;
+  *np++ = '\0';
+  return np - name;
+toolong:
+  return namesiz >= DNS_MAXNAME ? -1 : 0;
+}
+
+#ifdef TEST
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+  int i;
+  int sz;
+  dnsc_t dn[DNS_MAXDN+10];
+  dnsc_t *dl, *dp;
+  int isabs;
+
+  sz = (argc > 1) ? atoi(argv[1]) : 0;
+
+  for(i = 2; i < argc; ++i) {
+    int r = dns_ptodn(argv[i], 0, dn, sz, &isabs);
+    printf("%s: ", argv[i]);
+    if (r < 0) printf("error\n");
+    else if (!r) printf("buffer too small\n");
+    else {
+      printf("len=%d dnlen=%d size=%d name:",
+             r, dns_dnlen(dn), dns_dntop_size(dn));
+      dl = dn;
+      while(*dl) {
+        printf(" %d=", *dl);
+        dp = dl + 1;
+        dl = dp + *dl;
+        while(dp < dl) {
+          if (*dp <= ' ' || *dp >= 0x7f)
+            printf("\\%03d", *dp);
+          else if (*dp == '.' || *dp == '\\')
+            printf("\\%c", *dp);
+          else
+            putchar(*dp);
+          ++dp;
+        }
+      }
+      if (isabs) putchar('.');
+      putchar('\n');
+    }
+  }
+  return 0;
+}
+
+#endif /* TEST */

Added: freeswitch/trunk/libs/udns/udns_dntosp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_dntosp.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,30 @@
+/* $Id: udns_dntosp.c,v 1.5 2005/04/19 21:48:09 mjt Exp $
+   dns_dntosp() = convert DN to asciiz string using static buffer
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include "udns.h"
+
+static char name[DNS_MAXNAME];
+
+const char *dns_dntosp(dnscc_t *dn) {
+  return dns_dntop(dn, name, sizeof(name)) > 0 ? name : 0;
+}

Added: freeswitch/trunk/libs/udns/udns_misc.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_misc.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,67 @@
+/* $Id: udns_misc.c,v 1.8 2005/04/05 22:51:32 mjt Exp $
+   miscellaneous routines
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include "udns.h"
+
+int dns_findname(const struct dns_nameval *nv, const char *name) {
+  register const char *a, *b;
+  for(; nv->name; ++nv)
+    for(a = name, b = nv->name; ; ++a, ++b)
+      if (DNS_DNUC(*a) != *b) break;
+      else if (!*a) return nv->val;
+  return -1;
+}
+
+const char *_dns_format_code(char *buf, const char *prefix, int code) {
+  char *bp = buf;
+  unsigned c, n;
+  do *bp++ = DNS_DNUC(*prefix);
+  while(*++prefix);
+  *bp++ = '#';
+  if (code < 0) code = -code, *bp++ = '-';
+  n = 0; c = code;
+  do ++n;
+  while((c /= 10));
+  c = code;
+  bp[n--] = '\0';
+  do bp[n--] = c % 10 + '0';
+  while((c /= 10));
+  return buf;
+}
+
+const char *dns_strerror(int err) {
+  if (err >= 0) return "successeful completion";
+  switch(err) {
+  case DNS_E_TEMPFAIL:	return "temporary failure in name resolution";
+  case DNS_E_PROTOCOL:	return "protocol error";
+  case DNS_E_NXDOMAIN:	return "domain name does not exist";
+  case DNS_E_NODATA:	return "valid domain but no data of requested type";
+  case DNS_E_NOMEM:	return "out of memory";
+  case DNS_E_BADQUERY:	return "malformed query";
+  default:		return "unknown error";
+  }
+}
+
+const char *dns_version(void) {
+  return UDNS_VERSION;
+}

Added: freeswitch/trunk/libs/udns/udns_parse.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_parse.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,169 @@
+/* $Id: udns_parse.c,v 1.14 2005/09/12 10:55:21 mjt Exp $
+   raw DNS packet parsing routines
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <string.h>
+#include <assert.h>
+#include "udns.h"
+
+dnscc_t *dns_skipdn(dnscc_t *cur, dnscc_t *end) {
+  unsigned c;
+  for(;;) {
+    if (cur >= end)
+      return NULL;
+    c = *cur++;
+    if (!c)
+      return cur;
+    if (c & 192)		/* jump */
+      return cur + 1 >= end ? NULL : cur + 1;
+    cur += c;
+  }
+}
+
+int
+dns_getdn(dnscc_t *pkt, dnscc_t **cur, dnscc_t *end,
+          register dnsc_t *dn, unsigned dnsiz) {
+  unsigned c;
+  dnscc_t *pp = *cur;		/* current packet pointer */
+  dnsc_t *dp = dn;		/* current dn pointer */
+  dnsc_t *const de		/* end of the DN dest */
+       = dn + (dnsiz < DNS_MAXDN ? dnsiz : DNS_MAXDN);
+  dnscc_t *jump = NULL;		/* ptr after first jump if any */
+  unsigned loop = 100;		/* jump loop counter */
+
+  for(;;) {		/* loop by labels */
+    if (pp >= end)		/* reached end of packet? */
+      return -1;
+    c = *pp++;			/* length of the label */
+    if (!c) {			/* empty label: terminate */
+      if (dn >= de)		/* can't fit terminator */
+        goto noroom;
+      *dp++ = 0;
+      /* return next pos: either after the first jump or current */
+      *cur = jump ? jump : pp;
+      return dp - dn;
+    }
+    if (c & 192) {		/* jump */
+      if (pp >= end)		/* eop instead of jump pos */
+        return -1;
+      if (!jump) jump = pp + 1;	/* remember first jump */
+      else if (!--loop) return -1; /* too many jumps */
+      c = ((c & ~192) << 8) | *pp; /* new pos */
+      if (c < DNS_HSIZE)	/* don't allow jump into the header */
+        return -1;
+      pp = pkt + c;
+      continue;
+    }
+    if (c > DNS_MAXLABEL)	/* too long label? */
+      return -1;
+    if (pp + c > end)		/* label does not fit in packet? */
+      return -1;
+    if (dp + c + 1 > de)	/* if enouth room for the label */
+      goto noroom;
+    *dp++ = c;			/* label length */
+    memcpy(dp, pp, c);		/* and the label itself */
+    dp += c;
+    pp += c;			/* advance to the next label */
+  }
+noroom:
+  return dnsiz < DNS_MAXDN ? 0 : -1;
+}
+
+void dns_rewind(struct dns_parse *p, dnscc_t *qdn) {
+  p->dnsp_qdn = qdn;
+  p->dnsp_cur = p->dnsp_ans;
+  p->dnsp_rrl = dns_numan(p->dnsp_pkt);
+  p->dnsp_ttl = 0xffffffffu;
+  p->dnsp_nrr = 0;
+}
+
+void
+dns_initparse(struct dns_parse *p, dnscc_t *qdn,
+              dnscc_t *pkt, dnscc_t *cur, dnscc_t *end) {
+  p->dnsp_pkt = pkt;
+  p->dnsp_end = end;
+  p->dnsp_rrl = dns_numan(pkt);
+  p->dnsp_qdn = qdn;
+  assert(cur + 4 <= end);
+  if ((p->dnsp_qtyp = dns_get16(cur+0)) == DNS_T_ANY) p->dnsp_qtyp = 0;
+  if ((p->dnsp_qcls = dns_get16(cur+2)) == DNS_C_ANY) p->dnsp_qcls = 0;
+  p->dnsp_cur = p->dnsp_ans = cur + 4;
+  p->dnsp_ttl = 0xffffffffu;
+  p->dnsp_nrr = 0;
+}
+
+int dns_nextrr(struct dns_parse *p, struct dns_rr *rr) {
+  dnscc_t *cur = p->dnsp_cur;
+  while(p->dnsp_rrl > 0) {
+    --p->dnsp_rrl;
+    if (dns_getdn(p->dnsp_pkt, &cur, p->dnsp_end,
+                  rr->dnsrr_dn, sizeof(rr->dnsrr_dn)) <= 0)
+      return -1;
+    if (cur + 10 > p->dnsp_end)
+      return -1;
+    rr->dnsrr_typ = dns_get16(cur);
+    rr->dnsrr_cls = dns_get16(cur+2);
+    rr->dnsrr_ttl = dns_get32(cur+4);
+    rr->dnsrr_dsz = dns_get16(cur+8);
+    rr->dnsrr_dptr = cur = cur + 10;
+    rr->dnsrr_dend = cur = cur + rr->dnsrr_dsz;
+    if (cur > p->dnsp_end)
+      return -1;
+    if (p->dnsp_qdn && !dns_dnequal(p->dnsp_qdn, rr->dnsrr_dn))
+      continue;
+    if ((!p->dnsp_qcls || p->dnsp_qcls == rr->dnsrr_cls) &&
+        (!p->dnsp_qtyp || p->dnsp_qtyp == rr->dnsrr_typ)) {
+      p->dnsp_cur = cur;
+      ++p->dnsp_nrr;
+      if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl;
+      return 1;
+    }
+    if (p->dnsp_qdn && rr->dnsrr_typ == DNS_T_CNAME && !p->dnsp_nrr) {
+      if (dns_getdn(p->dnsp_pkt, &rr->dnsrr_dptr, p->dnsp_end,
+                    p->dnsp_dnbuf, sizeof(p->dnsp_dnbuf)) <= 0 ||
+          rr->dnsrr_dptr != rr->dnsrr_dend)
+        return -1;
+      p->dnsp_qdn = p->dnsp_dnbuf;
+      if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl;
+    }
+  }
+  p->dnsp_cur = cur;
+  return 0;
+}
+
+int dns_stdrr_size(const struct dns_parse *p) {
+  return
+    dns_dntop_size(p->dnsp_qdn) +
+    (p->dnsp_qdn == dns_payload(p->dnsp_pkt) ? 0 :
+     dns_dntop_size(dns_payload(p->dnsp_pkt)));
+}
+
+void *dns_stdrr_finish(struct dns_rr_null *ret, char *cp,
+                       const struct dns_parse *p) {
+  cp += dns_dntop(p->dnsp_qdn, (ret->dnsn_cname = cp), DNS_MAXNAME);
+  if (p->dnsp_qdn == dns_payload(p->dnsp_pkt))
+    ret->dnsn_qname = ret->dnsn_cname;
+  else
+    dns_dntop(dns_payload(p->dnsp_pkt), (ret->dnsn_qname = cp), DNS_MAXNAME);
+  ret->dnsn_ttl = p->dnsp_ttl;
+  return ret;
+}

Added: freeswitch/trunk/libs/udns/udns_resolver.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_resolver.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,1334 @@
+/* $Id: udns_resolver.c,v 1.57 2006/11/29 01:17:43 mjt Exp $
+   resolver stuff (main module)
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#ifdef WIN32
+# include <winsock2.h>          /* includes <windows.h> */
+# include <ws2tcpip.h>          /* needed for struct in6_addr */
+# include <iphlpapi.h>		/* for dns server addresses etc */
+# undef HAVE_POLL
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>		/* for inet_pton() */
+# include <unistd.h>
+# include <fcntl.h>
+# include <sys/time.h>
+# ifdef HAVE_CONFIG_H
+#  include <config.h>
+# endif
+# ifdef HAVE_POLL
+#  include <sys/poll.h>
+# endif
+# define closesocket(sock) close(sock)
+#endif	/* !WIN32 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+#include <stddef.h>
+#include "udns.h"
+
+#define DNS_QEXTRA	16	/* size of extra buffer space */
+#define DNS_QBUF	DNS_HSIZE+DNS_MAXDN+DNS_QEXTRA
+
+#if !defined(HAVE_INET6) && defined(AF_INET6)
+# define HAVE_INET6 1
+#endif
+#ifdef NO_INET6
+# undef HAVE_INET6
+#endif
+
+#ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT EINVAL
+#endif
+
+union sockaddr_ns {
+  struct sockaddr sa;
+  struct sockaddr_in sin;
+#if HAVE_INET6
+  struct sockaddr_in6 sin6;
+#endif
+};
+
+struct dns_qlink {
+  struct dns_query *next, *prev;
+};
+
+struct dns_query {
+  struct dns_qlink dnsq_link;		/* list entry (should be first) */
+  dnsc_t dnsq_buf[DNS_QBUF];		/* the query buffer */
+  enum dns_class dnsq_cls;		/* requested RR class */
+  enum dns_type  dnsq_typ;		/* requested RR type */
+  unsigned dnsq_len;			/* length of the query packet */
+  unsigned dnsq_origdnl;		/* original length of the dnsq_dn */
+  unsigned dnsq_flags;			/* control flags for this query */
+  unsigned dnsq_servi;			/* index of next server to try */
+  unsigned dnsq_servwait;		/* bitmask: servers left to wait */
+  unsigned dnsq_servskip;		/* bitmask: servers to skip */
+  unsigned dnsq_try;			/* number of tries made so far */
+  unsigned dnsq_srchi;			/* current search index */
+  time_t dnsq_deadline;			/* when current try will expire */
+  dns_parse_fn *dnsq_parse;		/* parse: raw => application */
+  dns_query_fn *dnsq_cbck;		/* the callback to call when done */
+  void *dnsq_cbdata;			/* user data for the callback */
+#ifndef NDEBUG
+  struct dns_ctx *dnsq_ctx;		/* the resolver context */
+#endif
+};
+
+/* working with dns_query lists */
+
+static __inline void qlist_init(struct dns_qlink *list) {
+  list->next = list->prev = (struct dns_query *)list;
+}
+
+static __inline int qlist_empty(const struct dns_qlink *list) {
+  return list->next == (const struct dns_query *)list ? 1 : 0;
+}
+
+static __inline struct dns_query *qlist_first(struct dns_qlink *list) {
+  return list->next == (struct dns_query *)list ? 0 : list->next;
+}
+
+static __inline void qlist_remove(struct dns_query *q) {
+  q->dnsq_link.next->dnsq_link.prev = q->dnsq_link.prev;
+  q->dnsq_link.prev->dnsq_link.next = q->dnsq_link.next;
+}
+
+static __inline struct dns_query *qlist_pop(struct dns_qlink *list) {
+  struct dns_query *q = list->next;
+  if (q == (struct dns_query *)list)
+    return NULL;
+  qlist_remove(q);
+  return q;
+}
+
+/* insert q between prev and next */
+static __inline void
+qlist_insert(struct dns_query *q,
+             struct dns_query *prev, struct dns_query *next) {
+  q->dnsq_link.next = next;
+  q->dnsq_link.prev = prev;
+  prev->dnsq_link.next = next->dnsq_link.prev = q;
+}
+
+static __inline void
+qlist_insert_after(struct dns_query *q, struct dns_query *prev) {
+  qlist_insert(q, prev, prev->dnsq_link.next);
+}
+
+static __inline void
+qlist_insert_before(struct dns_query *q, struct dns_query *next) {
+  qlist_insert(q, next->dnsq_link.prev, next);
+}
+
+static __inline void
+qlist_add_tail(struct dns_query *q, struct dns_qlink *top) {
+  qlist_insert_before(q, (struct dns_query *)top);
+}
+
+static __inline void
+qlist_add_head(struct dns_query *q, struct dns_qlink *top) {
+  qlist_insert_after(q, (struct dns_query *)top);
+}
+
+#define QLIST_FIRST(list, direction) ((list)->direction)
+#define QLIST_ISLAST(list, q) ((q) == (struct dns_query*)(list))
+#define QLIST_NEXT(q, direction) ((q)->dnsq_link.direction)
+
+#define QLIST_FOR_EACH(list, q, direction) \
+  for(q = QLIST_FIRST(list, direction); \
+      !QLIST_ISLAST(list, q); q = QLIST_NEXT(q, direction))
+
+struct dns_ctx {		/* resolver context */
+  /* settings */
+  unsigned dnsc_flags;			/* various flags */
+  unsigned dnsc_timeout;		/* timeout (base value) for queries */
+  unsigned dnsc_ntries;			/* number of retries */
+  unsigned dnsc_ndots;			/* ndots to assume absolute name */
+  unsigned dnsc_port;			/* default port (DNS_PORT) */
+  unsigned dnsc_udpbuf;			/* size of UDP buffer */
+  /* array of nameserver addresses */
+  union sockaddr_ns dnsc_serv[DNS_MAXSERV];
+  unsigned dnsc_nserv;			/* number of nameservers */
+  unsigned dnsc_salen;			/* length of socket addresses */
+  /* search list for unqualified names */
+  dnsc_t dnsc_srch[DNS_MAXSRCH][DNS_MAXDN];
+  unsigned dnsc_nsrch;			/* number of srch[] */
+
+  dns_utm_fn *dnsc_utmfn;		/* register/cancel timer events */
+  void *dnsc_utmctx;			/* user timer context for utmfn() */
+  time_t dnsc_utmexp;			/* when user timer expires */
+
+  dns_dbgfn *dnsc_udbgfn;		/* debugging function */
+
+  /* dynamic data */
+  unsigned short dnsc_nextid;		/* next queue ID to use */
+  int dnsc_udpsock;			/* UDP socket */
+  struct dns_qlink dnsc_qactive;	/* active list sorted by deadline */
+  int dnsc_nactive;			/* number entries in dnsc_qactive */
+  dnsc_t *dnsc_pbuf;			/* packet buffer (udpbuf size) */
+  int dnsc_qstatus;			/* last query status value */
+};
+
+static const struct {
+  const char *name;
+  enum dns_opt opt;
+  unsigned offset;
+  unsigned min, max;
+} dns_opts[] = {
+#define opt(name,opt,field,min,max) \
+	{name,opt,offsetof(struct dns_ctx,field),min,max}
+  opt("retrans", DNS_OPT_TIMEOUT, dnsc_timeout, 1,300),
+  opt("timeout", DNS_OPT_TIMEOUT, dnsc_timeout, 1,300),
+  opt("retry",    DNS_OPT_NTRIES, dnsc_ntries, 1,50),
+  opt("attempts", DNS_OPT_NTRIES, dnsc_ntries, 1,50),
+  opt("ndots", DNS_OPT_NDOTS, dnsc_ndots, 0,1000),
+  opt("port", DNS_OPT_PORT, dnsc_port, 1,0xffff),
+  opt("udpbuf", DNS_OPT_UDPSIZE, dnsc_udpbuf, DNS_MAXPACKET,65536),
+#undef opt
+};
+#define dns_ctxopt(ctx,offset) (*((unsigned*)(((char*)ctx)+offset)))
+
+#define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n')
+
+static const char space[] = " \t\r\n";
+
+struct dns_ctx dns_defctx;
+
+#define SETCTX(ctx) if (!ctx) ctx = &dns_defctx
+#define SETCTXINITED(ctx) SETCTX(ctx); assert(CTXINITED(ctx))
+#define CTXINITED(ctx) (ctx->dnsc_flags & DNS_INITED)
+#define SETCTXFRESH(ctx) SETCTXINITED(ctx); assert(!CTXOPEN(ctx))
+#define SETCTXINACTIVE(ctx) SETCTXINITED(ctx); assert(qlist_empty(&ctx->dnsc_qactive))
+#define SETCTXOPEN(ctx) SETCTXINITED(ctx); assert(CTXOPEN(ctx))
+#define CTXOPEN(ctx) (ctx->dnsc_udpsock >= 0)
+
+#if defined(NDEBUG) || !defined(DEBUG)
+#define dns_assert_ctx(ctx)
+#else
+static void dns_assert_ctx(const struct dns_ctx *ctx) {
+  int nactive = 0;
+  const struct dns_query *q;
+  QLIST_FOR_EACH(&ctx->dnsc_qactive, q, next) {
+    assert(q->dnsq_ctx == ctx);
+    assert(q->dnsq_link.next->dnsq_link.prev == q);
+    assert(q->dnsq_link.prev->dnsq_link.next == q);
+    ++nactive;
+  }
+  assert(nactive == ctx->dnsc_nactive);
+}
+#endif
+
+enum {
+  DNS_INTERNAL		= 0xffff, /* internal flags mask */
+  DNS_INITED		= 0x0001, /* the context is initialized */
+  DNS_ASIS_DONE		= 0x0002, /* search: skip the last as-is query */
+  DNS_SEEN_NODATA	= 0x0004, /* search: NODATA has been received */
+  DNS_SEEN_FAIL		= 0x0008, /* search: SERVFAIL has been received */
+  DNS_SEEN_WRONG	= 0x0010, /* search: something wrong happened */
+};
+
+static int dns_add_serv_internal(struct dns_ctx *ctx, const char *serv) {
+  union sockaddr_ns *sns;
+  if (!serv)
+    return (ctx->dnsc_nserv = 0);
+  if (ctx->dnsc_nserv >= DNS_MAXSERV)
+    return errno = ENFILE, -1;
+  sns = &ctx->dnsc_serv[ctx->dnsc_nserv];
+  memset(sns, 0, sizeof(*sns));
+#if HAVE_INET6
+  { struct in_addr addr;
+    struct in6_addr addr6;
+    if (inet_pton(AF_INET, serv, &addr) > 0) {
+      sns->sin.sin_family = AF_INET;
+      sns->sin.sin_addr = addr;
+      return ++ctx->dnsc_nserv;
+    }
+    if (inet_pton(AF_INET6, serv, &addr6) > 0) {
+      sns->sin6.sin6_family = AF_INET6;
+      sns->sin6.sin6_addr = addr6;
+      return ++ctx->dnsc_nserv;
+    }
+  }
+#else
+  { struct in_addr addr;
+    if (inet_aton(serv, &addr) > 0) {
+      sns->sin.sin_family = AF_INET;
+      sns->sin.sin_addr = addr;
+      return ++ctx->dnsc_nserv;
+    }
+  }
+#endif
+  errno = EINVAL;
+  return -1;
+}
+
+int dns_add_serv(struct dns_ctx *ctx, const char *serv) {
+  SETCTXFRESH(ctx);
+  return dns_add_serv_internal(ctx, serv);
+}
+
+static void dns_set_serv_internal(struct dns_ctx *ctx, char *serv) {
+  ctx->dnsc_nserv = 0;
+  for(serv = strtok(serv, space); serv; serv = strtok(NULL, space))
+    dns_add_serv_internal(ctx, serv);
+}
+
+static int
+dns_add_serv_s_internal(struct dns_ctx *ctx, const struct sockaddr *sa) {
+  if (!sa)
+    return (ctx->dnsc_nserv = 0);
+  if (ctx->dnsc_nserv >= DNS_MAXSERV)
+    return errno = ENFILE, -1;
+#if HAVE_INET6
+  else if (sa->sa_family == AF_INET6)
+    ctx->dnsc_serv[ctx->dnsc_nserv].sin6 = *(struct sockaddr_in6*)sa;
+#endif
+  else if (sa->sa_family == AF_INET)
+    ctx->dnsc_serv[ctx->dnsc_nserv].sin = *(struct sockaddr_in*)sa;
+  else
+    return errno = EAFNOSUPPORT, -1;
+  return ++ctx->dnsc_nserv;
+}
+
+int dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa) {
+  SETCTXFRESH(ctx);
+  return dns_add_serv_s_internal(ctx, sa);
+}
+
+static void dns_set_opts_internal(struct dns_ctx *ctx, const char *opts) {
+  unsigned i, v;
+  for(;;) {
+    while(ISSPACE(*opts)) ++opts;
+    if (!*opts) break;
+    for(i = 0; i < sizeof(dns_opts)/sizeof(dns_opts[0]); ++i) {
+      v = strlen(dns_opts[i].name);
+      if (strncmp(dns_opts[i].name, opts, v) != 0 ||
+          (opts[v] != ':' && opts[v] != '='))
+        continue;
+      opts += v + 1;
+      v = 0;
+      if (*opts < '0' || *opts > '9') break;
+      do v = v * 10 + (*opts++ - '0');
+      while (*opts >= '0' && *opts <= '9');
+      if (dns_opts[i].min && v < dns_opts[i].min) v = dns_opts[i].min;
+      else if (v > dns_opts[i].max) v = dns_opts[i].max;
+      dns_ctxopt(ctx, dns_opts[i].offset) = v;
+      break;
+    }
+    while(*opts && !ISSPACE(*opts)) ++opts;
+  }
+}
+
+int dns_set_opts(struct dns_ctx *ctx, const char *opts) {
+  SETCTXINACTIVE(ctx);
+  dns_set_opts_internal(ctx, opts);
+  return 0;
+}
+
+int dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val) {
+  int prev;
+  unsigned i;
+  SETCTXINACTIVE(ctx);
+  for(i = 0; i < sizeof(dns_opts)/sizeof(dns_opts[0]); ++i) {
+    if (dns_opts[i].opt != opt) continue;
+    prev = dns_ctxopt(ctx, dns_opts[i].offset);
+    if (val >= 0) {
+      unsigned v = val;
+      if (v < dns_opts[i].min || v > dns_opts[i].max) {
+        errno = EINVAL;
+        return -1;
+      }
+      dns_ctxopt(ctx, dns_opts[i].offset) = v;
+    }
+    return prev;
+  }
+  if (opt == DNS_OPT_FLAGS) {
+    prev = ctx->dnsc_flags & ~DNS_INTERNAL;
+    if (val >= 0)
+      ctx->dnsc_flags =
+        (ctx->dnsc_flags & DNS_INTERNAL) | (val & ~DNS_INTERNAL);
+    return prev;
+  }
+  errno = ENOSYS;
+  return -1;
+}
+
+static int dns_add_srch_internal(struct dns_ctx *ctx, const char *srch) {
+  if (!srch)
+    return (ctx->dnsc_nsrch = 0);
+  else if (ctx->dnsc_nsrch >= DNS_MAXSRCH)
+    return errno = ENFILE, -1;
+  else if (dns_sptodn(srch, ctx->dnsc_srch[ctx->dnsc_nsrch], DNS_MAXDN) <= 0)
+    return errno = EINVAL, -1;
+  else
+    return ++ctx->dnsc_nsrch;
+}
+
+int dns_add_srch(struct dns_ctx *ctx, const char *srch) {
+  SETCTXINACTIVE(ctx);
+  return dns_add_srch_internal(ctx, srch);
+}
+
+static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) {
+  ctx->dnsc_nsrch = 0;
+  for(srch = strtok(srch, space); srch; srch = strtok(NULL, space))
+    dns_add_srch_internal(ctx, srch);
+}
+
+static void dns_drop_utm(struct dns_ctx *ctx) {
+  if (ctx->dnsc_utmfn)
+    ctx->dnsc_utmfn(NULL, -1, ctx->dnsc_utmctx);
+  ctx->dnsc_utmctx = NULL;
+  ctx->dnsc_utmexp = -1;
+}
+
+static void
+dns_request_utm(struct dns_ctx *ctx, time_t now) {
+  struct dns_query *q;
+  time_t deadline;
+  int timeout;
+  if (!ctx->dnsc_utmfn)
+    return;
+  q = QLIST_FIRST(&ctx->dnsc_qactive, next);
+  if (QLIST_ISLAST(&ctx->dnsc_qactive, q))
+    deadline = -1, timeout = -1;
+  else if (!now || q->dnsq_deadline <= now)
+    deadline = 0, timeout = 0;
+  else
+    deadline = q->dnsq_deadline, timeout = deadline - now;
+  if (ctx->dnsc_utmexp == deadline)
+    return;
+  ctx->dnsc_utmfn(ctx, timeout, ctx->dnsc_utmctx);
+  ctx->dnsc_utmexp = deadline;
+}
+
+void dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn) {
+  SETCTXINITED(ctx);
+  ctx->dnsc_udbgfn = dbgfn;
+}
+
+void
+dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data) {
+  SETCTXINITED(ctx);
+  dns_drop_utm(ctx);
+  ctx->dnsc_utmfn = fn;
+  ctx->dnsc_utmctx = data;
+}
+
+static void dns_firstid(struct dns_ctx *ctx) {
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  ctx->dnsc_nextid = (tv.tv_usec ^ getpid()) & 0xffff;
+}
+
+#ifdef WIN32
+
+typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(
+  ULONG Family, DWORD Flags, PVOID Reserved,
+  PIP_ADAPTER_ADDRESSES pAdapterAddresses,
+  PULONG pOutBufLen);
+
+static int dns_initns_iphlpapi(struct dns_ctx *ctx) {
+  HANDLE h_iphlpapi;
+  GetAdaptersAddressesFunc pfnGetAdAddrs;
+  PIP_ADAPTER_ADDRESSES pAddr, pAddrBuf;
+  PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr;
+  ULONG ulOutBufLen;
+  DWORD dwRetVal;
+  int ret = -1;
+
+  h_iphlpapi = LoadLibrary("iphlpapi.dll");
+  if (!h_iphlpapi)
+    return -1;
+  pfnGetAdAddrs = (GetAdaptersAddressesFunc)
+    GetProcAddress(h_iphlpapi, "GetAdaptersAddresses");
+  if (!pfnGetAdAddrs) goto freelib;
+  ulOutBufLen = 0;
+  dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
+  if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib;
+  pAddrBuf = malloc(ulOutBufLen);
+  if (!pAddrBuf) goto freelib;
+  dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
+  if (dwRetVal != ERROR_SUCCESS) goto freemem;
+  for (pAddr = pAddrBuf;
+       pAddr && ctx->dnsc_nserv <= DNS_MAXSERV;
+       pAddr = pAddr->Next)
+    for (pDnsAddr = pAddr->FirstDnsServerAddress;
+         pDnsAddr && ctx->dnsc_nserv <= DNS_MAXSERV;
+         pDnsAddr = pDnsAddr->Next)
+      dns_add_serv_s_internal(ctx, pDnsAddr->Address.lpSockaddr);
+  ret = 0;
+freemem:
+  free(pAddrBuf);
+freelib:
+  FreeLibrary(h_iphlpapi);
+  return ret;
+}
+
+static int dns_initns_registry(struct dns_ctx *ctx) {
+  LONG res;
+  HKEY hk;
+  DWORD type = REG_EXPAND_SZ | REG_SZ;
+  DWORD len;
+  char valBuf[1024];
+
+#define REGKEY_WINNT "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+#define REGKEY_WIN9x "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
+  res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINNT, 0, KEY_QUERY_VALUE, &hk);
+  if (res != ERROR_SUCCESS)
+    res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WIN9x,
+                       0, KEY_QUERY_VALUE, &hk);
+  if (res != ERROR_SUCCESS)
+    return -1;
+  len = sizeof(valBuf) - 1;
+  res = RegQueryValueEx(hk, "NameServer", NULL, &type, valBuf, &len);
+  if (res != ERROR_SUCCESS || !len || !valBuf[0]) {
+    len = sizeof(valBuf) - 1;
+    res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type, valBuf, &len);
+  }
+  RegCloseKey(hk);
+  if (res != ERROR_SUCCESS || !len || !valBuf[0])
+    return -1;
+  valBuf[len] = '\0';
+  /* nameservers are stored as a whitespace-seperate list:
+   * "192.168.1.1 123.21.32.12" */
+  dns_set_serv_internal(ctx, valBuf);
+  return 0;
+}
+
+static int dns_init_internal(struct dns_ctx *ctx) {
+  if (dns_initns_iphlpapi(ctx) != 0)
+    dns_initns_registry(ctx);
+  /*XXX WIN32: probably good to get default domain and search list too...
+   * And options.  Something is in registry. */
+  /*XXX WIN32: maybe environment variables are also useful? */
+  return 0;
+}
+
+#else /* !WIN32 */
+
+static int dns_init_internal(struct dns_ctx *ctx) {
+  char *v;
+  char buf[2049];	/* this buffer is used to hold /etc/resolv.conf */
+
+  /* read resolv.conf... */
+  { int fd = open("/etc/resolv.conf", O_RDONLY);
+    if (fd >= 0) {
+      int l = read(fd, buf, sizeof(buf) - 1);
+      close(fd);
+      buf[l < 0 ? 0 : l] = '\0';
+    }
+    else
+      buf[0] = '\0';
+  }
+  if (buf[0]) {	/* ...and parse it */
+    char *line, *nextline;
+    line = buf;
+    do {
+      nextline = strchr(line, '\n');
+      if (nextline) *nextline++ = '\0';
+      v = line;
+      while(*v && !ISSPACE(*v)) ++v;
+      if (!*v) continue;
+      *v++ = '\0';
+      while(ISSPACE(*v)) ++v;
+      if (!*v) continue;
+      if (strcmp(line, "domain") == 0)
+        dns_set_srch_internal(ctx, strtok(v, space));
+      else if (strcmp(line, "search") == 0)
+        dns_set_srch_internal(ctx, v);
+      else if (strcmp(line, "nameserver") == 0)
+        dns_add_serv_internal(ctx, strtok(v, space));
+      else if (strcmp(line, "options") == 0)
+        dns_set_opts_internal(ctx, v);
+    } while((line = nextline) != NULL);
+  }
+
+  buf[sizeof(buf)-1] = '\0';
+
+  /* get list of nameservers from env. vars. */
+  if ((v = getenv("NSCACHEIP")) != NULL ||
+      (v = getenv("NAMESERVERS")) != NULL) {
+    strncpy(buf, v, sizeof(buf) - 1);
+    dns_set_serv_internal(ctx, buf);
+  }
+  /* if $LOCALDOMAIN is set, use it for search list */
+  if ((v = getenv("LOCALDOMAIN")) != NULL) {
+    strncpy(buf, v, sizeof(buf) - 1);
+    dns_set_srch_internal(ctx, buf);
+  }
+  if ((v = getenv("RES_OPTIONS")) != NULL)
+    dns_set_opts_internal(ctx, v);
+
+  /* if still no search list, use local domain name */
+  if (!ctx->dnsc_nsrch &&
+      gethostname(buf, sizeof(buf) - 1) == 0 &&
+      (v = strchr(buf, '.')) != NULL &&
+      *++v != '\0')
+    dns_add_srch_internal(ctx, v);
+
+  return 0;
+}
+
+#endif /* dns_init_internal() for !WIN32 */
+
+int dns_init(int do_open) {
+  struct dns_ctx *ctx = &dns_defctx;
+  assert(!CTXINITED(ctx));
+  memset(ctx, 0, sizeof(*ctx));
+  ctx->dnsc_timeout = 4;
+  ctx->dnsc_ntries = 3;
+  ctx->dnsc_ndots = 1;
+  ctx->dnsc_udpbuf = DNS_EDNS0PACKET;
+  ctx->dnsc_port = DNS_PORT;
+  ctx->dnsc_udpsock = -1;
+  qlist_init(&ctx->dnsc_qactive);
+  if (dns_init_internal(ctx) != 0)
+    return -1;
+  dns_firstid(ctx);
+  ctx->dnsc_flags |= DNS_INITED;
+  return do_open ? dns_open(ctx) : 0;
+}
+
+struct dns_ctx *dns_new(const struct dns_ctx *ctx) {
+  struct dns_ctx *n;
+  SETCTXINITED(ctx);
+  dns_assert_ctx(ctx);
+  n = malloc(sizeof(*n));
+  if (!n)
+    return NULL;
+  *n = *ctx;
+  n->dnsc_udpsock = -1;
+  qlist_init(&n->dnsc_qactive);
+  n->dnsc_nactive = 0;
+  n->dnsc_pbuf = NULL;
+  n->dnsc_qstatus = 0;
+  n->dnsc_utmfn = NULL;
+  n->dnsc_utmctx = NULL;
+  dns_firstid(n);
+  return n;
+}
+
+void dns_free(struct dns_ctx *ctx) {
+  struct dns_query *q;
+  SETCTXINITED(ctx);
+  dns_assert_ctx(ctx);
+  dns_drop_utm(ctx);
+  if (ctx->dnsc_udpsock >= 0)
+    closesocket(ctx->dnsc_udpsock);
+  if (ctx->dnsc_pbuf)
+    free(ctx->dnsc_pbuf);
+  while((q = qlist_pop(&ctx->dnsc_qactive)))
+    free(q);
+  if (ctx != &dns_defctx)
+    free(ctx);
+  else
+    memset(ctx, 0, sizeof(*ctx));
+}
+
+int dns_open(struct dns_ctx *ctx) {
+  int sock;
+  unsigned i;
+  int port;
+  union sockaddr_ns *sns;
+#if HAVE_INET6
+  unsigned have_inet6 = 0;
+#endif
+
+  SETCTXINITED(ctx);
+  assert(!CTXOPEN(ctx));
+
+  port = htons(ctx->dnsc_port);
+  /* ensure we have at least one server */
+  if (!ctx->dnsc_nserv) {
+    sns = ctx->dnsc_serv;
+    sns->sin.sin_family = AF_INET;
+    sns->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    ctx->dnsc_nserv = 1;
+  }
+
+  for (i = 0; i < ctx->dnsc_nserv; ++i) {
+    sns = &ctx->dnsc_serv[i];
+    /* set port for each sockaddr */
+#if HAVE_INET6
+    if (sns->sa.sa_family == AF_INET6) {
+      if (!sns->sin6.sin6_port) sns->sin6.sin6_port = port;
+      ++have_inet6;
+    }
+    else
+#endif
+    {
+      assert(sns->sa.sa_family == AF_INET);
+      if (!sns->sin.sin_port) sns->sin.sin_port = port;
+    }
+  }
+
+#if !HAVE_INET6
+  ctx->dnsc_salen = sizeof(struct sockaddr_in);
+#else
+  if (have_inet6 && have_inet6 < ctx->dnsc_nserv) {
+    /* convert all IPv4 addresses to IPv6 V4MAPPED */
+    struct sockaddr_in6 sin6;
+    memset(&sin6, 0, sizeof(sin6));
+    sin6.sin6_family = AF_INET6;
+    /* V4MAPPED: ::ffff:1.2.3.4 */
+    sin6.sin6_addr.s6_addr[10] = 0xff;
+    sin6.sin6_addr.s6_addr[11] = 0xff;
+    for(i = 0; i < ctx->dnsc_nserv; ++i) {
+      sns = &ctx->dnsc_serv[i];
+      if (sns->sa.sa_family == AF_INET) {
+        sin6.sin6_port = sns->sin.sin_port;
+        ((struct in_addr*)&sin6.sin6_addr)[3] = sns->sin.sin_addr;
+        sns->sin6 = sin6;
+      }
+    }
+  }
+
+  ctx->dnsc_salen = have_inet6 ?
+    sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
+
+  if (have_inet6)
+    sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+  else
+#endif /* HAVE_INET6 */
+    sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+  if (sock < 0) {
+    ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
+    return -1;
+  }
+#ifdef WIN32
+  { unsigned long on = 1;
+    if (ioctlsocket(sock, FIONBIO, &on) == SOCKET_ERROR) {
+      closesocket(sock);
+      ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
+      return -1;
+    }
+  }
+#else	/* !WIN32 */
+  if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0 ||
+      fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
+    closesocket(sock);
+    ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
+    return -1;
+  }
+#endif	/* WIN32 */
+  /* allocate the packet buffer */
+  if (!(ctx->dnsc_pbuf = malloc(ctx->dnsc_udpbuf))) {
+    closesocket(sock);
+    ctx->dnsc_qstatus = DNS_E_NOMEM;
+    errno = ENOMEM;
+    return -1;
+  }
+
+  ctx->dnsc_udpsock = sock;
+  return sock;
+}
+
+void dns_close(struct dns_ctx *ctx) {
+  SETCTXINITED(ctx);
+  if (ctx->dnsc_udpsock < 0) return;
+  closesocket(ctx->dnsc_udpsock);
+  ctx->dnsc_udpsock = -1;
+  free(ctx->dnsc_pbuf);
+  ctx->dnsc_pbuf = NULL;
+}
+
+int dns_sock(const struct dns_ctx *ctx) {
+  SETCTXINITED(ctx);
+  return ctx->dnsc_udpsock;
+}
+
+int dns_active(const struct dns_ctx *ctx) {
+  SETCTXINITED(ctx);
+  dns_assert_ctx(ctx);
+  return ctx->dnsc_nactive;
+}
+
+int dns_status(const struct dns_ctx *ctx) {
+  SETCTX(ctx);
+  return ctx->dnsc_qstatus;
+}
+void dns_setstatus(struct dns_ctx *ctx, int status) {
+  SETCTX(ctx);
+  ctx->dnsc_qstatus = status;
+}
+
+/* End the query and return the result to the caller.
+ */
+static void
+dns_end_query(struct dns_ctx *ctx, struct dns_query *q,
+              int status, void *result) {
+  dns_query_fn *cbck = q->dnsq_cbck;
+  void *cbdata = q->dnsq_cbdata;
+  ctx->dnsc_qstatus = status;
+  assert((status < 0 && result == 0) || (status >= 0 && result != 0));
+  assert(cbck != 0);	/*XXX callback may be NULL */
+  assert(ctx->dnsc_nactive > 0);
+  --ctx->dnsc_nactive;
+  /* force the query to be unconnected */
+  /*memset(q, 0, sizeof(*q));*/
+#ifndef NDEBUG
+  q->dnsq_ctx = NULL;
+#endif
+  free(q);
+  cbck(ctx, result, cbdata);
+}
+
+#define DNS_DBG(ctx, code, sa, slen, pkt, plen) \
+  do { \
+    if (ctx->dnsc_udbgfn) \
+      ctx->dnsc_udbgfn(code, (sa), slen, pkt, plen, 0, 0); \
+  } while(0)
+#define DNS_DBGQ(ctx, q, code, sa, slen, pkt, plen) \
+  do { \
+    if (ctx->dnsc_udbgfn) \
+      ctx->dnsc_udbgfn(code, (sa), slen, pkt, plen, q, q->dnsq_cbdata); \
+  } while(0)
+
+/* Try next search, filling in qDN in query.
+ * Return new qDN len or 0 if no more to search.
+ * Caller should fill up the rest of the query.
+ */
+static unsigned dns_next_srch(const struct dns_ctx *ctx, struct dns_query *q) {
+  unsigned ol = q->dnsq_origdnl - 1;	/* origdnl is at least 1 */
+  dnsc_t *p = dns_payload(q->dnsq_buf) + ol;
+  dnscc_t *dn;
+  int n;
+  while (q->dnsq_srchi < ctx->dnsc_nsrch) {
+    dn = ctx->dnsc_srch[q->dnsq_srchi++];
+    if (!*dn) {			/* root dn */
+      if (!(q->dnsq_flags & DNS_ASIS_DONE))
+        break;
+    }
+    else if ((n = dns_dntodn(dn, p, DNS_MAXDN - ol)) > 0)
+      return n + ol;
+  }
+  if (q->dnsq_flags & DNS_ASIS_DONE)
+    return 0;
+  q->dnsq_flags |= DNS_ASIS_DONE;
+  *p = '\0';
+  return ol + 1;
+}
+
+/* find the next server which isn't skipped starting from current.
+ * return 0 if ok, >0 if ok but we started next cycle, or <0 if
+ * number of tries exceeded or no more servers.
+ */
+static int dns_find_serv(const struct dns_ctx *ctx, struct dns_query *q) {
+  int cycle;
+  if (q->dnsq_try < ctx->dnsc_ntries) for(cycle = 0;;) {
+    if (q->dnsq_servi < ctx->dnsc_nserv) {
+      if (!(q->dnsq_servskip & (1 << q->dnsq_servi)))
+        return cycle;
+      ++q->dnsq_servi;
+    }
+    else if (cycle || ++q->dnsq_try >= ctx->dnsc_ntries)
+      break;
+    else {
+      cycle = 1;
+      q->dnsq_servi = 0;
+    }
+  }
+  return -1;
+}
+
+/* send the query out and add it to the active list. */
+static void dns_send(struct dns_ctx *ctx, struct dns_query *q, time_t now) {
+  int n;
+  struct dns_query *p;
+
+  /* if we can't send the query, return TEMPFAIL even when searching:
+   * we can't be sure whenever the name we tried to search exists or not,
+   * so don't continue searching, or we may find the wrong name. */
+
+  /* if there's no more servers, fail the query */
+  n = dns_find_serv(ctx, q);
+  if (n < 0) {
+    dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0);
+    return;
+  }
+
+  /* send the query */
+  n = 10;
+  while (sendto(ctx->dnsc_udpsock, q->dnsq_buf, q->dnsq_len, 0,
+                &ctx->dnsc_serv[q->dnsq_servi].sa, ctx->dnsc_salen) < 0) {
+    /*XXX just ignore the sendto() error for now and try again.
+     * In the future, it may be possible to retrieve the error code
+     * and find which operation/query failed.
+     *XXX try the next server too?
+     */
+    if (--n) continue;
+    /* if we can't send the query, fail it. */
+    dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0);
+    return;
+  }
+  DNS_DBGQ(ctx, q, 1,
+           &ctx->dnsc_serv[q->dnsq_servi].sa, sizeof(union sockaddr_ns),
+           q->dnsq_buf, q->dnsq_len);
+  q->dnsq_servwait |= 1 << q->dnsq_servi;	/* expect reply from this ns */
+
+  /* advance to the next server, and choose a timeout.
+   * we will try next server in 1 secound, but start next
+   * cycle waiting for proper timeout. */
+  ++q->dnsq_servi;
+  n = dns_find_serv(ctx, q) ? ctx->dnsc_timeout << (q->dnsq_try - 1) : 1;
+
+  q->dnsq_deadline = now = now + n;
+
+  /* insert the query to the tail of the list */
+  QLIST_FOR_EACH(&ctx->dnsc_qactive, p, prev)
+    if (p->dnsq_deadline <= now)
+      break;
+  qlist_insert_after(q, p);
+
+}
+
+static void dns_dummy_cb(struct dns_ctx *ctx, void *result, void *data) {
+  if (result) free(result);
+  data = ctx = 0;	/* used */
+}
+
+struct dns_query *
+dns_submit_dn(struct dns_ctx *ctx,
+              dnscc_t *dn, int qcls, int qtyp, int flags,
+              dns_parse_fn *parse, dns_query_fn *cbck, void *data) {
+  dnsc_t *p;
+  unsigned dnl;
+  struct dns_query *q;
+  SETCTXOPEN(ctx);
+  dns_assert_ctx(ctx);
+
+  q = calloc(sizeof(*q), 1);
+  if (!q) {
+    ctx->dnsc_qstatus = DNS_E_NOMEM;
+    return NULL;
+  }
+
+#ifndef NDEBUG
+  q->dnsq_ctx = ctx;
+#endif
+  q->dnsq_parse = parse;
+  q->dnsq_cbck = cbck ? cbck : dns_dummy_cb;
+  q->dnsq_cbdata = data;
+
+  flags = (flags | ctx->dnsc_flags) & ~DNS_INTERNAL;
+  if (!ctx->dnsc_nsrch) q->dnsq_flags |= DNS_NOSRCH;
+  if (!(flags & DNS_NORD)) q->dnsq_buf[DNS_H_F1] |= DNS_HF1_RD;
+  if (flags & DNS_AAONLY) q->dnsq_buf[DNS_H_F1] |= DNS_HF1_AA;
+  q->dnsq_buf[DNS_H_QDCNT2] = 1;
+  dns_put16(q->dnsq_buf + DNS_H_QID, ctx->dnsc_nextid++);
+
+  q->dnsq_origdnl = dns_dnlen(dn);
+  assert(q->dnsq_origdnl > 0 && q->dnsq_origdnl <= DNS_MAXDN);
+  memcpy(dns_payload(q->dnsq_buf), dn, q->dnsq_origdnl);
+  p = dns_payload(q->dnsq_buf) + q->dnsq_origdnl;
+  if (flags & DNS_NOSRCH || dns_dnlabels(dn) > ctx->dnsc_ndots)
+    flags |= DNS_ASIS_DONE;
+  else if ((dnl = dns_next_srch(ctx, q)) > 0)
+    p = dns_payload(q->dnsq_buf) + dnl;
+  else
+    p[-1] = '\0';
+  q->dnsq_flags = flags;
+  q->dnsq_typ = qtyp;
+  p = dns_put16(p, qtyp);
+  q->dnsq_cls = qcls;
+  p = dns_put16(p, qcls);
+  if (ctx->dnsc_udpbuf > DNS_MAXPACKET) {
+    p++;			/* empty (root) DN */
+    p = dns_put16(p, DNS_T_OPT);
+    p = dns_put16(p, ctx->dnsc_udpbuf);
+    p += 2;		/* EDNS0 RCODE & VERSION */
+    p += 2;		/* rest of the TTL field */
+    p += 2;		/* RDLEN */
+    q->dnsq_buf[DNS_H_ARCNT2] = 1;
+  }
+  assert(p <= q->dnsq_buf + DNS_QBUF);
+  q->dnsq_len = p - q->dnsq_buf;
+
+  qlist_add_head(q, &ctx->dnsc_qactive);
+  ++ctx->dnsc_nactive;
+  dns_request_utm(ctx, 0);
+
+  return q;
+}
+
+struct dns_query *
+dns_submit_p(struct dns_ctx *ctx,
+             const char *name, int qcls, int qtyp, int flags,
+             dns_parse_fn *parse, dns_query_fn *cbck, void *data) {
+  int isabs;
+  SETCTXOPEN(ctx);
+  if (dns_ptodn(name, 0, ctx->dnsc_pbuf, DNS_MAXDN, &isabs) <= 0) {
+    ctx->dnsc_qstatus = DNS_E_BADQUERY;
+    return NULL;
+  }
+  if (isabs)
+    flags |= DNS_NOSRCH;
+  return
+    dns_submit_dn(ctx, ctx->dnsc_pbuf, qcls, qtyp, flags, parse, cbck, data);
+}
+
+/* process readable fd condition.
+ * To be usable in edge-triggered environment, the routine
+ * should consume all input so it should loop over.
+ * Note it isn't really necessary to loop here, because
+ * an application may perform the loop just fine by it's own,
+ * but in this case we should return some sensitive result,
+ * to indicate when to stop calling and error conditions.
+ * Note also we may encounter all sorts of recvfrom()
+ * errors which aren't fatal, and at the same time we may
+ * loop forever if an error IS fatal.
+ * Current loop/goto looks just terrible... */
+void dns_ioevent(struct dns_ctx *ctx, time_t now) {
+  int r;
+  unsigned servi, l;
+  struct dns_query *q;
+  dnsc_t *pbuf;
+  dnscc_t *pend, *pcur;
+  void *result;
+  union sockaddr_ns sns;
+  socklen_t slen;
+
+  SETCTX(ctx);
+  if (!CTXOPEN(ctx))
+    return;
+  dns_assert_ctx(ctx);
+  pbuf = ctx->dnsc_pbuf;
+
+  if (!now) now = time(NULL);
+
+again:
+
+  for(;;) { /* receive the reply */
+    dnsc_t dn[DNS_MAXDN];
+
+    slen = sizeof(sns);
+    r = recvfrom(ctx->dnsc_udpsock, pbuf, ctx->dnsc_udpbuf, 0, &sns.sa, &slen);
+    if (r < 0) {
+      /*XXX just ignore recvfrom() errors for now.
+       * in the future it may be possible to determine which
+       * query failed and requeue it.
+       * Note there may be various error conditions, triggered
+       * by both local problems and remote problems.  It isn't
+       * quite trivial to determine whenever an error is local
+       * or remote.  On local errors, we should stop, while
+       * remote errors should be ignored (for now anyway).
+       */
+#ifdef WIN32
+      if (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+      if (errno == EAGAIN)
+#endif
+      {
+        dns_request_utm(ctx, now);
+	return;
+      }
+      continue;
+    }
+    /* ignore replies from wrong server */
+#if HAVE_INET6
+    if (sns.sa.sa_family == AF_INET6 && slen >= sizeof(sns.sin6)) {
+      for (servi = 0; servi < ctx->dnsc_nserv; ++servi)
+        if (ctx->dnsc_serv[servi].sin6.sin6_port == sns.sin6.sin6_port &&
+            memcmp(&ctx->dnsc_serv[servi].sin6.sin6_addr,
+                   &sns.sin6.sin6_addr, sizeof(sns.sin6.sin6_addr)) == 0)
+          break;
+    }
+    else
+#endif
+    if (sns.sa.sa_family == AF_INET && slen >= sizeof(sns.sin)) {
+      for (servi = 0; servi < ctx->dnsc_nserv; ++servi)
+        if (ctx->dnsc_serv[servi].sin.sin_addr.s_addr == sns.sin.sin_addr.s_addr &&
+            ctx->dnsc_serv[servi].sin.sin_port == sns.sin.sin_port)
+          break;
+    }
+    else {
+      DNS_DBG(ctx, -1, &sns.sa, slen, pbuf, r);
+      continue;
+    }
+    if (servi >= ctx->dnsc_nserv) {
+      DNS_DBG(ctx, -2, &sns.sa, slen, pbuf, r);
+      continue;
+    }
+
+    pend = pbuf + r;
+    pcur = dns_payload(pbuf);
+    if (pcur >= pend || dns_numqd(pbuf) != 1 || dns_opcode(pbuf) != 0 ||
+        dns_getdn(pbuf, &pcur, pend, dn, sizeof(dn)) < 0 ||
+        pcur + 4 > pend) {
+      /*XXX ignore non-query replies and replies with numqd!=1? */
+      DNS_DBG(ctx, -3, &sns.sa, slen, pbuf, r);
+      continue;
+    }
+
+    /* truncation bit (TC).  Ooh, we don't handle TCP (yet?),
+     * but we do handle larger UDP sizes.
+     * Note that e.g. djbdns will only send header if resp.
+     * does not fit, not whatever is fit in 512 bytes. */
+    if (dns_tc(pbuf)) {
+      DNS_DBG(ctx, -4, &sns.sa, slen, pbuf, r);
+      continue;	/* just ignore response for now.. any hope? */
+    }
+
+    /* find the request for this reply in active queue
+     * Note we pick any request, even queued for another
+     * server - in case first server replies a bit later
+     * than we expected. */
+    for (q = QLIST_FIRST(&ctx->dnsc_qactive, next);; q = QLIST_NEXT(q, next)) {
+      if (QLIST_ISLAST(&ctx->dnsc_qactive, q)) {
+        /* no more requests: old reply? */
+        DNS_DBG(ctx, -5, &sns.sa, slen, pbuf, r);
+        goto again;
+      }
+      /* ignore replies that has not been sent to this server.
+       * Note dnsq_servi is the *next* server to try. */
+      if (!q->dnsq_try && q->dnsq_servi <= servi)
+        continue;
+      /*XXX ignore replies from servers we're ignoring? o/
+      if (q->dnsq_servskip & (1 << servi))
+        continue; */
+      /* check qID */
+      if (q->dnsq_buf[DNS_H_QID1] != pbuf[DNS_H_QID1] ||
+          q->dnsq_buf[DNS_H_QID2] != pbuf[DNS_H_QID2])
+        continue;
+      /* check qDN, qCLS and qTYP */
+      if (!(l = dns_dnequal(dn, dns_payload(q->dnsq_buf))) ||
+          memcmp(pcur, dns_payload(q->dnsq_buf) + l, 4) != 0)
+        continue;
+      /* ok, this is expected reply with matching query. */
+      break;
+    }
+
+    break;
+
+  }
+
+  DNS_DBGQ(ctx, q, 0, &sns.sa, slen, pbuf, r);
+
+  /* we got a reply for our query */
+  q->dnsq_servwait &= ~(1 << servi);	/* don't expect reply from this serv */
+
+  /* process the RCODE */
+  switch(dns_rcode(pbuf)) {
+
+  case DNS_R_NOERROR:
+    qlist_remove(q);
+    if (!dns_numan(pbuf)) {	/* no data of requested type */
+      q->dnsq_flags |= DNS_SEEN_NODATA;
+      r = DNS_E_NODATA;
+      break;
+    }
+    /* the only case where we may succeed */
+    if (q->dnsq_parse) {
+      r = q->dnsq_parse(dns_payload(q->dnsq_buf), pbuf, pcur, pend, &result);
+      if (r < 0)
+        result = NULL;
+    }
+    else if ((result = malloc(r)) != NULL)
+      memcpy(result, pbuf, r);
+    else
+      r = DNS_E_NOMEM;
+    /* (maybe) successeful answer (modulo nomem and parsing probs) */
+    /* note we pass DNS_E_NODATA here */
+    dns_end_query(ctx, q, r, result);
+    goto again;
+
+  case DNS_R_NXDOMAIN:
+    qlist_remove(q);
+    r = DNS_E_NXDOMAIN;
+    break;
+
+  case DNS_R_SERVFAIL:
+    q->dnsq_flags |= DNS_SEEN_FAIL;
+  case DNS_R_NOTIMPL:
+  case DNS_R_REFUSED:
+    /* for these rcodes, advance this request
+     * to the next server and reschedule */
+  default: /* unknown rcode? hmmm... */
+    /* try next server */
+    q->dnsq_servskip |= 1 << servi;	/* don't retry this server */
+    if (!q->dnsq_servwait) {
+      qlist_remove(q);
+      dns_send(ctx, q, now);
+    }
+    else {
+      /* else this is the only place where q will be left unconnected
+       * if we will move qlist_remove() before the switch{}. */
+    }
+    goto again;
+
+  }
+
+  /* here we have either NODATA or NXDOMAIN */
+  if (!(q->dnsq_flags & DNS_NOSRCH)) {
+    /* try next element from search list */
+    unsigned sl;
+
+    l = dns_dnlen(dns_payload(q->dnsq_buf)) + DNS_HSIZE;	/* past qDN */
+    /* save qcls, qtyp and EDNS0 stuff (of len sl) in pbuf */
+    sl = q->dnsq_len - l;
+    memcpy(pbuf, q->dnsq_buf + l, sl);
+    /* try next search list */
+    l = dns_next_srch(ctx, q);
+    if (l) {	/* something else to try, of len l */
+      l += DNS_HSIZE;
+      memcpy(q->dnsq_buf + l, pbuf, sl);
+      q->dnsq_len = l + sl;
+      q->dnsq_try = 0; q->dnsq_servi = 0;
+      q->dnsq_servwait = q->dnsq_servskip = 0;
+      dns_send(ctx, q, now);
+      goto again;
+    }
+    /* else we have nothing more to search, end the query. */
+    if (q->dnsq_flags & DNS_SEEN_FAIL)
+      /* at least one server/query failed, fail the query */
+      r = DNS_E_TEMPFAIL;
+    else if (q->dnsq_flags & DNS_SEEN_NODATA)
+      /* for one domain we have seen NODATA, return it */
+      r = DNS_E_NODATA;
+    else /* else all should be NXDOMAINs */
+      r = DNS_E_NXDOMAIN;
+  }
+
+  dns_end_query(ctx, q, r, 0);
+  goto again;
+}
+
+/* handle all timeouts */
+int dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now) {
+  struct dns_query *q;
+  int w;
+  SETCTX(ctx);
+  dns_assert_ctx(ctx);
+  if (!now) now = time(NULL);
+  while((q = qlist_first(&ctx->dnsc_qactive)) && q->dnsq_deadline <= now) {
+    qlist_remove(q);
+    dns_send(ctx, q, now);
+  }
+  dns_request_utm(ctx, now);
+  if (!q)
+    return maxwait;
+  w = q->dnsq_deadline - now;
+  return maxwait < 0 || maxwait > w ? w : maxwait;
+}
+
+struct dns_resolve_data {
+  int   dnsrd_done;
+  void *dnsrd_result;
+};
+
+static void dns_resolve_cb(struct dns_ctx *ctx, void *result, void *data) {
+  struct dns_resolve_data *d = data;
+  d->dnsrd_result = result;
+  d->dnsrd_done = 1;
+  ctx = ctx;
+}
+
+void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q) {
+  time_t now;
+#ifdef HAVE_POLL
+  struct pollfd pfd;
+#else
+  fd_set rfd;
+  struct timeval tv;
+#endif
+  struct dns_resolve_data d;
+  int n;
+  SETCTXOPEN(ctx);
+
+  if (!q)
+    return NULL;
+
+  assert(ctx == q->dnsq_ctx);
+  dns_assert_ctx(ctx);
+  /* do not allow re-resolving syncronous queries */
+  assert(q->dnsq_cbck != dns_resolve_cb && "can't resolve syncronous query");
+  if (q->dnsq_cbck == dns_resolve_cb) {
+    ctx->dnsc_qstatus = DNS_E_BADQUERY;
+    return NULL;
+  }
+  q->dnsq_cbck = dns_resolve_cb;
+  q->dnsq_cbdata = &d;
+  d.dnsrd_done = 0;
+
+#ifdef HAVE_POLL
+  pfd.fd = ctx->dnsc_udpsock;
+  pfd.events = POLLIN;
+#else
+  FD_ZERO(&rfd);
+#endif
+
+  now = time(NULL);
+  while(!d.dnsrd_done && (n = dns_timeouts(ctx, -1, now)) >= 0) {
+#ifdef HAVE_POLL
+    n = poll(&pfd, 1, n * 1000);
+#else
+    tv.tv_sec = n;
+    tv.tv_usec = 0;
+    FD_SET(ctx->dnsc_udpsock, &rfd);
+    n = select(ctx->dnsc_udpsock + 1, &rfd, NULL, NULL, &tv);
+#endif
+    now = time(NULL);
+    if (n > 0)
+      dns_ioevent(ctx, now);
+  }
+
+  return d.dnsrd_result;
+}
+
+void *dns_resolve_dn(struct dns_ctx *ctx,
+                     dnscc_t *dn, int qcls, int qtyp, int flags,
+                     dns_parse_fn *parse) {
+  return
+    dns_resolve(ctx,
+      dns_submit_dn(ctx, dn, qcls, qtyp, flags, parse, NULL, NULL));
+}
+
+void *dns_resolve_p(struct dns_ctx *ctx,
+                    const char *name, int qcls, int qtyp, int flags,
+                    dns_parse_fn *parse) {
+  return
+    dns_resolve(ctx,
+      dns_submit_p(ctx, name, qcls, qtyp, flags, parse, NULL, NULL));
+}
+
+int dns_cancel(struct dns_ctx *ctx, struct dns_query *q) {
+  SETCTX(ctx);
+  dns_assert_ctx(ctx);
+  assert(q->dnsq_ctx == ctx);
+  /* do not allow cancelling syncronous queries */
+  assert(q->dnsq_cbck != dns_resolve_cb && "can't cancel syncronous query");
+  if (q->dnsq_cbck == dns_resolve_cb)
+    return (ctx->dnsc_qstatus = DNS_E_BADQUERY);
+  qlist_remove(q);
+  --ctx->dnsc_nactive;
+  dns_request_utm(ctx, 0);
+  return 0;
+}
+

Added: freeswitch/trunk/libs/udns/udns_rr_a.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_rr_a.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,124 @@
+/* $Id: udns_rr_a.c,v 1.14 2005/04/20 06:44:34 mjt Exp $
+   parse/query A/AAAA IN records
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef WIN32
+# include <winsock2.h>          /* includes <windows.h> */
+# include <ws2tcpip.h>          /* needed for struct in6_addr */
+#else
+# include <sys/types.h>
+# include <netinet/in.h>
+#endif
+#include "udns.h"
+
+/* here, we use common routine to parse both IPv4 and IPv6 addresses.
+ */
+
+/* this structure should match dns_rr_a[46] */
+struct dns_rr_a {
+  dns_rr_common(dnsa);
+  unsigned char *dnsa_addr;
+};
+
+static int
+dns_parse_a(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+            void **result, unsigned dsize) {
+  struct dns_rr_a *ret;
+  struct dns_parse p;
+  struct dns_rr rr;
+  int r;
+
+  /* first, validate and count number of addresses */
+  dns_initparse(&p, qdn, pkt, cur, end);
+  while((r = dns_nextrr(&p, &rr)) > 0)
+    if (rr.dnsrr_dsz != dsize)
+      return DNS_E_PROTOCOL;
+  if (r < 0)
+    return DNS_E_PROTOCOL;
+  else if (!p.dnsp_nrr)
+    return DNS_E_NODATA;
+
+  ret = malloc(sizeof(*ret) + dsize * p.dnsp_nrr + dns_stdrr_size(&p));
+  if (!ret)
+    return DNS_E_NOMEM;
+
+  ret->dnsa_nrr = p.dnsp_nrr;
+  ret->dnsa_addr = (unsigned char*)(ret+1);
+
+  /* copy the RRs */
+  for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r)
+    memcpy(ret->dnsa_addr + dsize * r, rr.dnsrr_dptr, dsize);
+
+  dns_stdrr_finish((struct dns_rr_null *)ret,
+                   (char *)(ret->dnsa_addr + dsize * p.dnsp_nrr), &p);
+  *result = ret;
+  return 0;
+}
+
+int
+dns_parse_a4(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+             void **result) {
+  assert(sizeof(struct in_addr) == 4);
+  assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_A);
+  return dns_parse_a(qdn, pkt, cur, end, result, 4);
+}
+
+struct dns_query *
+dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_a4_fn *cbck, void *data) {
+  return
+    dns_submit_p(ctx, name, DNS_C_IN, DNS_T_A, flags,
+                 dns_parse_a4, (dns_query_fn*)cbck, data);
+}
+
+struct dns_rr_a4 *
+dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags) {
+  return (struct dns_rr_a4 *)
+    dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_A, flags, dns_parse_a4);
+}
+
+int
+dns_parse_a6(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+             void **result) {
+#ifdef AF_INET6
+  assert(sizeof(struct in6_addr) == 16);
+#endif
+  assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_AAAA);
+  return dns_parse_a(qdn, pkt, cur, end, result, 16);
+}
+
+struct dns_query *
+dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_a6_fn *cbck, void *data) {
+  return
+    dns_submit_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags,
+                 dns_parse_a6, (dns_query_fn*)cbck, data);
+}
+
+struct dns_rr_a6 *
+dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags) {
+  return (struct dns_rr_a6 *)
+    dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags, dns_parse_a6);
+}

Added: freeswitch/trunk/libs/udns/udns_rr_mx.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_rr_mx.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,91 @@
+/* $Id: udns_rr_mx.c,v 1.13 2005/04/20 06:44:34 mjt Exp $
+   parse/query MX IN records
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "udns.h"
+
+int
+dns_parse_mx(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+             void **result) {
+  struct dns_rr_mx *ret;
+  struct dns_parse p;
+  struct dns_rr rr;
+  int r, l;
+  char *sp;
+  dnsc_t mx[DNS_MAXDN];
+
+  assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_MX);
+
+  /* first, validate the answer and count size of the result */
+  l = 0;
+  dns_initparse(&p, qdn, pkt, cur, end);
+  while((r = dns_nextrr(&p, &rr)) > 0) {
+    cur = rr.dnsrr_dptr + 2;
+    r = dns_getdn(pkt, &cur, end, mx, sizeof(mx));
+    if (r <= 0 || cur != rr.dnsrr_dend)
+      return DNS_E_PROTOCOL;
+    l += dns_dntop_size(mx);
+  }
+  if (r < 0)
+    return DNS_E_PROTOCOL;
+  if (!p.dnsp_nrr)
+    return DNS_E_NODATA;
+
+  /* next, allocate and set up result */
+  l += dns_stdrr_size(&p);
+  ret = malloc(sizeof(*ret) + sizeof(struct dns_mx) * p.dnsp_nrr + l);
+  if (!ret)
+    return DNS_E_NOMEM;
+  ret->dnsmx_nrr = p.dnsp_nrr;
+  ret->dnsmx_mx = (struct dns_mx *)(ret+1);
+
+  /* and 3rd, fill in result, finally */
+  sp = (char*)(ret->dnsmx_mx + p.dnsp_nrr);
+  for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
+    ret->dnsmx_mx[r].name = sp;
+    cur = rr.dnsrr_dptr;
+    ret->dnsmx_mx[r].priority = dns_get16(cur);
+    cur += 2;
+    dns_getdn(pkt, &cur, end, mx, sizeof(mx));
+    sp += dns_dntop(mx, sp, DNS_MAXNAME);
+  }
+  dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+  *result = ret;
+  return 0;
+}
+
+struct dns_query *
+dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_mx_fn *cbck, void *data) {
+  return
+    dns_submit_p(ctx, name, DNS_C_IN, DNS_T_MX, flags,
+                 dns_parse_mx, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_mx *
+dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags) {
+  return (struct dns_rr_mx *)
+    dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_MX, flags, dns_parse_mx);
+}

Added: freeswitch/trunk/libs/udns/udns_rr_naptr.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_rr_naptr.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,128 @@
+/* $Id: udns_rr_naptr.c,v 1.1 2006/11/28 22:58:04 mjt Exp $
+   parse/query NAPTR IN records
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   Copyright (C) 2006  Mikael Magnusson <mikma at users.sourceforge.net>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "udns.h"
+
+/* Get a single string for NAPTR record, pretty much like a DN label.
+ * String length is in first byte in *cur, so it can't be >255.
+ */
+static int dns_getstr(dnscc_t **cur, dnscc_t *ep, char *buf)
+{
+  unsigned l;
+  dnscc_t *cp = *cur;
+
+  l = *cp++;
+  if (cp + l > ep)
+    return DNS_E_PROTOCOL;
+  if (buf) {
+    memcpy(buf, cp, l);
+    buf[l] = '\0';
+  }
+  cp += l;
+
+  *cur = cp;
+  return l + 1;
+}
+
+int
+dns_parse_naptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+                void **result) {
+  struct dns_rr_naptr *ret;
+  struct dns_parse p;
+  struct dns_rr rr;
+  int r, l;
+  char *sp;
+  dnsc_t dn[DNS_MAXDN];
+
+  assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_NAPTR);
+
+  /* first, validate the answer and count size of the result */
+  l = 0;
+  dns_initparse(&p, qdn, pkt, cur, end);
+  while((r = dns_nextrr(&p, &rr)) > 0) {
+    int i;
+    dnscc_t *ep = rr.dnsrr_dend;
+
+    /* first 4 bytes: order & preference */
+    cur = rr.dnsrr_dptr + 4;
+
+    /* flags, services and regexp */
+    for (i = 0; i < 3; i++) {
+      r = dns_getstr(&cur, ep, NULL);
+      if (r < 0)
+        return r;
+      l += r;
+    }
+    /* replacement */
+    r = dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+    if (r <= 0 || cur != rr.dnsrr_dend)
+      return DNS_E_PROTOCOL;
+    l += dns_dntop_size(dn);
+  }
+  if (r < 0)
+    return DNS_E_PROTOCOL;
+  if (!p.dnsp_nrr)
+    return DNS_E_NODATA;
+
+  /* next, allocate and set up result */
+  l += dns_stdrr_size(&p);
+  ret = malloc(sizeof(*ret) + sizeof(struct dns_naptr) * p.dnsp_nrr + l);
+  if (!ret)
+    return DNS_E_NOMEM;
+  ret->dnsnaptr_nrr = p.dnsp_nrr;
+  ret->dnsnaptr_naptr = (struct dns_naptr *)(ret+1);
+
+  /* and 3rd, fill in result, finally */
+  sp = (char*)(&ret->dnsnaptr_naptr[p.dnsp_nrr]);
+  for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
+    cur = rr.dnsrr_dptr;
+    ret->dnsnaptr_naptr[r].order = dns_get16(cur); cur += 2;
+    ret->dnsnaptr_naptr[r].preference = dns_get16(cur); cur += 2;
+    sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].flags = sp));
+    sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].service = sp));
+    sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].regexp = sp));
+    dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+    sp += dns_dntop(dn, (ret->dnsnaptr_naptr[r].replacement = sp), DNS_MAXNAME);
+  }
+  dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+  *result = ret;
+  return 0;
+}
+
+struct dns_query *
+dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
+                 dns_query_naptr_fn *cbck, void *data) {
+  return
+    dns_submit_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags,
+                 dns_parse_naptr, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_naptr *
+dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags) {
+  return (struct dns_rr_naptr *)
+    dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, dns_parse_naptr);
+}

Added: freeswitch/trunk/libs/udns/udns_rr_ptr.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_rr_ptr.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,109 @@
+/* $Id: udns_rr_ptr.c,v 1.15 2005/09/12 11:21:06 mjt Exp $
+   parse/query PTR records
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "udns.h"
+
+int
+dns_parse_ptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+              void **result) {
+  struct dns_rr_ptr *ret;
+  struct dns_parse p;
+  struct dns_rr rr;
+  int r, l, c;
+  char *sp;
+  dnsc_t ptr[DNS_MAXDN];
+
+  assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_PTR);
+
+  /* first, validate the answer and count size of the result */
+  l = c = 0;
+  dns_initparse(&p, qdn, pkt, cur, end);
+  while((r = dns_nextrr(&p, &rr)) > 0) {
+    cur = rr.dnsrr_dptr;
+    r = dns_getdn(pkt, &cur, end, ptr, sizeof(ptr));
+    if (r <= 0 || cur != rr.dnsrr_dend)
+      return DNS_E_PROTOCOL;
+    l += dns_dntop_size(ptr);
+    ++c;
+  }
+  if (r < 0)
+    return DNS_E_PROTOCOL;
+  if (!c)
+    return DNS_E_NODATA;
+
+  /* next, allocate and set up result */
+  ret = malloc(sizeof(*ret) + sizeof(char **) * c + l + dns_stdrr_size(&p));
+  if (!ret)
+    return DNS_E_NOMEM;
+  ret->dnsptr_nrr = c;
+  ret->dnsptr_ptr = (char **)(ret+1);
+
+  /* and 3rd, fill in result, finally */
+  sp = (char*)(ret->dnsptr_ptr + c);
+  c = 0;
+  dns_rewind(&p, qdn);
+  while((r = dns_nextrr(&p, &rr)) > 0) {
+    ret->dnsptr_ptr[c] = sp;
+    cur = rr.dnsrr_dptr;
+    dns_getdn(pkt, &cur, end, ptr, sizeof(ptr));
+    sp += dns_dntop(ptr, sp, DNS_MAXNAME);
+    ++c;
+  }
+  dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+  *result = ret;
+  return 0;
+}
+
+struct dns_query *
+dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr,
+                 dns_query_ptr_fn *cbck, void *data) {
+  dnsc_t dn[DNS_A4RSIZE];
+  dns_a4todn(addr, 0, dn, sizeof(dn));
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH,
+                  dns_parse_ptr, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_ptr *
+dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr) {
+  return (struct dns_rr_ptr *)
+    dns_resolve(ctx, dns_submit_a4ptr(ctx, addr, NULL, NULL));
+}
+
+struct dns_query *
+dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr,
+                 dns_query_ptr_fn *cbck, void *data) {
+  dnsc_t dn[DNS_A6RSIZE];
+  dns_a6todn(addr, 0, dn, sizeof(dn));
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH,
+                  dns_parse_ptr, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_ptr *
+dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr) {
+  return (struct dns_rr_ptr *)
+    dns_resolve(ctx, dns_submit_a6ptr(ctx, addr, NULL, NULL));
+}

Added: freeswitch/trunk/libs/udns/udns_rr_srv.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_rr_srv.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,154 @@
+/* $Id: udns_rr_srv.c,v 1.2 2005/09/12 12:26:22 mjt Exp $
+   parse/query SRV IN (rfc2782) records
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+   Copyright 2005 Thadeu Lima de Souza Cascardo <cascardo at minaslivre.org>
+
+   2005-09-11:
+   Changed MX parser file into a SRV parser file
+
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "udns.h"
+
+int
+dns_parse_srv(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+              void **result) {
+  struct dns_rr_srv *ret;
+  struct dns_parse p;
+  struct dns_rr rr;
+  int r, l;
+  char *sp;
+  dnsc_t srv[DNS_MAXDN];
+
+  assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_SRV);
+
+  /* first, validate the answer and count size of the result */
+  l = 0;
+  dns_initparse(&p, qdn, pkt, cur, end);
+  while((r = dns_nextrr(&p, &rr)) > 0) {
+    cur = rr.dnsrr_dptr + 6;
+    r = dns_getdn(pkt, &cur, end, srv, sizeof(srv));
+    if (r <= 0 || cur != rr.dnsrr_dend)
+      return DNS_E_PROTOCOL;
+    l += dns_dntop_size(srv);
+  }
+  if (r < 0)
+    return DNS_E_PROTOCOL;
+  if (!p.dnsp_nrr)
+    return DNS_E_NODATA;
+
+  /* next, allocate and set up result */
+  l += dns_stdrr_size(&p);
+  ret = malloc(sizeof(*ret) + sizeof(struct dns_srv) * p.dnsp_nrr + l);
+  if (!ret)
+    return DNS_E_NOMEM;
+  ret->dnssrv_nrr = p.dnsp_nrr;
+  ret->dnssrv_srv = (struct dns_srv *)(ret+1);
+
+  /* and 3rd, fill in result, finally */
+  sp = (char*)(ret->dnssrv_srv + p.dnsp_nrr);
+  for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
+    ret->dnssrv_srv[r].name = sp;
+    cur = rr.dnsrr_dptr;
+    ret->dnssrv_srv[r].priority = dns_get16(cur);
+    ret->dnssrv_srv[r].weight = dns_get16(cur+2);
+    ret->dnssrv_srv[r].port = dns_get16(cur+4);
+    cur += 6;
+    dns_getdn(pkt, &cur, end, srv, sizeof(srv));
+    sp += dns_dntop(srv, sp, DNS_MAXNAME);
+  }
+  dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+  *result = ret;
+  return 0;
+}
+
+/* Add a single service or proto name prepending an undescore (_),
+ * according to rfc2782 rules.
+ * Return 0 or the label length.
+ * Routing assumes dn holds enouth space for a single DN label. */
+static unsigned add_sname(dnsc_t *dn, const char *sn) {
+  unsigned l;
+  l = dns_ptodn(sn, 0, dn + 1, DNS_MAXLABEL-1, NULL);
+  if (l <= 1 || l - 2 != dn[1])
+    /* Should we really check if sn is exactly one label?  Do we care? */
+    return 0;
+  dn[0] = l - 1;
+  dn[1] = '_';
+  return l;
+}
+
+/* Construct a domain name for SRV query from the given name, service and
+ * protocol (service may be NULL in which case protocol isn't used).
+ * Return negative value on error (malformed query),
+ * or addition query flag(s) to use.
+ */
+static int
+build_srv_dn(dnsc_t *dn, const char *name, const char *srv, const char *proto)
+{
+  unsigned p = 0, l;
+  int isabs;
+  if (srv) {
+    l = add_sname(dn + p, srv);
+    if (!l)
+      return -1;
+    p += l;
+    l = add_sname(dn + p, proto);
+    if (!l)
+      return -1;
+    p += l;
+  }
+  l = dns_ptodn(name, 0, dn + p, DNS_MAXDN - p, &isabs);
+  if (!l)
+    return -1;
+  return isabs ? DNS_NOSRCH : 0;
+}
+
+struct dns_query *
+dns_submit_srv(struct dns_ctx *ctx,
+               const char *name, const char *srv, const char *proto,
+               int flags, dns_query_srv_fn *cbck, void *data) {
+  dnsc_t dn[DNS_MAXDN];
+  int r = build_srv_dn(dn, name, srv, proto);
+  if (r < 0) {
+    dns_setstatus (ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r,
+                  dns_parse_srv, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_srv *
+dns_resolve_srv(struct dns_ctx *ctx,
+                const char *name, const char *srv, const char *proto, int flags)
+{
+  dnsc_t dn[DNS_MAXDN];
+  int r = build_srv_dn(dn, name, srv, proto);
+  if (r < 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return (struct dns_rr_srv *)
+    dns_resolve_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r, dns_parse_srv);
+}

Added: freeswitch/trunk/libs/udns/udns_rr_txt.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/udns/udns_rr_txt.c	Thu Nov 30 16:28:32 2006
@@ -0,0 +1,98 @@
+/* $Id: udns_rr_txt.c,v 1.15 2006/11/28 22:45:20 mjt Exp $
+   parse/query TXT records
+
+   Copyright (C) 2005  Michael Tokarev <mjt at corpit.ru>
+   This file is part of UDNS library, an async DNS stub resolver.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library, in file named COPYING.LGPL; if not,
+   write to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA  02111-1307  USA
+
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "udns.h"
+
+int
+dns_parse_txt(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+              void **result) {
+  struct dns_rr_txt *ret;
+  struct dns_parse p;
+  struct dns_rr rr;
+  int r, l;
+  dnsc_t *sp;
+  dnscc_t *cp, *ep;
+
+  assert(dns_get16(cur+0) == DNS_T_TXT);
+
+  /* first, validate the answer and count size of the result */
+  l = 0;
+  dns_initparse(&p, qdn, pkt, cur, end);
+  while((r = dns_nextrr(&p, &rr)) > 0) {
+    cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend;
+    while(cp < ep) {
+      r = *cp++;
+      if (cp + r > ep)
+        return DNS_E_PROTOCOL;
+      l += r;
+      cp += r;
+    }
+  }
+  if (r < 0)
+    return DNS_E_PROTOCOL;
+  if (!p.dnsp_nrr)
+    return DNS_E_NODATA;
+
+  /* next, allocate and set up result */
+  l +=  (sizeof(struct dns_txt) + 1) * p.dnsp_nrr + dns_stdrr_size(&p);
+  ret = malloc(sizeof(*ret) + l);
+  if (!ret)
+    return DNS_E_NOMEM;
+  ret->dnstxt_nrr = p.dnsp_nrr;
+  ret->dnstxt_txt = (struct dns_txt *)(ret+1);
+
+  /* and 3rd, fill in result, finally */
+  sp = (dnsc_t*)(ret->dnstxt_txt + p.dnsp_nrr);
+  for(dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr) > 0; ++r) {
+    ret->dnstxt_txt[r].txt = sp;
+    cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend;
+    while(cp < ep) {
+      l = *cp++;
+      memcpy(sp, cp, l);
+      sp += l;
+      cp += l;
+    }
+    ret->dnstxt_txt[r].len = sp - ret->dnstxt_txt[r].txt;
+    *sp++ = '\0';
+  }
+  dns_stdrr_finish((struct dns_rr_null *)ret, (char*)sp, &p);
+  *result = ret;
+  return 0;
+}
+
+struct dns_query *
+dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags,
+               dns_query_txt_fn *cbck, void *data) {
+  return
+    dns_submit_p(ctx, name, qcls, DNS_T_TXT, flags,
+                 dns_parse_txt, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_txt *
+dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags) {
+  return (struct dns_rr_txt *)
+    dns_resolve_p(ctx, name, qcls, DNS_T_TXT, flags, dns_parse_txt);
+}

Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h	(original)
+++ freeswitch/trunk/src/include/switch_types.h	Thu Nov 30 16:28:32 2006
@@ -86,6 +86,8 @@
 #define SWITCH_LOCAL_MEDIA_PORT_VARIABLE "_local_media_port_"
 #define SWITCH_REMOTE_MEDIA_IP_VARIABLE "_remote_media_ip_"
 #define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "_remote_media_port_"
+#define SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE "hangup_after_bridge"
+
 #define SWITCH_SPEECH_KEY "_speech_"
 #define SWITCH_UUID_BRIDGE "_uuid_bridge_"
 #define SWITCH_BITS_PER_BYTE 8

Modified: freeswitch/trunk/src/include/switch_utils.h
==============================================================================
--- freeswitch/trunk/src/include/switch_utils.h	(original)
+++ freeswitch/trunk/src/include/switch_utils.h	Thu Nov 30 16:28:32 2006
@@ -39,6 +39,7 @@
 #define SWITCH_UTILS_H
 
 #include <switch.h>
+#include <pcre.h>
 
 SWITCH_BEGIN_EXTERN_C
 
@@ -231,8 +232,15 @@
 */
 SWITCH_DECLARE(char *) switch_cut_path(char *in);
 
+#define switch_clean_re(re)	if (re) {\
+				pcre_free(re);\
+				re = NULL;\
+			}
+
 SWITCH_DECLARE(char *) switch_string_replace(const char *string, const char *search, const char *replace);
 SWITCH_DECLARE(switch_status_t) switch_string_match(const char *string, size_t string_len, const char *search, size_t search_len);
+SWITCH_DECLARE(int) switch_perform_regex(char *field, char *expression, pcre **new_re, int *ovector, uint32_t olen);
+SWITCH_DECLARE(void) switch_perform_substitution(pcre *re, int match_count, char *data, char *field_data, char *substituted, uint32_t len, int *ovector);
 
 #define SWITCH_READ_ACCEPTABLE(status) status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK
 SWITCH_DECLARE(size_t) switch_url_encode(char *url, char *buf, size_t len);

Modified: freeswitch/trunk/src/mod/applications/mod_bridgecall/mod_bridgecall.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_bridgecall/mod_bridgecall.c	(original)
+++ freeswitch/trunk/src/mod/applications/mod_bridgecall/mod_bridgecall.c	Thu Nov 30 16:28:32 2006
@@ -45,6 +45,10 @@
 	uint8_t no_media_bridge = 0;
 	switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
 
+    if (switch_strlen_zero(data)) {
+        return;
+    }
+
 	caller_channel = switch_core_session_get_channel(session);
 	assert(caller_channel != NULL);
 

Modified: freeswitch/trunk/src/mod/codecs/mod_gsm/mod_gsm.c
==============================================================================
--- freeswitch/trunk/src/mod/codecs/mod_gsm/mod_gsm.c	(original)
+++ freeswitch/trunk/src/mod/codecs/mod_gsm/mod_gsm.c	Thu Nov 30 16:28:32 2006
@@ -135,7 +135,7 @@
 static const switch_codec_implementation_t gsm_8k_implementation = { 
 		/*.codec_type */ SWITCH_CODEC_TYPE_AUDIO, 
 		/*.ianacode */ 3, 
-		/*.iananame */ "gsm", 
+		/*.iananame */ "GSM", 
 		/*.fmtp */ NULL,
 		/*.samples_per_second */ 8000, 
 		/*.bits_per_second */ 13200, 

Modified: freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c
==============================================================================
--- freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c	(original)
+++ freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c	Thu Nov 30 16:28:32 2006
@@ -37,96 +37,8 @@
 
 static const char modname[] = "mod_dialplan_xml";
 
-#define cleanre(re)	if (re) {\
-				pcre_free(re);\
-				re = NULL;\
-			}
 
 
-static int perform_regex(switch_channel_t *channel, char *field, char *expression, pcre **new_re, int *ovector, uint32_t olen)
-{
-	const char *error = NULL;
-	int erroffset = 0;
-	pcre *re = NULL;
-	int match_count = 0;
-	
-	if (!(field && expression)) {
-		return 0;
-	}
-
-	re = pcre_compile(expression, /* the pattern */
-					  0,		  /* default options */
-					  &error,	  /* for error message */
-					  &erroffset, /* for error offset */
-					  NULL);	  /* use default character tables */
-	if (error) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "COMPILE ERROR: %d [%s]\n", erroffset, error);
-		cleanre(re);
-		return 0;
-	}
-
-	match_count = pcre_exec(re,	/* result of pcre_compile() */
-							NULL,	/* we didn't study the pattern */
-							field,	/* the subject string */
-							(int) strlen(field), /* the length of the subject string */
-							0,	/* start at offset 0 in the subject */
-							0,	/* default options */
-							ovector,	/* vector of integers for substring information */
-							olen); /* number of elements (NOT size in bytes) */
-
-	if (match_count <= 0) {
-		cleanre(re);
-		match_count = 0;
-	}
-
-	*new_re = re;
-
-	return match_count;
-}
-
-
-static void perform_substitution(pcre *re, int match_count, char *data, char *field_data, char *substituted, uint32_t len, int *ovector)
-{
-	char index[10] = "";
-	char replace[1024] = "";
-	uint32_t x, y = 0, z = 0, num = 0;
-
-	for (x = 0; x < (len-1) && x < strlen(data);) {
-		if (data[x] == '$') {
-			x++;
-			
-			if (!(data[x] > 47 && data[x] < 58)) {
-				substituted[y++] = data[x-1];
-				continue;
-			}
-
-			while (data[x] > 47 && data[x] < 58) {
-				index[z++] = data[x];
-				x++;
-			}
-			index[z++] = '\0';
-			z = 0;
-			num = atoi(index);
-			
-			if (pcre_copy_substring(field_data,
-									ovector,
-									match_count,
-									num,
-									replace,
-									sizeof(replace)) > 0) {
-				unsigned int r;
-				for (r = 0; r < strlen(replace); r++) {
-					substituted[y++] = replace[r];
-				}
-			}
-		} else {
-			substituted[y++] = data[x];
-			x++;
-		}
-	}
-	substituted[y++] = '\0';
-}
-
 typedef enum {
 	BREAK_ON_TRUE,
 	BREAK_ON_FALSE,
@@ -197,7 +109,7 @@
 				field_data = "";
 			}
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "test conditions %s(%s) =~ /%s/\n", field, field_data, expression);
-			if (!(proceed = perform_regex(channel, field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
+			if (!(proceed = switch_perform_regex(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Regex mismatch\n");
 
 				for (xaction = switch_xml_child(xcond, "anti-action"); xaction; xaction = xaction->next) {
@@ -232,7 +144,7 @@
 			char *app_data = NULL;
 
 			if (field && strchr(expression, '(')) {
-				perform_substitution(re, proceed, data, field_data, substituted, sizeof(substituted), ovector);
+				switch_perform_substitution(re, proceed, data, field_data, substituted, sizeof(substituted), ovector);
 				app_data = substituted;
 			} else {
 				app_data = data;
@@ -249,7 +161,7 @@
 			switch_caller_extension_add_application(session, *extension, application, app_data);
 		}
 
-		cleanre(re);
+		switch_clean_re(re);
 
 		if (do_break_i == BREAK_ON_TRUE || do_break_i == BREAK_ALWAYS) {
 			break;

Modified: freeswitch/trunk/src/switch_ivr.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr.c	(original)
+++ freeswitch/trunk/src/switch_ivr.c	Thu Nov 30 16:28:32 2006
@@ -137,7 +137,7 @@
 	switch_status_t status = SWITCH_STATUS_SUCCESS;
 	switch_channel_t *channel;
 	switch_frame_t *frame;
-	int stream_id;
+	int stream_id = 0;
 	switch_event_t *event;
 	
 	channel = switch_core_session_get_channel(session);
@@ -152,19 +152,18 @@
 
 	switch_channel_set_flag(channel, CF_CONTROLLED);
 	while (switch_channel_ready(channel)) {
-		for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
-			if ((status = switch_core_session_read_frame(session, &frame, -1, stream_id)) == SWITCH_STATUS_SUCCESS) {
-				if (!SWITCH_READ_ACCEPTABLE(status)) {
-					break;
-				}
-
-				if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
-					switch_ivr_parse_event(session, event);
-					switch_event_destroy(&event);
-				}
-
-			}
-		}
+        
+        if ((status = switch_core_session_read_frame(session, &frame, -1, stream_id)) == SWITCH_STATUS_SUCCESS) {
+            if (!SWITCH_READ_ACCEPTABLE(status)) {
+                break;
+            }
+            
+            if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
+                switch_ivr_parse_event(session, event);
+                switch_event_destroy(&event);
+            }
+        }
+		
 	}
 	switch_channel_clear_flag(channel, CF_CONTROLLED);
 
@@ -966,7 +965,7 @@
 	switch_codec_t codec;
 	switch_memory_pool_t *pool = switch_core_session_get_pool(session);
 	char *codec_name;
-	int stream_id;
+	int stream_id = 0;
 	switch_status_t status = SWITCH_STATUS_SUCCESS;
 	switch_file_handle_t lfh;
 	switch_codec_t *read_codec = switch_core_session_get_read_codec(session);
@@ -975,11 +974,6 @@
 	uint8_t asis = 0;
 	char *ext;
 	
-	if (fh->samples > 0) {
-		sample_start = fh->samples;
-		fh->samples = 0;
-	}
-
 	if (file) {
 		if ((ext = strrchr(file, '.'))) {
 			ext++;
@@ -1000,6 +994,13 @@
 		memset(fh, 0, sizeof(lfh));
 	}
 
+
+	if (fh->samples > 0) {
+		sample_start = fh->samples;
+		fh->samples = 0;
+	}
+
+
 	channel = switch_core_session_get_channel(session);
 	assert(channel != NULL);
 
@@ -1259,21 +1260,23 @@
 		if (!asis) {switch_swap_linear(write_frame.data, (int) write_frame.datalen / 2);}
 #endif
 #endif
-		for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
-			status = switch_core_session_write_frame(session, &write_frame, -1, stream_id);
+		stream_id = 0; 
 
-			if (status == SWITCH_STATUS_MORE_DATA) {
-				status = SWITCH_STATUS_SUCCESS;
-				continue;
-			} else if (status != SWITCH_STATUS_SUCCESS) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
-				done = 1;
-				break;
-			}
-			if (done) {
-				break;
-			}
-		}
+        status = switch_core_session_write_frame(session, &write_frame, -1, stream_id);
+        
+        if (status == SWITCH_STATUS_MORE_DATA) {
+            status = SWITCH_STATUS_SUCCESS;
+            continue;
+        } else if (status != SWITCH_STATUS_SUCCESS) {
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
+            done = 1;
+            break;
+        }
+
+        if (done) {
+            break;
+        }
+    
 		
 		if (timer_name) {
 			if (switch_core_timer_next(&timer) < 0) {
@@ -1487,7 +1490,7 @@
 	switch_size_t ilen = 0;
 	switch_frame_t write_frame = {0};
 	int x;
-	int stream_id;
+	int stream_id = 0;
 	int done = 0;
 	int lead_in_out = 10;
 	switch_status_t status = SWITCH_STATUS_SUCCESS;
@@ -1522,13 +1525,11 @@
 	write_frame.codec = codec;
 
 	for( x = 0; !done && x < lead_in_out; x++) {
-		for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
-			if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
-				done = 1;
-				break;
-			}
-		}
+        if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
+            done = 1;
+            break;
+        }		
 	}
 
 	ilen = len;
@@ -1606,13 +1607,11 @@
 
 		if (status != SWITCH_STATUS_SUCCESS) {
 			for( x = 0; !done && x < lead_in_out; x++) {
-				for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
-					if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
-						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
-						done = 1;
-						break;
-					}
-				}
+                if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
+                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
+                    done = 1;
+                    break;
+                }
 			}
 			if (status == SWITCH_STATUS_BREAK) {
 				status = SWITCH_STATUS_SUCCESS;
@@ -1627,17 +1626,15 @@
 		write_frame.datalen = (uint32_t)ilen;
 		write_frame.samples = (uint32_t)(ilen / 2);
 
-		for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
-			if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
-				done = 1;
-				break;
-			}
+        if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
+            done = 1;
+            break;
+        }
 
-			if (done) {
-				break;
-			}
-		}
+        if (done) {
+            break;
+        }
 
 		if (timer) {
 			if ((x = switch_core_timer_next(timer)) < 0) {
@@ -1686,7 +1683,7 @@
 	switch_codec_t codec;
 	switch_memory_pool_t *pool = switch_core_session_get_pool(session);
 	char *codec_name;
-	int stream_id;
+	int stream_id = 0;
 	switch_status_t status = SWITCH_STATUS_SUCCESS;
 	switch_speech_handle_t sh;
 	switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
@@ -3130,8 +3127,6 @@
 	/*.on_hibernate*/ signal_bridge_on_hibernate
 };
 
-
-
 SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session, switch_core_session_t *peer_session)
 {
 	switch_channel_t *caller_channel, *peer_channel;
@@ -3319,9 +3314,15 @@
 						  switch_channel_get_name(peer_channel)
 						  );
 		switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER);
-	}
+	} 
 
  done:
+
+    if (switch_channel_get_state(caller_channel) < CS_HANGUP && 
+        switch_true(switch_channel_get_variable(caller_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) {
+        switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_CLEARING);
+    }
+
 	return status;
 }
 

Modified: freeswitch/trunk/src/switch_utils.c
==============================================================================
--- freeswitch/trunk/src/switch_utils.c	(original)
+++ freeswitch/trunk/src/switch_utils.c	Thu Nov 30 16:28:32 2006
@@ -35,6 +35,92 @@
 #include <stdlib.h>
 
 
+
+SWITCH_DECLARE(int) switch_perform_regex(char *field, char *expression, pcre **new_re, int *ovector, uint32_t olen)
+{
+	const char *error = NULL;
+	int erroffset = 0;
+	pcre *re = NULL;
+	int match_count = 0;
+	
+	if (!(field && expression)) {
+		return 0;
+	}
+
+	re = pcre_compile(expression, /* the pattern */
+					  0,		  /* default options */
+					  &error,	  /* for error message */
+					  &erroffset, /* for error offset */
+					  NULL);	  /* use default character tables */
+	if (error) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "COMPILE ERROR: %d [%s]\n", erroffset, error);
+		switch_clean_re(re);
+		return 0;
+	}
+
+	match_count = pcre_exec(re,	/* result of pcre_compile() */
+							NULL,	/* we didn't study the pattern */
+							field,	/* the subject string */
+							(int) strlen(field), /* the length of the subject string */
+							0,	/* start at offset 0 in the subject */
+							0,	/* default options */
+							ovector,	/* vector of integers for substring information */
+							olen); /* number of elements (NOT size in bytes) */
+
+	if (match_count <= 0) {
+		switch_clean_re(re);
+		match_count = 0;
+	}
+
+	*new_re = re;
+
+	return match_count;
+}
+
+
+SWITCH_DECLARE(void) switch_perform_substitution(pcre *re, int match_count, char *data, char *field_data, char *substituted, uint32_t len, int *ovector)
+{
+	char index[10] = "";
+	char replace[1024] = "";
+	uint32_t x, y = 0, z = 0, num = 0;
+
+	for (x = 0; x < (len-1) && x < strlen(data);) {
+		if (data[x] == '$') {
+			x++;
+			
+			if (!(data[x] > 47 && data[x] < 58)) {
+				substituted[y++] = data[x-1];
+				continue;
+			}
+
+			while (data[x] > 47 && data[x] < 58) {
+				index[z++] = data[x];
+				x++;
+			}
+			index[z++] = '\0';
+			z = 0;
+			num = atoi(index);
+			
+			if (pcre_copy_substring(field_data,
+									ovector,
+									match_count,
+									num,
+									replace,
+									sizeof(replace)) > 0) {
+				unsigned int r;
+				for (r = 0; r < strlen(replace); r++) {
+					substituted[y++] = replace[r];
+				}
+			}
+		} else {
+			substituted[y++] = data[x];
+			x++;
+		}
+	}
+	substituted[y++] = '\0';
+}
+
+
 SWITCH_DECLARE(char *) switch_priority_name(switch_priority_t priority)
 {
 	switch(priority) { /*lol*/



More information about the Freeswitch-svn mailing list