[Twisted-Python] mktap dns is broken if you switch subnets

Tommi Virtanen tv at twistedmatrix.com
Wed Apr 30 12:01:59 EDT 2003


	Hi. Lately, I've been playing with using "mktap dns" as a
	resolver for my laptop. Except, it's making me angry.

	It doesn't reload resolv.conf. My resolv.conf nameserver list
	is changed by DHCP about twice per day, atleast.

	In fact, it even loads the resolv.conf only in __init__, so
	the list gets stored in the tap file. I need to mktap, tap2deb
	and dpkg -i whenever I switch subnets!

	Here's a quick-and-stupid patch that makes it reload
	resolv.conf regularly, currently made to reread it every
	minute. This is "close enough". Actually, I want to make
	it get a notification from somewhere..

	I definitely want this implemented. Please tell what direction
	should I go with the patch, and what do you think is missing
	from "production quality"?

Index: twisted/names/client.py
===================================================================
RCS file: /cvs/Twisted/twisted/names/client.py,v
retrieving revision 1.31
diff -u -r1.31 client.py
--- twisted/names/client.py	29 Mar 2003 18:10:14 -0000	1.31
+++ twisted/names/client.py	30 Apr 2003 15:56:00 -0000
@@ -30,6 +30,8 @@
 
 import socket
 import os
+import errno
+import time
 
 # Twisted imports
 from twisted.python.runtime import platform
@@ -52,6 +54,10 @@
     protocol = None
     connections = None
 
+    resolv = None
+    resolv_last_read = 0
+    resolv_read_interval = 60
+
     def __init__(self, resolv = None, servers = None, timeout = (1, 3, 11, 45)):
         """
         @type servers: C{list} of C{(str, int)} or C{None}
@@ -78,10 +84,9 @@
         else:
             self.servers = servers
         
-        if resolv and os.path.exists(resolv):
-            self.parseConfig(resolv)
+        self.resolv = resolv
         
-        if not len(self.servers):
+        if not len(self.servers) and not resolv:
             raise ValueError, "No nameservers specified"
         
         self.factory = DNSClientFactory(self, timeout)
@@ -99,20 +104,36 @@
         d['connections'] = []
         return d
 
+    def maybeParseConfig(self):
+        if self.resolv_last_read + self.resolv_read_interval < time.time():
+            self.parseConfig()
 
-    def parseConfig(self, conf):
-        lines = open(conf).readlines()
+    def parseConfig(self):
+        try:
+            file = open(self.resolv)
+        except IOError, e:
+            if e.errno == errno.ENOENT:
+                return
+            else:
+                raise
+
+        lines = file.readlines()
+        self.resolv_last_read = os.fstat(file.fileno()).st_mtime
+        file.close()
+        servers = []
         for l in lines:
             l = l.strip()
             if l.startswith('nameserver'):
-                self.servers.append((l.split()[1], dns.PORT))
-                log.msg("Resolver added %r to server list" % (self.servers[-1],))
+                resolver = (l.split()[1], dns.PORT)
+                servers.append(resolver)
+                log.msg("Resolver added %r to server list" % (resolver,))
             elif l.startswith('domain'):
                 self.domain = l.split()[1]
                 self.search = None
             elif l.startswith('search'):
                 self.search = l.split()[1:]
                 self.domain = None
+        self.dynamicServers = servers
 
 
     def pickServer(self):
@@ -122,8 +143,15 @@
         TODO: Weight servers for response time so faster ones can be
         preferred.
         """
-        self.index = (self.index + 1) % len(self.servers)
-        return self.servers[self.index]
+        self.parseConfig()
+        if not self.servers and not self.dynamicServers:
+            return None
+        self.index = ((self.index + 1)
+                      % (len(self.servers) + len(self.dynamicServers)))
+        if self.index < len(self.servers):
+            return self.servers[self.index]
+        else:
+            return self.dynamicServers[self.index - len(self.servers)]
 
 
     def connectionMade(self, protocol):
@@ -155,7 +183,10 @@
         if timeout is None:
             timeout = self.timeout
         address = self.pickServer()
-        d = self.protocol.query(address, queries, timeout[0])
+        if address is not None:
+            d = self.protocol.query(address, queries, timeout[0])
+        else:
+            d = defer.fail()
         d.addErrback(self._reissue, address, queries, timeout[1:])
         return d
 
@@ -186,7 +217,10 @@
         @rtype: C{Deferred}
         """
         if not len(self.connections):
-            host, port = self.pickServer()
+            address = self.pickServer()
+            if address is None:
+                return defer.fail()
+            host, port = address
             from twisted.internet import reactor
             reactor.connectTCP(host, port, self.factory)
             self.pending.append((defer.Deferred(), queries, timeout))

-- 
:(){ :|:&};:




More information about the Twisted-Python mailing list