Commit 5ea3d0f9 authored by Giampaolo Rodolà's avatar Giampaolo Rodolà

Fix Issue 6706: return None on connect() in case of EWOULDBLOCK/ECONNABORTED error.

parent 8581c7e1
...@@ -209,10 +209,13 @@ any that have been added to the map during asynchronous service) is closed. ...@@ -209,10 +209,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()
...@@ -222,6 +225,12 @@ any that have been added to the map during asynchronous service) is closed. ...@@ -222,6 +225,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 :term:`file object` along A file_dispatcher takes a file descriptor or :term:`file object` along
...@@ -238,7 +247,7 @@ any that have been added to the map during asynchronous service) is closed. ...@@ -238,7 +247,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
---------------------------------- ----------------------------------
...@@ -248,7 +257,7 @@ implement its socket handling:: ...@@ -248,7 +257,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)
...@@ -272,6 +281,45 @@ implement its socket handling:: ...@@ -272,6 +281,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-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:
return
else:
sock, addr = pair
print('Incoming connection from %s' % repr(addr))
handler = EchoHandler(sock)
server = EchoServer('localhost', 8080)
asyncore.loop() asyncore.loop()
...@@ -346,12 +346,15 @@ class dispatcher: ...@@ -346,12 +346,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:
return None
except socket.error as why: except socket.error as why:
if why.args[0] == EWOULDBLOCK: if why.args[0] in (EWOULDBLOCK, ECONNABORTED):
pass return None
else: else:
raise raise
else:
return conn, addr
def send(self, data): def send(self, data):
try: try:
......
...@@ -297,20 +297,9 @@ class SMTPServer(asyncore.dispatcher): ...@@ -297,20 +297,9 @@ class SMTPServer(asyncore.dispatcher):
localaddr, remoteaddr), file=DEBUGSTREAM) localaddr, remoteaddr), file=DEBUGSTREAM)
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
return
except socket.error as err:
# ECONNABORTED might be thrown
if err.args[0] != errno.ECONNABORTED:
raise
return
else:
# sometimes addr == None instead of (ip, port)
if addr == None:
return
print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM) print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM)
channel = SMTPChannel(self, conn, addr) channel = SMTPChannel(self, conn, addr)
......
...@@ -143,6 +143,9 @@ C-API ...@@ -143,6 +143,9 @@ C-API
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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment