Permalink
Browse files

stub_resolver.lookup(): avoid qid collisions

  • Loading branch information...
1 parent 1aeee94 commit d9cf6f148fcca85ff2a6c549db6502cb02f8b3af @samrushing samrushing committed Mar 15, 2012
Showing with 16 additions and 3 deletions.
  1. +16 −3 coro/dns/stub_resolver.py
View
@@ -14,12 +14,17 @@ class stub_resolver:
def __init__ (self, nameservers, inflight=200):
self.nameservers = nameservers
self.inflight = coro.semaphore (inflight)
+ self.inflight_ids = set()
def lookup (self, qname, qtype, timeout=10, retries=3):
m = packet.Packer()
h = packet.Header()
- # XXX need to avoid collisions
- h.id = random.randrange (65536)
+ while 1:
+ qid = random.randrange (65536)
+ # avoid collisions
+ if qid not in self.inflight_ids:
+ break
+ h.id = qid
h.opcode = packet.OPCODE.QUERY
h.rd = 1
h.qdcount = 1
@@ -29,18 +34,26 @@ def lookup (self, qname, qtype, timeout=10, retries=3):
for addr in self.nameservers:
for i in range (retries):
self.inflight.acquire (1)
+ self.inflight_ids.add (qid)
try:
s = coro.udp_sock()
s.connect ((addr, 53))
s.send (p)
try:
reply = coro.with_timeout (timeout, s.recv, 1000)
u = packet.Unpacker (reply)
- return u.unpack()
+ result = u.unpack()
+ rh = result[0]
+ if rh.id != qid:
+ raise QueryFailed ("bad id in reply")
+ else:
+ return result
except coro.TimeoutError:
pass
finally:
self.inflight.release (1)
+ self.inflight_ids.remove (qid)
+
raise QueryFailed ("no reply from nameservers")
def gethostbyname (self, name, qtype):

3 comments on commit d9cf6f1

Owner

halayli replied Apr 5, 2012

Since it's udp it feels more natural to do s.sendto (p, (addr, 53)) instead of connect + send.

Owner

samrushing replied Apr 5, 2012

The advantage of connect() is that you don't have to check to make sure that the reply comes back from who you sent it to. [idea from djb]

Owner

halayli replied Apr 6, 2012

Ah cool trick! My intention was to avoid a system call but in this case it's worth it. :)

Please sign in to comment.