From: JINMEI Tatuya Date: Thu, 7 Jun 2012 22:02:55 +0000 (-0700) Subject: [2003] supported a simple case with TCP response. X-Git-Tag: trac2351_base~226^2~59^2~1^2~10 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=37883d293de17711407fd435d69cd6b79c2713d1;p=thirdparty%2Fkea.git [2003] supported a simple case with TCP response. it only handles the case where the initial send() completes the transmission. --- diff --git a/src/bin/ddns/ddns.py.in b/src/bin/ddns/ddns.py.in index 9c432f4bd3..843d385c7e 100755 --- a/src/bin/ddns/ddns.py.in +++ b/src/bin/ddns/ddns.py.in @@ -30,6 +30,7 @@ import isc.util.process import isc.util.cio.socketsession from isc.notify.notify_out import ZONE_NEW_DATA_READY_CMD import isc.server_common.tsig_keyring +from isc.server_common.dns_tcp import DNSTCPContext from isc.datasrc import DataSourceClient import select import errno @@ -342,8 +343,6 @@ class DDNSServer: # or dropped by the sender, so if such error is detected we treat it # as an internal error and don't bother to respond. try: - if sock.proto == socket.IPPROTO_TCP: - raise self.InternalError('TCP requests are not yet supported') self.__request_msg.clear(Message.PARSE) # specify PRESERVE_ORDER as we need to handle each RR separately. self.__request_msg.from_wire(req_data, Message.PRESERVE_ORDER) @@ -402,7 +401,12 @@ class DDNSServer: ''' try: - sock.sendto(data, dest) + if sock.proto == socket.IPPROTO_UDP: + sock.sendto(data, dest) + else: + tcp_ctx = DNSTCPContext(sock) + tcp_ctx.send(data) + tcp_ctx.close() except socket.error as ex: logger.error(DDNS_RESPONSE_SOCKET_ERROR, ClientFormatter(dest), ex) return False diff --git a/src/bin/ddns/tests/ddns_test.py b/src/bin/ddns/tests/ddns_test.py index 992e587df6..7c1e7f8328 100755 --- a/src/bin/ddns/tests/ddns_test.py +++ b/src/bin/ddns/tests/ddns_test.py @@ -64,12 +64,16 @@ class FakeSocket: self.__fileno = fileno self._sent_data = None self._sent_addr = None + self._close_called = 0 # number of calls to close() # customizable by tests; if set to True, sendto() will throw after # recording the parameters. self._raise_on_send = False def fileno(self): return self.__fileno def getpeername(self): + if self.proto == socket.IPPROTO_UDP or \ + self.proto == socket.IPPROTO_TCP: + return TEST_CLIENT4 return "fake_unix_socket" def accept(self): return FakeSocket(self.__fileno + 1), '/dummy/path' @@ -78,6 +82,17 @@ class FakeSocket: self._sent_addr = addr if self._raise_on_send: raise socket.error('test socket failure') + def send(self, data): + if self._sent_data is None: + self._sent_data = data + else: + self._sent_data += data + return len(data) + def setblocking(self, on): + # We only need a faked NO-OP implementation. + pass + def close(self): + self._close_called += 1 def clear(self): '''Clear internal instrumental data.''' self._sent_data = None @@ -633,7 +648,7 @@ class TestDDNSSession(unittest.TestCase): self.__faked_result) def check_update_response(self, resp_wire, expected_rcode=Rcode.NOERROR(), - tsig_ctx=None): + tsig_ctx=None, tcp=False): '''Check if given wire data are valid form of update response. In this implementation, zone/prerequisite/update sections should be @@ -643,7 +658,15 @@ class TestDDNSSession(unittest.TestCase): be TSIG signed and the signature should be verifiable with the context that has signed the corresponding request. + if tcp is True, the wire data are expected to be prepended with + a 2-byte length field. + ''' + if tcp: + data_len = resp_wire[0] * 256 + resp_wire[1] + resp_wire = resp_wire[2:] + self.assertEqual(len(resp_wire), data_len) + msg = Message(Message.PARSE) msg.from_wire(resp_wire) if tsig_ctx is not None: @@ -716,19 +739,22 @@ class TestDDNSSession(unittest.TestCase): self.__sock._raise_on_send = True # handle_request indicates the failure self.assertFalse(self.server.handle_request((self.__sock, TEST_SERVER6, - TEST_SERVER4, + TEST_CLIENT6, create_msg()))) # this check ensures sendto() was really attempted. self.check_update_response(self.__sock._sent_data, Rcode.NOERROR()) def test_tcp_request(self): - # Right now TCP request is not supported. + # A simple case using TCP: all resopnse data are sent out at once. s = self.__sock s.proto = socket.IPPROTO_TCP - self.assertFalse(self.server.handle_request((s, TEST_SERVER6, - TEST_SERVER4, - create_msg()))) - self.assertEqual((None, None), (s._sent_data, s._sent_addr)) + self.assertTrue(self.server.handle_request((s, TEST_SERVER6, + TEST_CLIENT6, + create_msg()))) + self.check_update_response(s._sent_data, Rcode.NOERROR(), tcp=True) + # In the current implementation, the socket should be closed + # immedidately after a successful send. + self.assertEqual(1, s._close_called) def test_request_message(self): '''Test if the request message stores RRs separately.'''