Commit 8f74718c authored by John DuBois's avatar John DuBois
parents 631c5c2d 956a0a58
325. [func] jinmei
Python isc.datasrc: added interfaces for difference management:
DataSourceClient.get_updater() now has the 'journaling' parameter
to enable storing diffs to the data source, and a new class
ZoneJournalReader was introduced to retrieve them, which can be
created by the new DataSourceClient.get_journal_reader() method.
(Trac #1333, git 3e19362bc1ba7dc67a87768e2b172c48b32417f5,
git 39def1d39c9543fc485eceaa5d390062edb97676)
324. [bug] jinmei
Fixed reference leak in the isc.log Python module. Most of all
BIND 10 Python programs had memory leak (even though the pace of
leak may be slow) due to this bug.
(Trac #1359, git 164d651a0e4c1059c71f56b52ea87ac72b7f6c77)
323. [bug] jinmei
b10-xfrout incorrectly skipped adding TSIG RRs to some
intermediate responses (when TSIG is to be used for the
responses). While RFC2845 optionally allows to skip intermediate
TSIGs (as long as the digest for the skipped part was included
in a later TSIG), the underlying TSIG API doesn't support this
mode of signing.
(Trac #1370, git 76fb414ea5257b639ba58ee336fae9a68998b30d)
322. [func] jinmei
datasrc: Added C++ API for retrieving difference of two versions
of a zone. A new ZoneJournalReader class was introduced for this
purpose, and a corresponding factory method was added to
DataSourceClient.
(Trac #1332, git c1138d13b2692fa3a4f2ae1454052c866d24e654)
321. [func]* jinmei
b10-xfrin now installs IXFR differences into the underlying data
source (if it supports journaling) so that the stored differences
can be used for subsequent IXFR-out transactions.
Note: this is a backward incompatibility change for older sqlite3
database files. They need to be upgraded to have a "diffs" table.
(Trac #1376, git 1219d81b49e51adece77dc57b5902fa1c6be1407)
320. [func]* vorner
The --brittle switch was removed from the bind10 executable.
It didn't work after change #316 (Trac #213) and the same
effect can be accomplished by declaring all components as core.
(Trac #1340, git f9224368908dd7ba16875b0d36329cf1161193f0)
319. [func] naokikambe
b10-stats-httpd was updated. In addition of the access to all
statistics items of all modules, the specified item or the items of the
......@@ -9,12 +54,12 @@
only for the XML documents but also is for the XSD and XSL documents.
(Trac #917, git b34bf286c064d44746ec0b79e38a6177d01e6956)
318. [func] stephen
318. [func] stephen
Add C++ API for accessing zone difference information in database-based
data sources.
(Trac #1330, git 78770f52c7f1e7268d99e8bfa8c61e889813bb33)
317. [func] vorner
317. [func] vorner
datasrc: the getUpdater method of DataSourceClient supports an optional
'journaling' parameter to indicate the generated updater to store diffs.
The database based derived class implements this extension.
......
......@@ -51,7 +51,6 @@
<arg><option>-u <replaceable>user</replaceable></option></arg>
<arg><option>-v</option></arg>
<arg><option>-w <replaceable>wait_time</replaceable></option></arg>
<arg><option>--brittle</option></arg>
<arg><option>--cmdctl-port</option> <replaceable>port</replaceable></arg>
<arg><option>--config-file</option> <replaceable>config-filename</replaceable></arg>
<arg><option>--data-path</option> <replaceable>directory</replaceable></arg>
......@@ -90,20 +89,6 @@
<variablelist>
<varlistentry>
<term>
<option>--brittle</option>
</term>
<listitem>
<para>
Shutdown if any of the child processes of
<command>bind10</command> exit. This is intended to
help developers debug the server, and should not be
used in production.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-c</option> <replaceable>config-filename</replaceable>,
......
......@@ -219,7 +219,7 @@ class BoB:
def __init__(self, msgq_socket_file=None, data_path=None,
config_filename=None, nocache=False, verbose=False, setuid=None,
username=None, cmdctl_port=None, brittle=False, wait_time=10):
username=None, cmdctl_port=None, wait_time=10):
"""
Initialize the Boss of BIND. This is a singleton (only one can run).
......@@ -233,19 +233,12 @@ class BoB:
The cmdctl_port is passed to cmdctl and specify on which port it
should listen.
brittle is a debug option that controls whether the Boss shuts down
after any process dies.
wait_time controls the amount of time (in seconds) that Boss waits
for selected processes to initialize before continuing with the
initialization. Currently this is only the configuration manager.
"""
self.cc_session = None
self.ccs = None
self.cfg_start_auth = True
self.cfg_start_resolver = False
self.cfg_start_dhcp6 = False
self.cfg_start_dhcp4 = False
self.curproc = None
# XXX: Not used now, waits for reintroduction of restarts.
self.dead_processes = {}
......@@ -264,7 +257,6 @@ class BoB:
self.data_path = data_path
self.config_filename = config_filename
self.cmdctl_port = cmdctl_port
self.brittle = brittle
self.wait_time = wait_time
self._component_configurator = isc.bind10.component.Configurator(self,
isc.bind10.special_component.get_specials())
......@@ -940,8 +932,6 @@ def parse_args(args=sys.argv[1:], Parser=OptionParser):
parser.add_option("--pid-file", dest="pid_file", type="string",
default=None,
help="file to dump the PID of the BIND 10 process")
parser.add_option("--brittle", dest="brittle", action="store_true",
help="debugging flag: exit if any component dies")
parser.add_option("-w", "--wait", dest="wait_time", type="int",
default=10, help="Time (in seconds) to wait for config manager to start up")
......@@ -1046,7 +1036,7 @@ def main():
# Go bob!
boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
options.config_file, options.nocache, options.verbose,
setuid, username, options.cmdctl_port, options.brittle,
setuid, username, options.cmdctl_port,
options.wait_time)
startup_result = boss_of_bind.startup()
if startup_result:
......
......@@ -110,11 +110,6 @@ class TestBoB(unittest.TestCase):
self.assertEqual(bob.uid, None)
self.assertEqual(bob.username, None)
self.assertEqual(bob.nocache, False)
self.assertEqual(bob.cfg_start_auth, True)
self.assertEqual(bob.cfg_start_resolver, False)
self.assertEqual(bob.cfg_start_dhcp4, False)
self.assertEqual(bob.cfg_start_dhcp6, False)
def test_init_alternate_socket(self):
bob = BoB("alt_socket_file")
......@@ -128,10 +123,6 @@ class TestBoB(unittest.TestCase):
self.assertEqual(bob.uid, None)
self.assertEqual(bob.username, None)
self.assertEqual(bob.nocache, False)
self.assertEqual(bob.cfg_start_auth, True)
self.assertEqual(bob.cfg_start_resolver, False)
self.assertEqual(bob.cfg_start_dhcp4, False)
self.assertEqual(bob.cfg_start_dhcp6, False)
def test_command_handler(self):
class DummySession():
......@@ -740,15 +731,6 @@ class TestParseArgs(unittest.TestCase):
options = parse_args(['--cmdctl-port=1234'], TestOptParser)
self.assertEqual(1234, options.cmdctl_port)
def test_brittle(self):
"""
Test we can use the "brittle" flag.
"""
options = parse_args([], TestOptParser)
self.assertFalse(options.brittle)
options = parse_args(['--brittle'], TestOptParser)
self.assertTrue(options.brittle)
class TestPIDFile(unittest.TestCase):
def setUp(self):
self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
......@@ -796,37 +778,6 @@ class TestPIDFile(unittest.TestCase):
self.assertRaises(IOError, dump_pid,
'nonexistent_dir' + os.sep + 'bind10.pid')
# TODO: Do we want brittle mode? Probably yes. So we need to re-enable to after that.
@unittest.skip("Brittle mode temporarily broken")
class TestBrittle(unittest.TestCase):
def test_brittle_disabled(self):
bob = MockBob()
bob.start_all_components()
bob.runnable = True
bob.reap_children()
self.assertTrue(bob.runnable)
def simulated_exit(self):
ret_val = self.exit_info
self.exit_info = (0, 0)
return ret_val
def test_brittle_enabled(self):
bob = MockBob()
bob.start_all_components()
bob.runnable = True
bob.brittle = True
self.exit_info = (5, 0)
bob._get_process_exit_status = self.simulated_exit
old_stdout = sys.stdout
sys.stdout = open("/dev/null", "w")
bob.reap_children()
sys.stdout = old_stdout
self.assertFalse(bob.runnable)
class TestBossComponents(unittest.TestCase):
"""
Test the boss propagates component configuration properly to the
......
......@@ -14,8 +14,10 @@
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import unittest
import re
import shutil
import socket
import sqlite3
import sys
import io
from isc.testutils.tsigctx_mock import MockTSIGContext
......@@ -170,7 +172,8 @@ class MockDataSourceClient():
return (ZoneFinder.SUCCESS, dup_soa_rrset)
raise ValueError('Unexpected input to mock finder: bug in test case?')
def get_updater(self, zone_name, replace):
def get_updater(self, zone_name, replace, journaling=False):
self._journaling_enabled = journaling
return self
def add_rrset(self, rrset):
......@@ -1132,6 +1135,7 @@ class TestAXFR(TestXfrinConnection):
def test_do_xfrin(self):
self.conn.response_generator = self._create_normal_response_data
self.assertEqual(self.conn.do_xfrin(False), XFRIN_OK)
self.assertFalse(self.conn._datasrc_client._journaling_enabled)
def test_do_xfrin_with_tsig(self):
# use TSIG with a mock context. we fake all verify results to
......@@ -1283,6 +1287,7 @@ class TestIXFRResponse(TestXfrinConnection):
answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
self.assertTrue(self.conn._datasrc_client._journaling_enabled)
self.assertEqual([], self.conn._datasrc_client.diffs)
check_diffs(self.assertEqual,
[[('delete', begin_soa_rrset), ('add', soa_rrset)]],
......@@ -1387,6 +1392,8 @@ class TestIXFRResponse(TestXfrinConnection):
answers=[soa_rrset, ns_rr, a_rr, soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
# In the case AXFR-style IXFR, journaling must have been disabled.
self.assertFalse(self.conn._datasrc_client._journaling_enabled)
self.assertEqual([], self.conn._datasrc_client.diffs)
# The SOA should be added exactly once, and in our implementation
# it should be added at the end of the sequence.
......@@ -1540,6 +1547,19 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
self.assertEqual(1234, self.get_zone_serial())
# Also confirm the corresponding diffs are stored in the diffs table
conn = sqlite3.connect(self.sqlite3db_obj)
cur = conn.cursor()
cur.execute('SELECT name, rrtype, ttl, rdata FROM diffs ORDER BY id')
soa_rdata_base = 'master.example.com. admin.example.com. ' + \
'SERIAL 3600 1800 2419200 7200'
self.assertEqual(cur.fetchall(),
[(TEST_ZONE_NAME_STR, 'SOA', 3600,
re.sub('SERIAL', str(1230), soa_rdata_base)),
(TEST_ZONE_NAME_STR, 'SOA', 3600,
re.sub('SERIAL', str(1234), soa_rdata_base))])
conn.close()
def test_do_ixfrin_sqlite3_fail(self):
'''Similar to the previous test, but xfrin fails due to error.
......
......@@ -367,7 +367,10 @@ class XfrinIXFRDeleteSOA(XfrinState):
' RR is given in IXFRDeleteSOA state')
# This is the beginning state of one difference sequence (changes
# for one SOA update). We need to create a new Diff object now.
conn._diff = Diff(conn._datasrc_client, conn._zone_name)
# Note also that we (unconditionally) enable journaling here. The
# Diff constructor may internally disable it, however, if the
# underlying data source doesn't support journaling.
conn._diff = Diff(conn._datasrc_client, conn._zone_name, False, True)
conn._diff.delete_data(rr)
self.set_xfrstate(conn, XfrinIXFRDelete())
return True
......
......@@ -470,34 +470,28 @@ class TestXfroutSession(TestXfroutSessionBase):
msg = self.getmsg()
msg.make_response()
# packet number less than TSIG_SIGN_EVERY_NTH
packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
self.xfrsess._send_message_with_last_soa(msg, self.sock,
self.soa_rrset, 0,
packet_neet_not_sign)
self.soa_rrset, 0)
get_msg = self.sock.read_msg()
# tsig context is not exist
# tsig context does not exist
self.assertFalse(self.message_has_tsig(get_msg))
self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
#answer_rrset_iter = section_iter(get_msg, section.ANSWER())
answer = get_msg.get_section(Message.SECTION_ANSWER)[0]#answer_rrset_iter.get_rrset()
answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
self.assertEqual(answer.get_name().to_text(), "example.com.")
self.assertEqual(answer.get_class(), RRClass("IN"))
self.assertEqual(answer.get_type().to_text(), "SOA")
rdata = answer.get_rdata()
self.assertEqual(rdata[0], self.soa_rrset.get_rdata()[0])
# msg is the TSIG_SIGN_EVERY_NTH one
# sending the message with last soa together
# Sending the message with last soa together
self.xfrsess._send_message_with_last_soa(msg, self.sock,
self.soa_rrset, 0,
TSIG_SIGN_EVERY_NTH)
self.soa_rrset, 0)
get_msg = self.sock.read_msg()
# tsig context is not exist
# tsig context does not exist
self.assertFalse(self.message_has_tsig(get_msg))
def test_send_message_with_last_soa_with_tsig(self):
......@@ -507,13 +501,9 @@ class TestXfroutSession(TestXfroutSessionBase):
msg = self.getmsg()
msg.make_response()
# packet number less than TSIG_SIGN_EVERY_NTH
packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
# msg is not the TSIG_SIGN_EVERY_NTH one
# sending the message with last soa together
# Sending the message with last soa together
self.xfrsess._send_message_with_last_soa(msg, self.sock,
self.soa_rrset, 0,
packet_neet_not_sign)
self.soa_rrset, 0)
get_msg = self.sock.read_msg()
self.assertTrue(self.message_has_tsig(get_msg))
......@@ -521,14 +511,6 @@ class TestXfroutSession(TestXfroutSessionBase):
self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
# msg is the TSIG_SIGN_EVERY_NTH one
# sending the message with last soa together
self.xfrsess._send_message_with_last_soa(msg, self.sock,
self.soa_rrset, 0,
TSIG_SIGN_EVERY_NTH)
get_msg = self.sock.read_msg()
self.assertTrue(self.message_has_tsig(get_msg))
def test_trigger_send_message_with_last_soa(self):
rrset_a = RRset(Name("example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
rrset_a.add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
......@@ -540,8 +522,6 @@ class TestXfroutSession(TestXfroutSessionBase):
# length larger than MAX-len(rrset)
length_need_split = xfrout.XFROUT_MAX_MESSAGE_SIZE - \
get_rrset_len(self.soa_rrset) + 1
# packet number less than TSIG_SIGN_EVERY_NTH
packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
# give the function a value that is larger than MAX-len(rrset)
# this should have triggered the sending of two messages
......@@ -549,8 +529,7 @@ class TestXfroutSession(TestXfroutSessionBase):
# the sending in _with_last_soa)
self.xfrsess._send_message_with_last_soa(msg, self.sock,
self.soa_rrset,
length_need_split,
packet_neet_not_sign)
length_need_split)
get_msg = self.sock.read_msg()
self.assertFalse(self.message_has_tsig(get_msg))
self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
......@@ -570,7 +549,6 @@ class TestXfroutSession(TestXfroutSessionBase):
self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
#answer_rrset_iter = section_iter(get_msg, Message.SECTION_ANSWER)
answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
self.assertEqual(answer.get_name().to_text(), "example.com.")
self.assertEqual(answer.get_class(), RRClass("IN"))
......@@ -590,8 +568,6 @@ class TestXfroutSession(TestXfroutSessionBase):
# length larger than MAX-len(rrset)
length_need_split = xfrout.XFROUT_MAX_MESSAGE_SIZE - \
get_rrset_len(self.soa_rrset) + 1
# packet number less than TSIG_SIGN_EVERY_NTH
packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
# give the function a value that is larger than MAX-len(rrset)
# this should have triggered the sending of two messages
......@@ -599,26 +575,10 @@ class TestXfroutSession(TestXfroutSessionBase):
# the sending in _with_last_soa)
self.xfrsess._send_message_with_last_soa(msg, self.sock,
self.soa_rrset,
length_need_split,
packet_neet_not_sign)
get_msg = self.sock.read_msg()
# msg is not the TSIG_SIGN_EVERY_NTH one, it shouldn't be tsig signed
self.assertFalse(self.message_has_tsig(get_msg))
# the last packet should be tsig signed
length_need_split)
# Both messages should have TSIG RRs
get_msg = self.sock.read_msg()
self.assertTrue(self.message_has_tsig(get_msg))
# and it should not have sent anything else
self.assertEqual(0, len(self.sock.sendqueue))
# msg is the TSIG_SIGN_EVERY_NTH one, it should be tsig signed
self.xfrsess._send_message_with_last_soa(msg, self.sock,
self.soa_rrset,
length_need_split,
xfrout.TSIG_SIGN_EVERY_NTH)
get_msg = self.sock.read_msg()
self.assertTrue(self.message_has_tsig(get_msg))
# the last packet should be tsig signed
get_msg = self.sock.read_msg()
self.assertTrue(self.message_has_tsig(get_msg))
# and it should not have sent anything else
......@@ -697,29 +657,18 @@ class TestXfroutSession(TestXfroutSessionBase):
self.xfrsess._tsig_ctx = self.create_mock_tsig_ctx(TSIGError.NOERROR)
self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock)
# tsig signed first package
reply_msg = self.sock.read_msg()
self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 1)
self.assertTrue(self.message_has_tsig(reply_msg))
# (TSIG_SIGN_EVERY_NTH - 1) packets have no tsig
for i in range(0, xfrout.TSIG_SIGN_EVERY_NTH - 1):
reply_msg = self.sock.read_msg()
self.assertFalse(self.message_has_tsig(reply_msg))
# TSIG_SIGN_EVERY_NTH packet has tsig
reply_msg = self.sock.read_msg()
self.assertTrue(self.message_has_tsig(reply_msg))
for i in range(0, 100 - TSIG_SIGN_EVERY_NTH):
# All messages must have TSIG as we don't support the feature of
# skipping intermediate TSIG records (with bulk signing).
for i in range(0, 102): # 102 = all 100 RRs from iterator and 2 SOAs
reply_msg = self.sock.read_msg()
self.assertFalse(self.message_has_tsig(reply_msg))
# tsig signed last package
reply_msg = self.sock.read_msg()
self.assertTrue(self.message_has_tsig(reply_msg))
# With the hack of get_rrset_len() above, every message must have
# exactly one RR in the answer section.
self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 1)
self.assertTrue(self.message_has_tsig(reply_msg))
# and it should not have sent anything else
self.assertEqual(0, len(self.sock.sendqueue))
class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
'''Tests for XFR-out sessions using an SQLite3 DB.
......
......@@ -92,9 +92,6 @@ init_paths()
SPECFILE_LOCATION = SPECFILE_PATH + "/xfrout.spec"
AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + os.sep + "auth.spec"
VERBOSE_MODE = False
# tsig sign every N axfr packets.
TSIG_SIGN_EVERY_NTH = 96
XFROUT_MAX_MESSAGE_SIZE = 65535
# borrowed from xfrin.py @ #1298. We should eventually unify it.
......@@ -316,11 +313,11 @@ class XfroutSession():
self._server.get_db_file() + '"}'
self._datasrc_client = self.ClientClass('sqlite3', datasrc_config)
try:
# Note that we disable 'adjust_ttl'. In xfr-out we need to
# Note that we enable 'separate_rrs'. In xfr-out we need to
# preserve as many things as possible (even if it's half broken)
# stored in the zone.
self._iterator = self._datasrc_client.get_iterator(zone_name,
False)
True)
except isc.datasrc.Error:
# If the current name server does not have authority for the
# zone, xfrout can't serve for it, return rcode NOTAUTH.
......@@ -398,22 +395,15 @@ class XfroutSession():
msg.set_header_flag(Message.HEADERFLAG_QR)
return msg
def _send_message_with_last_soa(self, msg, sock_fd, rrset_soa, message_upper_len,
count_since_last_tsig_sign):
def _send_message_with_last_soa(self, msg, sock_fd, rrset_soa,
message_upper_len):
'''Add the SOA record to the end of message. If it can't be
added, a new message should be created to send out the last soa .
'''
rrset_len = get_rrset_len(rrset_soa)
if (count_since_last_tsig_sign == TSIG_SIGN_EVERY_NTH and
message_upper_len + rrset_len >= XFROUT_MAX_MESSAGE_SIZE):
# If tsig context exist, sign the packet with serial number TSIG_SIGN_EVERY_NTH
if (message_upper_len + self._tsig_len + get_rrset_len(rrset_soa) >=
XFROUT_MAX_MESSAGE_SIZE):
self._send_message(sock_fd, msg, self._tsig_ctx)
msg = self._clear_message(msg)
elif (count_since_last_tsig_sign != TSIG_SIGN_EVERY_NTH and
message_upper_len + rrset_len + self._tsig_len >= XFROUT_MAX_MESSAGE_SIZE):
self._send_message(sock_fd, msg)
msg = self._clear_message(msg)
# If tsig context exist, sign the last packet
msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
......@@ -422,7 +412,6 @@ class XfroutSession():
def _reply_xfrout_query(self, msg, sock_fd):
#TODO, there should be a better way to insert rrset.
count_since_last_tsig_sign = TSIG_SIGN_EVERY_NTH
msg.make_response()
msg.set_header_flag(Message.HEADERFLAG_AA)
msg.add_rrset(Message.SECTION_ANSWER, self._soa)
......@@ -447,27 +436,17 @@ class XfroutSession():
message_upper_len += rrset_len
continue
# If tsig context exist, sign every N packets
if count_since_last_tsig_sign == TSIG_SIGN_EVERY_NTH:
count_since_last_tsig_sign = 0
self._send_message(sock_fd, msg, self._tsig_ctx)
else:
self._send_message(sock_fd, msg)
self._send_message(sock_fd, msg, self._tsig_ctx)
count_since_last_tsig_sign += 1
msg = self._clear_message(msg)
# Add the RRset to the new message
msg.add_rrset(Message.SECTION_ANSWER, rrset)
# Reserve tsig space for signed packet
if count_since_last_tsig_sign == TSIG_SIGN_EVERY_NTH:
message_upper_len = rrset_len + self._tsig_len
else:
message_upper_len = rrset_len
message_upper_len = rrset_len + self._tsig_len
self._send_message_with_last_soa(msg, sock_fd, self._soa,
message_upper_len,
count_since_last_tsig_sign)
message_upper_len)
class UnixSockServer(socketserver_mixin.NoPollMixIn,
ThreadingUnixStreamServer):
......
......@@ -15,6 +15,8 @@
#ifndef __DATA_SOURCE_CLIENT_H
#define __DATA_SOURCE_CLIENT_H 1
#include <utility>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
......@@ -215,18 +217,19 @@ public:
///
/// \param name The name of zone apex to be traversed. It doesn't do
/// nearest match as findZone.
/// \param adjust_ttl If true, the iterator will treat RRs with the same
/// name and type but different TTL values to be of the
/// same RRset, and will adjust the TTL to the lowest
/// value found. If false, it will consider the RR to
/// belong to a different RRset.
/// \param separate_rrs If true, the iterator will return each RR as a
/// new RRset object. If false, the iterator will
/// combine consecutive RRs with the name and type
/// into 1 RRset. The capitalization of the RRset will
/// be that of the first RR read, and TTLs will be
/// adjusted to the lowest one found.
/// \return Pointer to the iterator.
virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name,
bool adjust_ttl = true) const {
bool separate_rrs = false) const {
// This is here to both document the parameter in doxygen (therefore it
// needs a name) and avoid unused parameter warning.
static_cast<void>(name);
static_cast<void>(adjust_ttl);
static_cast<void>(separate_rrs);
isc_throw(isc::NotImplemented,
"Data source doesn't support iteration");
......@@ -310,6 +313,55 @@ public:
virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name& name,
bool replace, bool journaling = false)
const = 0;
/// Return a journal reader to retrieve differences of a zone.
///
/// A derived version of this method creates a concrete
/// \c ZoneJournalReader object specific to the underlying data source
/// for the specified name of zone and differences between the versions
/// specified by the beginning and ending serials of the corresponding
/// SOA RRs.
/// The RR class of the zone is the one that the client is expected to
/// handle (see the detailed description of this class).
///
/// Note that the SOA serials are compared by the semantics of the serial
/// number arithmetic. So, for example, \c begin_serial can be larger than
/// \c end_serial as bare unsigned integers. The underlying data source
/// implementation is assumed to keep track of sufficient history to
/// identify (if exist) the corresponding difference between the specified
/// versions.
///
/// This method returns the result as a pair of a result code and
/// a pointer to a \c ZoneJournalReader object. On success, the result
/// code is \c SUCCESS and the pointer must be non NULL; otherwise
/// the result code is something other than \c SUCCESS and the pinter
/// must be NULL.
///
/// If the specified zone is not found in the data source, the result
/// code is \c NO_SUCH_ZONE.
/// Otherwise, if specified range of difference for the zone is not found
/// in the data source, the result code is \c NO_SUCH_VERSION.
///
/// Handling differences is an optional feature of data source.
/// If the underlying data source does not support difference handling,
/// this method for that type of data source can throw an exception of
/// class \c NotImplemented.
///
/// \exception NotImplemented The data source does not support differences.
/// \exception DataSourceError Other operational errors at the data source
/// level.
///
/// \param zone The name of the zone for which the difference should be
/// retrieved.
/// \param begin_serial The SOA serial of the beginning version of the
/// differences.
/// \param end_serial The SOA serial of the ending version of the
/// differences.
///
/// \return A pair of result code and a pointer to \c ZoneJournalReader.
virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
getJournalReader(const isc::dns::Name& zone, uint32_t begin_serial,
uint32_t end_serial) const = 0;
};
}
}
......
......@@ -13,6 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <string>
#include <utility>
#include <vector>
#include <datasrc/database.h>
......@@ -707,11 +708,11 @@ public: