Browse Source

When xfrout is launched, check whether the socket file is being used by one running xfrout process, if it is, exit from python. If the file isn't a socket file or nobody is listening, it will be removed. If it can't be removed, exit from python.

git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@2091 e5f2f494-b856-4b98-b285-d166d9295462
Likun Zhang 15 years ago
parent
commit
990e977d86
3 changed files with 112 additions and 7 deletions
  1. 8 0
      ChangeLog
  2. 64 0
      src/bin/xfrout/tests/xfrout_test.py
  3. 40 7
      src/bin/xfrout/xfrout.py.in

+ 8 - 0
ChangeLog

@@ -1,3 +1,11 @@
+  52.   [func]      zhanglikun
+	bin/xfrout: When xfrout is launched, check whether the
+	socket file is being used by one running xfrout process, 
+	if it is, exit from python.	If the file isn't a socket file 
+	or nobody is listening, it will be removed. If it can't 
+	be removed, exit from python.
+	(Trac #151, svn r2084)
+
 bind10-devel-20100602 released on June 2, 2010
 bind10-devel-20100602 released on June 2, 2010
 
 
   51.   [build]         jelte
   51.   [build]         jelte

+ 64 - 0
src/bin/xfrout/tests/xfrout_test.py

@@ -278,6 +278,70 @@ class TestUnixSockServer(unittest.TestCase):
         self.unix.decrease_transfers_counter()
         self.unix.decrease_transfers_counter()
         self.assertEqual(count - 1, self.unix._transfers_counter)
         self.assertEqual(count - 1, self.unix._transfers_counter)
 
 
+    def _remove_file(self, sock_file):
+        try:
+            os.remove(sock_file)
+        except OSError:
+            pass
+ 
+    def test_sock_file_in_use_file_exist(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self.assertFalse(os.path.exists(sock_file))
+
+    def test_sock_file_in_use_file_not_exist(self):
+        self.assertFalse(self.unix._sock_file_in_use('temp.sock.file'))
+
+    def _start_unix_sock_server(self, sock_file):
+        serv = ThreadingUnixStreamServer(sock_file, BaseRequestHandler)
+        serv_thread = threading.Thread(target=serv.serve_forever)
+        serv_thread.setDaemon(True)
+        serv_thread.start()
+
+    def test_sock_file_in_use(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self._start_unix_sock_server(sock_file)
+
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        self.assertTrue(self.unix._sock_file_in_use(sock_file))
+        sys.stdout = old_stdout
+
+    def test_remove_unused_sock_file_in_use(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self._start_unix_sock_server(sock_file)
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        try:
+            self.unix._remove_unused_sock_file(sock_file)
+        except SystemExit:
+            pass
+        else:
+            # This should never happen
+            self.assertTrue(False)
+
+        sys.stdout = old_stdout
+
+    def test_remove_unused_sock_file_dir(self):
+        import tempfile
+        dir_name = tempfile.mkdtemp()
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        try:
+            self.unix._remove_unused_sock_file(dir_name)
+        except SystemExit:
+            pass
+        else:
+            # This should never happen
+            self.assertTrue(False)
+
+        sys.stdout = old_stdout
+        os.rmdir(dir_name)
 
 
 if __name__== "__main__":
 if __name__== "__main__":
     unittest.main()
     unittest.main()

+ 40 - 7
src/bin/xfrout/xfrout.py.in

@@ -28,6 +28,7 @@ import os
 from isc.config.ccsession import *
 from isc.config.ccsession import *
 from isc.cc import SessionError
 from isc.cc import SessionError
 import socket
 import socket
+import errno
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
 try:
 try:
     from bind10_xfr import *
     from bind10_xfr import *
@@ -57,7 +58,13 @@ class XfroutSession(BaseRequestHandler):
     def handle(self):
     def handle(self):
         fd = recv_fd(self.request.fileno())
         fd = recv_fd(self.request.fileno())
         if fd < 0:
         if fd < 0:
-            raise XfroutException("failed to receive the FD for XFR connection")
+            # This may happen when one xfrout process try to connect to
+            # xfrout unix socket server, to check whether there is another
+            # xfrout running. 
+            print("[b10-xfrout] Failed to receive the FD for XFR connection, "
+                  "maybe because another xfrout process was started.")
+            return
+
         data_len = self.request.recv(2)
         data_len = self.request.recv(2)
         msg_len = struct.unpack('!H', data_len)[0]
         msg_len = struct.unpack('!H', data_len)[0]
         msgdata = self.request.recv(msg_len)
         msgdata = self.request.recv(msg_len)
@@ -277,18 +284,44 @@ class UnixSockServer(ThreadingUnixStreamServer):
     '''The unix domain socket server which accept xfr query sent from auth server.'''
     '''The unix domain socket server which accept xfr query sent from auth server.'''
 
 
     def __init__(self, sock_file, handle_class, shutdown_event, config_data):
     def __init__(self, sock_file, handle_class, shutdown_event, config_data):
-        try:
-            os.unlink(sock_file)
-        except:
-            pass
- 
+        self._remove_unused_sock_file(sock_file)
         self._sock_file = sock_file
         self._sock_file = sock_file
         ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
         ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
         self._lock = threading.Lock()
         self._lock = threading.Lock()
         self._transfers_counter = 0
         self._transfers_counter = 0
         self._shutdown_event = shutdown_event
         self._shutdown_event = shutdown_event
         self.update_config_data(config_data)
         self.update_config_data(config_data)
-    
+
+    def _remove_unused_sock_file(self, sock_file):
+        '''Try to remove the socket file. If the file is being used 
+        by one running xfrout process, exit from python. 
+        If it's not a socket file or nobody is listening
+        , it will be removed. If it can't be removed, exit from python. '''
+        if self._sock_file_in_use(sock_file):
+            print("[b10-xfrout] Fail to start xfrout process, unix socket" 
+                  " file '%s' is being used by another xfrout process" % sock_file)
+            sys.exit(0)
+        else:
+            if not os.path.exists(sock_file):
+                return
+
+            try:
+                os.unlink(sock_file)
+            except OSError as err:
+                print('[b10-xfrout] Fail to remove file ' + sock_file, err)
+                sys.exit(0)
+   
+    def _sock_file_in_use(self, sock_file):
+        '''Check whether the socket file 'sock_file' exists and 
+        is being used by one running xfrout process. If it is, 
+        return True, or else return False. '''
+        try:
+            sock = socket.socket(socket.AF_UNIX)
+            sock.connect(sock_file)
+        except socket.error as err:
+            return False
+        else:
+            return True 
 
 
     def shutdown(self):
     def shutdown(self):
         ThreadingUnixStreamServer.shutdown(self)
         ThreadingUnixStreamServer.shutdown(self)