<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][16745] </title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=16745">16745</a></dd>
<dt>Author</dt> <dd>anthm</dd>
<dt>Date</dt> <dd>2010-02-23 18:01:39 -0600 (Tue, 23 Feb 2010)</dd>
</dl>

<h3>Log Message</h3>
<pre>add sofia_dig [xml] api func</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiaMakefileam">freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile.am</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiamod_sofiac">freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiamod_sofiah">freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiasipdigc">freeswitch/trunk/src/mod/endpoints/mod_sofia/sip-dig.c</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunksrcmodendpointsmod_sofiaMakefileam"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile.am (16744 => 16745)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile.am        2010-02-23 22:56:54 UTC (rev 16744)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile.am        2010-02-24 00:01:39 UTC (rev 16745)
</span><span class="lines">@@ -9,7 +9,7 @@
</span><span class="cx"> SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la
</span><span class="cx"> 
</span><span class="cx"> mod_LTLIBRARIES = mod_sofia.la
</span><del>-mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c  mod_sofia.h
</del><ins>+mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c sip-dig.c mod_sofia.h
</ins><span class="cx"> mod_sofia_la_CFLAGS  = $(AM_CFLAGS) -I.
</span><span class="cx"> mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf
</span><span class="cx"> mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiamod_sofiac"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (16744 => 16745)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c        2010-02-23 22:56:54 UTC (rev 16744)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c        2010-02-24 00:01:39 UTC (rev 16745)
</span><span class="lines">@@ -3935,6 +3935,7 @@
</span><span class="cx">         return status;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
</span><span class="cx"> {
</span><span class="cx">         switch_chat_interface_t *chat_interface;
</span><span class="lines">@@ -4084,6 +4085,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">         SWITCH_ADD_API(api_interface, &quot;sofia_contact&quot;, &quot;Sofia Contacts&quot;, sofia_contact_function, &quot;[profile/]&lt;user&gt;@&lt;domain&gt;&quot;);
</span><ins>+        SWITCH_ADD_API(api_interface, &quot;sofia_dig&quot;, &quot;SIP DIG&quot;, sip_dig_function, &quot;&lt;url&gt;&quot;);
</ins><span class="cx">         SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
</span><span class="cx"> 
</span><span class="cx">         /* indicate that the module should continue to be loaded */
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiamod_sofiah"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h (16744 => 16745)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h        2010-02-23 22:56:54 UTC (rev 16744)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h        2010-02-24 00:01:39 UTC (rev 16745)
</span><span class="lines">@@ -973,3 +973,4 @@
</span><span class="cx"> void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *session);
</span><span class="cx"> int sofia_glue_recover(switch_bool_t flush);
</span><span class="cx"> void sofia_profile_destroy(sofia_profile_t *profile);
</span><ins>+switch_status_t sip_dig_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream);
</ins></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiasipdigc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/mod/endpoints/mod_sofia/sip-dig.c (0 => 16745)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sip-dig.c                                (rev 0)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sip-dig.c        2010-02-24 00:01:39 UTC (rev 16745)
</span><span class="lines">@@ -0,0 +1,896 @@
</span><ins>+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi &lt;pekka.pessi@nokia.com&gt;
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * This is an example program for @b sresolv library in synchronous mode.
+ *
+ * @author Pekka Pessi &lt;Pekka.Pessi@nokia.com&gt;
+ *
+ * @date Original Created: Tue Jul 16 18:50:14 2002 ppessi
+ */
+
+/**@page sip-dig Resolve SIP URIs.
+ *
+ * @section sip_dig_synopsis Synopsis
+ * &lt;tt&gt;sip-dig [OPTIONS] uri...&lt;/tt&gt;
+ *
+ * @section sip_dig_description Description
+ * The @em sip-dig utility resolves SIP URIs as described in @RFC3263. It
+ * queries NAPTR, SRV and A/AAAA records and prints out the resulting
+ * transport addresses.
+ *
+ * The default transports are: UDP, TCP, SCTP, TLS and TLS-SCTP. The SIPS
+ * URIs are resolved using only TLS transports, TLS and TLS-SCTP. If not
+ * otherwise indicated by NAPTR or SRV records, the sip-dig uses UDP and TCP
+ * as transports for SIP and TLS for SIPS URIs.
+ *
+ * The results are printed intended, with a preference followed by weight,
+ * then protocol name, port number and IP address in numeric format.
+ *
+ * @section sip_dig_options Command Line Options
+ * The @e sip-dig utility accepts following command line options:
+ * &lt;dl&gt;
+ * &lt;dt&gt;-p &lt;em&gt;protoname&lt;/em&gt;&lt;/dt&gt;
+ * &lt;dd&gt;Use named transport protocol. The &lt;em&gt;protoname&lt;/em&gt; can be either
+ * well-known, e.g., &quot;udp&quot;, or it can specify NAPTR service and SRV
+ * identifier, e.g., &quot;tls-udp/SIPS+D2U/_sips._udp.&quot;.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;--udp&lt;/dt&gt;
+ * &lt;dd&gt;Use UDP transport protocol.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;--tcp&lt;/dt&gt;
+ * &lt;dd&gt;Use TCP transport protocol.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;--tls&lt;/dt&gt;
+ * &lt;dd&gt;Use TLS over TCP transport protocol.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;--sctp&lt;/dt&gt;
+ * &lt;dd&gt;Use SCTP transport protocol.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;--tls-sctp&lt;/dt&gt;
+ * &lt;dd&gt;Use TLS over SCTP transport protocol.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;--no-sctp&lt;/dt&gt;
+ * &lt;dd&gt;Ignore SCTP or TLS-SCTP records in the list of default transports.
+ * This option has no effect if transport protocols has been explicitly
+ * listed.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;-4&lt;/dt&gt;
+ * &lt;dd&gt;Query IP4 addresses (A records)
+ * &lt;/dd&gt;
+ * &lt;dt&gt;-6&lt;/dt&gt;
+ * &lt;dd&gt;Query IP6 addresses (AAAA records).
+ * &lt;/dd&gt;
+ * &lt;dt&gt;-v&lt;/dt&gt;
+ * &lt;dd&gt;Be verbatim.
+ * &lt;/dd&gt;
+ * &lt;dt&gt;&lt;/dt&gt;
+ * &lt;dd&gt;
+ * &lt;/dd&gt;
+ * &lt;/dl&gt;
+ *
+ * @section sip_dig_return Return Codes
+ * &lt;table&gt;
+ * &lt;tr&gt;&lt;td&gt;0&lt;td&gt;when successful (a 2XX-series response is received)
+ * &lt;tr&gt;&lt;td&gt;1&lt;td&gt;when unsuccessful (a 3XX..6XX-series response is received)
+ * &lt;tr&gt;&lt;td&gt;2&lt;td&gt;initialization failure
+ * &lt;/table&gt;
+ *
+ * @section sip_dig_examples Examples
+ *
+ * Resolve sip:openlaboratory.net, prefer TLS over TCP, TCP over UDP:
+ * @code
+ * $ sip-dig --tls --tcp --udp sip:openlaboratory.net
+ *        1 0.333 tls 5061 212.213.221.127
+ *        2 0.333 tcp 5060 212.213.221.127
+ *        3 0.333 udp 5060 212.213.221.127
+ * @endcode
+ *
+ * Resolve sips:example.net with TLS over SCTP (TLS-SCTP) and TLS:
+ * @code
+ * $ sip-dig -p tls-sctp --tls sips:example.net
+ *        1 0.500 tls-udp 5061 172.21.55.26
+ *        2 0.500 tls 5061 172.21.55.26
+ * @endcode
+ *
+ * @section sip_dig_environment Environment
+ * #SRESOLV_DEBUG, SRESOLV_CONF
+ *
+ * @section sip_dig_bugs Reporting Bugs
+ * Report bugs to &lt;sofia-sip-devel@lists.sourceforge.net&gt;.
+ *
+ * @section sip_dig_author Author
+ * Written by Pekka Pessi &lt;pekka -dot pessi -at- nokia -dot- com&gt;
+ *
+ * @section sip_dig_copyright Copyright
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+
+#include &quot;switch.h&quot;
+#include &quot;../../config.h&quot;
+
+#include &quot;sofia-sip/su.h&quot;
+
+#include &quot;sofia-resolv/sres.h&quot;
+#include &quot;sofia-resolv/sres_record.h&quot;
+
+#include &quot;sofia-sip/url.h&quot;
+#include &quot;sofia-sip/su_alloc.h&quot;
+#include &quot;sofia-sip/su_string.h&quot;
+#include &quot;sofia-sip/hostdomain.h&quot;
+
+char const name[] = &quot;sip-dig&quot;;
+
+#include &lt;assert.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+#include &lt;stdio.h&gt;
+
+enum { N_TPORT = 16 };
+
+struct transport { char const *name, *service, *srv; };
+
+struct dig {
+        sres_resolver_t *sres;
+
+        unsigned preference, ip4, ip6, sips, print;
+
+        struct transport tports[N_TPORT + 1];
+};
+
+int dig_naptr(struct dig *dig, char const *host, double weight, switch_stream_handle_t *stream);
+
+int dig_all_srvs(struct dig *dig, char const *tport, char const *host,
+                                 double weight, switch_stream_handle_t *stream);
+
+int dig_srv(struct dig *dig, char const *tport, char const *host,
+                        double weight, switch_stream_handle_t *stream);
+
+int dig_srv_at(struct dig *dig,
+                           char const *tport, sres_record_t **answers,
+                           double weight, int pweight,
+                           int priority, switch_stream_handle_t *stream);
+
+int dig_addr(struct dig *dig,
+                         char const *tport, char const *host, char const *port,
+                         double weight, switch_stream_handle_t *stream);
+
+void print_addr_results(struct transport const *tports,
+                                                char const *tport, char const *tport2,
+                                                sres_record_t **answers, int type, int af,
+                                                char const *port,
+                                                double weight, int preference, switch_stream_handle_t *stream);
+
+void print_result(char const *addr, char const *port, char const *tport,
+                                  double weight,
+                                  unsigned preference,
+                                  switch_stream_handle_t *stream);
+
+int prepare_transport(struct dig *dig, char const *tport);
+
+int count_transports(struct dig *dig,
+                                         char const *tp1,
+                                         char const *tp2);
+
+void _usage(int exitcode, switch_stream_handle_t *stream)
+{
+        stream-&gt;write_function(stream, &quot;%s&quot;, &quot;usage: sofia_dig [OPTIONS] [@dnsserver] uri\n&quot;);
+}
+
+#define usage(_x) _usage(_x, stream); goto fail
+
+switch_status_t sip_dig_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream)
+
+{
+        int exitcode = 0;
+        int o_sctp = 1, o_tls_sctp = 1, o_verbatim = 1;
+        int family = 0, multiple = 0;
+        char const *dnsserver = NULL;
+        char const *string;
+        url_t *uri = NULL;
+
+        char const *host;
+        char const *port;
+        char *transport = NULL, tport[32];
+        int argc;
+        char *argv_[25] = { 0 };
+        char *mycmd = NULL;
+        char **argv;
+        struct dig dig[1] = {{ NULL }};
+        su_home_t *home = NULL;
+        int xml = 0;
+
+        home = su_home_new(sizeof(*home));
+
+        argv = argv_;
+        argv++;
+
+        if (!cmd) {
+                {usage(1);}
+        }
+
+        mycmd = strdup(cmd);
+
+        argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv_) / sizeof(argv_[0])) - 1);
+        argv = argv_;
+        
+        if (!strcasecmp(argv[1], &quot;xml&quot;)) {
+                switch_event_add_header_string(stream-&gt;param_event, SWITCH_STACK_BOTTOM, &quot;xml&quot;, &quot;true&quot;);
+                argv++;
+                xml++;
+        }
+
+        argv[0] = &quot;sofia_dig&quot;;
+
+
+        //if (su_init() != 0)
+        //return -1;
+
+        while (argv[1] &amp;&amp; argv[1][0] == '-') {
+                if (strcmp(argv[1], &quot;-v&quot;) == 0)
+                        o_verbatim++;
+                else if (strcmp(argv[1], &quot;-6&quot;) == 0)
+                        dig-&gt;ip6 = ++family;
+                else if (strcmp(argv[1], &quot;-4&quot;) == 0)
+                        dig-&gt;ip4 = ++family;
+                else if (strncmp(argv[1], &quot;-p&quot;, 2) == 0) {
+                        char const *proto;
+
+                        if (argv[1][2] == '=')
+                                proto = argv[1] + 3;
+                        else if (argv[1][2])
+                                proto = argv[1] + 2;
+                        else
+                                proto = argv++[2];
+
+                        if (proto == NULL)
+                                {usage(2);}
+
+                        if (prepare_transport(dig, proto) &lt; 0) {
+                                goto fail;
+                        }
+                }
+                else if (strcmp(argv[1], &quot;--udp&quot;) == 0)
+                        prepare_transport(dig, &quot;udp&quot;);
+                else if (strcmp(argv[1], &quot;--tcp&quot;) == 0)
+                        prepare_transport(dig, &quot;tcp&quot;);
+                else if (strcmp(argv[1], &quot;--tls&quot;) == 0)
+                        prepare_transport(dig, &quot;tls&quot;);
+                else if (strcmp(argv[1], &quot;--sctp&quot;) == 0)
+                        prepare_transport(dig, &quot;sctp&quot;);
+                else if (strcmp(argv[1], &quot;--tls-sctp&quot;) == 0)
+                        prepare_transport(dig, &quot;tls-sctp&quot;);
+                else if (strcmp(argv[1], &quot;--tls-udp&quot;) == 0)
+                        prepare_transport(dig, &quot;tls-udp&quot;);
+                else if (strcmp(argv[1], &quot;--no-sctp&quot;) == 0)
+                        o_sctp = 0, o_tls_sctp = 0;
+                else if (strcmp(argv[1], &quot;--help&quot;) == 0)
+                        {usage(0);}
+                else if (strcmp(argv[1], &quot;-h&quot;) == 0)
+                        {usage(0);}
+                else if (strcmp(argv[1], &quot;-?&quot;) == 0)
+                        {usage(0);}
+                else if (strcmp(argv++[1], &quot;-&quot;) == 0)
+                        break;
+                else
+                        {usage(2);}
+                argv++;
+        }
+
+
+        if (xml) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, &quot;&lt;routes&gt;\n&quot;);
+        } else {
+                stream-&gt;write_function(stream, &quot;%10s\t%10s\t%10s\t%10s\t%10s\n&quot;, &quot;Preference&quot;, &quot;Weight&quot;, &quot;Transport&quot;, &quot;Port&quot;, &quot;Address&quot;);
+                stream-&gt;write_function(stream, &quot;================================================================================\n&quot;);
+        }
+
+        if (!family)
+                dig-&gt;ip4 = 1, dig-&gt;ip6 = 2;
+
+        if (argv[1] &amp;&amp; argv[1][0] == '@')
+                dnsserver = argv++[1] + 1;
+
+
+
+        if (!argv[1])
+                {usage(2);}
+
+
+        multiple = argv[1] &amp;&amp; argv[2];
+
+        if (!count_transports(dig, NULL, NULL)) {
+                prepare_transport(dig, &quot;udp&quot;);
+                prepare_transport(dig, &quot;tcp&quot;);
+                if (o_sctp)
+                        prepare_transport(dig, &quot;sctp&quot;);
+                prepare_transport(dig, &quot;tls&quot;);
+                if (o_tls_sctp)
+                        prepare_transport(dig, &quot;tls-sctp&quot;);
+        }
+
+        dig-&gt;sres = sres_resolver_new(getenv(&quot;SRESOLV_CONF&quot;));
+        if (!dig-&gt;sres)
+                {usage(1);}
+        
+        for (; (string = argv[1]); argv++) {
+                if (multiple)
+                        stream-&gt;write_function(stream, &quot;%s&quot;, string);
+
+                uri = url_hdup(home, (void *)string);
+
+                if (uri &amp;&amp; uri-&gt;url_type == url_unknown)
+                        url_sanitize(uri);
+
+                if (uri &amp;&amp; uri-&gt;url_type == url_any)
+                        continue;
+
+                if (!uri || (uri-&gt;url_type != url_sip &amp;&amp; uri-&gt;url_type != url_sips)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;%s: invalid uri\n&quot;, string);
+                        exitcode = 1;
+                        continue;
+                }
+
+                port = url_port(uri);
+                if (port &amp;&amp; !port[0]) port = NULL;
+                if (url_param(uri-&gt;url_params, &quot;transport=&quot;, tport, sizeof tport) &gt; 0)
+                        transport = tport;
+
+                host = uri-&gt;url_host;
+
+                if (host_is_ip_address(host)) {
+                        if (transport) {
+                                print_result(host, port, transport, 1.0, 1, stream);
+                        }
+                        else if (uri-&gt;url_type == url_sips) {
+                                print_result(host, port, &quot;tls&quot;, 1.0, 1, stream);
+                        }
+                        else {
+                                print_result(host, port, &quot;udp&quot;, 1.0, 1, stream);
+                                print_result(host, port, &quot;tcp&quot;, 1.0, 2, stream);
+                        }
+                        continue;
+                }
+
+                if (!host_is_domain(host)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;%s: invalid host\n&quot;, string);
+                        exitcode = 1;
+                        continue;
+                }
+
+                dig-&gt;sips = uri-&gt;url_type == url_sips;
+                dig-&gt;preference = 1;
+
+                if (!port &amp;&amp; !transport &amp;&amp; dig_naptr(dig, host, 1.0, stream))
+                        continue /* resolved naptr */;
+                else if (!port &amp;&amp; dig_all_srvs(dig, transport, host, 1.0, stream))
+                        continue /* resolved srv */;
+                else if (dig_addr(dig, transport, host, port, 1.0, stream))
+                        continue /* resolved a/aaaa */;
+
+                stream-&gt;write_function(stream, &quot;-ERR: %s: not found\n&quot;, string);
+                exitcode = 1;
+        }
+
+        if (xml) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, &quot;&lt;/routes&gt;\n&quot;);
+        }
+
+
+ fail:
+        su_home_unref(home);
+        sres_resolver_unref(dig-&gt;sres);
+        switch_safe_free(mycmd);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+
+int transport_is_secure(char const *tportname)
+{
+        return su_casenmatch(tportname, &quot;tls&quot;, 3);
+}
+
+int prepare_transport(struct dig *dig, char const *tport)
+{
+        struct transport *tports = dig-&gt;tports;
+        int j;
+
+        for (j = 0; j &lt; N_TPORT; j++) {
+                if (!tports[j].name)
+                        break;
+                if (su_casematch(tports[j].name, tport))
+                        return 1;
+        }
+
+        if (j == N_TPORT)
+                return 0;
+
+        if (strchr(tport, '/')) {
+                char *service = strchr(tport, '/');
+                char *srv = strchr(service + 1, '/');
+
+                if (!srv || srv[strlen(srv) - 1] != '.') {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;%s: invalid transport specifier \&quot;%s\&quot;\n&quot;
+                                                
+                                                          &quot;\tspecifier should have name/service/srv-id\n&quot;
+                                                          &quot;\twhere name is protocol name (e.g, \&quot;tls-udp\&quot;)\n&quot;
+                                                          &quot;\t      service specifies service as per RFC 2915 (e.g., \&quot;SIPS+D2U\&quot;)\n&quot;
+                                                          &quot;\t      srv-id is prefix for SRV lookup (e.g., \&quot;_sips._udp.\&quot;)\n%s&quot;, 
+                                                          name, 
+                                                          tport,
+                                                          srv ? &quot;\t      and it should end with a dot \&quot;.\&quot;\n&quot; : &quot;&quot;);
+
+                        return -1;
+                }
+
+                *service++ = '\0', *srv++ = '\0';
+
+                tports[j].name = tport,
+                        tports[j].service = service;
+                tports[j].srv = srv;
+        }
+        else if (su_casematch(tport, &quot;udp&quot;)) {
+                tports[j].name = &quot;udp&quot;;
+                tports[j].service = &quot;SIP+D2U&quot;;
+                tports[j].srv = &quot;_sip._udp.&quot;;
+        }
+        else if (su_casematch(tport, &quot;tcp&quot;)) {
+                tports[j].name = &quot;tcp&quot;;
+                tports[j].service = &quot;SIP+D2T&quot;;
+                tports[j].srv = &quot;_sip._tcp.&quot;;
+        }
+        else if (su_casematch(tport, &quot;tls&quot;)) {
+                tports[j].name = &quot;tls&quot;;
+                tports[j].service = &quot;SIPS+D2T&quot;;
+                tports[j].srv = &quot;_sips._tcp.&quot;;
+        }
+        else if (su_casematch(tport, &quot;sctp&quot;)) {
+                tports[j].name = &quot;sctp&quot;;
+                tports[j].service = &quot;SIP+D2S&quot;;
+                tports[j].srv = &quot;_sip._sctp.&quot;;
+        }
+        else if (su_casematch(tport, &quot;tls-sctp&quot;)) {
+                tports[j].name = &quot;tls-sctp&quot;;
+                tports[j].service = &quot;SIPS+D2S&quot;;
+                tports[j].srv = &quot;_sips._sctp.&quot;;
+        }
+        else {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;%s: unknown transport \&quot;%s\&quot;\n&quot;, name, tport);
+                return -1;
+        }
+
+        j++;
+
+        tports[j].service = tports[j].srv = tports[j].name = NULL;
+
+        return 1;
+}
+
+int
+count_transports(struct dig *dig,
+                                 char const *tport,
+                                 char const *tport2)
+{
+
+        int i, tcount = 0;
+        struct transport const *tports = dig-&gt;tports;
+
+        for (i = 0; tports[i].name; i++) {
+                if (dig-&gt;sips &amp;&amp; !transport_is_secure(tports[i].name))
+                        continue;
+                if (!tport || su_casematch(tport, tports[i].name))
+                        tcount++;
+                else if (tport2 &amp;&amp; su_casematch(tport2, tports[i].name))
+                        tcount++;
+        }
+
+        return tcount;
+}
+
+struct transport const *
+transport_by_service(struct transport const *tports, char const *s)
+{
+        int i;
+
+        for (i = 0; tports[i].name; i++) {
+                if (su_casematch(tports[i].service, s))
+                        return tports + i;
+        }
+
+        return NULL;
+}
+
+int dig_naptr(struct dig *dig,
+                          char const *host,
+                          double weight,
+                          switch_stream_handle_t *stream)
+{
+        sres_record_t **answers = NULL;
+        struct transport const *tp;
+        int i, error;
+        int order = 0, count = 0, nacount = 0, scount = 0;
+
+        error = sres_blocking_query(dig-&gt;sres, sres_type_naptr, host, 0, &amp;answers);
+        if (error &lt; 0)
+                return 0;
+
+        /* Sort by priority */
+        sres_sort_answers(dig-&gt;sres, answers);
+
+        /* Count number of matching naptrs */
+        for (i = 0; answers[i]; i++) {
+                sres_naptr_record_t const *na = answers[i]-&gt;sr_naptr;
+
+                if (na-&gt;na_record-&gt;r_type != sres_type_naptr || na-&gt;na_record-&gt;r_status)
+                        continue;
+
+                if (dig-&gt;print)
+                        stream-&gt;write_function(stream, &quot;%s\n\t%d IN NAPTR %u %u \&quot;%s\&quot; \&quot;%s\&quot; \&quot;%s\&quot; %s\n&quot;,
+                                                                   na-&gt;na_record-&gt;r_name, na-&gt;na_record-&gt;r_ttl,
+                                                                   na-&gt;na_order, na-&gt;na_prefer,
+                                                                   na-&gt;na_flags, na-&gt;na_services,
+                                                                   na-&gt;na_regexp, na-&gt;na_replace);
+
+                if (!su_casematch(na-&gt;na_flags, &quot;s&quot;) &amp;&amp; !su_casematch(na-&gt;na_flags, &quot;a&quot;))
+                        continue;
+
+                if (nacount &amp;&amp; order != na-&gt;na_order)
+                        continue;
+
+                if (dig-&gt;sips &amp;&amp; !su_casenmatch(na-&gt;na_services, &quot;SIPS+&quot;, 5))
+                        continue;
+
+                if (!transport_by_service(dig-&gt;tports, na-&gt;na_services))
+                        continue;
+
+                order = na-&gt;na_order, nacount++;
+        }
+
+        if (nacount == 0) {
+                sres_free_answers(dig-&gt;sres, answers);
+                return 0;
+        }
+
+        for (i = 0; answers[i]; i++) {
+                sres_naptr_record_t const *na = answers[i]-&gt;sr_naptr;
+
+                if (na-&gt;na_record-&gt;r_type != sres_type_naptr || na-&gt;na_record-&gt;r_status)
+                        continue;
+                if (order != na-&gt;na_order)
+                        continue;
+                if (!su_casematch(na-&gt;na_flags, &quot;s&quot;) &amp;&amp; !su_casematch(na-&gt;na_flags, &quot;a&quot;))
+                        continue;
+                if (dig-&gt;sips &amp;&amp; !su_casenmatch(na-&gt;na_services, &quot;SIPS+&quot;, 5))
+                        continue;
+
+                tp = transport_by_service(dig-&gt;tports, na-&gt;na_services);
+                if (!tp)
+                        continue;
+
+                if (su_casematch(na-&gt;na_flags, &quot;s&quot;)) {
+                        scount = dig_srv(dig, tp-&gt;name, na-&gt;na_replace, weight / nacount, stream);
+                }
+                else if (su_casematch(na-&gt;na_flags, &quot;a&quot;)) {
+                        scount = dig_addr(dig, tp-&gt;name, na-&gt;na_replace, NULL, weight / nacount, stream);
+                }
+                else
+                        scount = 0;
+
+                count += scount;
+        }
+
+        return count;
+}
+
+int dig_all_srvs(struct dig *dig,
+                                 char const *tport,
+                                 char const *host,
+                                 double weight,
+                                 switch_stream_handle_t *stream)
+{
+        int i, j, n;
+        int tcount, count = 0, scount;
+        char *domain;
+
+        struct {
+                char const *proto; sres_record_t **answers;
+        } srvs[N_TPORT + 1] = {{ NULL }};
+
+        tcount = count_transports(dig, tport, NULL);
+        if (!tcount)
+                return 0;
+
+        for (i = 0, n = 0; dig-&gt;tports[i].name; i++) {
+                if (tport &amp;&amp; !su_casematch(dig-&gt;tports[i].name, tport))
+                        continue;
+
+                if (dig-&gt;sips &amp;&amp; !transport_is_secure(dig-&gt;tports[i].name))
+                        continue;
+
+                domain = su_strcat(NULL, dig-&gt;tports[i].srv, host);
+
+                if (domain) {
+                        if (sres_blocking_query(dig-&gt;sres, sres_type_srv, domain, 0,
+                                                                        &amp;srvs[n].answers) &gt;= 0) {
+                                srvs[n++].proto = dig-&gt;tports[i].name;
+                        }
+                        free(domain);
+                }
+        }
+
+        if (n == 0)
+                return 0;
+
+        for (i = 0; i &lt; n; i++) {
+                unsigned priority = 0, pweight = 0, m = 0;
+                sres_record_t **answers = srvs[i].answers;
+                char const *tport = srvs[i].proto;
+
+                for (j = 0; answers[j]; j++) {
+                        sres_srv_record_t const *srv = answers[j]-&gt;sr_srv;
+
+                        if (srv-&gt;srv_record-&gt;r_type != sres_type_srv)
+                                continue;
+                        if (srv-&gt;srv_record-&gt;r_status != 0)
+                                continue;
+
+                        if (srv-&gt;srv_priority != priority &amp;&amp; pweight != 0) {
+                                scount = dig_srv_at(dig, tport, answers, weight / n, pweight,
+                                                                        priority, stream);
+                                if (scount) dig-&gt;preference++;
+                                count += scount;
+                                pweight = 0, m = 0;
+                        }
+
+                        priority = srv-&gt;srv_priority, pweight += srv-&gt;srv_weight, m++;
+                }
+
+                if (m) {
+                        scount = dig_srv_at(dig, tport, answers, weight / n, pweight, priority, stream);
+                        if (scount)
+                                dig-&gt;preference++;
+                        count += scount;
+                }
+        }
+
+        return count;
+}
+
+int dig_srv(struct dig *dig,
+                        char const *tport,
+                        char const *domain,
+                        double weight,
+                        switch_stream_handle_t *stream)
+{
+        sres_record_t **answers = NULL;
+        int j, n, error;
+        int count = 0, scount = 0;
+
+        uint32_t priority, pweight;
+
+        assert(tport &amp;&amp; domain);
+
+        error = sres_blocking_query(dig-&gt;sres, sres_type_srv, domain, 0, &amp;answers);
+        if (error &lt; 0)
+                return 0;
+
+        /* Sort by priority */
+        sres_sort_answers(dig-&gt;sres, answers);
+
+        priority = 0; pweight = 0; n = 0;
+
+        for (j = 0; answers[j]; j++) {
+                sres_srv_record_t const *srv = answers[j]-&gt;sr_srv;
+
+                if (srv-&gt;srv_record-&gt;r_type != sres_type_srv)
+                        continue;
+                if (srv-&gt;srv_record-&gt;r_status != 0)
+                        continue;
+
+                if (srv-&gt;srv_priority != priority &amp;&amp; pweight != 0) {
+                        scount = dig_srv_at(dig, tport, answers, weight, pweight,
+                                                                priority, stream);
+                        if (scount) dig-&gt;preference++;
+                        count += scount;
+                        pweight = 0, n = 0;
+                }
+
+                priority = srv-&gt;srv_priority, pweight += srv-&gt;srv_weight, n++;
+        }
+
+        if (n) {
+                scount = dig_srv_at(dig, tport, answers, weight, pweight, priority, stream);
+                if (scount) dig-&gt;preference++;
+                count += scount;
+        }
+
+        sres_free_answers(dig-&gt;sres, answers);
+
+        return count;
+}
+
+int dig_srv_at(struct dig *dig,
+                           char const *tport,
+                           sres_record_t **answers,
+                           double weight, int pweight,
+                           int priority,
+                           switch_stream_handle_t *stream)
+{
+        int count = 0;
+        int i;
+        char port[8];
+
+        if (pweight == 0)
+                pweight = 1;
+
+        for (i = 0; answers[i]; i++) {
+                sres_srv_record_t const *srv = answers[i]-&gt;sr_srv;
+                if (srv-&gt;srv_record-&gt;r_type != sres_type_srv)
+                        continue;
+                if (srv-&gt;srv_record-&gt;r_status != 0)
+                        continue;
+                if (srv-&gt;srv_priority != priority)
+                        continue;
+                snprintf(port, sizeof port, &quot;%u&quot;, srv-&gt;srv_port);
+
+                count += dig_addr(dig, tport, srv-&gt;srv_target, port,
+                                                  weight * srv-&gt;srv_weight / pweight, stream);
+        }
+
+        return count;
+}
+
+int dig_addr(struct dig *dig,
+                         char const *tport,
+                         char const *host,
+                         char const *port,
+                         double weight,
+                         switch_stream_handle_t *stream)
+{
+        int error, i;
+        char const *tport2 = NULL;
+        sres_record_t **answers1 = NULL, **answers2 = NULL;
+        unsigned count1 = 0, count2 = 0, tcount = 0;
+        int type1 = 0, type2 = 0, family1 = 0, family2 = 0;
+
+        if (dig-&gt;ip6 &gt; dig-&gt;ip4) {
+                type1 = sres_type_aaaa, family1 = AF_INET6;
+                if (dig-&gt;ip4)
+                        type2 = sres_type_a, family2 = AF_INET;
+        }
+        else {
+                type1 = sres_type_a, family1 = AF_INET;
+                if (dig-&gt;ip6)
+                        type2 = sres_type_aaaa, family2 = AF_INET6;
+        }
+
+        if (tport == NULL) {
+                if (dig-&gt;sips)
+                        tport = &quot;tls&quot;;
+                else
+                        tport = &quot;udp&quot;, tport2 = &quot;tcp&quot;;
+        }
+
+        tcount = count_transports(dig, tport, tport2);
+        if (!tcount)
+                return 0;
+
+        if (type1) {
+                error = sres_blocking_query(dig-&gt;sres, type1, host, 0, &amp;answers1);
+                if (error &gt;= 0)
+                        for (i = 0; answers1[i]; i++) {
+                                sres_common_t *r = answers1[i]-&gt;sr_record;
+                                count1 += r-&gt;r_type == type1 &amp;&amp;        r-&gt;r_status == 0;
+                        }
+        }
+
+        if (type2) {
+                error = sres_blocking_query(dig-&gt;sres, type2, host, 0, &amp;answers2);
+                if (error &gt;= 0)
+                        for (i = 0; answers2[i]; i++) {
+                                sres_common_t *r = answers2[i]-&gt;sr_record;
+                                count2 += r-&gt;r_type == type2 &amp;&amp;        r-&gt;r_status == 0;
+                        }
+        }
+
+        if (count1 + count2) {
+                double w = weight / (count1 + count2) / tcount;
+
+                if (count1)
+                        print_addr_results(dig-&gt;tports, tport, tport2,
+                                                           answers1, type1, family1, port,
+                                                           w, dig-&gt;preference, stream);
+                if (count2)
+                        print_addr_results(dig-&gt;tports, tport, tport2,
+                                                           answers2, type2, family2, port,
+                                                           w, dig-&gt;preference, stream);
+        }
+
+        sres_free_answers(dig-&gt;sres, answers1);
+        sres_free_answers(dig-&gt;sres, answers2);
+
+        return count1 + count2;
+}
+
+void
+print_addr_results(struct transport const *tports,
+                                   char const *tport, char const *tport2,
+                                   sres_record_t **answers, int type, int af,
+                                   char const *port,
+                                   double weight, int preference, switch_stream_handle_t *stream)
+{
+        int i, j;
+        char addr[64];
+
+        for (i = 0; answers[i]; i++) {
+                if (answers[i]-&gt;sr_record-&gt;r_type != type)
+                        continue;
+                if (answers[i]-&gt;sr_record-&gt;r_status != 0)
+                        continue;
+
+                su_inet_ntop(af, &amp;answers[i]-&gt;sr_a-&gt;a_addr, addr, sizeof addr);
+
+                for (j = 0; tports[j].name; j++) {
+                        if (su_casematch(tport, tports[j].name))
+                                print_result(addr, port, tport, weight, preference, stream);
+                        if (su_casematch(tport2, tports[j].name))
+                                print_result(addr, port, tport2, weight, preference, stream);
+                }
+        }
+}
+
+void print_result(char const *addr,
+                                  char const *port,
+                                  char const *tport,
+                                  double weight,
+                                  unsigned preference,
+                                  switch_stream_handle_t *stream)
+{
+        int xml = switch_true(switch_event_get_header(stream-&gt;param_event, &quot;xml&quot;));
+
+        if (!port || !port[0])
+                port = transport_is_secure(tport) ? &quot;5061&quot; : &quot;5060&quot;;
+
+        if (xml) {
+                stream-&gt;write_function(stream, 
+                                                           &quot; &lt;route&gt;\n&quot;
+                                                           &quot;  &lt;preference&gt;%u&lt;/preference&gt;\n&quot;
+                                                           &quot;  &lt;weight&gt;%.3f&lt;/weight&gt;\n&quot;
+                                                           &quot;  &lt;transport&gt;%s&lt;/transport&gt;\n&quot;
+                                                           &quot;  &lt;port&gt;%s&lt;/port&gt;\n&quot;
+                                                           &quot;  &lt;address&gt;%s&lt;/address&gt;\n&quot;
+                                                           &quot; &lt;/route&gt;\n&quot;,
+                                                           preference, weight, tport, port, addr);
+        } else {
+                stream-&gt;write_function(stream, &quot;%10u\t%10.3f\t%10s\t%10s\t%10s\n&quot;, preference, weight, tport, port, addr);
+        }
+}
+
+
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>