Fixes a bug with socket interrupt handling under Python3.5

This change fixes a bug introduced with the addition of Python3.5
support. In Python3.5, SIGINT is silently ignored for system calls
(e.g., socket.accept) if the SIGINT signal handler does not raise
an exception. This causes the server to delay shutdown when
receiving SIGINT until after a new connection has been made. This
change updates the server's SIGINT signal handler to raise the
correct exception and updates the error handling code while serving
connections to account for this change in SIGINT processing. This
allows the server to shutdown immediately upon receiving SIGINT.
The server unit tests are updated to account for this change.
This commit is contained in:
Peter Hamilton 2017-01-04 16:02:14 -05:00
parent bbc2d8e58a
commit 28209bd60a
2 changed files with 23 additions and 13 deletions

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import errno
import logging
import logging.handlers as handlers
import optparse
@ -287,6 +286,13 @@ class KmipServer(object):
def _signal_handler(signal_number, stack_frame):
self._is_serving = False
# Python3.5+ silently ignores SIGINT and retries system calls if
# the signal handler does not raise an exception. Explicitly
# detect SIGINT and raise a KeyboardInterrupt exception to regain
# old functionality.
if signal_number == signal.SIGINT:
raise KeyboardInterrupt("SIGINT received")
signal.signal(signal.SIGINT, _signal_handler)
signal.signal(signal.SIGTERM, _signal_handler)
@ -296,14 +302,14 @@ class KmipServer(object):
try:
connection, address = self._socket.accept()
except socket.error as e:
if e.errno == errno.EINTR:
self._logger.warning("Interrupting connection service.")
break
else:
self._logger.warning(
"Error detected while establishing new connection."
)
self._logger.exception(e)
self._logger.warning(
"Error detected while establishing new connection."
)
self._logger.exception(e)
except KeyboardInterrupt:
self._logger.warning("Interrupting connection service.")
self._is_serving = False
break
except Exception as e:
self._logger.warning(
"Error detected while establishing new connection."

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import errno
import logging
try:
@ -363,8 +362,7 @@ class TestKmipServer(testtools.TestCase):
s._socket = mock.MagicMock()
s._setup_connection_handler = mock.MagicMock()
expected_error = socket.error()
expected_error.errno = errno.EINTR
expected_error = KeyboardInterrupt
# Test the expected behavior for a normal server/interrupt sequence
s._socket.accept = mock.MagicMock(
@ -418,7 +416,13 @@ class TestKmipServer(testtools.TestCase):
# Test the signal handler for each expected signal
s._is_serving = True
handler = signal.getsignal(signal.SIGINT)
handler(None, None)
args = (signal.SIGINT, None)
self.assertRaisesRegex(
KeyboardInterrupt,
"SIGINT received",
handler,
*args
)
self.assertFalse(s._is_serving)
s._is_serving = True