<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Glyphy</title>
  <link rel="alternate" type="text/html" href="http://glyphy.com/asynchronous-dns-queries-python-2008-02-09"/>
  <link rel="self" type="application/atom+xml" href="http://glyphy.com/node/15/atom/feed"/>
  <id>http://glyphy.com/node/15/atom/feed</id>
  <updated>2008-02-09T12:39:14-08:00</updated>
  <entry>
    <title>Asynchronous DNS queries in Python</title>
    <link rel="alternate" type="text/html" href="http://glyphy.com/asynchronous-dns-queries-python-2008-02-09" />
    <id>http://glyphy.com/asynchronous-dns-queries-python-2008-02-09</id>
    <published>2008-02-09T12:38:35-08:00</published>
    <updated>2008-02-09T12:39:14-08:00</updated>
    <author>
      <name>dv</name>
    </author>
    <category term="490" />
    <category term="python" />
    <category term="xmpp" />
    <summary type="html"><![CDATA[<p>When you have an application that&#8217;s event-driven (like <a href="http://twistedmatrix.com/trac/">twisted</a>), you&#8217;ve gotta eliminate all potentially blocking operations, or you risk putting your entire app to sleep while you wait for the blocking operation to complete. The XMPP server I&#8217;m working on has to send out DNS queries all the time, and these could take a while. I had to figure out how to make these queries asynchronous, so that they wouldn&#8217;t block the entire server. There are <a href="http://dustman.net/andy/python/adns-python">adns bindings</a>, but the GNU adns library is licensed under the GPL (I&#8217;m trying to stick to more liberal licenses) and not straightforward to install on Windows. There&#8217;s a <a href="http://www.dnspython.org/">DNS toolkit library</a> for python, but it doesn&#8217;t support asynchronous lookups natively. Enter the <a href="http://docs.python.org/lib/module-asyncore.html">asyncore module</a>. The following should allow you to query DNS and then get callbacks to <span class="geshifilter"><span class="geshifilter"><code class="geshifilter-text">handle_read()</code></span></span> when the data is available.</p>

<div class="geshifilter"><pre class="python geshifilter-python"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">asyncore</span>, <span style="color: #dc143c;">socket</span>
<span style="color: #ff7700;font-weight:bold;">from</span> dns <span style="color: #ff7700;font-weight:bold;">import</span> resolver, rdatatype, rdataclass, message
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> AsyncDNS<span style="color: black;">&#40;</span><span style="color: #dc143c;">asyncore</span>.<span style="color: black;">dispatcher</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">asyncore</span>.<span style="color: black;">dispatcher</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">r</span> = resolver.<span style="color: black;">Resolver</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">query</span> = <span style="color: #483d8b;">''</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">create_socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_DGRAM</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">r</span>.<span style="color: black;">nameservers</span><span style="color: black;">&#91;</span>0<span style="color: black;">&#93;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">r</span>.<span style="color: black;">port</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> makeQuery<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, server<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">query</span> = message.<span style="color: black;">make_query</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'_xmpp-server._tcp.%s'</span> <span style="color: #66cc66;">%</span> server,
                                   rdatatype.<span style="color: black;">SRV</span>, rdataclass.<span style="color: black;">IN</span><span style="color: black;">&#41;</span>.<span style="color: black;">to_wire</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> writable<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">query</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> 0<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        data = <span style="color: #008000;">self</span>.<span style="color: black;">recv</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4096</span><span style="color: black;">&#41;</span>
        answer = message.<span style="color: black;">from_wire</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> answer.<span style="color: black;">answer</span><span style="color: black;">&#91;</span>0<span style="color: black;">&#93;</span>.<span style="color: black;">to_text</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_write<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">query</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">query</span> = <span style="color: #483d8b;">''</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_accept<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">pass</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_connect<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">pass</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_bind<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">pass</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_close<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    d = AsyncDNS<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    d.<span style="color: black;">makeQuery</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'livejournal.com'</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">asyncore</span>.<span style="color: black;">loop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div>
    ]]></summary>
    <content type="html"><![CDATA[<p>When you have an application that&#8217;s event-driven (like <a href="http://twistedmatrix.com/trac/">twisted</a>), you&#8217;ve gotta eliminate all potentially blocking operations, or you risk putting your entire app to sleep while you wait for the blocking operation to complete. The XMPP server I&#8217;m working on has to send out DNS queries all the time, and these could take a while. I had to figure out how to make these queries asynchronous, so that they wouldn&#8217;t block the entire server. There are <a href="http://dustman.net/andy/python/adns-python">adns bindings</a>, but the GNU adns library is licensed under the GPL (I&#8217;m trying to stick to more liberal licenses) and not straightforward to install on Windows. There&#8217;s a <a href="http://www.dnspython.org/">DNS toolkit library</a> for python, but it doesn&#8217;t support asynchronous lookups natively. Enter the <a href="http://docs.python.org/lib/module-asyncore.html">asyncore module</a>. The following should allow you to query DNS and then get callbacks to <span class="geshifilter"><code class="geshifilter-text">handle_read()</code></span> when the data is available.</p>

<div class="geshifilter"><pre class="python geshifilter-python"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">asyncore</span>, <span style="color: #dc143c;">socket</span>
<span style="color: #ff7700;font-weight:bold;">from</span> dns <span style="color: #ff7700;font-weight:bold;">import</span> resolver, rdatatype, rdataclass, message
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> AsyncDNS<span style="color: black;">&#40;</span><span style="color: #dc143c;">asyncore</span>.<span style="color: black;">dispatcher</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">asyncore</span>.<span style="color: black;">dispatcher</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">r</span> = resolver.<span style="color: black;">Resolver</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">query</span> = <span style="color: #483d8b;">''</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">create_socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_DGRAM</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">r</span>.<span style="color: black;">nameservers</span><span style="color: black;">&#91;</span>0<span style="color: black;">&#93;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">r</span>.<span style="color: black;">port</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> makeQuery<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, server<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">query</span> = message.<span style="color: black;">make_query</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'_xmpp-server._tcp.%s'</span> <span style="color: #66cc66;">%</span> server,
                                   rdatatype.<span style="color: black;">SRV</span>, rdataclass.<span style="color: black;">IN</span><span style="color: black;">&#41;</span>.<span style="color: black;">to_wire</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> writable<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">query</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> 0<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        data = <span style="color: #008000;">self</span>.<span style="color: black;">recv</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4096</span><span style="color: black;">&#41;</span>
        answer = message.<span style="color: black;">from_wire</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> answer.<span style="color: black;">answer</span><span style="color: black;">&#91;</span>0<span style="color: black;">&#93;</span>.<span style="color: black;">to_text</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_write<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">query</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">query</span> = <span style="color: #483d8b;">''</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_accept<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">pass</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_connect<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">pass</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_bind<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">pass</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> handle_close<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    d = AsyncDNS<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    d.<span style="color: black;">makeQuery</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'livejournal.com'</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">asyncore</span>.<span style="color: black;">loop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div>
    ]]></content>
  </entry>
</feed>
