summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiampaolo RodolĂ  <g.rodola@gmail.com>2010-11-01 15:07:14 (GMT)
committerGiampaolo RodolĂ  <g.rodola@gmail.com>2010-11-01 15:07:14 (GMT)
commit19e9fefc660d623ce7c31fb008cde1157ae12aba (patch)
tree55124f9a3949ae80b5b361330e29c4843680307c
parentabacccc50c891f32c83dcf9ae38fe310ecf87409 (diff)
downloadcpython-19e9fefc660d623ce7c31fb008cde1157ae12aba.zip
cpython-19e9fefc660d623ce7c31fb008cde1157ae12aba.tar.gz
cpython-19e9fefc660d623ce7c31fb008cde1157ae12aba.tar.bz2
Fix Issue 6706: return None on connect() in case of EWOULDBLOCK/ECONNABORTED error.
-rw-r--r--Doc/library/asyncore.rst62
-rw-r--r--Lib/asyncore.py11
-rwxr-xr-xLib/smtpd.py31
-rw-r--r--Misc/NEWS3
4 files changed, 70 insertions, 37 deletions
diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst
index 468e5b5..58691ab 100644
--- a/Doc/library/asyncore.rst
+++ b/Doc/library/asyncore.rst
@@ -211,10 +211,13 @@ any that have been added to the map during asynchronous service) is closed.
.. method:: accept()
Accept a connection. The socket must be bound to an address and listening
- for connections. The return value is a pair ``(conn, address)`` where
- *conn* is a *new* socket object usable to send and receive data on the
- connection, and *address* is the address bound to the socket on the other
- end of the connection.
+ for connections. The return value can be either ``None`` or a pair
+ ``(conn, address)`` where *conn* is a *new* socket object usable to send
+ and receive data on the connection, and *address* is the address bound to
+ 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()
@@ -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
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()
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.
-.. _asyncore-example:
+.. _asyncore-example-1:
asyncore Example basic HTTP client
----------------------------------
@@ -250,7 +259,7 @@ implement its socket handling::
import asyncore, socket
- class http_client(asyncore.dispatcher):
+ class HTTPClient(asyncore.dispatcher):
def __init__(self, host, path):
asyncore.dispatcher.__init__(self)
@@ -274,6 +283,45 @@ implement its socket handling::
sent = self.send(self.buffer)
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:
+ pass
+ else:
+ sock, addr = pair
+ print 'Incoming connection from %s' % repr(addr)
+ handler = EchoHandler(sock)
+
+ server = EchoServer('localhost', 8080)
+ asyncore.loop()
+
diff --git a/Lib/asyncore.py b/Lib/asyncore.py
index 083920c..daf6644 100644
--- a/Lib/asyncore.py
+++ b/Lib/asyncore.py
@@ -350,12 +350,15 @@ class dispatcher:
# XXX can return either an address pair or None
try:
conn, addr = self.socket.accept()
- return conn, addr
- except socket.error, why:
- if why.args[0] == EWOULDBLOCK:
- pass
+ except TypeError:
+ return None
+ except socket.error as why:
+ if why.args[0] in (EWOULDBLOCK, ECONNABORTED):
+ return None
else:
raise
+ else:
+ return conn, addr
def send(self, data):
try:
diff --git a/Lib/smtpd.py b/Lib/smtpd.py
index 2d17b8d..e0544e4 100755
--- a/Lib/smtpd.py
+++ b/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.
"""
-
# Overview:
#
# This file implements the minimal SMTP protocol as defined in RFC 821. It
@@ -96,7 +95,6 @@ EMPTYSTRING = ''
COMMASPACE = ', '
-
def usage(code, msg=''):
print >> sys.stderr, __doc__ % globals()
if msg:
@@ -104,7 +102,6 @@ def usage(code, msg=''):
sys.exit(code)
-
class SMTPChannel(asynchat.async_chat):
COMMAND = 0
DATA = 1
@@ -276,7 +273,6 @@ class SMTPChannel(asynchat.async_chat):
self.push('354 End data with <CR><LF>.<CR><LF>')
-
class SMTPServer(asyncore.dispatcher):
def __init__(self, localaddr, remoteaddr):
self._localaddr = localaddr
@@ -299,22 +295,11 @@ class SMTPServer(asyncore.dispatcher):
localaddr, remoteaddr)
def handle_accept(self):
- try:
- conn, addr = self.accept()
- except TypeError:
- # sometimes accept() might return None
- return
- 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)
+ pair = self.accept()
+ if pair is not None:
+ conn, addr = pair
+ print >> DEBUGSTREAM, 'Incoming connection from %s' % repr(addr)
+ channel = SMTPChannel(self, conn, addr)
# API for "doing something useful with the message"
def process_message(self, peer, mailfrom, rcpttos, data):
@@ -342,7 +327,6 @@ class SMTPServer(asyncore.dispatcher):
raise NotImplementedError
-
class DebuggingServer(SMTPServer):
# Do something with the gathered message
def process_message(self, peer, mailfrom, rcpttos, data):
@@ -358,7 +342,6 @@ class DebuggingServer(SMTPServer):
print '------------ END MESSAGE ------------'
-
class PureProxy(SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data):
lines = data.split('\n')
@@ -399,7 +382,6 @@ class PureProxy(SMTPServer):
return refused
-
class MailmanProxy(PureProxy):
def process_message(self, peer, mailfrom, rcpttos, data):
from cStringIO import StringIO
@@ -478,13 +460,11 @@ class MailmanProxy(PureProxy):
msg.Enqueue(mlist, torequest=1)
-
class Options:
setuid = 1
classname = 'PureProxy'
-
def parseargs():
global DEBUGSTREAM
try:
@@ -541,7 +521,6 @@ def parseargs():
return options
-
if __name__ == '__main__':
options = parseargs()
# Become nobody
diff --git a/Misc/NEWS b/Misc/NEWS
index bfb1ebb..b9e38e2 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -66,6 +66,9 @@ Core and Builtins
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
as a filename. Patch by Brian Brazil.