You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
757 lines
28 KiB
757 lines
28 KiB
5 years ago
|
# Port of Python 3.3's socket module to gevent
|
||
|
"""
|
||
|
Python 3 socket module.
|
||
|
"""
|
||
|
# Our import magic sadly makes this warning useless
|
||
|
# pylint: disable=undefined-variable
|
||
|
# pylint: disable=too-many-statements,too-many-branches
|
||
|
# pylint: disable=too-many-public-methods,unused-argument
|
||
|
from __future__ import absolute_import
|
||
|
import io
|
||
|
import os
|
||
|
import sys
|
||
|
|
||
|
from gevent import _socketcommon
|
||
|
from gevent._util import copy_globals
|
||
|
from gevent._compat import PYPY
|
||
|
from gevent.timeout import Timeout
|
||
|
import _socket
|
||
|
from os import dup
|
||
|
|
||
|
|
||
|
copy_globals(_socketcommon, globals(),
|
||
|
names_to_ignore=_socketcommon.__extensions__,
|
||
|
dunder_names_to_keep=())
|
||
|
|
||
|
try:
|
||
|
from errno import EHOSTUNREACH
|
||
|
from errno import ECONNREFUSED
|
||
|
except ImportError:
|
||
|
EHOSTUNREACH = -1
|
||
|
ECONNREFUSED = -1
|
||
|
|
||
|
|
||
|
__socket__ = _socketcommon.__socket__
|
||
|
__implements__ = _socketcommon._implements
|
||
|
__extensions__ = _socketcommon.__extensions__
|
||
|
__imports__ = _socketcommon.__imports__
|
||
|
__dns__ = _socketcommon.__dns__
|
||
|
|
||
|
|
||
|
SocketIO = __socket__.SocketIO # pylint:disable=no-member
|
||
|
|
||
|
|
||
|
def _get_memory(data):
|
||
|
mv = memoryview(data)
|
||
|
if mv.shape:
|
||
|
return mv
|
||
|
# No shape, probably working with a ctypes object,
|
||
|
# or something else exotic that supports the buffer interface
|
||
|
return mv.tobytes()
|
||
|
|
||
|
timeout_default = object()
|
||
|
|
||
|
|
||
|
class _wrefsocket(_socket.socket):
|
||
|
# Plain stdlib socket.socket objects subclass _socket.socket
|
||
|
# and add weakref ability. The ssl module, for one, counts on this.
|
||
|
# We don't create socket.socket objects (because they may have been
|
||
|
# monkey patched to be the object from this module), but we still
|
||
|
# need to make sure what we do create can be weakrefd.
|
||
|
|
||
|
__slots__ = ("__weakref__", )
|
||
|
|
||
|
if PYPY:
|
||
|
# server.py unwraps the socket object to get the raw _sock;
|
||
|
# it depends on having a timeout property alias, which PyPy does not
|
||
|
# provide.
|
||
|
timeout = property(lambda s: s.gettimeout(),
|
||
|
lambda s, nv: s.settimeout(nv))
|
||
|
|
||
|
from gevent._hub_primitives import wait_on_socket as _wait_on_socket
|
||
|
|
||
|
class socket(object):
|
||
|
"""
|
||
|
gevent `socket.socket <https://docs.python.org/3/library/socket.html#socket-objects>`_
|
||
|
for Python 3.
|
||
|
|
||
|
This object should have the same API as the standard library socket linked to above. Not all
|
||
|
methods are specifically documented here; when they are they may point out a difference
|
||
|
to be aware of or may document a method the standard library does not.
|
||
|
"""
|
||
|
|
||
|
# Subclasses can set this to customize the type of the
|
||
|
# native _socket.socket we create. It MUST be a subclass
|
||
|
# of _wrefsocket. (gevent internal usage only)
|
||
|
_gevent_sock_class = _wrefsocket
|
||
|
|
||
|
_io_refs = 0
|
||
|
_closed = False
|
||
|
_read_event = None
|
||
|
_write_event = None
|
||
|
|
||
|
|
||
|
# Take the same approach as socket2: wrap a real socket object,
|
||
|
# don't subclass it. This lets code that needs the raw _sock (not tied to the hub)
|
||
|
# get it. This shows up in tests like test__example_udp_server.
|
||
|
|
||
|
if sys.version_info[:2] < (3, 7):
|
||
|
def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
|
||
|
self._sock = self._gevent_sock_class(family, type, proto, fileno)
|
||
|
self.timeout = None
|
||
|
self.__init_common()
|
||
|
else:
|
||
|
# In 3.7, socket changed to auto-detecting family, type, and proto
|
||
|
# when given a fileno.
|
||
|
def __init__(self, family=-1, type=-1, proto=-1, fileno=None):
|
||
|
if fileno is None:
|
||
|
if family == -1:
|
||
|
family = AF_INET
|
||
|
if type == -1:
|
||
|
type = SOCK_STREAM
|
||
|
if proto == -1:
|
||
|
proto = 0
|
||
|
self._sock = self._gevent_sock_class(family, type, proto, fileno)
|
||
|
self.timeout = None
|
||
|
self.__init_common()
|
||
|
|
||
|
def __init_common(self):
|
||
|
_socket.socket.setblocking(self._sock, False)
|
||
|
fileno = _socket.socket.fileno(self._sock)
|
||
|
self.hub = get_hub()
|
||
|
io_class = self.hub.loop.io
|
||
|
self._read_event = io_class(fileno, 1)
|
||
|
self._write_event = io_class(fileno, 2)
|
||
|
self.timeout = _socket.getdefaulttimeout()
|
||
|
|
||
|
def __getattr__(self, name):
|
||
|
return getattr(self._sock, name)
|
||
|
|
||
|
if hasattr(_socket, 'SOCK_NONBLOCK'):
|
||
|
# Only defined under Linux
|
||
|
@property
|
||
|
def type(self):
|
||
|
# See https://github.com/gevent/gevent/pull/399
|
||
|
if self.timeout != 0.0:
|
||
|
return self._sock.type & ~_socket.SOCK_NONBLOCK # pylint:disable=no-member
|
||
|
return self._sock.type
|
||
|
|
||
|
def getblocking(self):
|
||
|
"""
|
||
|
Returns whether the socket will approximate blocking
|
||
|
behaviour.
|
||
|
|
||
|
.. versionadded:: 1.3a2
|
||
|
Added in Python 3.7.
|
||
|
"""
|
||
|
return self.timeout != 0.0
|
||
|
|
||
|
def __enter__(self):
|
||
|
return self
|
||
|
|
||
|
def __exit__(self, *args):
|
||
|
if not self._closed:
|
||
|
self.close()
|
||
|
|
||
|
def __repr__(self):
|
||
|
"""Wrap __repr__() to reveal the real class name."""
|
||
|
try:
|
||
|
s = _socket.socket.__repr__(self._sock)
|
||
|
except Exception as ex: # pylint:disable=broad-except
|
||
|
# Observed on Windows Py3.3, printing the repr of a socket
|
||
|
# that just suffered a ConnectionResetError [WinError 10054]:
|
||
|
# "OverflowError: no printf formatter to display the socket descriptor in decimal"
|
||
|
# Not sure what the actual cause is or if there's a better way to handle this
|
||
|
s = '<socket [%r]>' % ex
|
||
|
|
||
|
if s.startswith("<socket object"):
|
||
|
s = "<%s.%s%s%s" % (self.__class__.__module__,
|
||
|
self.__class__.__name__,
|
||
|
getattr(self, '_closed', False) and " [closed] " or "",
|
||
|
s[7:])
|
||
|
return s
|
||
|
|
||
|
def __getstate__(self):
|
||
|
raise TypeError("Cannot serialize socket object")
|
||
|
|
||
|
def _get_ref(self):
|
||
|
return self._read_event.ref or self._write_event.ref
|
||
|
|
||
|
def _set_ref(self, value):
|
||
|
self._read_event.ref = value
|
||
|
self._write_event.ref = value
|
||
|
|
||
|
ref = property(_get_ref, _set_ref)
|
||
|
|
||
|
_wait = _wait_on_socket
|
||
|
|
||
|
def dup(self):
|
||
|
"""dup() -> socket object
|
||
|
|
||
|
Return a new socket object connected to the same system resource.
|
||
|
"""
|
||
|
fd = dup(self.fileno())
|
||
|
sock = self.__class__(self.family, self.type, self.proto, fileno=fd)
|
||
|
sock.settimeout(self.gettimeout())
|
||
|
return sock
|
||
|
|
||
|
def accept(self):
|
||
|
"""accept() -> (socket object, address info)
|
||
|
|
||
|
Wait for an incoming connection. Return a new socket
|
||
|
representing the connection, and the address of the client.
|
||
|
For IP sockets, the address info is a pair (hostaddr, port).
|
||
|
"""
|
||
|
while True:
|
||
|
try:
|
||
|
fd, addr = self._accept()
|
||
|
break
|
||
|
except BlockingIOError:
|
||
|
if self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._read_event)
|
||
|
sock = socket(self.family, self.type, self.proto, fileno=fd)
|
||
|
# Python Issue #7995: if no default timeout is set and the listening
|
||
|
# socket had a (non-zero) timeout, force the new socket in blocking
|
||
|
# mode to override platform-specific socket flags inheritance.
|
||
|
# XXX do we need to do this?
|
||
|
if getdefaulttimeout() is None and self.gettimeout():
|
||
|
sock.setblocking(True)
|
||
|
return sock, addr
|
||
|
|
||
|
def makefile(self, mode="r", buffering=None, *,
|
||
|
encoding=None, errors=None, newline=None):
|
||
|
"""Return an I/O stream connected to the socket
|
||
|
|
||
|
The arguments are as for io.open() after the filename,
|
||
|
except the only mode characters supported are 'r', 'w' and 'b'.
|
||
|
The semantics are similar too.
|
||
|
"""
|
||
|
# (XXX refactor to share code?)
|
||
|
for c in mode:
|
||
|
if c not in {"r", "w", "b"}:
|
||
|
raise ValueError("invalid mode %r (only r, w, b allowed)")
|
||
|
writing = "w" in mode
|
||
|
reading = "r" in mode or not writing
|
||
|
assert reading or writing
|
||
|
binary = "b" in mode
|
||
|
rawmode = ""
|
||
|
if reading:
|
||
|
rawmode += "r"
|
||
|
if writing:
|
||
|
rawmode += "w"
|
||
|
raw = SocketIO(self, rawmode)
|
||
|
self._io_refs += 1
|
||
|
if buffering is None:
|
||
|
buffering = -1
|
||
|
if buffering < 0:
|
||
|
buffering = io.DEFAULT_BUFFER_SIZE
|
||
|
if buffering == 0:
|
||
|
if not binary:
|
||
|
raise ValueError("unbuffered streams must be binary")
|
||
|
return raw
|
||
|
if reading and writing:
|
||
|
buffer = io.BufferedRWPair(raw, raw, buffering)
|
||
|
elif reading:
|
||
|
buffer = io.BufferedReader(raw, buffering)
|
||
|
else:
|
||
|
assert writing
|
||
|
buffer = io.BufferedWriter(raw, buffering)
|
||
|
if binary:
|
||
|
return buffer
|
||
|
text = io.TextIOWrapper(buffer, encoding, errors, newline)
|
||
|
text.mode = mode
|
||
|
return text
|
||
|
|
||
|
def _decref_socketios(self):
|
||
|
# Called by SocketIO when it is closed.
|
||
|
if self._io_refs > 0:
|
||
|
self._io_refs -= 1
|
||
|
if self._closed:
|
||
|
self.close()
|
||
|
|
||
|
def _drop_events(self):
|
||
|
if self._read_event is not None:
|
||
|
self.hub.cancel_wait(self._read_event, cancel_wait_ex, True)
|
||
|
self._read_event = None
|
||
|
if self._write_event is not None:
|
||
|
self.hub.cancel_wait(self._write_event, cancel_wait_ex, True)
|
||
|
self._write_event = None
|
||
|
|
||
|
def _real_close(self, _ss=_socket.socket, cancel_wait_ex=cancel_wait_ex):
|
||
|
# This function should not reference any globals. See Python issue #808164.
|
||
|
|
||
|
# Break any reference to the loop.io objects. Our fileno,
|
||
|
# which they were tied to, is now free to be reused, so these
|
||
|
# objects are no longer functional.
|
||
|
self._drop_events()
|
||
|
|
||
|
_ss.close(self._sock)
|
||
|
|
||
|
# Break any references to the underlying socket object. Tested
|
||
|
# by test__refcount. (Why does this matter?). Be sure to
|
||
|
# preserve our same family/type/proto if possible (if we
|
||
|
# don't, we can get TypeError instead of OSError; see
|
||
|
# test_socket.SendmsgUDP6Test.testSendmsgAfterClose)... but
|
||
|
# this isn't always possible (see test_socket.test_unknown_socket_family_repr)
|
||
|
# TODO: Can we use a simpler proxy, like _socket2 does?
|
||
|
try:
|
||
|
self._sock = self._gevent_sock_class(self.family, self.type, self.proto)
|
||
|
except OSError:
|
||
|
pass
|
||
|
else:
|
||
|
_ss.close(self._sock)
|
||
|
|
||
|
|
||
|
def close(self):
|
||
|
# This function should not reference any globals. See Python issue #808164.
|
||
|
self._closed = True
|
||
|
if self._io_refs <= 0:
|
||
|
self._real_close()
|
||
|
|
||
|
@property
|
||
|
def closed(self):
|
||
|
return self._closed
|
||
|
|
||
|
def detach(self):
|
||
|
"""detach() -> file descriptor
|
||
|
|
||
|
Close the socket object without closing the underlying file descriptor.
|
||
|
The object cannot be used after this call, but the file descriptor
|
||
|
can be reused for other purposes. The file descriptor is returned.
|
||
|
"""
|
||
|
self._closed = True
|
||
|
return self._sock.detach()
|
||
|
|
||
|
def connect(self, address):
|
||
|
if self.timeout == 0.0:
|
||
|
return _socket.socket.connect(self._sock, address)
|
||
|
address = _socketcommon._resolve_addr(self._sock, address)
|
||
|
|
||
|
with Timeout._start_new_or_dummy(self.timeout, timeout("timed out")):
|
||
|
while True:
|
||
|
err = self.getsockopt(SOL_SOCKET, SO_ERROR)
|
||
|
if err:
|
||
|
raise error(err, strerror(err))
|
||
|
result = _socket.socket.connect_ex(self._sock, address)
|
||
|
|
||
|
if not result or result == EISCONN:
|
||
|
break
|
||
|
elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows):
|
||
|
self._wait(self._write_event)
|
||
|
else:
|
||
|
if (isinstance(address, tuple)
|
||
|
and address[0] == 'fe80::1'
|
||
|
and result == EHOSTUNREACH):
|
||
|
# On Python 3.7 on mac, we see EHOSTUNREACH
|
||
|
# returned for this link-local address, but it really is
|
||
|
# supposed to be ECONNREFUSED according to the standard library
|
||
|
# tests (test_socket.NetworkConnectionNoServer.test_create_connection)
|
||
|
# (On previous versions, that code passed the '127.0.0.1' IPv4 address, so
|
||
|
# ipv6 link locals were never a factor; 3.7 passes 'localhost'.)
|
||
|
# It is something of a mystery how the stdlib socket code doesn't
|
||
|
# produce EHOSTUNREACH---I (JAM) can't see how socketmodule.c would avoid
|
||
|
# that. The normal connect just calls connect_ex much like we do.
|
||
|
result = ECONNREFUSED
|
||
|
raise error(result, strerror(result))
|
||
|
|
||
|
def connect_ex(self, address):
|
||
|
try:
|
||
|
return self.connect(address) or 0
|
||
|
except timeout:
|
||
|
return EAGAIN
|
||
|
except gaierror: # pylint:disable=try-except-raise
|
||
|
# gaierror/overflowerror/typerror is not silenced by connect_ex;
|
||
|
# gaierror extends OSError (aka error) so catch it first
|
||
|
raise
|
||
|
except error as ex:
|
||
|
# error is now OSError and it has various subclasses.
|
||
|
# Only those that apply to actually connecting are silenced by
|
||
|
# connect_ex.
|
||
|
if ex.errno:
|
||
|
return ex.errno
|
||
|
raise # pragma: no cover
|
||
|
|
||
|
def recv(self, *args):
|
||
|
while True:
|
||
|
try:
|
||
|
return _socket.socket.recv(self._sock, *args)
|
||
|
except error as ex:
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._read_event)
|
||
|
|
||
|
if hasattr(_socket.socket, 'recvmsg'):
|
||
|
# Only on Unix; PyPy 3.5 5.10.0 provides sendmsg and recvmsg, but not
|
||
|
# recvmsg_into (at least on os x)
|
||
|
|
||
|
def recvmsg(self, *args):
|
||
|
while True:
|
||
|
try:
|
||
|
return _socket.socket.recvmsg(self._sock, *args)
|
||
|
except error as ex:
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._read_event)
|
||
|
|
||
|
if hasattr(_socket.socket, 'recvmsg_into'):
|
||
|
|
||
|
def recvmsg_into(self, *args):
|
||
|
while True:
|
||
|
try:
|
||
|
return _socket.socket.recvmsg_into(self._sock, *args)
|
||
|
except error as ex:
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._read_event)
|
||
|
|
||
|
def recvfrom(self, *args):
|
||
|
while True:
|
||
|
try:
|
||
|
return _socket.socket.recvfrom(self._sock, *args)
|
||
|
except error as ex:
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._read_event)
|
||
|
|
||
|
def recvfrom_into(self, *args):
|
||
|
while True:
|
||
|
try:
|
||
|
return _socket.socket.recvfrom_into(self._sock, *args)
|
||
|
except error as ex:
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._read_event)
|
||
|
|
||
|
def recv_into(self, *args):
|
||
|
while True:
|
||
|
try:
|
||
|
return _socket.socket.recv_into(self._sock, *args)
|
||
|
except error as ex:
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._read_event)
|
||
|
|
||
|
def send(self, data, flags=0, timeout=timeout_default):
|
||
|
if timeout is timeout_default:
|
||
|
timeout = self.timeout
|
||
|
try:
|
||
|
return _socket.socket.send(self._sock, data, flags)
|
||
|
except error as ex:
|
||
|
if ex.args[0] not in _socketcommon.GSENDAGAIN or timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._write_event)
|
||
|
try:
|
||
|
return _socket.socket.send(self._sock, data, flags)
|
||
|
except error as ex2:
|
||
|
if ex2.args[0] == EWOULDBLOCK:
|
||
|
return 0
|
||
|
raise
|
||
|
|
||
|
def sendall(self, data, flags=0):
|
||
|
# XXX Now that we run on PyPy3, see the notes in _socket2.py's sendall()
|
||
|
# and implement that here if needed.
|
||
|
# PyPy3 is not optimized for performance yet, and is known to be slower than
|
||
|
# PyPy2, so it's possibly premature to do this. However, there is a 3.5 test case that
|
||
|
# possibly exposes this in a severe way.
|
||
|
data_memory = _get_memory(data)
|
||
|
return _socketcommon._sendall(self, data_memory, flags)
|
||
|
|
||
|
def sendto(self, *args):
|
||
|
try:
|
||
|
return _socket.socket.sendto(self._sock, *args)
|
||
|
except error as ex:
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._write_event)
|
||
|
try:
|
||
|
return _socket.socket.sendto(self._sock, *args)
|
||
|
except error as ex2:
|
||
|
if ex2.args[0] == EWOULDBLOCK:
|
||
|
return 0
|
||
|
raise
|
||
|
|
||
|
if hasattr(_socket.socket, 'sendmsg'):
|
||
|
# Only on Unix
|
||
|
def sendmsg(self, buffers, ancdata=(), flags=0, address=None):
|
||
|
try:
|
||
|
return _socket.socket.sendmsg(self._sock, buffers, ancdata, flags, address)
|
||
|
except error as ex:
|
||
|
if flags & getattr(_socket, 'MSG_DONTWAIT', 0):
|
||
|
# Enable non-blocking behaviour
|
||
|
# XXX: Do all platforms that have sendmsg have MSG_DONTWAIT?
|
||
|
raise
|
||
|
|
||
|
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
|
||
|
raise
|
||
|
self._wait(self._write_event)
|
||
|
try:
|
||
|
return _socket.socket.sendmsg(self._sock, buffers, ancdata, flags, address)
|
||
|
except error as ex2:
|
||
|
if ex2.args[0] == EWOULDBLOCK:
|
||
|
return 0
|
||
|
raise
|
||
|
|
||
|
def setblocking(self, flag):
|
||
|
# Beginning in 3.6.0b3 this is supposed to raise
|
||
|
# if the file descriptor is closed, but the test for it
|
||
|
# involves closing the fileno directly. Since we
|
||
|
# don't touch the fileno here, it doesn't make sense for
|
||
|
# us.
|
||
|
if flag:
|
||
|
self.timeout = None
|
||
|
else:
|
||
|
self.timeout = 0.0
|
||
|
|
||
|
def settimeout(self, howlong):
|
||
|
if howlong is not None:
|
||
|
try:
|
||
|
f = howlong.__float__
|
||
|
except AttributeError:
|
||
|
raise TypeError('a float is required')
|
||
|
howlong = f()
|
||
|
if howlong < 0.0:
|
||
|
raise ValueError('Timeout value out of range')
|
||
|
self.__dict__['timeout'] = howlong
|
||
|
|
||
|
def gettimeout(self):
|
||
|
return self.__dict__['timeout']
|
||
|
|
||
|
def shutdown(self, how):
|
||
|
if how == 0: # SHUT_RD
|
||
|
self.hub.cancel_wait(self._read_event, cancel_wait_ex)
|
||
|
elif how == 1: # SHUT_WR
|
||
|
self.hub.cancel_wait(self._write_event, cancel_wait_ex)
|
||
|
else:
|
||
|
self.hub.cancel_wait(self._read_event, cancel_wait_ex)
|
||
|
self.hub.cancel_wait(self._write_event, cancel_wait_ex)
|
||
|
self._sock.shutdown(how)
|
||
|
|
||
|
# sendfile: new in 3.5. But there's no real reason to not
|
||
|
# support it everywhere. Note that we can't use os.sendfile()
|
||
|
# because it's not cooperative.
|
||
|
def _sendfile_use_sendfile(self, file, offset=0, count=None):
|
||
|
# This is called directly by tests
|
||
|
raise __socket__._GiveupOnSendfile() # pylint:disable=no-member
|
||
|
|
||
|
def _sendfile_use_send(self, file, offset=0, count=None):
|
||
|
self._check_sendfile_params(file, offset, count)
|
||
|
if self.gettimeout() == 0:
|
||
|
raise ValueError("non-blocking sockets are not supported")
|
||
|
if offset:
|
||
|
file.seek(offset)
|
||
|
blocksize = min(count, 8192) if count else 8192
|
||
|
total_sent = 0
|
||
|
# localize variable access to minimize overhead
|
||
|
file_read = file.read
|
||
|
sock_send = self.send
|
||
|
try:
|
||
|
while True:
|
||
|
if count:
|
||
|
blocksize = min(count - total_sent, blocksize)
|
||
|
if blocksize <= 0:
|
||
|
break
|
||
|
data = memoryview(file_read(blocksize))
|
||
|
if not data:
|
||
|
break # EOF
|
||
|
while True:
|
||
|
try:
|
||
|
sent = sock_send(data)
|
||
|
except BlockingIOError:
|
||
|
continue
|
||
|
else:
|
||
|
total_sent += sent
|
||
|
if sent < len(data):
|
||
|
data = data[sent:]
|
||
|
else:
|
||
|
break
|
||
|
return total_sent
|
||
|
finally:
|
||
|
if total_sent > 0 and hasattr(file, 'seek'):
|
||
|
file.seek(offset + total_sent)
|
||
|
|
||
|
def _check_sendfile_params(self, file, offset, count):
|
||
|
if 'b' not in getattr(file, 'mode', 'b'):
|
||
|
raise ValueError("file should be opened in binary mode")
|
||
|
if not self.type & SOCK_STREAM:
|
||
|
raise ValueError("only SOCK_STREAM type sockets are supported")
|
||
|
if count is not None:
|
||
|
if not isinstance(count, int):
|
||
|
raise TypeError(
|
||
|
"count must be a positive integer (got {!r})".format(count))
|
||
|
if count <= 0:
|
||
|
raise ValueError(
|
||
|
"count must be a positive integer (got {!r})".format(count))
|
||
|
|
||
|
def sendfile(self, file, offset=0, count=None):
|
||
|
"""sendfile(file[, offset[, count]]) -> sent
|
||
|
|
||
|
Send a file until EOF is reached by using high-performance
|
||
|
os.sendfile() and return the total number of bytes which
|
||
|
were sent.
|
||
|
*file* must be a regular file object opened in binary mode.
|
||
|
If os.sendfile() is not available (e.g. Windows) or file is
|
||
|
not a regular file socket.send() will be used instead.
|
||
|
*offset* tells from where to start reading the file.
|
||
|
If specified, *count* is the total number of bytes to transmit
|
||
|
as opposed to sending the file until EOF is reached.
|
||
|
File position is updated on return or also in case of error in
|
||
|
which case file.tell() can be used to figure out the number of
|
||
|
bytes which were sent.
|
||
|
The socket must be of SOCK_STREAM type.
|
||
|
Non-blocking sockets are not supported.
|
||
|
|
||
|
.. versionadded:: 1.1rc4
|
||
|
Added in Python 3.5, but available under all Python 3 versions in
|
||
|
gevent.
|
||
|
"""
|
||
|
return self._sendfile_use_send(file, offset, count)
|
||
|
|
||
|
# get/set_inheritable new in 3.4
|
||
|
if hasattr(os, 'get_inheritable') or hasattr(os, 'get_handle_inheritable'):
|
||
|
# pylint:disable=no-member
|
||
|
if os.name == 'nt':
|
||
|
def get_inheritable(self):
|
||
|
return os.get_handle_inheritable(self.fileno())
|
||
|
|
||
|
def set_inheritable(self, inheritable):
|
||
|
os.set_handle_inheritable(self.fileno(), inheritable)
|
||
|
else:
|
||
|
def get_inheritable(self):
|
||
|
return os.get_inheritable(self.fileno())
|
||
|
|
||
|
def set_inheritable(self, inheritable):
|
||
|
os.set_inheritable(self.fileno(), inheritable)
|
||
|
_added = "\n\n.. versionadded:: 1.1rc4 Added in Python 3.4"
|
||
|
get_inheritable.__doc__ = "Get the inheritable flag of the socket" + _added
|
||
|
set_inheritable.__doc__ = "Set the inheritable flag of the socket" + _added
|
||
|
del _added
|
||
|
|
||
|
|
||
|
if sys.version_info[:2] == (3, 4) and sys.version_info[:3] <= (3, 4, 2):
|
||
|
# Python 3.4, up to and including 3.4.2, had a bug where the
|
||
|
# SocketType enumeration overwrote the SocketType class imported
|
||
|
# from _socket. This was fixed in 3.4.3 (http://bugs.python.org/issue20386
|
||
|
# and https://github.com/python/cpython/commit/0d2f85f38a9691efdfd1e7285c4262cab7f17db7).
|
||
|
# Prior to that, if we replace SocketType with our own class, the implementation
|
||
|
# of socket.type breaks with "OSError: [Errno 97] Address family not supported by protocol".
|
||
|
# Therefore, on these old versions, we must preserve it as an enum; while this
|
||
|
# seems like it could lead to non-green behaviour, code on those versions
|
||
|
# cannot possibly be using SocketType as a class anyway.
|
||
|
SocketType = __socket__.SocketType # pylint:disable=no-member
|
||
|
# Fixup __all__; note that we get exec'd multiple times during unit tests
|
||
|
if 'SocketType' in __implements__:
|
||
|
__implements__.remove('SocketType')
|
||
|
if 'SocketType' not in __imports__:
|
||
|
__imports__.append('SocketType')
|
||
|
else:
|
||
|
SocketType = socket
|
||
|
|
||
|
|
||
|
def fromfd(fd, family, type, proto=0):
|
||
|
""" fromfd(fd, family, type[, proto]) -> socket object
|
||
|
|
||
|
Create a socket object from a duplicate of the given file
|
||
|
descriptor. The remaining arguments are the same as for socket().
|
||
|
"""
|
||
|
nfd = dup(fd)
|
||
|
return socket(family, type, proto, nfd)
|
||
|
|
||
|
|
||
|
if hasattr(_socket.socket, "share"):
|
||
|
def fromshare(info):
|
||
|
""" fromshare(info) -> socket object
|
||
|
|
||
|
Create a socket object from a the bytes object returned by
|
||
|
socket.share(pid).
|
||
|
"""
|
||
|
return socket(0, 0, 0, info)
|
||
|
|
||
|
__implements__.append('fromshare')
|
||
|
|
||
|
if hasattr(_socket, "socketpair"):
|
||
|
|
||
|
def socketpair(family=None, type=SOCK_STREAM, proto=0):
|
||
|
"""socketpair([family[, type[, proto]]]) -> (socket object, socket object)
|
||
|
|
||
|
Create a pair of socket objects from the sockets returned by the platform
|
||
|
socketpair() function.
|
||
|
The arguments are the same as for socket() except the default family is
|
||
|
AF_UNIX if defined on the platform; otherwise, the default is AF_INET.
|
||
|
|
||
|
.. versionchanged:: 1.2
|
||
|
All Python 3 versions on Windows supply this function (natively
|
||
|
supplied by Python 3.5 and above).
|
||
|
"""
|
||
|
if family is None:
|
||
|
try:
|
||
|
family = AF_UNIX
|
||
|
except NameError:
|
||
|
family = AF_INET
|
||
|
a, b = _socket.socketpair(family, type, proto)
|
||
|
a = socket(family, type, proto, a.detach())
|
||
|
b = socket(family, type, proto, b.detach())
|
||
|
return a, b
|
||
|
|
||
|
else: # pragma: no cover
|
||
|
# Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
|
||
|
|
||
|
# gevent: taken from 3.6 release. Expected to be used only on Win. Added to Win/3.5
|
||
|
# gevent: for < 3.5, pass the default value of 128 to lsock.listen()
|
||
|
# (3.5+ uses this as a default and the original code passed no value)
|
||
|
|
||
|
_LOCALHOST = '127.0.0.1'
|
||
|
_LOCALHOST_V6 = '::1'
|
||
|
|
||
|
def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0):
|
||
|
if family == AF_INET:
|
||
|
host = _LOCALHOST
|
||
|
elif family == AF_INET6:
|
||
|
host = _LOCALHOST_V6
|
||
|
else:
|
||
|
raise ValueError("Only AF_INET and AF_INET6 socket address families "
|
||
|
"are supported")
|
||
|
if type != SOCK_STREAM:
|
||
|
raise ValueError("Only SOCK_STREAM socket type is supported")
|
||
|
if proto != 0:
|
||
|
raise ValueError("Only protocol zero is supported")
|
||
|
|
||
|
# We create a connected TCP socket. Note the trick with
|
||
|
# setblocking(False) that prevents us from having to create a thread.
|
||
|
lsock = socket(family, type, proto)
|
||
|
try:
|
||
|
lsock.bind((host, 0))
|
||
|
lsock.listen(128)
|
||
|
# On IPv6, ignore flow_info and scope_id
|
||
|
addr, port = lsock.getsockname()[:2]
|
||
|
csock = socket(family, type, proto)
|
||
|
try:
|
||
|
csock.setblocking(False)
|
||
|
try:
|
||
|
csock.connect((addr, port))
|
||
|
except (BlockingIOError, InterruptedError):
|
||
|
pass
|
||
|
csock.setblocking(True)
|
||
|
ssock, _ = lsock.accept()
|
||
|
except:
|
||
|
csock.close()
|
||
|
raise
|
||
|
finally:
|
||
|
lsock.close()
|
||
|
return (ssock, csock)
|
||
|
|
||
|
if sys.version_info[:2] < (3, 5):
|
||
|
# Not provided natively
|
||
|
if 'socketpair' in __implements__:
|
||
|
# Multiple imports can cause this to be missing if _socketcommon
|
||
|
# was successfully imported, leading to subsequent imports to cause
|
||
|
# ValueError
|
||
|
__implements__.remove('socketpair')
|
||
|
|
||
|
|
||
|
if hasattr(__socket__, 'close'): # Python 3.7b1+
|
||
|
close = __socket__.close # pylint:disable=no-member
|
||
|
__imports__ += ['close']
|
||
|
|
||
|
__all__ = __implements__ + __extensions__ + __imports__
|