BIND 10 trac1454, updated. 9af13dfc788b7ddf5667545aa483ced00c349a20 [1454] Accept implemented

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Jan 3 15:50:00 UTC 2012


The branch, trac1454 has been updated
       via  9af13dfc788b7ddf5667545aa483ced00c349a20 (commit)
       via  e7b1c03c8c93645f923e842f4af89bdaf0a59576 (commit)
       via  e1cf741287a9203fbe00b18858cc908f677c449c (commit)
       via  ba9038e23c411ba6249a5bc38e2da30f7d95fb49 (commit)
      from  0cfe92d0076a6b8108cb232a5fbfddddd9197c0b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 9af13dfc788b7ddf5667545aa483ced00c349a20
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Jan 3 16:49:27 2012 +0100

    [1454] Accept implemented

commit e7b1c03c8c93645f923e842f4af89bdaf0a59576
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Jan 3 15:56:05 2012 +0100

    [1454] Test for the accept method

commit e1cf741287a9203fbe00b18858cc908f677c449c
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Thu Dec 29 19:48:12 2011 +0100

    [1454] Check we check for new commands

commit ba9038e23c411ba6249a5bc38e2da30f7d95fb49
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Thu Dec 29 19:43:42 2011 +0100

    [1454] Loop to listen

-----------------------------------------------------------------------

Summary of changes:
 src/bin/ddns/ddns.py.in         |   27 +++++++++-
 src/bin/ddns/tests/ddns_test.py |  110 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 2 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/bin/ddns/ddns.py.in b/src/bin/ddns/ddns.py.in
index e5ce31d..b5a0383 100755
--- a/src/bin/ddns/ddns.py.in
+++ b/src/bin/ddns/ddns.py.in
@@ -23,6 +23,8 @@ from isc.dns import *
 from isc.config.ccsession import *
 from isc.cc import SessionError, SessionTimeout
 import isc.util.process
+import isc.util.io.socketsession
+import select
 
 from isc.log_messages.ddns_messages import *
 
@@ -85,6 +87,8 @@ class DDNSServer:
         self._config_data = self._cc.get_full_config()
         self._cc.start()
         self._shutdown = False
+        # List of the sessions where we get the packets
+        self._socket_sessions = {}
 
     def config_handler(self, new_config):
         '''Update config data.'''
