Browse Source

[2013] handle socket error from sendto().

JINMEI Tatuya 13 years ago
parent
commit
b9bde80941
3 changed files with 27 additions and 1 deletions
  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 *
 from isc.dns import *
 import isc.ddns.session
 import isc.ddns.session
 from isc.ddns.zone_config import ZoneConfig
 from isc.ddns.zone_config import ZoneConfig
+from isc.ddns.logger import ClientFormatter
 from isc.config.ccsession import *
 from isc.config.ccsession import *
 from isc.cc import SessionError, SessionTimeout
 from isc.cc import SessionError, SessionTimeout
 import isc.util.process
 import isc.util.process
@@ -363,7 +364,12 @@ class DDNSServer:
             msg.to_wire(self.__response_renderer, tsig_ctx)
             msg.to_wire(self.__response_renderer, tsig_ctx)
         else:
         else:
             msg.to_wire(self.__response_renderer)
             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
         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
 rather be considered an internal bug.  This event is therefore logged
 at the error level, and the request is simply dropped.  Additional
 at the error level, and the request is simply dropped.  Additional
 information of the error is also logged.
 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.__fileno = fileno
         self._sent_data = None
         self._sent_data = None
         self._sent_addr = 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):
     def fileno(self):
         return self.__fileno
         return self.__fileno
     def getpeername(self):
     def getpeername(self):
@@ -70,6 +73,8 @@ class FakeSocket:
     def sendto(self, data, addr):
     def sendto(self, data, addr):
         self._sent_data = data
         self._sent_data = data
         self._sent_addr = addr
         self._sent_addr = addr
+        if self._raise_on_send:
+            raise socket.error('test socket failure')
     def clear(self):
     def clear(self):
         '''Clear internal instrumental data.'''
         '''Clear internal instrumental data.'''
         self._sent_data = None
         self._sent_data = None
@@ -660,6 +665,16 @@ class TestDDNSession(unittest.TestCase):
         self.check_session(result=UPDATE_DROP, ipv6=False,
         self.check_session(result=UPDATE_DROP, ipv6=False,
                            tsig_key=BAD_TSIG_KEY)
                            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):
     def test_session_with_config(self):
         '''Check a session with more relistic config setups
         '''Check a session with more relistic config setups