diff options
author | R David Murray <rdmurray@bitdance.com> | 2014-06-11 17:48:58 (GMT) |
---|---|---|
committer | R David Murray <rdmurray@bitdance.com> | 2014-06-11 17:48:58 (GMT) |
commit | 6fe56a329dd427f2a5363b43ad24f04785d2091d (patch) | |
tree | af2b051bbdb771ad2932d6888b9405d7984ff9b6 | |
parent | 1144da5821553449739744f08d041b4ba7114ecb (diff) | |
download | cpython-6fe56a329dd427f2a5363b43ad24f04785d2091d.zip cpython-6fe56a329dd427f2a5363b43ad24f04785d2091d.tar.gz cpython-6fe56a329dd427f2a5363b43ad24f04785d2091d.tar.bz2 |
#14758: add IPv6 support to smtpd.
Patch by Milan Oberkirch.
-rw-r--r-- | Doc/library/smtpd.rst | 4 | ||||
-rw-r--r-- | Doc/whatsnew/3.5.rst | 4 | ||||
-rwxr-xr-x | Lib/smtpd.py | 3 | ||||
-rw-r--r-- | Lib/test/mock_socket.py | 11 | ||||
-rw-r--r-- | Lib/test/test_smtpd.py | 51 |
5 files changed, 58 insertions, 15 deletions
diff --git a/Doc/library/smtpd.rst b/Doc/library/smtpd.rst index e6625df..0f4a0bf 100644 --- a/Doc/library/smtpd.rst +++ b/Doc/library/smtpd.rst @@ -68,8 +68,8 @@ SMTPServer Objects .. versionchanged:: 3.4 The *map* argument was added. - .. versionchanged:: 3.5 - the *decode_data* argument was added. + .. versionchanged:: 3.5 the *decode_data* argument was added, and *localaddr* + and *remoteaddr* may now contain IPv6 addresses. DebuggingServer Objects diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 68106c1..846a416 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -194,6 +194,10 @@ smtpd is ``True`` for backward compatibility reasons, but will change to ``False`` in Python 3.6. (Contributed by Maciej Szulik in :issue:`19662`.) +* It is now possible to provide, directly or via name resolution, IPv6 + addresses in the :class:`~smtpd.SMTPServer` constructor, and have it + successfully connect. (Contributed by Milan Oberkirch in :issue:`14758`.) + socket ------ diff --git a/Lib/smtpd.py b/Lib/smtpd.py index 569b42e..d828c5f 100755 --- a/Lib/smtpd.py +++ b/Lib/smtpd.py @@ -610,7 +610,8 @@ class SMTPServer(asyncore.dispatcher): self._decode_data = decode_data asyncore.dispatcher.__init__(self, map=map) try: - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + gai_results = socket.getaddrinfo(*localaddr) + self.create_socket(gai_results[0][0], gai_results[0][1]) # try to re-use a server port if possible self.set_reuse_addr() self.bind(localaddr) diff --git a/Lib/test/mock_socket.py b/Lib/test/mock_socket.py index e36724f..a4fbca6 100644 --- a/Lib/test/mock_socket.py +++ b/Lib/test/mock_socket.py @@ -35,8 +35,9 @@ class MockFile: class MockSocket: """Mock socket object used by smtpd and smtplib tests. """ - def __init__(self): + def __init__(self, family=None): global _reply_data + self.family = family self.output = [] self.lines = [] if _reply_data: @@ -108,8 +109,7 @@ class MockSocket: def socket(family=None, type=None, proto=None): - return MockSocket() - + return MockSocket(family) def create_connection(address, timeout=socket_module._GLOBAL_DEFAULT_TIMEOUT, source_address=None): @@ -144,13 +144,16 @@ def gethostname(): def gethostbyname(name): return "" +def getaddrinfo(host, port): + return socket_module.getaddrinfo(host, port) gaierror = socket_module.gaierror error = socket_module.error # Constants -AF_INET = None +AF_INET = socket_module.AF_INET +AF_INET6 = socket_module.AF_INET6 SOCK_STREAM = None SOL_SOCKET = None SO_REUSEADDR = None diff --git a/Lib/test/test_smtpd.py b/Lib/test/test_smtpd.py index db1f52b..caeb797 100644 --- a/Lib/test/test_smtpd.py +++ b/Lib/test/test_smtpd.py @@ -36,7 +36,8 @@ class SMTPDServerTest(unittest.TestCase): smtpd.socket = asyncore.socket = mock_socket def test_process_message_unimplemented(self): - server = smtpd.SMTPServer('a', 'b', decode_data=True) + server = smtpd.SMTPServer((support.HOST, 0), ('b', 0), + decode_data=True) conn, addr = server.accept() channel = smtpd.SMTPChannel(server, conn, addr, decode_data=True) @@ -52,19 +53,39 @@ class SMTPDServerTest(unittest.TestCase): def test_decode_data_default_warns(self): with self.assertWarns(DeprecationWarning): - smtpd.SMTPServer('a', 'b') + smtpd.SMTPServer((support.HOST, 0), ('b', 0)) def tearDown(self): asyncore.close_all() asyncore.socket = smtpd.socket = socket +class TestFamilyDetection(unittest.TestCase): + def setUp(self): + smtpd.socket = asyncore.socket = mock_socket + + def tearDown(self): + asyncore.close_all() + asyncore.socket = smtpd.socket = socket + + @unittest.skipUnless(support.IPV6_ENABLED, "IPv6 not enabled") + def test_socket_uses_IPv6(self): + server = smtpd.SMTPServer((support.HOSTv6, 0), (support.HOST, 0), + decode_data=False) + self.assertEqual(server.socket.family, socket.AF_INET6) + + def test_socket_uses_IPv4(self): + server = smtpd.SMTPServer((support.HOST, 0), (support.HOSTv6, 0), + decode_data=False) + self.assertEqual(server.socket.family, socket.AF_INET) + + class SMTPDChannelTest(unittest.TestCase): def setUp(self): smtpd.socket = asyncore.socket = mock_socket self.old_debugstream = smtpd.DEBUGSTREAM self.debug = smtpd.DEBUGSTREAM = io.StringIO() - self.server = DummyServer('a', 'b') + self.server = DummyServer((support.HOST, 0), ('b', 0)) conn, addr = self.server.accept() self.channel = smtpd.SMTPChannel(self.server, conn, addr, decode_data=True) @@ -79,7 +100,9 @@ class SMTPDChannelTest(unittest.TestCase): self.channel.handle_read() def test_broken_connect(self): - self.assertRaises(DummyDispatcherBroken, BrokenDummyServer, 'a', 'b') + self.assertRaises( + DummyDispatcherBroken, BrokenDummyServer, + (support.HOST, 0), ('b', 0)) def test_server_accept(self): self.server.handle_accept() @@ -513,11 +536,21 @@ class SMTPDChannelTest(unittest.TestCase): self.channel._SMTPChannel__addr = 'spam' def test_decode_data_default_warning(self): - server = DummyServer('a', 'b') + server = DummyServer((support.HOST, 0), ('b', 0)) conn, addr = self.server.accept() with self.assertWarns(DeprecationWarning): smtpd.SMTPChannel(server, conn, addr) +@unittest.skipUnless(support.IPV6_ENABLED, "IPv6 not enabled") +class SMTPDChannelIPv6Test(SMTPDChannelTest): + def setUp(self): + smtpd.socket = asyncore.socket = mock_socket + self.old_debugstream = smtpd.DEBUGSTREAM + self.debug = smtpd.DEBUGSTREAM = io.StringIO() + self.server = DummyServer((support.HOSTv6, 0), ('b', 0)) + conn, addr = self.server.accept() + self.channel = smtpd.SMTPChannel(self.server, conn, addr, + decode_data=True) class SMTPDChannelWithDataSizeLimitTest(unittest.TestCase): @@ -525,7 +558,7 @@ class SMTPDChannelWithDataSizeLimitTest(unittest.TestCase): smtpd.socket = asyncore.socket = mock_socket self.old_debugstream = smtpd.DEBUGSTREAM self.debug = smtpd.DEBUGSTREAM = io.StringIO() - self.server = DummyServer('a', 'b') + self.server = DummyServer((support.HOST, 0), ('b', 0)) conn, addr = self.server.accept() # Set DATA size limit to 32 bytes for easy testing self.channel = smtpd.SMTPChannel(self.server, conn, addr, 32, @@ -576,7 +609,8 @@ class SMTPDChannelWithDecodeDataFalse(unittest.TestCase): smtpd.socket = asyncore.socket = mock_socket self.old_debugstream = smtpd.DEBUGSTREAM self.debug = smtpd.DEBUGSTREAM = io.StringIO() - self.server = DummyServer('a', 'b', decode_data=False) + self.server = DummyServer((support.HOST, 0), ('b', 0), + decode_data=False) conn, addr = self.server.accept() # Set decode_data to False self.channel = smtpd.SMTPChannel(self.server, conn, addr, @@ -620,7 +654,8 @@ class SMTPDChannelWithDecodeDataTrue(unittest.TestCase): smtpd.socket = asyncore.socket = mock_socket self.old_debugstream = smtpd.DEBUGSTREAM self.debug = smtpd.DEBUGSTREAM = io.StringIO() - self.server = DummyServer('a', 'b') + self.server = DummyServer((support.HOST, 0), ('b', 0), + decode_data=True) conn, addr = self.server.accept() # Set decode_data to True self.channel = smtpd.SMTPChannel(self.server, conn, addr, |