135 lines
4.0 KiB
Python
135 lines
4.0 KiB
Python
|
"""
|
||
|
SocketIO imported from socket module in Python 3.
|
||
|
|
||
|
Copyright (c) 2001-2013 Python Software Foundation; All Rights Reserved.
|
||
|
"""
|
||
|
|
||
|
from socket import *
|
||
|
import io
|
||
|
import errno
|
||
|
|
||
|
__all__ = ['SocketIO']
|
||
|
|
||
|
EINTR = errno.EINTR
|
||
|
_blocking_errnos = (errno.EAGAIN, errno.EWOULDBLOCK)
|
||
|
|
||
|
class SocketIO(io.RawIOBase):
|
||
|
|
||
|
"""Raw I/O implementation for stream sockets.
|
||
|
|
||
|
This class supports the makefile() method on sockets. It provides
|
||
|
the raw I/O interface on top of a socket object.
|
||
|
"""
|
||
|
|
||
|
# One might wonder why not let FileIO do the job instead. There are two
|
||
|
# main reasons why FileIO is not adapted:
|
||
|
# - it wouldn't work under Windows (where you can't used read() and
|
||
|
# write() on a socket handle)
|
||
|
# - it wouldn't work with socket timeouts (FileIO would ignore the
|
||
|
# timeout and consider the socket non-blocking)
|
||
|
|
||
|
# XXX More docs
|
||
|
|
||
|
def __init__(self, sock, mode):
|
||
|
if mode not in ("r", "w", "rw", "rb", "wb", "rwb"):
|
||
|
raise ValueError("invalid mode: %r" % mode)
|
||
|
io.RawIOBase.__init__(self)
|
||
|
self._sock = sock
|
||
|
if "b" not in mode:
|
||
|
mode += "b"
|
||
|
self._mode = mode
|
||
|
self._reading = "r" in mode
|
||
|
self._writing = "w" in mode
|
||
|
self._timeout_occurred = False
|
||
|
|
||
|
def readinto(self, b):
|
||
|
"""Read up to len(b) bytes into the writable buffer *b* and return
|
||
|
the number of bytes read. If the socket is non-blocking and no bytes
|
||
|
are available, None is returned.
|
||
|
|
||
|
If *b* is non-empty, a 0 return value indicates that the connection
|
||
|
was shutdown at the other end.
|
||
|
"""
|
||
|
self._checkClosed()
|
||
|
self._checkReadable()
|
||
|
if self._timeout_occurred:
|
||
|
raise IOError("cannot read from timed out object")
|
||
|
while True:
|
||
|
try:
|
||
|
return self._sock.recv_into(b)
|
||
|
except timeout:
|
||
|
self._timeout_occurred = True
|
||
|
raise
|
||
|
except error as e:
|
||
|
n = e.args[0]
|
||
|
if n == EINTR:
|
||
|
continue
|
||
|
if n in _blocking_errnos:
|
||
|
return None
|
||
|
raise
|
||
|
|
||
|
def write(self, b):
|
||
|
"""Write the given bytes or bytearray object *b* to the socket
|
||
|
and return the number of bytes written. This can be less than
|
||
|
len(b) if not all data could be written. If the socket is
|
||
|
non-blocking and no bytes could be written None is returned.
|
||
|
"""
|
||
|
self._checkClosed()
|
||
|
self._checkWritable()
|
||
|
try:
|
||
|
return self._sock.send(b)
|
||
|
except error as e:
|
||
|
# XXX what about EINTR?
|
||
|
if e.args[0] in _blocking_errnos:
|
||
|
return None
|
||
|
raise
|
||
|
|
||
|
def readable(self):
|
||
|
"""True if the SocketIO is open for reading.
|
||
|
"""
|
||
|
if self.closed:
|
||
|
raise ValueError("I/O operation on closed socket.")
|
||
|
return self._reading
|
||
|
|
||
|
def writable(self):
|
||
|
"""True if the SocketIO is open for writing.
|
||
|
"""
|
||
|
if self.closed:
|
||
|
raise ValueError("I/O operation on closed socket.")
|
||
|
return self._writing
|
||
|
|
||
|
def seekable(self):
|
||
|
"""True if the SocketIO is open for seeking.
|
||
|
"""
|
||
|
if self.closed:
|
||
|
raise ValueError("I/O operation on closed socket.")
|
||
|
return super().seekable()
|
||
|
|
||
|
def fileno(self):
|
||
|
"""Return the file descriptor of the underlying socket.
|
||
|
"""
|
||
|
self._checkClosed()
|
||
|
return self._sock.fileno()
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
if not self.closed:
|
||
|
return self.fileno()
|
||
|
else:
|
||
|
return -1
|
||
|
|
||
|
@property
|
||
|
def mode(self):
|
||
|
return self._mode
|
||
|
|
||
|
def close(self):
|
||
|
"""Close the SocketIO object. This doesn't close the underlying
|
||
|
socket, except if all references to it have disappeared.
|
||
|
"""
|
||
|
if self.closed:
|
||
|
return
|
||
|
io.RawIOBase.close(self)
|
||
|
self._sock._decref_socketios()
|
||
|
self._sock = None
|
||
|
|