diff options
Diffstat (limited to 'python/gevent/resolver/__init__.py')
-rw-r--r-- | python/gevent/resolver/__init__.py | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/python/gevent/resolver/__init__.py b/python/gevent/resolver/__init__.py new file mode 100644 index 0000000..3da38e3 --- /dev/null +++ b/python/gevent/resolver/__init__.py @@ -0,0 +1,103 @@ +# Copyright (c) 2018 gevent contributors. See LICENSE for details. + +from _socket import gaierror +from _socket import error +from _socket import getservbyname +from _socket import getaddrinfo + +from gevent._compat import string_types +from gevent._compat import integer_types + +from gevent.socket import SOCK_STREAM +from gevent.socket import SOCK_DGRAM +from gevent.socket import SOL_TCP +from gevent.socket import AI_CANONNAME +from gevent.socket import EAI_SERVICE +from gevent.socket import AF_INET +from gevent.socket import AI_PASSIVE + + +def _lookup_port(port, socktype): + # pylint:disable=too-many-branches + socktypes = [] + if isinstance(port, string_types): + try: + port = int(port) + except ValueError: + try: + if socktype == 0: + origport = port + try: + port = getservbyname(port, 'tcp') + socktypes.append(SOCK_STREAM) + except error: + port = getservbyname(port, 'udp') + socktypes.append(SOCK_DGRAM) + else: + try: + if port == getservbyname(origport, 'udp'): + socktypes.append(SOCK_DGRAM) + except error: + pass + elif socktype == SOCK_STREAM: + port = getservbyname(port, 'tcp') + elif socktype == SOCK_DGRAM: + port = getservbyname(port, 'udp') + else: + raise gaierror(EAI_SERVICE, 'Servname not supported for ai_socktype') + except error as ex: + if 'not found' in str(ex): + raise gaierror(EAI_SERVICE, 'Servname not supported for ai_socktype') + else: + raise gaierror(str(ex)) + except UnicodeEncodeError: + raise error('Int or String expected', port) + elif port is None: + port = 0 + elif isinstance(port, integer_types): + pass + else: + raise error('Int or String expected', port, type(port)) + port = int(port % 65536) + if not socktypes and socktype: + socktypes.append(socktype) + return port, socktypes + +hostname_types = tuple(set(string_types + (bytearray, bytes))) + +def _resolve_special(hostname, family): + if not isinstance(hostname, hostname_types): + raise TypeError("argument 1 must be str, bytes or bytearray, not %s" % (type(hostname),)) + + if hostname == '': + result = getaddrinfo(None, 0, family, SOCK_DGRAM, 0, AI_PASSIVE) + if len(result) != 1: + raise error('wildcard resolved to multiple address') + return result[0][4][0] + return hostname + + +class AbstractResolver(object): + + def gethostbyname(self, hostname, family=AF_INET): + hostname = _resolve_special(hostname, family) + return self.gethostbyname_ex(hostname, family)[-1][0] + + def gethostbyname_ex(self, hostname, family=AF_INET): + aliases = self._getaliases(hostname, family) + addresses = [] + tuples = self.getaddrinfo(hostname, 0, family, + SOCK_STREAM, + SOL_TCP, AI_CANONNAME) + canonical = tuples[0][3] + for item in tuples: + addresses.append(item[4][0]) + # XXX we just ignore aliases + return (canonical, aliases, addresses) + + def getaddrinfo(self, host, port, family=0, socktype=0, proto=0, flags=0): + raise NotImplementedError() + + def _getaliases(self, hostname, family): + # pylint:disable=unused-argument + return [] |