Browse Source

update request handling logic to fix #419

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac419@3738 e5f2f494-b856-4b98-b285-d166d9295462
Jerry 14 years ago
parent
commit
4548257a1d
2 changed files with 71 additions and 44 deletions
  1. 2 2
      src/bin/xfrout/tests/xfrout_test.py
  2. 69 42
      src/bin/xfrout/xfrout.py.in

+ 2 - 2
src/bin/xfrout/tests/xfrout_test.py

@@ -87,8 +87,8 @@ class TestXfroutSession(unittest.TestCase):
     def setUp(self):
         request = MySocket(socket.AF_INET,socket.SOCK_STREAM)
         self.log = isc.log.NSLogger('xfrout', '',  severity = 'critical', log_to_console = False )
-        (self.write_sock, self.read_sock) = socket.socketpair()
-        self.xfrsess = MyXfroutSession(request, None, None, self.log, self.read_sock)
+        self.xfrsess = MyXfroutSession(request, None, None, self.log)
+        self.write_sock, self.read_sock = socket.socketpair()
         self.xfrsess.server = Dbserver()
         self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
         self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)

+ 69 - 42
src/bin/xfrout/xfrout.py.in

@@ -74,55 +74,37 @@ def get_rrset_len(rrset):
 
 
 class XfroutSession(BaseRequestHandler):
-    def __init__(self, request, client_address, server, log, sock):
+    def __init__(self, request, client_address, server, log):
         # The initializer for the superclass may call functions
         # that need _log to be set, so we set it first
         self._log = log
-        self._shutdown_sock = sock
         BaseRequestHandler.__init__(self, request, client_address, server)
 
     def handle(self):
-        '''Handle a request until shutdown or xfrout client is closed.'''
-        # check self.server._shutdown_event to ensure the real shutdown comes.
-        # Linux could trigger a spurious readable event on the _shutdown_sock 
-        # due to a bug, so we need perform a double check. 
-        while not self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
-            try:
-                (rlist, wlist, xlist) = select.select([self._shutdown_sock, self.request], [], [])
-            except select.error as e:
-                if e.args[0] == errno.EINTR:
-                    (rlist, wlist, xlist) = ([], [], [])
-                    continue
-                else:
-                    self._log.log_message("error", "Error with select(): %s" %e)
-                    break
-            # self.server._shutdown_evnet will be set by now, if it is not a false
-            # alarm
-            if self._shutdown_sock in rlist:
-                continue
-
-            sock_fd = recv_fd(self.request.fileno())
+        ''' Handle a xfrout query. First, xfrout server receive
+        socket fd and query message from auth. Then, send xfrout
+        response via the socket fd.'''
+        sock_fd = recv_fd(self.request.fileno())
+        if sock_fd < 0:
+            # This may happen when one xfrout process try to connect to
+            # xfrout unix socket server, to check whether there is another
+            # xfrout running.
+            if sock_fd == XFR_FD_RECEIVE_FAIL:
+                self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
+            return
+
+        # receive query msg
+        msgdata = self._receive_query_message(self.request)
+        if not msgdata:
+            return
 
-            if sock_fd < 0:
-                # This may happen when one xfrout process try to connect to
-                # xfrout unix socket server, to check whether there is another
-                # xfrout running.
-                if sock_fd == XFR_FD_RECEIVE_FAIL:
-                    self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
-                break
-
-            # receive query msg
-            msgdata = self._receive_query_message(self.request)
-            if not msgdata:
-                break
-
-            try:
-                self.dns_xfrout_start(sock_fd, msgdata)
-                #TODO, avoid catching all exceptions
-            except Exception as e:
-                self._log.log_message("error", str(e))
+        try:
+            self.dns_xfrout_start(sock_fd, msgdata)
+            #TODO, avoid catching all exceptions
+        except Exception as e:
+            self._log.log_message("error", str(e))
 
-            os.close(sock_fd)
+        os.close(sock_fd)
 
     def _receive_query_message(self, sock):
         ''' receive query message from sock'''
@@ -342,9 +324,54 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer):
         self.update_config_data(config_data)
         self._cc = cc
 
+    def _handle_request_noblock(self):
+        '''Rewrite _handle_request_noblock() from parent class ThreadingUnixStreamServer,
+        enable server handle a request until shutdown or xfrout client is closed.'''
+        try:
+            request, client_address = self.get_request()
+        except socket.error:
+            return
+
+        if self.verify_request(request, client_address):
+            # Check self._shutdown_event to ensure the real shutdown comes.
+            # Linux could trigger a spurious readable event on the _read_sock
+            # due to a bug, so we need perform a double check.
+            while not self._shutdown_event.is_set(): # Check if xfrout is shutdown
+                try:
+                    (rlist, wlist, xlist) = select.select([self._read_sock, request], [], [])
+                except select.error as e:
+                    if e.args[0] == errno.EINTR:
+                        (rlist, wlist, xlist) = ([], [], [])
+                        continue
+                    else:
+                        self._log.log_message("error", "Error with select(): %s" %e)
+                        break
+
+                # self.server._shutdown_event will be set by now, if it is not a false
+                # alarm
+                if self._read_sock in rlist:
+                    continue
+
+                try:
+                    self.process_request(request, client_address)
+                except:
+                    self.handle_error(request, client_address)
+                    self.close_request(request)
+                    break
+
+    def process_request_thread(self, request, client_address):
+        ''' Rewrite process_request_thread() from parent class ThreadingUnixStreamServer,
+        server won't close the connection after handling a xfrout query, the connection
+        should be kept for handling upcoming xfrout queries.'''
+        try:
+            self.finish_request(request, client_address)
+        except Exception as e:
+            self.handle_error(request, client_address)
+            self.close_request(request)
+
     def finish_request(self, request, client_address):
         '''Finish one request by instantiating RequestHandlerClass.'''
-        self.RequestHandlerClass(request, client_address, self, self._log, self._read_sock)
+        self.RequestHandlerClass(request, client_address, self, self._log)
 
     def _remove_unused_sock_file(self, sock_file):
         '''Try to remove the socket file. If the file is being used