OK, after a bit of a chat with Tony Finch I had a go at making Net::DNS use one socket. Tony is working on patching Net::DNS to facilitate this, but I decided that was too much work and decided to try doing it without a patch.

I can't give you code, for two reasons - 1) IP (sorry), but mostly it's because of 2) I use Danga::Socket to do my asynch I/O, and my code is very tied to that architecture.

So here's a basic recipe:

I use two objects. One which is the resolver, and one singleton which is a high level interface onto making the DNS queries and getting responses.

A query method accepts a number of hosts/IPs to query for. This calls make_query_packet on a Net::DNS::Resolver class to create the query packet. Out of that query packet you get the packet_data, and the ID from the header.

Use the ID to map back to the "asker" (an object that encapsulates the query)

Here's my query() code (in the high level interface object):

sub query {
    my Danga::DNS::Resolver $self = shift;
    my ($asker, @hosts) = @_;

    foreach my $host (@hosts) {
        my $packet = $self->{res}->make_query_packet($host);
        my $packet_data = $packet->data;

        my $h = $packet->header;
        my $id = $h->id;

# dst here is:
# sockaddr_in($self->{res}{port}, inet_aton($self->{res}{nameservers}[0]));
if (!$self->sock->send($packet_data, 0, $self->{dst})) {
return;
}


        # print "Query: $host ($id)\n";

        $self->{id_to_asker}->{$id} = $asker;
    }

    return 1;
}

Then you select()/poll() on $self->sock, and when you can_read, you call:

    my $packet = $self->{res}->bgread($self->sock);
    my $err = $self->{res}->errorstring;
    my $answers = 0;
    if (defined($packet)) {
        my $header = $packet->header;
        my $id = $header->id;

        my $asker = delete $self->{id_to_asker}->{$id};
        if (!$asker) {
            warn("No asker for id: $id");
            return;
        }

        my @questions = $packet->question;
        #print STDERR "response to ", $questions[0]->string, "\n";
        foreach my $rr ($packet->answer) {
            # do something with the answers, calling into $asker
            ...
            $answers++;
        }
    }

That's all there is to it. You need to add in some timeout code of your own (though this might be sufficient in the SA architecture to just use the select() timeout), and it only queries one nameserver, but I'm sure you can probably adapt it.

Let me know if you have any questions about integrating this into SA. I'm sorry I can't just code it in for you.

Enjoy!

Matt.


______________________________________________________________________
This email has been scanned by the MessageLabs Email Security System.
For more information please visit http://www.messagelabs.com/email ______________________________________________________________________

Reply via email to