(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:
Robey Pointer 2006-10-31 14:37:47 -08:00
parent 4628a53acf
commit 482d0bcef2
1 changed files with 22 additions and 2 deletions

View File

@ -20,6 +20,7 @@
Packetizer.
"""
import errno
import select
import socket
import struct
@ -201,6 +202,7 @@ class Packetizer (object):
if PY22:
return self._py22_read_all(n, out)
while n > 0:
got_timeout = False
try:
x = self.__socket.recv(n)
if len(x) == 0:
@ -208,6 +210,16 @@ class Packetizer (object):
out += x
n -= len(x)
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:
raise EOFError()
if check_rekey and (len(out) == 0) and self.__need_rekey:
@ -218,15 +230,23 @@ class Packetizer (object):
def write_all(self, out):
self.__keepalive_last = time.time()
while len(out) > 0:
got_timeout = False
try:
n = self.__socket.send(out)
except socket.timeout:
n = 0
if self.__closed:
got_timeout = True
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
except Exception:
# could be: (32, 'Broken pipe')
n = -1
if got_timeout:
n = 0
if self.__closed:
n = -1
if n < 0:
raise EOFError()
if n == len(out):