(bug 69222) on some recent linux kernels, a socket can return "readable" from select, but a subsequent read() will return EAGAIN. this is against the contract of select(), so python's socketmodule doesn't catch it or handle it. therefore, we need to. EAGAIN should now be treated the same as a socket timeout.
This commit is contained in:
parent
4628a53acf
commit
482d0bcef2
|
@ -20,6 +20,7 @@
|
||||||
Packetizer.
|
Packetizer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import errno
|
||||||
import select
|
import select
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
@ -201,6 +202,7 @@ class Packetizer (object):
|
||||||
if PY22:
|
if PY22:
|
||||||
return self._py22_read_all(n, out)
|
return self._py22_read_all(n, out)
|
||||||
while n > 0:
|
while n > 0:
|
||||||
|
got_timeout = False
|
||||||
try:
|
try:
|
||||||
x = self.__socket.recv(n)
|
x = self.__socket.recv(n)
|
||||||
if len(x) == 0:
|
if len(x) == 0:
|
||||||
|
@ -208,6 +210,16 @@ class Packetizer (object):
|
||||||
out += x
|
out += x
|
||||||
n -= len(x)
|
n -= len(x)
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
|
got_timeout = True
|
||||||
|
except socket.error, e:
|
||||||
|
# on Linux, sometimes instead of socket.timeout, we get
|
||||||
|
# EAGAIN. this is a bug in recent (> 2.6.9) kernels but
|
||||||
|
# we need to work around it.
|
||||||
|
if (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EAGAIN):
|
||||||
|
got_timeout = True
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
if got_timeout:
|
||||||
if self.__closed:
|
if self.__closed:
|
||||||
raise EOFError()
|
raise EOFError()
|
||||||
if check_rekey and (len(out) == 0) and self.__need_rekey:
|
if check_rekey and (len(out) == 0) and self.__need_rekey:
|
||||||
|
@ -218,15 +230,23 @@ class Packetizer (object):
|
||||||
def write_all(self, out):
|
def write_all(self, out):
|
||||||
self.__keepalive_last = time.time()
|
self.__keepalive_last = time.time()
|
||||||
while len(out) > 0:
|
while len(out) > 0:
|
||||||
|
got_timeout = False
|
||||||
try:
|
try:
|
||||||
n = self.__socket.send(out)
|
n = self.__socket.send(out)
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
n = 0
|
got_timeout = True
|
||||||
if self.__closed:
|
except socket.error, e:
|
||||||
|
if (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EAGAIN):
|
||||||
|
got_timeout = True
|
||||||
|
else:
|
||||||
n = -1
|
n = -1
|
||||||
except Exception:
|
except Exception:
|
||||||
# could be: (32, 'Broken pipe')
|
# could be: (32, 'Broken pipe')
|
||||||
n = -1
|
n = -1
|
||||||
|
if got_timeout:
|
||||||
|
n = 0
|
||||||
|
if self.__closed:
|
||||||
|
n = -1
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise EOFError()
|
raise EOFError()
|
||||||
if n == len(out):
|
if n == len(out):
|
||||||
|
|
Loading…
Reference in New Issue