diff -r dac347701b4f -r fa55dc894947 Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst Sat Jun 02 18:22:31 2012 +0200 +++ b/Doc/library/asyncore.rst Mon Jun 04 09:19:28 2012 +0100 @@ -1,4 +1,3 @@ -:mod:`asyncore` --- Asynchronous socket handler =============================================== .. module:: asyncore @@ -184,14 +183,18 @@ Most of these are nearly identical to their socket partners. - .. method:: create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM) + .. method:: create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM, + map=None) This is identical to the creation of a normal socket, and will use the same options for creation. Refer to the :mod:`socket` documentation for - information on creating sockets. + information on creating sockets. The *map* parameter is the map of + channels; if unspecified, the global socket map will be used. For details + about *map*, see the documentation for :func:`loop`. .. versionchanged:: 3.3 - *family* and *type* arguments can be omitted. + *family* and *type* arguments can be omitted. The *map* parameter was + added. .. method:: connect(address) diff -r dac347701b4f -r fa55dc894947 Lib/asyncore.py --- a/Lib/asyncore.py Sat Jun 02 18:22:31 2012 +0200 +++ b/Lib/asyncore.py Mon Jun 04 09:19:28 2012 +0100 @@ -284,11 +284,12 @@ del map[fd] self._fileno = None - def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM): + def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM, + map=None): self.family_and_type = family, type sock = socket.socket(family, type) sock.setblocking(0) - self.set_socket(sock) + self.set_socket(sock, map=map) def set_socket(self, sock, map=None): self.socket = sock diff -r dac347701b4f -r fa55dc894947 Lib/smtpd.py --- a/Lib/smtpd.py Sat Jun 02 18:22:31 2012 +0200 +++ b/Lib/smtpd.py Mon Jun 04 09:19:28 2012 +0100 @@ -121,8 +121,9 @@ }) max_command_size_limit = max(command_size_limits.values()) - def __init__(self, server, conn, addr, data_size_limit=DATA_SIZE_DEFAULT): - asynchat.async_chat.__init__(self, conn) + def __init__(self, server, conn, addr, data_size_limit=DATA_SIZE_DEFAULT, + map=None): + asynchat.async_chat.__init__(self, conn, map) self.smtp_server = server self.conn = conn self.addr = addr @@ -576,13 +577,13 @@ channel_class = SMTPChannel def __init__(self, localaddr, remoteaddr, - data_size_limit=DATA_SIZE_DEFAULT): + data_size_limit=DATA_SIZE_DEFAULT, map=None): self._localaddr = localaddr self._remoteaddr = remoteaddr self.data_size_limit = data_size_limit - asyncore.dispatcher.__init__(self) + asyncore.dispatcher.__init__(self, map=map) try: - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.create_socket(socket.AF_INET, socket.SOCK_STREAM, map) # try to re-use a server port if possible self.set_reuse_addr() self.bind(localaddr) @@ -597,7 +598,8 @@ def handle_accepted(self, conn, addr): print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM) - channel = self.channel_class(self, conn, addr, self.data_size_limit) + channel = self.channel_class(self, conn, addr, self.data_size_limit, + self._map) # API for "doing something useful with the message" def process_message(self, peer, mailfrom, rcpttos, data): diff -r dac347701b4f -r fa55dc894947 Lib/test/test_logging.py --- a/Lib/test/test_logging.py Sat Jun 02 18:22:31 2012 +0200 +++ b/Lib/test/test_logging.py Mon Jun 04 09:19:28 2012 +0100 @@ -652,41 +652,6 @@ # -- if it proves to be of wider utility than just test_logging if threading: - class TestSMTPChannel(smtpd.SMTPChannel): - """ - This derived class has had to be created because smtpd does not - support use of custom channel maps, although they are allowed by - asyncore's design. Issue #11959 has been raised to address this, - and if resolved satisfactorily, some of this code can be removed. - """ - def __init__(self, server, conn, addr, sockmap): - asynchat.async_chat.__init__(self, conn, sockmap) - self.smtp_server = server - self.conn = conn - self.addr = addr - self.data_size_limit = None - self.received_lines = [] - self.smtp_state = self.COMMAND - self.seen_greeting = '' - self.mailfrom = None - self.rcpttos = [] - self.received_data = '' - self.fqdn = socket.getfqdn() - self.num_bytes = 0 - try: - self.peer = conn.getpeername() - except socket.error as err: - # a race condition may occur if the other end is closing - # before we can get the peername - self.close() - if err.args[0] != errno.ENOTCONN: - raise - return - self.push('220 %s %s' % (self.fqdn, smtpd.__version__)) - self.set_terminator(b'\r\n') - self.extended_smtp = False - - class TestSMTPServer(smtpd.SMTPServer): """ This class implements a test SMTP server. @@ -707,37 +672,14 @@ :func:`asyncore.loop`. This avoids changing the :mod:`asyncore` module's global state. """ - channel_class = TestSMTPChannel def __init__(self, addr, handler, poll_interval, sockmap): - self._localaddr = addr - self._remoteaddr = None - self.data_size_limit = None - self.sockmap = sockmap - asyncore.dispatcher.__init__(self, map=sockmap) - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setblocking(0) - self.set_socket(sock, map=sockmap) - # try to re-use a server port if possible - self.set_reuse_addr() - self.bind(addr) - self.port = sock.getsockname()[1] - self.listen(5) - except: - self.close() - raise + smtpd.SMTPServer.__init__(self, addr, None, map=sockmap) + self.port = self.socket.getsockname()[1] self._handler = handler self._thread = None self.poll_interval = poll_interval - def handle_accepted(self, conn, addr): - """ - Redefined only because the base class does not pass in a - map, forcing use of a global in :mod:`asyncore`. - """ - channel = self.channel_class(self, conn, addr, self.sockmap) - def process_message(self, peer, mailfrom, rcpttos, data): """ Delegates to the handler passed in to the server's constructor. @@ -768,7 +710,7 @@ :func:`asyncore.loop`. """ try: - asyncore.loop(poll_interval, map=self.sockmap) + asyncore.loop(poll_interval, map=self._map) except select.error: # On FreeBSD 8, closing the server repeatably # raises this error. We swallow it if the