fix implementation of connect_ex so it always returns the error code rather than raising

This commit is contained in:
Tavis Rudd
2010-02-24 19:49:21 -08:00
parent a0ab236669
commit 8072243926

View File

@@ -36,8 +36,8 @@ def socket_connect(descriptor, address):
def socket_accept(descriptor):
"""
Attempts to accept() on the descriptor, returns a client,address tuple
if it succeeds; returns None if it needs to trampoline, and raises
Attempts to accept() on the descriptor, returns a client,address tuple
if it succeeds; returns None if it needs to trampoline, and raises
any exceptions.
"""
try:
@@ -46,7 +46,7 @@ def socket_accept(descriptor):
if e[0] == errno.EWOULDBLOCK:
return None
raise
if sys.platform[:3]=="win":
# winsock sometimes throws ENOTCONN
@@ -62,7 +62,7 @@ else:
def set_nonblocking(fd):
"""
Sets the descriptor to be nonblocking. Works on many file-like
objects as well as sockets. Only sockets can be nonblocking on
objects as well as sockets. Only sockets can be nonblocking on
Windows, however.
"""
try:
@@ -96,7 +96,7 @@ try:
from socket import _GLOBAL_DEFAULT_TIMEOUT
except ImportError:
_GLOBAL_DEFAULT_TIMEOUT = object()
class GreenSocket(object):
"""
@@ -117,14 +117,14 @@ class GreenSocket(object):
self.timeout = fd.gettimeout() or socket.getdefaulttimeout()
except AttributeError:
self.timeout = socket.getdefaulttimeout()
set_nonblocking(fd)
self.fd = fd
self.closed = False
# when client calls setblocking(0) or settimeout(0) the socket must
# act non-blocking
self.act_non_blocking = False
@property
def _sock(self):
return self
@@ -195,11 +195,11 @@ class GreenSocket(object):
else:
end = time.time() + self.gettimeout()
while True:
if socket_connect(fd, address):
return 0
if time.time() >= end:
raise socket.timeout(errno.EAGAIN)
try:
if socket_connect(fd, address):
return 0
if time.time() >= end:
raise socket.timeout(errno.EAGAIN)
trampoline(fd, write=True, timeout=end-time.time(),
timeout_exc=socket.timeout(errno.EAGAIN))
except socket.error, ex:
@@ -254,9 +254,9 @@ class GreenSocket(object):
return ''
else:
raise
trampoline(fd,
read=True,
timeout=self.timeout,
trampoline(fd,
read=True,
timeout=self.timeout,
timeout_exc=socket.timeout("timed out"))
def recvfrom(self, *args):
@@ -357,11 +357,11 @@ class GreenPipe(object):
self.fd = fd
self.closed = False
self.recvbuffer = ''
def close(self):
self.fd.close()
self.closed = True
def fileno(self):
return self.fd.fileno()
@@ -419,7 +419,7 @@ class GreenPipe(object):
def flush(self):
pass
def readuntil(self, terminator, size=None):
buf, self.recvbuffer = self.recvbuffer, ''
checked = 0
@@ -449,7 +449,7 @@ class GreenPipe(object):
buf += d
chunk, self.recvbuffer = buf[:size], buf[size:]
return chunk
def readline(self, size=None):
return self.readuntil(self.newlines, size=size)
@@ -484,24 +484,24 @@ except ImportError:
class SSL(object):
class WantWriteError(object):
pass
class WantReadError(object):
pass
class ZeroReturnError(object):
pass
class SysCallError(object):
pass
def shutdown_safe(sock):
""" Shuts down the socket. This is a convenience method for
code that wants to gracefully handle regular sockets, SSL.Connection
code that wants to gracefully handle regular sockets, SSL.Connection
sockets from PyOpenSSL and ssl.SSLSocket objects from Python 2.6
interchangeably. Both types of ssl socket require a shutdown() before
close, but they have different arity on their shutdown method.
Regular sockets don't need a shutdown before close, but it doesn't hurt.
"""
try:
@@ -516,11 +516,11 @@ def shutdown_safe(sock):
# this will often be the case in an http server context
if e[0] != errno.ENOTCONN:
raise
def connect(addr, family=socket.AF_INET, bind=None):
"""Convenience function for opening client sockets.
:param addr: Address of the server to connect to. For TCP sockets, this is a (host, port) tuple.
:param family: Socket family, optional. See :mod:`socket` documentation for available families.
:param bind: Local address to bind to, optional.
@@ -531,14 +531,14 @@ def connect(addr, family=socket.AF_INET, bind=None):
sock.bind(bind)
sock.connect(addr)
return sock
def listen(addr, family=socket.AF_INET, backlog=50):
"""Convenience function for opening server sockets. This
socket can be used in an ``accept()`` loop.
Sets SO_REUSEADDR on the socket to save on annoyance.
:param addr: Address to listen on. For TCP sockets, this is a (host, port) tuple.
:param family: Socket family, optional. See :mod:`socket` documentation for available families.
:param backlog: The maximum number of queued connections. Should be at least 1; the maximum value is system-dependent.
@@ -552,41 +552,40 @@ def listen(addr, family=socket.AF_INET, backlog=50):
def wrap_ssl(sock, keyfile=None, certfile=None, server_side=False,
cert_reqs=None, ssl_version=None, ca_certs=None,
cert_reqs=None, ssl_version=None, ca_certs=None,
do_handshake_on_connect=True, suppress_ragged_eofs=True):
"""Convenience function for converting a regular socket into an SSL
socket. Has the same interface as :func:`ssl.wrap_socket`, but
"""Convenience function for converting a regular socket into an SSL
socket. Has the same interface as :func:`ssl.wrap_socket`, but
works on 2.5 or earlier, using PyOpenSSL.
The preferred idiom is to call wrap_ssl directly on the creation
method, e.g., ``wrap_ssl(connect(addr))`` or
method, e.g., ``wrap_ssl(connect(addr))`` or
``wrap_ssl(listen(addr), server_side=True)``. This way there is
no "naked" socket sitting around to accidentally corrupt the SSL
session.
:return Green SSL object.
"""
pass
def serve(sock, handle, concurrency=1000):
"""Runs a server on the supplied socket. Calls the function
*handle* in a separate greenthread for every incoming request.
This function blocks the calling greenthread; it won't return until
"""Runs a server on the supplied socket. Calls the function
*handle* in a separate greenthread for every incoming request.
This function blocks the calling greenthread; it won't return until
the server completes. If you desire an immediate return,
spawn a new greenthread for :func:`serve`.
The *handle* function must raise an EndServerException to
gracefully terminate the server -- that's the only way to get the
The *handle* function must raise an EndServerException to
gracefully terminate the server -- that's the only way to get the
server() function to return. Any other uncaught exceptions raised
in *handle* are raised as exceptions from :func:`serve`, so be
sure to do a good job catching exceptions that your application
in *handle* are raised as exceptions from :func:`serve`, so be
sure to do a good job catching exceptions that your application
raises. The return value of *handle* is ignored.
The value in *concurrency* controls the maximum number of
greenthreads that will be open at any time handling requests. When
the server hits the concurrency limit, it stops accepting new
The value in *concurrency* controls the maximum number of
greenthreads that will be open at any time handling requests. When
the server hits the concurrency limit, it stops accepting new
connections until the existing ones complete.
"""
pass