http://bugzilla.spamassassin.org/show_bug.cgi?id=3997
------- Additional Comments From [EMAIL PROTECTED] 2005-04-13 07:22 -------
Getting more relevant documentation in this one place... Here is Matt Sergeant's
post to sa-dev from last January with a recipe for the single-socket solution
which would have fixed this problem if we had only understood it back then:
Matt, I have a question about this. These four lines
my $packet = $self->{res}->make_query_packet($host);
my $packet_data = $packet->data;
my $h = $packet->header;
my $id = $h->id;
seem to imply that make_query_packet generates a unique ID when it makes a
header. Is that the case? Then we don't need all the counter code we just put in
to generate unique IDs?
------------
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.
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.