track embedded python distribution
This commit is contained in:
343
python/gevent/_socketcommon.py
Normal file
343
python/gevent/_socketcommon.py
Normal file
@@ -0,0 +1,343 @@
|
||||
# Copyright (c) 2009-2014 Denis Bilenko and gevent contributors. See LICENSE for details.
|
||||
from __future__ import absolute_import
|
||||
|
||||
# standard functions and classes that this module re-implements in a gevent-aware way:
|
||||
_implements = [
|
||||
'create_connection',
|
||||
'socket',
|
||||
'SocketType',
|
||||
'fromfd',
|
||||
'socketpair',
|
||||
]
|
||||
|
||||
__dns__ = [
|
||||
'getaddrinfo',
|
||||
'gethostbyname',
|
||||
'gethostbyname_ex',
|
||||
'gethostbyaddr',
|
||||
'getnameinfo',
|
||||
'getfqdn',
|
||||
]
|
||||
|
||||
_implements += __dns__
|
||||
|
||||
# non-standard functions that this module provides:
|
||||
__extensions__ = [
|
||||
'cancel_wait',
|
||||
'wait_read',
|
||||
'wait_write',
|
||||
'wait_readwrite',
|
||||
]
|
||||
|
||||
# standard functions and classes that this module re-imports
|
||||
__imports__ = [
|
||||
'error',
|
||||
'gaierror',
|
||||
'herror',
|
||||
'htonl',
|
||||
'htons',
|
||||
'ntohl',
|
||||
'ntohs',
|
||||
'inet_aton',
|
||||
'inet_ntoa',
|
||||
'inet_pton',
|
||||
'inet_ntop',
|
||||
'timeout',
|
||||
'gethostname',
|
||||
'getprotobyname',
|
||||
'getservbyname',
|
||||
'getservbyport',
|
||||
'getdefaulttimeout',
|
||||
'setdefaulttimeout',
|
||||
# Windows:
|
||||
'errorTab',
|
||||
]
|
||||
|
||||
__py3_imports__ = [
|
||||
# Python 3
|
||||
'AddressFamily',
|
||||
'SocketKind',
|
||||
'CMSG_LEN',
|
||||
'CMSG_SPACE',
|
||||
'dup',
|
||||
'if_indextoname',
|
||||
'if_nameindex',
|
||||
'if_nametoindex',
|
||||
'sethostname',
|
||||
]
|
||||
|
||||
__imports__.extend(__py3_imports__)
|
||||
|
||||
|
||||
import sys
|
||||
from gevent.hub import get_hub
|
||||
from gevent.hub import ConcurrentObjectUseError
|
||||
from gevent.timeout import Timeout
|
||||
from gevent._compat import string_types, integer_types, PY3
|
||||
from gevent._util import copy_globals
|
||||
from gevent._util import _NONE
|
||||
|
||||
is_windows = sys.platform == 'win32'
|
||||
# pylint:disable=no-name-in-module,unused-import
|
||||
if is_windows:
|
||||
# no such thing as WSAEPERM or error code 10001 according to winsock.h or MSDN
|
||||
from errno import WSAEINVAL as EINVAL
|
||||
from errno import WSAEWOULDBLOCK as EWOULDBLOCK
|
||||
from errno import WSAEINPROGRESS as EINPROGRESS
|
||||
from errno import WSAEALREADY as EALREADY
|
||||
from errno import WSAEISCONN as EISCONN
|
||||
from gevent.win32util import formatError as strerror
|
||||
EAGAIN = EWOULDBLOCK
|
||||
else:
|
||||
from errno import EINVAL
|
||||
from errno import EWOULDBLOCK
|
||||
from errno import EINPROGRESS
|
||||
from errno import EALREADY
|
||||
from errno import EAGAIN
|
||||
from errno import EISCONN
|
||||
from os import strerror
|
||||
|
||||
try:
|
||||
from errno import EBADF
|
||||
except ImportError:
|
||||
EBADF = 9
|
||||
|
||||
import _socket
|
||||
_realsocket = _socket.socket
|
||||
import socket as __socket__
|
||||
|
||||
_name = _value = None
|
||||
__imports__ = copy_globals(__socket__, globals(),
|
||||
only_names=__imports__,
|
||||
ignore_missing_names=True)
|
||||
|
||||
for _name in __socket__.__all__:
|
||||
_value = getattr(__socket__, _name)
|
||||
if isinstance(_value, (integer_types, string_types)):
|
||||
globals()[_name] = _value
|
||||
__imports__.append(_name)
|
||||
|
||||
del _name, _value
|
||||
|
||||
_timeout_error = timeout # pylint: disable=undefined-variable
|
||||
|
||||
|
||||
def wait(io, timeout=None, timeout_exc=_NONE):
|
||||
"""
|
||||
Block the current greenlet until *io* is ready.
|
||||
|
||||
If *timeout* is non-negative, then *timeout_exc* is raised after
|
||||
*timeout* second has passed. By default *timeout_exc* is
|
||||
``socket.timeout('timed out')``.
|
||||
|
||||
If :func:`cancel_wait` is called on *io* by another greenlet,
|
||||
raise an exception in this blocking greenlet
|
||||
(``socket.error(EBADF, 'File descriptor was closed in another
|
||||
greenlet')`` by default).
|
||||
|
||||
:param io: A libev watcher, most commonly an IO watcher obtained from
|
||||
:meth:`gevent.core.loop.io`
|
||||
:keyword timeout_exc: The exception to raise if the timeout expires.
|
||||
By default, a :class:`socket.timeout` exception is raised.
|
||||
If you pass a value for this keyword, it is interpreted as for
|
||||
:class:`gevent.timeout.Timeout`.
|
||||
"""
|
||||
if io.callback is not None:
|
||||
raise ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (io.callback, ))
|
||||
if timeout is not None:
|
||||
timeout_exc = timeout_exc if timeout_exc is not _NONE else _timeout_error('timed out')
|
||||
timeout = Timeout.start_new(timeout, timeout_exc)
|
||||
|
||||
try:
|
||||
return get_hub().wait(io)
|
||||
finally:
|
||||
if timeout is not None:
|
||||
timeout.cancel()
|
||||
# rename "io" to "watcher" because wait() works with any watcher
|
||||
|
||||
|
||||
def wait_read(fileno, timeout=None, timeout_exc=_NONE):
|
||||
"""
|
||||
Block the current greenlet until *fileno* is ready to read.
|
||||
|
||||
For the meaning of the other parameters and possible exceptions,
|
||||
see :func:`wait`.
|
||||
|
||||
.. seealso:: :func:`cancel_wait`
|
||||
"""
|
||||
io = get_hub().loop.io(fileno, 1)
|
||||
return wait(io, timeout, timeout_exc)
|
||||
|
||||
|
||||
def wait_write(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
|
||||
"""
|
||||
Block the current greenlet until *fileno* is ready to write.
|
||||
|
||||
For the meaning of the other parameters and possible exceptions,
|
||||
see :func:`wait`.
|
||||
|
||||
:keyword event: Ignored. Applications should not pass this parameter.
|
||||
In the future, it may become an error.
|
||||
|
||||
.. seealso:: :func:`cancel_wait`
|
||||
"""
|
||||
# pylint:disable=unused-argument
|
||||
io = get_hub().loop.io(fileno, 2)
|
||||
return wait(io, timeout, timeout_exc)
|
||||
|
||||
|
||||
def wait_readwrite(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
|
||||
"""
|
||||
Block the current greenlet until *fileno* is ready to read or
|
||||
write.
|
||||
|
||||
For the meaning of the other parameters and possible exceptions,
|
||||
see :func:`wait`.
|
||||
|
||||
:keyword event: Ignored. Applications should not pass this parameter.
|
||||
In the future, it may become an error.
|
||||
|
||||
.. seealso:: :func:`cancel_wait`
|
||||
"""
|
||||
# pylint:disable=unused-argument
|
||||
io = get_hub().loop.io(fileno, 3)
|
||||
return wait(io, timeout, timeout_exc)
|
||||
|
||||
#: The exception raised by default on a call to :func:`cancel_wait`
|
||||
class cancel_wait_ex(error): # pylint: disable=undefined-variable
|
||||
def __init__(self):
|
||||
super(cancel_wait_ex, self).__init__(
|
||||
EBADF,
|
||||
'File descriptor was closed in another greenlet')
|
||||
|
||||
|
||||
def cancel_wait(watcher, error=cancel_wait_ex):
|
||||
"""See :meth:`gevent.hub.Hub.cancel_wait`"""
|
||||
get_hub().cancel_wait(watcher, error)
|
||||
|
||||
|
||||
class BlockingResolver(object):
|
||||
|
||||
def __init__(self, hub=None):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
for method in ['gethostbyname',
|
||||
'gethostbyname_ex',
|
||||
'getaddrinfo',
|
||||
'gethostbyaddr',
|
||||
'getnameinfo']:
|
||||
locals()[method] = staticmethod(getattr(_socket, method))
|
||||
|
||||
|
||||
def gethostbyname(hostname):
|
||||
"""
|
||||
gethostbyname(host) -> address
|
||||
|
||||
Return the IP address (a string of the form '255.255.255.255') for a host.
|
||||
|
||||
.. seealso:: :doc:`dns`
|
||||
"""
|
||||
return get_hub().resolver.gethostbyname(hostname)
|
||||
|
||||
|
||||
def gethostbyname_ex(hostname):
|
||||
"""
|
||||
gethostbyname_ex(host) -> (name, aliaslist, addresslist)
|
||||
|
||||
Return the true host name, a list of aliases, and a list of IP addresses,
|
||||
for a host. The host argument is a string giving a host name or IP number.
|
||||
Resolve host and port into list of address info entries.
|
||||
|
||||
.. seealso:: :doc:`dns`
|
||||
"""
|
||||
return get_hub().resolver.gethostbyname_ex(hostname)
|
||||
|
||||
|
||||
def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0):
|
||||
"""
|
||||
Resolve host and port into list of address info entries.
|
||||
|
||||
Translate the host/port argument into a sequence of 5-tuples that contain
|
||||
all the necessary arguments for creating a socket connected to that service.
|
||||
host is a domain name, a string representation of an IPv4/v6 address or
|
||||
None. port is a string service name such as 'http', a numeric port number or
|
||||
None. By passing None as the value of host and port, you can pass NULL to
|
||||
the underlying C API.
|
||||
|
||||
The family, type and proto arguments can be optionally specified in order to
|
||||
narrow the list of addresses returned. Passing zero as a value for each of
|
||||
these arguments selects the full range of results.
|
||||
|
||||
.. seealso:: :doc:`dns`
|
||||
"""
|
||||
return get_hub().resolver.getaddrinfo(host, port, family, socktype, proto, flags)
|
||||
|
||||
if PY3:
|
||||
# The name of the socktype param changed to type in Python 3.
|
||||
# See https://github.com/gevent/gevent/issues/960
|
||||
# Using inspect here to directly detect the condition is painful because we have to
|
||||
# wrap it with a try/except TypeError because not all Python 2
|
||||
# versions can get the args of a builtin; we also have to use a with to suppress
|
||||
# the deprecation warning.
|
||||
d = getaddrinfo.__doc__
|
||||
|
||||
def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): # pylint:disable=function-redefined
|
||||
return get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags)
|
||||
getaddrinfo.__doc__ = d
|
||||
del d
|
||||
|
||||
|
||||
def gethostbyaddr(ip_address):
|
||||
"""
|
||||
gethostbyaddr(ip_address) -> (name, aliaslist, addresslist)
|
||||
|
||||
Return the true host name, a list of aliases, and a list of IP addresses,
|
||||
for a host. The host argument is a string giving a host name or IP number.
|
||||
|
||||
.. seealso:: :doc:`dns`
|
||||
"""
|
||||
return get_hub().resolver.gethostbyaddr(ip_address)
|
||||
|
||||
|
||||
def getnameinfo(sockaddr, flags):
|
||||
"""
|
||||
getnameinfo(sockaddr, flags) -> (host, port)
|
||||
|
||||
Get host and port for a sockaddr.
|
||||
|
||||
.. seealso:: :doc:`dns`
|
||||
"""
|
||||
return get_hub().resolver.getnameinfo(sockaddr, flags)
|
||||
|
||||
|
||||
def getfqdn(name=''):
|
||||
"""Get fully qualified domain name from name.
|
||||
|
||||
An empty argument is interpreted as meaning the local host.
|
||||
|
||||
First the hostname returned by gethostbyaddr() is checked, then
|
||||
possibly existing aliases. In case no FQDN is available, hostname
|
||||
from gethostname() is returned.
|
||||
"""
|
||||
# pylint: disable=undefined-variable
|
||||
name = name.strip()
|
||||
if not name or name == '0.0.0.0':
|
||||
name = gethostname()
|
||||
try:
|
||||
hostname, aliases, _ = gethostbyaddr(name)
|
||||
except error:
|
||||
pass
|
||||
else:
|
||||
aliases.insert(0, hostname)
|
||||
for name in aliases: # EWW! pylint:disable=redefined-argument-from-local
|
||||
if isinstance(name, bytes):
|
||||
if b'.' in name:
|
||||
break
|
||||
elif '.' in name:
|
||||
break
|
||||
else:
|
||||
name = hostname
|
||||
return name
|
||||
Reference in New Issue
Block a user