78
98
from errno import EISCONN
79
99
from os import strerror
102
from errno import EBADF
84
timeout = _socket.timeout
85
107
_realsocket = _socket.socket
86
108
__socket__ = __import__('socket')
87
109
_fileobject = __socket__._fileobject
88
gaierror = _socket.gaierror
90
# Import public constants from the standard socket (called __socket__ here) into this module.
111
for name in __imports__[:]:
113
value = getattr(__socket__, name)
114
globals()[name] = value
115
except AttributeError:
116
__imports__.remove(name)
92
118
for name in __socket__.__all__:
93
if name[:1].isupper():
94
value = getattr(__socket__, name)
95
if isinstance(value, (int, basestring)):
96
globals()[name] = value
98
elif name == 'getfqdn':
99
globals()[name] = getattr(__socket__, name)
119
value = getattr(__socket__, name)
120
if isinstance(value, (int, long, basestring)):
121
globals()[name] = value
122
__imports__.append(name)
104
inet_ntoa = _socket.inet_ntoa
105
inet_aton = _socket.inet_aton
107
inet_ntop = _socket.inet_ntop
108
except AttributeError:
126
if 'inet_ntop' not in globals():
127
# inet_ntop is required by our implementation of getaddrinfo
109
129
def inet_ntop(address_family, packed_ip):
110
130
if address_family == AF_INET:
111
131
return inet_ntoa(packed_ip)
112
132
# XXX: ipv6 won't work on windows
113
133
raise NotImplementedError('inet_ntop() is not available on this platform')
115
inet_pton = _socket.inet_pton
116
except AttributeError:
117
def inet_pton(address_family, ip_string):
118
if address_family == AF_INET:
119
return inet_aton(ip_string)
120
# XXX: ipv6 won't work on windows
121
raise NotImplementedError('inet_ntop() is not available on this platform')
123
# XXX: import other non-blocking stuff, like ntohl
124
135
# XXX: implement blocking functions that are not yet implemented
125
# XXX: add test that checks that socket.__all__ matches gevent.socket.__all__ on all supported platforms
127
137
from gevent.hub import getcurrent, get_hub
128
138
from gevent import core
139
from gevent import spawn
140
from gevent.util import wrap_errors
130
142
_ip4_re = re.compile('^[\d\.]+$')
279
294
self._sock.setblocking(0)
280
295
self._read_event = core.event(core.EV_READ, self.fileno(), _wait_helper)
281
296
self._write_event = core.event(core.EV_WRITE, self.fileno(), _wait_helper)
282
self._rw_event = core.event(core.EV_READ|core.EV_WRITE, self.fileno(), _wait_helper)
297
# regarding the following, see issue #31
298
# (http://code.google.com/p/gevent/issues/detail?id=31#c19)
300
self._rw_event = core.event(core.EV_READ | core.EV_WRITE, self.fileno(), _wait_helper)
302
self._rw_event = core.event(core.EV_WRITE, self.fileno(), _wait_helper)
284
304
def __repr__(self):
285
305
return '<%s at %s %s>' % (type(self).__name__, hex(id(self)), self._formatinfo())
545
576
SocketType = socket
547
578
if hasattr(_socket, 'socketpair'):
548
580
def socketpair(*args):
549
581
one, two = _socket.socketpair(*args)
550
582
return socket(_sock=one), socket(_sock=two)
552
__all__.remove('socketpair')
584
__implements__.remove('socketpair')
554
586
if hasattr(_socket, 'fromfd'):
555
588
def fromfd(*args):
556
589
return socket(_sock=_socket.fromfd(*args))
558
__all__.remove('fromfd')
591
__implements__.remove('fromfd')
561
594
def bind_and_listen(descriptor, address=('', 0), backlog=50, reuse_addr=True):
644
683
_ttl, addrs = resolve_ipv4(hostname)
645
684
return inet_ntoa(random.choice(addrs))
648
def getaddrinfo(host, port, *args, **kwargs):
686
def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0, evdns_flags=0):
649
687
"""*Some* approximation of :func:`socket.getaddrinfo` implemented using :mod:`gevent.dns`.
651
689
If *host* is not a string, does not has any dots or is a numeric IP address, then
652
690
the standard :func:`socket.getaddrinfo` is called.
654
Otherwise, calls either :func:`resolve_ipv4` or :func:`resolve_ipv6` and
655
formats the result the way :func:`socket.getaddrinfo` does it.
692
Otherwise, calls :func:`resolve_ipv4` (for ``AF_INET``) or :func:`resolve_ipv6` (for ``AF_INET6``) or
693
both (for ``AF_UNSPEC``) and formats the result the way :func:`socket.getaddrinfo` does it.
657
695
Differs in the following ways:
659
697
* raises :class:`DNSError` (a subclass of :class:`gaierror`) with libevent-dns error
660
698
codes instead of standard socket error codes
661
* IPv6 support is untested.
662
* AF_UNSPEC only tries IPv4
663
* only supports TCP, UDP, IP protocols
664
* port must be numeric, does not support string service names. see socket.getservbyname
665
699
* *flags* argument is ignored
700
* for IPv6, flow info and scope id are always 0
667
702
Additionally, supports *evdns_flags* keyword arguments (default ``0``) that is passed
668
703
to :mod:`dns` functions.
670
family, socktype, proto, _flags = args + (None, ) * (4 - len(args))
671
if not isinstance(host, str) or '.' not in host or _ip4_re.match(host):
672
return _socket.getaddrinfo(host, port, *args)
674
evdns_flags = kwargs.pop('evdns_flags', 0)
676
raise TypeError('Unsupported keyword arguments: %s' % (kwargs.keys(), ))
678
if family in (None, AF_INET, AF_UNSPEC):
680
# TODO: AF_UNSPEC means try both AF_INET and AF_INET6
681
_ttl, addrs = resolve_ipv4(host, evdns_flags)
682
elif family == AF_INET6:
683
_ttl, addrs = resolve_ipv6(host, evdns_flags)
685
raise NotImplementedError('family is not among AF_UNSPEC/AF_INET/AF_INET6: %r' % (family, ))
705
if isinstance(host, unicode):
706
host = host.encode('idna')
707
if not isinstance(host, str) or \
709
_ip4_re.match(host) is not None or \
710
family not in (AF_UNSPEC, AF_INET, AF_INET6):
711
return _socket.getaddrinfo(host, port, family, socktype, proto, flags)
713
if isinstance(port, basestring):
717
port = getservbyname(port, 'tcp')
718
socktype = SOCK_STREAM
720
port = getservbyname(port, 'udp')
721
socktype = SOCK_DGRAM
722
elif socktype == SOCK_STREAM:
723
port = getservbyname(port, 'tcp')
724
elif socktype == SOCK_DGRAM:
725
port = getservbyname(port, 'udp')
727
raise gaierror(EAI_SERVICE, 'Servname not supported for ai_socktype')
729
if 'not found' in str(ex):
730
raise gaierror(EAI_SERVICE, 'Servname not supported for ai_socktype')
732
raise gaierror(str(ex))
687
734
socktype_proto = [(SOCK_STREAM, 6), (SOCK_DGRAM, 17), (SOCK_RAW, 0)]
691
738
socktype_proto = [(x, y) for (x, y) in socktype_proto if proto == y]
695
for socktype, proto in socktype_proto:
696
result.append((family, socktype, proto, '', (inet_ntop(family, addr), port)))
742
if family == AF_INET:
743
for res in resolve_ipv4(host, evdns_flags)[1]:
744
sockaddr = (inet_ntop(family, res), port)
745
for socktype, proto in socktype_proto:
746
result.append((family, socktype, proto, '', sockaddr))
747
elif family == AF_INET6:
748
for res in resolve_ipv6(host, evdns_flags)[1]:
749
sockaddr = (inet_ntop(family, res), port, 0, 0)
750
for socktype, proto in socktype_proto:
751
result.append((family, socktype, proto, '', sockaddr))
754
job = spawn(wrap_errors(gaierror, resolve_ipv6), host, evdns_flags)
757
ipv4_res = resolve_ipv4(host, evdns_flags)[1]
758
except gaierror, failure:
761
if isinstance(ipv6_res, gaierror):
763
if failure is not None:
765
if ipv4_res is not None:
767
sockaddr = (inet_ntop(AF_INET, res), port)
768
for socktype, proto in socktype_proto:
769
result.append((AF_INET, socktype, proto, '', sockaddr))
770
if ipv6_res is not None:
771
for res in ipv6_res[1]:
772
sockaddr = (inet_ntop(AF_INET6, res), port, 0, 0)
773
for socktype, proto in socktype_proto:
774
result.append((AF_INET6, socktype, proto, '', sockaddr))
698
778
# TODO libevent2 has getaddrinfo that is probably better than the hack above; should wrap that.
701
781
_have_ssl = False
704
from gevent.ssl import sslwrap_simple as ssl, SSLError as sslerror
784
from gevent.ssl import sslwrap_simple as ssl, SSLError as sslerror, SSLSocket as SSLType
706
786
except ImportError:
708
from gevent.sslold import ssl, sslerror
788
from gevent.sslold import ssl, sslerror, SSLObject as SSLType
710
790
except ImportError:
714
__all__.remove('ssl')
715
__all__.remove('sslerror')
793
if sys.version_info[:2] <= (2, 5) and _have_ssl:
794
__implements__.extend(['ssl', 'sslerror', 'SSLType'])
797
__all__ = __implements__ + __extensions__ + __imports__