1
Description: If an operation times out, try one last time.
2
This addresses a problem where a timeout fires even though the
3
connection was actually correctly established.
4
Origin: Chris Behrens, https://bitbucket-assetroot.s3.amazonaws.com/which_linden/eventlet/20110601/87/eventlet-socket-timeout.diff
5
Bug: https://bitbucket.org/which_linden/eventlet/issue/87/socket-connects-are-incorrectly-reported
6
Bug-Ubuntu: https://launchpad.net/bugs/771512
7
Reviewed-By: Soren Hansen <soren@ubuntu.com>
8
Last-Update: 2011-06-01
10
--- a/eventlet/greenio.py
11
+++ b/eventlet/greenio.py
14
if time.time() >= end:
15
raise socket.timeout("timed out")
16
- trampoline(fd, write=True, timeout=end-time.time(),
17
- timeout_exc=socket.timeout("timed out"))
19
+ trampoline(fd, write=True, timeout=end-time.time(),
20
+ timeout_exc=socket.timeout("timed out"))
21
+ except socket.timeout, e:
23
+ if socket_connect(fd, address):
30
def connect_ex(self, address):
33
if time.time() >= end:
34
raise socket.timeout(errno.EAGAIN)
35
- trampoline(fd, write=True, timeout=end-time.time(),
36
- timeout_exc=socket.timeout(errno.EAGAIN))
38
+ trampoline(fd, write=True, timeout=end-time.time(),
39
+ timeout_exc=socket.timeout(errno.EAGAIN))
40
+ except socket.timeout, e:
42
+ if socket_connect(fd, address):
48
except socket.error, ex:
51
"makefile instead", DeprecationWarning, stacklevel=2)
52
return self.makefile(*args, **kw)
54
- def recv(self, buflen, flags=0):
56
+ def _read_io(self, fd, f, *args, **kwargs):
57
if self.act_non_blocking:
58
- return fd.recv(buflen, flags)
59
+ return f(*args, **kwargs)
62
- return fd.recv(buflen, flags)
63
+ return f(*args, **kwargs)
64
except socket.error, e:
65
if get_errno(e) in SOCKET_BLOCKING:
67
- elif get_errno(e) in SOCKET_CLOSED:
68
+ # XXX -- Why does recv() do this?
69
+ elif f == fd.recv and get_errno(e) in SOCKET_CLOSED:
75
- timeout=self.gettimeout(),
76
- timeout_exc=socket.timeout("timed out"))
80
+ timeout=self.gettimeout(),
81
+ timeout_exc=socket.timeout("timed out"))
82
+ except socket.timeout, e:
83
+ # Try one last time to see if the timeout is 'real'
85
+ return f(*args, **kwargs)
89
+ def recv(self, buflen, flags=0):
90
+ return self._read_io(self.fd, self.fd.recv, buflen, flags)
92
def recvfrom(self, *args):
93
- if not self.act_non_blocking:
94
- trampoline(self.fd, read=True, timeout=self.gettimeout(),
95
- timeout_exc=socket.timeout("timed out"))
96
- return self.fd.recvfrom(*args)
97
+ return self._read_io(self.fd, self.fd.recvfrom, *args)
99
def recvfrom_into(self, *args):
100
- if not self.act_non_blocking:
101
- trampoline(self.fd, read=True, timeout=self.gettimeout(),
102
- timeout_exc=socket.timeout("timed out"))
103
- return self.fd.recvfrom_into(*args)
104
+ return self._read_io(self.fd, self.fd.recvfrom_into, *args)
106
def recv_into(self, *args):
107
- if not self.act_non_blocking:
108
- trampoline(self.fd, read=True, timeout=self.gettimeout(),
109
- timeout_exc=socket.timeout("timed out"))
110
- return self.fd.recv_into(*args)
111
+ return self._read_io(self.fd, self.fd.recv_into, *args)
113
def send(self, data, flags=0):
122
total_sent += fd.send(data[total_sent:], flags)
123
except socket.error, e:
125
if total_sent == len_data:
128
- trampoline(self.fd, write=True, timeout=self.gettimeout(),
129
- timeout_exc=socket.timeout("timed out"))
131
+ trampoline(fd, write=True, timeout=self.gettimeout(),
132
+ timeout_exc=socket.timeout("timed out"))
133
+ except socket.timeout, e:
134
+ # Try one last time to see if the timeout is 'real'
136
+ total_sent += fd.send(data[total_sent:], flags)
143
tail += self.send(data[tail:], flags)
145
def sendto(self, *args):
146
- trampoline(self.fd, write=True)
147
- return self.fd.sendto(*args)
149
+ if self.act_non_blocking:
150
+ return fd.sendto(*args)
153
+ return fd.sendto(*args)
154
+ except socket.error, e:
155
+ if get_errno(e) in SOCKET_BLOCKING:
160
+ trampoline(fd, write=True, timeout=self.gettimeout(),
161
+ timeout_exc=socket.timeout("timed out"))
162
+ except socket.timeout, e:
163
+ # Try one last time to see if the timeout is 'real'
165
+ return fd.sendto(*args)
169
def setblocking(self, flag):
171
--- a/tests/greenio_test.py
172
+++ b/tests/greenio_test.py
174
self.assertEqual(e.args[0], 'timed out')
176
def test_recvfrom_into_timeout(self):
177
- buf = buffer(array.array('B'))
178
+ buf = array.array('B')
179
+ buf.fromstring('\0')
181
gs = greenio.GreenSocket(
182
socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
184
self.assertEqual(e.args[0], 'timed out')
186
def test_recv_into_timeout(self):
187
- buf = buffer(array.array('B'))
188
+ buf = array.array('B')
189
+ buf.fromstring('\0')
191
listener = greenio.GreenSocket(socket.socket())
192
listener.bind(('', 0))