summaryrefslogtreecommitdiffstats
path: root/Lib/socket.py
diff options
context:
space:
mode:
authorGregory P. Smith <greg@mad-scientist.com>2009-08-13 18:54:50 (GMT)
committerGregory P. Smith <greg@mad-scientist.com>2009-08-13 18:54:50 (GMT)
commitc4ad0345cf7789dc432ff57ab644db230d8baf1c (patch)
tree984552a9edaf0637ce702e8ffbf07029cac53e8d /Lib/socket.py
parentaa66a968d4842c7dca0063c27520162d96fd7fe7 (diff)
downloadcpython-c4ad0345cf7789dc432ff57ab644db230d8baf1c.zip
cpython-c4ad0345cf7789dc432ff57ab644db230d8baf1c.tar.gz
cpython-c4ad0345cf7789dc432ff57ab644db230d8baf1c.tar.bz2
Fix issue1628205: Socket file objects returned by socket.socket.makefile() now
properly handles EINTR within the read, readline, write & flush methods. The socket.sendall() method now properly handles interrupted system calls.
Diffstat (limited to 'Lib/socket.py')
-rw-r--r--Lib/socket.py69
1 files changed, 56 insertions, 13 deletions
diff --git a/Lib/socket.py b/Lib/socket.py
index dd0f327..a1e0386 100644
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -86,9 +86,11 @@ except ImportError:
from StringIO import StringIO
try:
- from errno import EBADF
+ import errno
except ImportError:
- EBADF = 9
+ errno = None
+EBADF = getattr(errno, 'EBADF', 9)
+EINTR = getattr(errno, 'EINTR', 4)
__all__ = ["getfqdn", "create_connection"]
__all__.extend(os._get_exports_list(_socket))
@@ -286,10 +288,22 @@ class _fileobject(object):
def flush(self):
if self._wbuf:
- buffer = "".join(self._wbuf)
+ data = "".join(self._wbuf)
self._wbuf = []
self._wbuf_len = 0
- self._sock.sendall(buffer)
+ buffer_size = max(self._rbufsize, self.default_bufsize)
+ data_size = len(data)
+ write_offset = 0
+ try:
+ while write_offset < data_size:
+ self._sock.sendall(buffer(data, write_offset, buffer_size))
+ write_offset += buffer_size
+ finally:
+ if write_offset < data_size:
+ remainder = data[write_offset:]
+ del data # explicit free
+ self._wbuf.append(remainder)
+ self._wbuf_len = len(remainder)
def fileno(self):
return self._sock.fileno()
@@ -329,7 +343,12 @@ class _fileobject(object):
# Read until EOF
self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
while True:
- data = self._sock.recv(rbufsize)
+ try:
+ data = self._sock.recv(rbufsize)
+ except error, e:
+ if e[0] == EINTR:
+ continue
+ raise
if not data:
break
buf.write(data)
@@ -353,7 +372,12 @@ class _fileobject(object):
# than that. The returned data string is short lived
# as we copy it into a StringIO and free it. This avoids
# fragmentation issues on many platforms.
- data = self._sock.recv(left)
+ try:
+ data = self._sock.recv(left)
+ except error, e:
+ if e[0] == EINTR:
+ continue
+ raise
if not data:
break
n = len(data)
@@ -396,17 +420,31 @@ class _fileobject(object):
self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
data = None
recv = self._sock.recv
- while data != "\n":
- data = recv(1)
- if not data:
- break
- buffers.append(data)
+ while True:
+ try:
+ while data != "\n":
+ data = recv(1)
+ if not data:
+ break
+ buffers.append(data)
+ except error, e:
+ # The try..except to catch EINTR was moved outside the
+ # recv loop to avoid the per byte overhead.
+ if e[0] == EINTR:
+ continue
+ raise
+ break
return "".join(buffers)
buf.seek(0, 2) # seek end
self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
while True:
- data = self._sock.recv(self._rbufsize)
+ try:
+ data = self._sock.recv(self._rbufsize)
+ except error, e:
+ if e[0] == EINTR:
+ continue
+ raise
if not data:
break
nl = data.find('\n')
@@ -430,7 +468,12 @@ class _fileobject(object):
return rv
self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
while True:
- data = self._sock.recv(self._rbufsize)
+ try:
+ data = self._sock.recv(self._rbufsize)
+ except error, e:
+ if e[0] == EINTR:
+ continue
+ raise
if not data:
break
left = size - buf_len