Set socket options in correct way
Currently socket options, socket.SO_REUSEADDR, socket.TCP_KEEPIDLE and socket.SO_KEEPALIVE are set only if SSL is enabled. socket.SO_REUSEADDR: This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway. It is useful if your server has been shut down, and then restarted right away while sockets are still active on its port. socket.SO_KEEPALIVE: To confirm that an idle connection is still active, these implementations send a probe segment designed to elicit a response from the peer TCP. The the probe causes the receiver to return an acknowledgement segment, confirming that the connection is still live. If the peer has dropped the connection due to a network partition or a crash, it will respond with a RST instead of an acknowledgement segment. socket.TCP_KEEPIDLE: It is useful to set this socket option, because if the other peers lose their connection (for example by rebooting) you will notice that the connection is broken, even if you don't have traffic on it. If the probes are not replied to by your peer, you can assert that the connection cannot be considered valid and then take the correct action. IMO, these options are useful in both the cases, whether SSL is enabled or not. Made provision to set socket.SO_REUSEADDR, socket.TCP_KEEPIDLE and socket.SO_KEEPALIVE socket options if SSL is enabled or not. Closes-Bug: #1369414 Change-Id: I25b353dcf1ca6eba1c54d297994d56c0064daca5
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
"""Unit tests for `nova.wsgi`."""
|
||||
|
||||
import os.path
|
||||
import socket
|
||||
import tempfile
|
||||
import urllib2
|
||||
|
||||
@@ -127,6 +128,24 @@ class TestWSGIServer(test.NoDBTestCase):
|
||||
server.stop()
|
||||
server.wait()
|
||||
|
||||
def test_socket_options_for_simple_server(self):
|
||||
# test normal socket options has set properly
|
||||
self.flags(tcp_keepidle=500)
|
||||
server = nova.wsgi.Server("test_socket_options", None,
|
||||
host="127.0.0.1", port=0)
|
||||
server.start()
|
||||
sock = server._socket
|
||||
self.assertEqual(1, sock.getsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_REUSEADDR))
|
||||
self.assertEqual(1, sock.getsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_KEEPALIVE))
|
||||
if hasattr(socket, 'TCP_KEEPIDLE'):
|
||||
self.assertEqual(CONF.tcp_keepidle,
|
||||
sock.getsockopt(socket.IPPROTO_TCP,
|
||||
socket.TCP_KEEPIDLE))
|
||||
server.stop()
|
||||
server.wait()
|
||||
|
||||
def test_server_pool_waitall(self):
|
||||
# test pools waitall method gets called while stopping server
|
||||
server = nova.wsgi.Server("test_server", None,
|
||||
@@ -270,6 +289,25 @@ class TestWSGIServerWithSSL(test.NoDBTestCase):
|
||||
fake_ssl_server.stop()
|
||||
fake_ssl_server.wait()
|
||||
|
||||
def test_socket_options_for_ssl_server(self):
|
||||
# test normal socket options has set properly
|
||||
self.flags(tcp_keepidle=500)
|
||||
server = nova.wsgi.Server("test_socket_options", None,
|
||||
host="127.0.0.1", port=0,
|
||||
use_ssl=True)
|
||||
server.start()
|
||||
sock = server._socket
|
||||
self.assertEqual(1, sock.getsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_REUSEADDR))
|
||||
self.assertEqual(1, sock.getsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_KEEPALIVE))
|
||||
if hasattr(socket, 'TCP_KEEPIDLE'):
|
||||
self.assertEqual(CONF.tcp_keepidle,
|
||||
sock.getsockopt(socket.IPPROTO_TCP,
|
||||
socket.TCP_KEEPIDLE))
|
||||
server.stop()
|
||||
server.wait()
|
||||
|
||||
@testtools.skipIf(not utils.is_ipv6_supported(), "no ipv6 support")
|
||||
def test_app_using_ipv6_and_ssl(self):
|
||||
greetings = 'Hello, World!!!'
|
||||
|
||||
25
nova/wsgi.py
25
nova/wsgi.py
@@ -159,6 +159,18 @@ class Server(object):
|
||||
# to keep file descriptor usable.
|
||||
|
||||
dup_socket = self._socket.dup()
|
||||
dup_socket.setsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_REUSEADDR, 1)
|
||||
# sockets can hang around forever without keepalive
|
||||
dup_socket.setsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_KEEPALIVE, 1)
|
||||
|
||||
# This option isn't available in the OS X version of eventlet
|
||||
if hasattr(socket, 'TCP_KEEPIDLE'):
|
||||
dup_socket.setsockopt(socket.IPPROTO_TCP,
|
||||
socket.TCP_KEEPIDLE,
|
||||
CONF.tcp_keepidle)
|
||||
|
||||
if self._use_ssl:
|
||||
try:
|
||||
ca_file = CONF.ssl_ca_file
|
||||
@@ -195,19 +207,6 @@ class Server(object):
|
||||
|
||||
dup_socket = eventlet.wrap_ssl(dup_socket,
|
||||
**ssl_kwargs)
|
||||
|
||||
dup_socket.setsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_REUSEADDR, 1)
|
||||
# sockets can hang around forever without keepalive
|
||||
dup_socket.setsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_KEEPALIVE, 1)
|
||||
|
||||
# This option isn't available in the OS X version of eventlet
|
||||
if hasattr(socket, 'TCP_KEEPIDLE'):
|
||||
dup_socket.setsockopt(socket.IPPROTO_TCP,
|
||||
socket.TCP_KEEPIDLE,
|
||||
CONF.tcp_keepidle)
|
||||
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Failed to start %(name)s on %(host)s"
|
||||
|
||||
Reference in New Issue
Block a user