@@ -125,19 +129,40 @@ class DDNSServer:
         '''
         pass
 
+    def accept(self):
+        """
+        Accept another connection and create the session receiver.
+        """
+        socket = self._listen_socket.accept()
+        fileno = socket.fileno()
+        session = isc.util.io.socketsession.SocketSessionReceiver(socket)
+        self._socket_sessions[fileno] = (socket, session)
+
     def run(self):
         '''
         Get and process all commands sent from cfgmgr or other modules.
         This loops waiting for events until self.shutdown() has been called.
         '''
         logger.info(DDNS_RUNNING)
+        cc_fileno = self._cc.get_socket().fileno()
+        listen_fileno = self._listen_socket.fileno()
         while not self._shutdown:
             # We do not catch any exceptions here right now, but this would
             # be a good place to catch any exceptions that b10-ddns can
             # recover from. We currently have no exception hierarchy to
             # make such a distinction easily, but once we do, this would
             # be the place to catch.
-            self._cc.check_command(False)
+
+            # TODO: Catch select exceptions, like EINTR
+            (reads, writes, exceptions) = \
+                select.select([cc_fileno, listen_fileno], [], [])
+            for fileno in reads:
+                if fileno == cc_fileno:
+                    self._cc.check_command(True)
+                elif fileno == listen_fileno:
+                    self.accept()
+                else:
+                    pass # TODO
         self.shutdown_cleanup()
         logger.info(DDNS_STOPPED)
 
diff --git a/src/bin/ddns/tests/ddns_test.py b/src/bin/ddns/tests/ddns_test.py
index 601c281..53ecfd2 100755
--- a/src/bin/ddns/tests/ddns_test.py
+++ b/src/bin/ddns/tests/ddns_test.py
@@ -19,6 +19,32 @@ import unittest
 import isc
 import ddns
 import isc.config
+import select
+import isc.util.io.socketsession
+
+class FakeSocket:
+    """
+    A fake socket. It only provides a file number.
+    """
+    def __init__(self, fileno):
+        self.__fileno = fileno
+    def fileno(self):
+        return self.__fileno
+    def accept(self):
+        return FakeSocket(self.__fileno + 1)
+
+class FakeSession:
+    """
+    A fake socket session receiver, for our tests.
+    """
+    def __init__(self, socket):
+        self._socket = socket
+    def socket(self):
+        """
+        This method is not present in the real receiver, but we use it to
+        inspect the socket passed to the constructor.
+        """
+        return self._socket
 
 class MyCCSession(isc.config.ConfigData):
     '''Fake session with minimal interface compliance'''
@@ -32,6 +58,12 @@ class MyCCSession(isc.config.ConfigData):
         '''Called by DDNSServer initialization, but not used in tests'''
         self._started = True
 
+    def get_socket(self):
+        """
+        Used to get the file number for select.
+        """
+        return FakeSocket(1)
+
 class MyDDNSServer():
     '''Fake DDNS server used to test the main() function'''
     def __init__(self):
@@ -63,7 +95,18 @@ class TestDDNSServer(unittest.TestCase):
         cc_session = MyCCSession()
         self.assertFalse(cc_session._started)
         self.ddns_server = ddns.DDNSServer(cc_session)
+        self.cc_session = cc_session
         self.assertTrue(cc_session._started)
+        self.__select_expected = None
+        self.__select_answer = None
+        self.__hook_called = False
+        self.ddns_server._listen_socket = FakeSocket(2)
+        ddns.select.select = self.__select
+
+    def tearDown(self):
+        ddns.select.select = select.select
+        ddns.isc.util.io.socketsession.SocketSessionReceiver = \
+            isc.util.io.socketsession.SocketSessionReceiver
 
     def test_config_handler(self):
         # Config handler does not do anything yet, but should at least
@@ -93,6 +136,72 @@ class TestDDNSServer(unittest.TestCase):
         signal_handler(None, None)
         self.assertTrue(self.ddns_server._shutdown)
 
+    def __select(self, reads, writes, exceptions, timeout=None):
+        """
+        A fake select. It checks it was called with the correct parameters and
+        returns a preset answer.
+        """
+        self.assertEqual(self.__select_expected, (reads, writes, exceptions,
+                                                  timeout))
+        answer = self.__select_answer
+        self.__select_answer = None
+        self.ddns_server._shutdown = True
+        return answer
+
+    def __hook(self, param=None):
+        """
+        A hook that can be installed to any nullary or unary function and see
+        if it was really called.
+        """
+        self.__hook_called = param
+
+    def test_accept_called(self):
+        """
+        Test we call the accept function when a new connection comes.
+        """
+        self.ddns_server.accept = self.__hook
+        self.__select_expected = ([1, 2], [], [], None)
+        self.__select_answer = ([2], [], [])
+        self.__hook_called = "Not called"
+        self.ddns_server.run()
+        self.assertTrue(self.ddns_server._shutdown)
+        # The answer got used
+        self.assertIsNone(self.__select_answer)
+        # Reset, when called without parameter
+        self.assertIsNone(self.__hook_called)
+
+    def test_check_command_called(self):
+        """
+        Test the check_command is called when there's something on the
+        socket.
+        """
+        self.cc_session.check_command = self.__hook
+        self.__select_expected = ([1, 2], [], [], None)
+        self.__select_answer = ([1], [], [])
+        self.ddns_server.run()
+        self.assertTrue(self.ddns_server._shutdown)
+        # The answer got used
+        self.assertIsNone(self.__select_answer)
+        # And the check_command was called with true parameter (eg.
+        # non-blocking)
+        self.assertTrue(self.__hook_called)
+
+    def test_accept(self):
+        """
+        Test that we can accept a new connection.
+        """
+        # There's nothing before the accept
+        ddns.isc.util.io.socketsession.SocketSessionReceiver = FakeSession
+        self.assertEqual({}, self.ddns_server._socket_sessions)
+        self.ddns_server.accept()
+        # Now the new session socket receiver is stored in the dict
+        self.assertEqual([3], list(self.ddns_server._socket_sessions.keys()))
+        (socket, session) = self.ddns_server._socket_sessions[3]
+        self.assertTrue(isinstance(socket, FakeSocket))
+        self.assertEqual(3, socket.fileno())
+        self.assertTrue(isinstance(session, FakeSession))
+        self.assertEqual(socket, session.socket())
+
 class TestMain(unittest.TestCase):
     def setUp(self):
         self._server = MyDDNSServer()
@@ -135,7 +244,6 @@ class TestMain(unittest.TestCase):
         self._server.set_exception(BaseException("error"))
         self.assertRaises(BaseException, ddns.main, self._server)
         self.assertTrue(self._server.exception_raised)
-        
 
 if __name__== "__main__":
     isc.log.resetUnitTestRootLogger()




More information about the bind10-changes mailing list