Package: python-gevent
Version: 0.13.6-1
Severity: grave
Tags: patch

Dear maintainer,

as somewhere else upstream stated themselves (I have forgotten the URL where they did) that gevent.dns is somewhat completely broken in 0.13.6 (which is based on libevent, and they say it is broken there), I recommend using 1.0b1 for wheezy instead.

I use python-gevent for python-x2go intensively and the performance is much better with 1.0b1 and stability has also improved (the used event library is libev now).

One issue is that IPv6 DNS resolution does not work with 0.13.6 at all. As the world moves towards IPv6 (esp. in non-US and non-European parts of the world) I consider this issue as somewhat grave.

Attached is a patch that tries to fix this behaviour for gevent 0.13.6. The patch is not perfect, sometimes you have to wait quite long for name resolution of IPv6 addresses, but at the end they finally resolve. Much better would be a transition to 1.0b1 for wheezy (though the RT may not like this...).


Reproduce (IPv6-only host):
===========================
"""
mike@fylgja:~ python
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import gevent.socket
gevent.socket.gethostbyname("minobo.das-netzwerkteam.de")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
File "/usr/lib/pymodules/python2.6/gevent/socket.py", line 683, in gethostbyname
    _ttl, addrs = resolve_ipv4(hostname)
  File "/usr/lib/pymodules/python2.6/gevent/dns.py", line 59, in resolve_ipv4
    raise DNSError(result)
gevent.dns.DNSError: [Errno 67] request timed out
"""

Should be:::
"""
mike@fylgja:~$ python
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import gevent
import gevent.socket
gevent.socket.gethostbyname("minobo.das-netzwerkteam.de")
'2001:6f8:900:e5d::2'
"""

Reproduce (IPv4/IPv6 host): (first request is IPv4, second request times out)
===========================
"""
mike@fylgja:~$ python
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import gevent.socket
gevent.socket.gethostbyname("vidar.das-netzwerkteam.de")
'178.63.100.242'
gevent.socket.gethostbyname("vidar.das-netzwerkteam.de")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
File "/usr/lib/pymodules/python2.6/gevent/socket.py", line 683, in gethostbyname
    _ttl, addrs = resolve_ipv4(hostname)
  File "/usr/lib/pymodules/python2.6/gevent/dns.py", line 59, in resolve_ipv4
    raise DNSError(result)
gevent.dns.DNSError: [Errno 67] request timed out
"""

Should be:::
"""
mike@fylgja:~$ python
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import gevent
import gevent.socket
gevent.socket.gethostbyname("vidar.das-netzwerkteam.de")
'2a01:4f8:121:5085:250:56ff:fe15:236e'
"""

With 1.0b1 the above tests work like a charm. With my provided patch applied to 0.13.6 it works, but with some serious time delays.

Mike


--

DAS-NETZWERKTEAM
mike gabriel, rothenstein 5, 24214 neudorf-bornstein
fon: +49 (1520) 1976 148

GnuPG Key ID 0x25771B31
mail: mike.gabr...@das-netzwerkteam.de, http://das-netzwerkteam.de

freeBusy:
https://mail.das-netzwerkteam.de/freebusy/m.gabriel%40das-netzwerkteam.de.xfb
Nur in python-gevent-0.13.6.patched//gevent: __init__.pyc.
diff -ur python-gevent-0.13.6/gevent/socket.py python-gevent-0.13.6.patched//gevent/socket.py
--- python-gevent-0.13.6/gevent/socket.py	2011-05-17 16:02:29.000000000 +0200
+++ python-gevent-0.13.6.patched//gevent/socket.py	2012-10-18 16:06:41.000000000 +0200
@@ -680,8 +680,14 @@
             return hostname
         if hostname == _socket.gethostname():
             return _socket.gethostbyname(hostname)
-        _ttl, addrs = resolve_ipv4(hostname)
-        return inet_ntoa(random.choice(addrs))
+        addrs = None
+        try:
+            _ttl, addrs = resolve_ipv4(hostname)
+        except:
+            _ttl, addrs = resolve_ipv6(hostname)
+            return inet_ntop(AF_INET6, random.choice(addrs))
+        else:
+            return inet_ntop(AF_INET, random.choice(addrs))
 
     def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0, evdns_flags=0):
         """*Some* approximation of :func:`socket.getaddrinfo` implemented using :mod:`gevent.dns`.
@@ -750,30 +756,28 @@
                 for socktype, proto in socktype_proto:
                     result.append((family, socktype, proto, '', sockaddr))
         else:
-            failure = None
-            job = spawn(wrap_errors(gaierror, resolve_ipv6), host, evdns_flags)
+
+            ipv4_res = None
+            ipv6_res = None
             try:
-                try:
-                    ipv4_res = resolve_ipv4(host, evdns_flags)[1]
-                except gaierror, failure:
-                    ipv4_res = None
-                ipv6_res = job.get()
-                if isinstance(ipv6_res, gaierror):
-                    ipv6_res = None
-                    if failure is not None:
-                        raise
-                if ipv4_res is not None:
-                    for res in ipv4_res:
-                        sockaddr = (inet_ntop(AF_INET, res), port)
-                        for socktype, proto in socktype_proto:
-                            result.append((AF_INET, socktype, proto, '', sockaddr))
-                if ipv6_res is not None:
-                    for res in ipv6_res[1]:
-                        sockaddr = (inet_ntop(AF_INET6, res), port, 0, 0)
-                        for socktype, proto in socktype_proto:
-                            result.append((AF_INET6, socktype, proto, '', sockaddr))
-            finally:
-                job.kill()
+                ipv4_res = resolve_ipv4(host, evdns_flags)[1]
+            except:
+                pass
+            if not ipv4_res:
+                ipv4_res = None
+                ipv6_res= resolve_ipv6(host, evdns_flags)[1]
+
+            if ipv4_res is not None:
+                for res in ipv4_res:
+                    sockaddr = (inet_ntop(AF_INET, res), port)
+                    for socktype, proto in socktype_proto:
+                        result.append((AF_INET, socktype, proto, '', sockaddr))
+            if ipv6_res is not None:
+                for res in ipv6_res:
+                    sockaddr = (inet_ntop(AF_INET6, res), port, 0, 0)
+                    for socktype, proto in socktype_proto:
+                        result.append((AF_INET6, socktype, proto, '', sockaddr))
+
         return result
         # TODO libevent2 has getaddrinfo that is probably better than the hack above; should wrap that.
 

Attachment: pgpYoXoRwrZLZ.pgp
Description: Digitale PGP-Unterschrift

Reply via email to