[svn] commit: r1729 - in /trunk/src/bin/xfrin: tests/xfrin_test.py xfrin.py.in
BIND 10 source code commits
bind10-changes at lists.isc.org
Sat Apr 17 11:13:43 UTC 2010
Author: zhanglikun
Date: Sat Apr 17 11:13:43 2010
New Revision: 1729
Log:
1. Add unittest and docstring to some functions in xfrin.
2. Minor fix to the xfrin.
Modified:
trunk/src/bin/xfrin/tests/xfrin_test.py
trunk/src/bin/xfrin/xfrin.py.in
Modified: trunk/src/bin/xfrin/tests/xfrin_test.py
==============================================================================
--- trunk/src/bin/xfrin/tests/xfrin_test.py (original)
+++ trunk/src/bin/xfrin/tests/xfrin_test.py Sat Apr 17 11:13:43 2010
@@ -18,11 +18,62 @@
import socket
from xfrin import *
+# An axfr response of the simple zone "example.com(without soa record at the end)."
+axfr_response1 = b'\x84\x00\x00\x01\x00\x06\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01\xc0\x0c\x00\x06\x00\x01\x00\x00\x0e\x10\x00$\x05dns01\xc0\x0c\x05admin\xc0\x0c\x00\x00\x04\xd2\x00\x00\x0e\x10\x00\x00\x07\x08\x00$\xea\x00\x00\x00\x1c \xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x02\xc0)\xc0)\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\xc0\xa8\x02\x02\x04sql1\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x02\xc0)\x04sql2\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x02\xc0)\x03ns1\x07subzone\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\xc0\xa8\x03\x01'
+
+# The second axfr response with only the end soa record.
+axfr_response2 = b'\x84\x00\x00\x00\x00\x01\x00\x00\x00\x00\x07example\x03com\x00\x00\x06\x00\x01\x00\x00\x0e\x10\x00$\x05dns01\xc0\x0c\x05admin\xc0\x0c\x00\x00\x04\xd2\x00\x00\x0e\x10\x00\x00\x07\x08\x00$\xea\x00\x00\x00\x1c '
+
+DB_FILE = 'db_file'
# Rewrite the class for unittest.
class MyXfrin(Xfrin):
def __init__(self):
pass
+class MyXfrinConnection(XfrinConnection):
+ query_data = b''
+ eply_data = b''
+
+ def _handle_xfrin_response(self):
+ for rr in super()._handle_xfrin_response():
+ pass
+
+ def _get_request_response(self, size):
+ ret = self.reply_data[:size]
+ self.reply_data = self.reply_data[size:]
+ if (len(ret) < size):
+ raise XfrinException('cannot get reply data')
+ return ret
+
+ def send(self, data):
+ self.query_data += data
+ return len(data)
+
+ def create_response_data(self, data):
+ reply_data = self.query_data[2:4] + data
+ size = socket.htons(len(reply_data))
+ reply_data = struct.pack('H', size) + reply_data
+ return reply_data
+
+
+class TestXfrinConnection(unittest.TestCase):
+ def setUp(self):
+ self.conn = MyXfrinConnection('example.com.', DB_FILE, threading.Event(), '1.1.1.1')
+
+ def test_response_with_invalid_msg(self):
+ self.conn.data_exchange = b'aaaxxxx'
+ self.assertRaises(Exception, self.conn._handle_xfrin_response)
+
+ def test_response_without_end_soa(self):
+ self.conn._send_query(rr_type.AXFR())
+ self.conn.reply_data = self.conn.create_response_data(axfr_response1)
+ self.assertRaises(XfrinException, self.conn._handle_xfrin_response)
+
+ def test_response(self):
+ self.conn._send_query(rr_type.AXFR())
+ self.conn.reply_data = self.conn.create_response_data(axfr_response1)
+ self.conn.reply_data += self.conn.create_response_data(axfr_response2)
+ self.conn._handle_xfrin_response()
class TestXfrin(unittest.TestCase):
def test_parse_cmd_params(self):
@@ -51,6 +102,10 @@
self.assertRaises(XfrinException, xfr._parse_cmd_params, {'zone_name':'ds.cn.'})
self.assertRaises(XfrinException, xfr._parse_cmd_params, {'master':'ds.cn.'})
+if __name__== "__main__":
+ try:
+ unittest.main()
+ os.remove(DB_FILE)
+ except KeyboardInterrupt as e:
+ print(e)
-if __name__== "__main__":
- unittest.main()
Modified: trunk/src/bin/xfrin/xfrin.py.in
==============================================================================
--- trunk/src/bin/xfrin/xfrin.py.in (original)
+++ trunk/src/bin/xfrin/xfrin.py.in Sat Apr 17 11:13:43 2010
@@ -50,15 +50,6 @@
__version__ = 'BIND10'
# define xfrin rcode
XFRIN_OK = 0
-XFRIN_RECV_TIMEOUT = 1
-XFRIN_NO_NEWDATA = 2
-XFRIN_QUOTA_ERROR = 3
-XFRIN_IS_DOING = 4
-
-# define xfrin state
-XFRIN_QUERY_SOA = 1
-XFRIN_FIRST_AXFR = 2
-XFRIN_FIRST_IXFR = 3
def log_error(msg):
sys.stderr.write("[b10-xfrin] ")
@@ -68,21 +59,17 @@
class XfrinException(Exception):
pass
-
class XfrinConnection(asyncore.dispatcher):
'''Do xfrin in this class. '''
- def __init__(self, zone_name, db_file,
- shutdown_event,
- master_addr,
- port = 53,
- check_soa = True,
- verbose = False,
- idle_timeout = 60):
+ def __init__(self,
+ zone_name, db_file, shutdown_event, master_addr,
+ port = 53, verbose = False, idle_timeout = 60):
''' idle_timeout: max idle time for read data from socket.
db_file: specify the data source file.
check_soa: when it's true, check soa first before sending xfr query
'''
+
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self._zone_name = zone_name
@@ -92,18 +79,22 @@
self.setblocking(1)
self._shutdown_event = shutdown_event
self._verbose = verbose
-
- def connect_to_master(self, master_addr, port):
+ self._master_addr = master_addr
+ self._port = port
+
+ def connect_to_master(self):
'''Connect to master in TCP.'''
+
try:
- self.connect((master_addr, port))
+ self.connect((self._master_addr, self._port))
return True
except socket.error as e:
- self.log_msg('Failed to connect:(%s:%d), %s' % (master_addr, port, str(e)))
+ self.log_msg('Failed to connect:(%s:%d), %s' % (self._master_addr, self._port, str(e)))
return False
def _create_query(self, query_type):
'''Create dns query message. '''
+
msg = message(message_mode.RENDER)
query_id = random.randint(1, 0xFFFF)
self._query_id = query_id
@@ -123,6 +114,7 @@
def _send_query(self, query_type):
'''Send query message over TCP. '''
+
msg = self._create_query(query_type)
obuf = output_buffer(0)
render = message_render(obuf)
@@ -147,26 +139,23 @@
return data
- def handle_read(self):
- '''Read query's response from socket. '''
- self._recvd_data = self.recv(self._need_recv_size)
- self._recvd_size = len(self._recvd_data)
- self._recv_time_out = False
-
def _check_soa_serial(self):
''' Compare the soa serial, if soa serial in master is less than
the soa serial in local, Finish xfrin.
False: soa serial in master is less or equal to the local one.
True: soa serial in master is bigger
'''
+
self._send_query(rr_type.SOA())
data_size = self._get_request_response(2)
soa_reply = self._get_request_response(int(data_size))
#TODO, need select soa record from data source then compare the two
- #serial
+ #serial, current just return OK, since this function hasn't been used now
return XFRIN_OK
def do_xfrin(self, check_soa, ixfr_first = False):
+ '''Do xfr by sending xfr request and parsing response. '''
+
try:
ret = XFRIN_OK
if check_soa:
@@ -194,6 +183,8 @@
return ret
def _check_response_status(self, msg):
+ '''Check validation of xfr response. '''
+
#TODO, check more?
msg_rcode = msg.get_rcode()
if msg_rcode != rcode.NOERROR():
@@ -212,6 +203,8 @@
raise XfrinException('query section count greater than 1')
def _handle_answer_section(self, rrset_iter):
+ '''Return a generator for the reponse in one tcp package to a zone transfer.'''
+
while not rrset_iter.is_last():
rrset = rrset_iter.get_rrset()
rrset_iter.next()
@@ -242,6 +235,8 @@
rdata_iter.next()
def _handle_xfrin_response(self):
+ '''Return a generator for the response to a zone transfer. '''
+
while True:
data_len = self._get_request_response(2)
msg_len = socket.htons(struct.unpack('H', data_len)[0])
@@ -258,12 +253,18 @@
break
if self._shutdown_event.is_set():
- #Check if xfrin process is shutdown.
- #TODO, xfrin may be blocked in one loop.
raise XfrinException('xfrin is forced to stop')
+
+ def handle_read(self):
+ '''Read query's response from socket. '''
+
+ self._recvd_data = self.recv(self._need_recv_size)
+ self._recvd_size = len(self._recvd_data)
+ self._recv_time_out = False
def writable(self):
'''Ignore the writable socket. '''
+
return False
def log_info(self, msg, type='info'):
@@ -282,9 +283,9 @@
port = int(port)
xfrin_recorder.increment(zone_name)
conn = XfrinConnection(zone_name, db_file, shutdown_event,
- master_addr, port, check_soa, verbose)
- if conn.connect_to_master(master_addr, port):
- conn.do_xfrin(False)
+ master_addr, port, verbose)
+ if conn.connect_to_master():
+ conn.do_xfrin(check_soa)
xfrin_recorder.decrement(zone_name)
More information about the bind10-changes
mailing list