Browse Source

[1371] supported incremental (pure) IXFR response

JINMEI Tatuya 13 years ago
parent
commit
96bf3ab527
2 changed files with 41 additions and 6 deletions
  1. 34 5
      src/bin/xfrout/tests/xfrout_test.py.in
  2. 7 1
      src/bin/xfrout/xfrout.py.in

+ 34 - 5
src/bin/xfrout/tests/xfrout_test.py.in

@@ -38,7 +38,7 @@ TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
 TEST_RRCLASS = RRClass.IN()
 IXFR_OK_VERSION = 2011111802
 IXFR_NG_VERSION = 2011112800
-SOA_CURRENT_VERSION = 2011111802
+SOA_CURRENT_VERSION = 2011112001
 
 # Shortcut functions to create RRsets commonly used in tests below.
 def create_a(address, ttl=3600):
@@ -851,11 +851,20 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(0, len(self.sock.sendqueue))
 
     def test_reply_xfrout_query_ixfr(self):
-        self.xfrsess._soa = self.soa_rrset
-        self.xfrsess._iterator = [self.soa_rrset]
+        # Creating an pure (incremental) IXFR response.  Intermediate SOA
+        # RRs won't be skipped.
+        self.xfrsess._soa = create_soa(SOA_CURRENT_VERSION)
+        self.xfrsess._iterator = [create_soa(IXFR_OK_VERSION),
+                                  create_a('192.0.2.2'),
+                                  create_soa(SOA_CURRENT_VERSION),
+                                  create_aaaa('2001:db8::1')]
+        self.xfrsess._jnl_reader = self.xfrsess._iterator
         self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock)
-        reply_msg = self.sock.read_msg()
-        self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 2)
+        reply_msg = self.sock.read_msg(Message.PRESERVE_ORDER)
+        # The answer section should contain everything in the "fake"
+        # iterator and two SOAs.
+        self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER),
+                         len(self.xfrsess._iterator) + 2)
 
 class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
     '''Tests for XFR-out sessions using an SQLite3 DB.
@@ -913,6 +922,26 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
         self.assertEqual(RRType.IXFR(), response.get_question()[0].get_type())
         self.check_axfr_stream(response)
 
+    def test_ixfr_normal_session(self):
+        # See testdata/creatediff.py.  There are 8 changes between two
+        # versions.  So the answer section should contain all of these and
+        # two beginning and trailing SOAs.
+        self.xfrsess._request_data = \
+            self.create_request_data(ixfr=IXFR_OK_VERSION)
+        XfroutSession._handle(self.xfrsess)
+        response = self.sock.read_msg(Message.PRESERVE_ORDER);
+        actual_records = response.get_section(Message.SECTION_ANSWER)
+        self.assertEqual(10, len(actual_records))
+        # The first and last RRs must be SOA whose serial is the latest one.
+        soa = actual_records[0]
+        self.assertEqual(RRType.SOA(), soa.get_type())
+        self.assertEqual(SOA_CURRENT_VERSION,
+                         xfrout.get_soa_serial(soa.get_rdata()[0]))
+        soa = actual_records[-1]
+        self.assertEqual(RRType.SOA(), soa.get_type())
+        self.assertEqual(SOA_CURRENT_VERSION,
+                         xfrout.get_soa_serial(soa.get_rdata()[0]))
+
 class MyUnixSockServer(UnixSockServer):
     def __init__(self):
         self._shutdown_event = threading.Event()

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

@@ -154,6 +154,7 @@ class XfroutSession():
         self._zone_config = zone_config
         self.ClientClass = client_class # parameterize this for testing
         self._soa = None # will be set in _xfrout_setup or in tests
+        self._jnl_reader = None # will be set to a reader for IXFR
         self._handle()
 
     def create_tsig_ctx(self, tsig_record, tsig_key_ring):
@@ -424,6 +425,9 @@ class XfroutSession():
                         format_zone_str(zone_name, zone_class))
             return Rcode.NOTAUTH()
 
+        # Use the reader as the iterator to generate the response.
+        self._iterator = self._jnl_reader
+
         return Rcode.NOERROR()
 
     def _xfrout_setup(self, request_msg, zone_name, zone_class):
@@ -537,7 +541,9 @@ class XfroutSession():
                 logger.info(XFROUT_STOPPING)
                 return
 
-            if rrset.get_type() == RRType.SOA():
+            # For AXFR (or AXFR-style IXFR), in which case _jnl_reader is None,
+            # we should skip SOAs from the iterator.
+            if self._jnl_reader is None and rrset.get_type() == RRType.SOA():
                 continue
 
             # We calculate the maximum size of the RRset (i.e. the