Parcourir la source

[2013] handle socket error from sendto().

JINMEI Tatuya il y a 13 ans
Parent
commit
b9bde80941
3 fichiers modifiés avec 27 ajouts et 1 suppressions
  1. 7 1
      src/bin/ddns/ddns.py.in
  2. 5 0
      src/bin/ddns/ddns_messages.mes
  3. 15 0
      src/bin/ddns/tests/ddns_test.py

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

@@ -23,6 +23,7 @@ import bind10_config
 from isc.dns import *
 import isc.ddns.session
 from isc.ddns.zone_config import ZoneConfig
+from isc.ddns.logger import ClientFormatter
 from isc.config.ccsession import *
 from isc.cc import SessionError, SessionTimeout
 import isc.util.process
@@ -363,7 +364,12 @@ class DDNSServer:
             msg.to_wire(self.__response_renderer, tsig_ctx)
         else:
             msg.to_wire(self.__response_renderer)
-        sock.sendto(self.__response_renderer.get_data(), remote_addr)
+        try:
+            sock.sendto(self.__response_renderer.get_data(), remote_addr)
+        except socket.error as ex:
+            logger.error(DDNS_RESPONSE_SOCKET_ERROR,
+                         ClientFormatter(remote_addr), ex)
+            return False
 
         return True
 

+ 5 - 0
src/bin/ddns/ddns_messages.mes

@@ -99,3 +99,8 @@ checks, such an error shouldn't be detected at this stage and should
 rather be considered an internal bug.  This event is therefore logged
 at the error level, and the request is simply dropped.  Additional
 information of the error is also logged.
+
+% DDNS_RESPONSE_SOCKET_ERROR failed to send update response to %1: %2
+Network I/O error happens in sending an update request.  The
+client's address that caused the error and error details are also
+logged.

+ 15 - 0
src/bin/ddns/tests/ddns_test.py

@@ -61,6 +61,9 @@ class FakeSocket:
         self.__fileno = fileno
         self._sent_data = None
         self._sent_addr = None
+        # 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):
@@ -70,6 +73,8 @@ class FakeSocket:
     def sendto(self, data, addr):
         self._sent_data = data
         self._sent_addr = addr
+        if self._raise_on_send:
+            raise socket.error('test socket failure')
     def clear(self):
         '''Clear internal instrumental data.'''
         self._sent_data = None
@@ -660,6 +665,16 @@ class TestDDNSession(unittest.TestCase):
         self.check_session(result=UPDATE_DROP, ipv6=False,
                            tsig_key=BAD_TSIG_KEY)
 
+    def test_socket_error(self):
+        # Have the faked socket raise an exception on sendto()
+        self.__sock._raise_on_send = True
+        # handle_request indicates the failure
+        self.assertFalse(self.server.handle_request((self.__sock, TEST_SERVER6,
+                                                     TEST_SERVER4,
+                                                     create_msg())))
+        # this check ensures sendto() was really attempted.
+        self.check_update_response(self.__sock._sent_data, Rcode.NOERROR())
+
     def test_session_with_config(self):
         '''Check a session with more relistic config setups