diff -r de81e0fe4905 Lib/smtpd.py --- a/Lib/smtpd.py Sun Mar 02 20:29:18 2014 +0100 +++ b/Lib/smtpd.py Wed Mar 05 17:45:35 2014 +0100 @@ -583,7 +583,8 @@ self.data_size_limit = data_size_limit asyncore.dispatcher.__init__(self, map=map) try: - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + gai_results = socket.getaddrinfo(localaddr[0], localaddr[1]) + 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 -r de81e0fe4905 Lib/test/mock_socket.py --- a/Lib/test/mock_socket.py Sun Mar 02 20:29:18 2014 +0100 +++ b/Lib/test/mock_socket.py Wed Mar 05 17:45:35 2014 +0100 @@ -35,8 +35,9 @@ 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 @@ 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 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 -r de81e0fe4905 Lib/test/test_smtpd.py --- a/Lib/test/test_smtpd.py Sun Mar 02 20:29:18 2014 +0100 +++ b/Lib/test/test_smtpd.py Wed Mar 05 17:45:35 2014 +0100 @@ -5,6 +5,9 @@ import smtpd import asyncore +HOST_IPv4 = "127.0.0.1" +HOST_IPv6 = "::1" + class DummyServer(smtpd.SMTPServer): def __init__(self, localaddr, remoteaddr): @@ -27,35 +30,47 @@ class SMTPDServerTest(unittest.TestCase): + def write_line(self, line): + self.channel.socket.queue_recv(line) + self.channel.handle_read() + + def empty_message(self): + self.write_line(b'HELO example') + self.write_line(b'MAIL From:eggs@example') + self.write_line(b'RCPT To:spam@example') + self.write_line(b'DATA') + def setUp(self): smtpd.socket = asyncore.socket = mock_socket def test_process_message_unimplemented(self): - server = smtpd.SMTPServer('a', 'b') + server = smtpd.SMTPServer((HOST_IPv4, 0), ('b',0)) conn, addr = server.accept() - channel = smtpd.SMTPChannel(server, conn, addr) - - def write_line(line): - channel.socket.queue_recv(line) - channel.handle_read() - - write_line(b'HELO example') - write_line(b'MAIL From:eggs@example') - write_line(b'RCPT To:spam@example') - write_line(b'DATA') - self.assertRaises(NotImplementedError, write_line, b'spam\r\n.\r\n') + self.channel = smtpd.SMTPChannel(server, conn, addr) + self.empty_message() + self.assertRaises( + NotImplementedError, self.write_line, b'spam\r\n.\r\n') def tearDown(self): asyncore.close_all() asyncore.socket = smtpd.socket = socket +@unittest.skipUnless(support.IPV6_ENABLED, "IPv6 not enabled") +class TestIPv6Enovirenment(unittest.TestCase): + def test_socket_uses_IPv6(self): + server = smtpd.SMTPServer((HOST_IPv6, 0), (HOST_IPv4, 0)) + self.assertEqual(server.socket.family, socket.AF_INET6) + + def test_socket_uses_IPv4(self): + server = smtpd.SMTPServer((HOST_IPv4, 0), (HOST_IPv6, 0)) + 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((HOST_IPv4, 0), ('b', 0)) conn, addr = self.server.accept() self.channel = smtpd.SMTPChannel(self.server, conn, addr) @@ -69,7 +84,7 @@ self.channel.handle_read() def test_broken_connect(self): - self.assertRaises(DummyDispatcherBroken, BrokenDummyServer, 'a', 'b') + self.assertRaises(DummyDispatcherBroken, BrokenDummyServer, HOST_IPv4, 'b') def test_server_accept(self): self.server.handle_accept() @@ -502,6 +517,15 @@ with support.check_warnings(('', DeprecationWarning)): self.channel._SMTPChannel__addr = 'spam' +@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((HOST_IPv6, 0), ('b', 0)) + conn, addr = self.server.accept() + self.channel = smtpd.SMTPChannel(self.server, conn, addr) class SMTPDChannelWithDataSizeLimitTest(unittest.TestCase): @@ -509,7 +533,7 @@ 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((HOST_IPv4, 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)