mirror of
https://github.com/python/cpython.git
synced 2025-11-24 20:30:18 +00:00
Fix Issue 6706: return None on connect() in case of EWOULDBLOCK/ECONNABORTED error.
This commit is contained in:
parent
abacccc50c
commit
19e9fefc66
4 changed files with 70 additions and 37 deletions
|
|
@ -211,10 +211,13 @@ any that have been added to the map during asynchronous service) is closed.
|
||||||
.. method:: accept()
|
.. method:: accept()
|
||||||
|
|
||||||
Accept a connection. The socket must be bound to an address and listening
|
Accept a connection. The socket must be bound to an address and listening
|
||||||
for connections. The return value is a pair ``(conn, address)`` where
|
for connections. The return value can be either ``None`` or a pair
|
||||||
*conn* is a *new* socket object usable to send and receive data on the
|
``(conn, address)`` where *conn* is a *new* socket object usable to send
|
||||||
connection, and *address* is the address bound to the socket on the other
|
and receive data on the connection, and *address* is the address bound to
|
||||||
end of the connection.
|
the socket on the other end of the connection.
|
||||||
|
When ``None`` is returned it means the connection didn't take place, in
|
||||||
|
which case the server should just ignore this event and keep listening
|
||||||
|
for further incoming connections.
|
||||||
|
|
||||||
|
|
||||||
.. method:: close()
|
.. method:: close()
|
||||||
|
|
@ -224,6 +227,12 @@ any that have been added to the map during asynchronous service) is closed.
|
||||||
flushed). Sockets are automatically closed when they are
|
flushed). Sockets are automatically closed when they are
|
||||||
garbage-collected.
|
garbage-collected.
|
||||||
|
|
||||||
|
.. class:: dispatcher_with_send()
|
||||||
|
|
||||||
|
A :class:`dispatcher` subclass which adds simple buffered output capability,
|
||||||
|
useful for simple clients. For more sophisticated usage use
|
||||||
|
:class:`asynchat.async_chat`.
|
||||||
|
|
||||||
.. class:: file_dispatcher()
|
.. class:: file_dispatcher()
|
||||||
|
|
||||||
A file_dispatcher takes a file descriptor or file object along with an
|
A file_dispatcher takes a file descriptor or file object along with an
|
||||||
|
|
@ -240,7 +249,7 @@ any that have been added to the map during asynchronous service) is closed.
|
||||||
socket for use by the :class:`file_dispatcher` class. Availability: UNIX.
|
socket for use by the :class:`file_dispatcher` class. Availability: UNIX.
|
||||||
|
|
||||||
|
|
||||||
.. _asyncore-example:
|
.. _asyncore-example-1:
|
||||||
|
|
||||||
asyncore Example basic HTTP client
|
asyncore Example basic HTTP client
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
@ -250,7 +259,7 @@ implement its socket handling::
|
||||||
|
|
||||||
import asyncore, socket
|
import asyncore, socket
|
||||||
|
|
||||||
class http_client(asyncore.dispatcher):
|
class HTTPClient(asyncore.dispatcher):
|
||||||
|
|
||||||
def __init__(self, host, path):
|
def __init__(self, host, path):
|
||||||
asyncore.dispatcher.__init__(self)
|
asyncore.dispatcher.__init__(self)
|
||||||
|
|
@ -274,6 +283,45 @@ implement its socket handling::
|
||||||
sent = self.send(self.buffer)
|
sent = self.send(self.buffer)
|
||||||
self.buffer = self.buffer[sent:]
|
self.buffer = self.buffer[sent:]
|
||||||
|
|
||||||
c = http_client('www.python.org', '/')
|
|
||||||
|
|
||||||
|
client = HTTPClient('www.python.org', '/')
|
||||||
asyncore.loop()
|
asyncore.loop()
|
||||||
|
|
||||||
|
.. _asyncore-example-2:
|
||||||
|
|
||||||
|
asyncore Example basic echo server
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
Here is abasic echo server that uses the :class:`dispatcher` class to accept
|
||||||
|
connections and dispatches the incoming connections to a handler::
|
||||||
|
|
||||||
|
import asyncore
|
||||||
|
import socket
|
||||||
|
|
||||||
|
class EchoHandler(asyncore.dispatcher_with_send):
|
||||||
|
|
||||||
|
def handle_read(self):
|
||||||
|
data = self.recv(8192)
|
||||||
|
self.send(data)
|
||||||
|
|
||||||
|
class EchoServer(asyncore.dispatcher):
|
||||||
|
|
||||||
|
def __init__(self, host, port):
|
||||||
|
asyncore.dispatcher.__init__(self)
|
||||||
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.set_reuse_addr()
|
||||||
|
self.bind((host, port))
|
||||||
|
self.listen(5)
|
||||||
|
|
||||||
|
def handle_accept(self):
|
||||||
|
pair = self.accept()
|
||||||
|
if pair is None:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
sock, addr = pair
|
||||||
|
print 'Incoming connection from %s' % repr(addr)
|
||||||
|
handler = EchoHandler(sock)
|
||||||
|
|
||||||
|
server = EchoServer('localhost', 8080)
|
||||||
|
asyncore.loop()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -350,12 +350,15 @@ class dispatcher:
|
||||||
# XXX can return either an address pair or None
|
# XXX can return either an address pair or None
|
||||||
try:
|
try:
|
||||||
conn, addr = self.socket.accept()
|
conn, addr = self.socket.accept()
|
||||||
return conn, addr
|
except TypeError:
|
||||||
except socket.error, why:
|
return None
|
||||||
if why.args[0] == EWOULDBLOCK:
|
except socket.error as why:
|
||||||
pass
|
if why.args[0] in (EWOULDBLOCK, ECONNABORTED):
|
||||||
|
return None
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
else:
|
||||||
|
return conn, addr
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
31
Lib/smtpd.py
31
Lib/smtpd.py
|
|
@ -35,7 +35,6 @@ given then 8025 is used. If remotehost is not given then `localhost' is used,
|
||||||
and if remoteport is not given, then 25 is used.
|
and if remoteport is not given, then 25 is used.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
# Overview:
|
# Overview:
|
||||||
#
|
#
|
||||||
# This file implements the minimal SMTP protocol as defined in RFC 821. It
|
# This file implements the minimal SMTP protocol as defined in RFC 821. It
|
||||||
|
|
@ -96,7 +95,6 @@ EMPTYSTRING = ''
|
||||||
COMMASPACE = ', '
|
COMMASPACE = ', '
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def usage(code, msg=''):
|
def usage(code, msg=''):
|
||||||
print >> sys.stderr, __doc__ % globals()
|
print >> sys.stderr, __doc__ % globals()
|
||||||
if msg:
|
if msg:
|
||||||
|
|
@ -104,7 +102,6 @@ def usage(code, msg=''):
|
||||||
sys.exit(code)
|
sys.exit(code)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SMTPChannel(asynchat.async_chat):
|
class SMTPChannel(asynchat.async_chat):
|
||||||
COMMAND = 0
|
COMMAND = 0
|
||||||
DATA = 1
|
DATA = 1
|
||||||
|
|
@ -276,7 +273,6 @@ class SMTPChannel(asynchat.async_chat):
|
||||||
self.push('354 End data with <CR><LF>.<CR><LF>')
|
self.push('354 End data with <CR><LF>.<CR><LF>')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SMTPServer(asyncore.dispatcher):
|
class SMTPServer(asyncore.dispatcher):
|
||||||
def __init__(self, localaddr, remoteaddr):
|
def __init__(self, localaddr, remoteaddr):
|
||||||
self._localaddr = localaddr
|
self._localaddr = localaddr
|
||||||
|
|
@ -299,22 +295,11 @@ class SMTPServer(asyncore.dispatcher):
|
||||||
localaddr, remoteaddr)
|
localaddr, remoteaddr)
|
||||||
|
|
||||||
def handle_accept(self):
|
def handle_accept(self):
|
||||||
try:
|
pair = self.accept()
|
||||||
conn, addr = self.accept()
|
if pair is not None:
|
||||||
except TypeError:
|
conn, addr = pair
|
||||||
# sometimes accept() might return None
|
print >> DEBUGSTREAM, 'Incoming connection from %s' % repr(addr)
|
||||||
return
|
channel = SMTPChannel(self, conn, addr)
|
||||||
except socket.error, err:
|
|
||||||
# ECONNABORTED might be thrown
|
|
||||||
if err[0] != errno.ECONNABORTED:
|
|
||||||
raise
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
# sometimes addr == None instead of (ip, port)
|
|
||||||
if addr == None:
|
|
||||||
return
|
|
||||||
print >> DEBUGSTREAM, 'Incoming connection from %s' % repr(addr)
|
|
||||||
channel = SMTPChannel(self, conn, addr)
|
|
||||||
|
|
||||||
# API for "doing something useful with the message"
|
# API for "doing something useful with the message"
|
||||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||||
|
|
@ -342,7 +327,6 @@ class SMTPServer(asyncore.dispatcher):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DebuggingServer(SMTPServer):
|
class DebuggingServer(SMTPServer):
|
||||||
# Do something with the gathered message
|
# Do something with the gathered message
|
||||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||||
|
|
@ -358,7 +342,6 @@ class DebuggingServer(SMTPServer):
|
||||||
print '------------ END MESSAGE ------------'
|
print '------------ END MESSAGE ------------'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PureProxy(SMTPServer):
|
class PureProxy(SMTPServer):
|
||||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||||
lines = data.split('\n')
|
lines = data.split('\n')
|
||||||
|
|
@ -399,7 +382,6 @@ class PureProxy(SMTPServer):
|
||||||
return refused
|
return refused
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MailmanProxy(PureProxy):
|
class MailmanProxy(PureProxy):
|
||||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
@ -478,13 +460,11 @@ class MailmanProxy(PureProxy):
|
||||||
msg.Enqueue(mlist, torequest=1)
|
msg.Enqueue(mlist, torequest=1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Options:
|
class Options:
|
||||||
setuid = 1
|
setuid = 1
|
||||||
classname = 'PureProxy'
|
classname = 'PureProxy'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def parseargs():
|
def parseargs():
|
||||||
global DEBUGSTREAM
|
global DEBUGSTREAM
|
||||||
try:
|
try:
|
||||||
|
|
@ -541,7 +521,6 @@ def parseargs():
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
options = parseargs()
|
options = parseargs()
|
||||||
# Become nobody
|
# Become nobody
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue 6706: asyncore accept() method no longer raises EWOULDBLOCK/ECONNABORTED
|
||||||
|
on incomplete connection attempt but returns None instead.
|
||||||
|
|
||||||
- Issue #10266: uu.decode didn't close in_file explicitly when it was given
|
- Issue #10266: uu.decode didn't close in_file explicitly when it was given
|
||||||
as a filename. Patch by Brian Brazil.
|
as a filename. Patch by Brian Brazil.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue