From: <am...@us...> - 2011-01-25 23:46:33
|
Revision: 7191 http://jython.svn.sourceforge.net/jython/?rev=7191&view=rev Author: amak Date: 2011-01-25 23:46:27 +0000 (Tue, 25 Jan 2011) Log Message: ----------- 1. Re-enabling the use of IPV6/AF_INET6 addresses 2. Adding workarounds for systems that have problems with IPV6 on java 3. Test for #2 Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2011-01-23 15:58:55 UTC (rev 7190) +++ trunk/jython/Lib/socket.py 2011-01-25 23:46:27 UTC (rev 7191) @@ -94,29 +94,40 @@ class timeout(error): pass class sslerror(error): pass +def _unmapped_exception(exc): + return error(-1, 'Unmapped exception: %s' % exc) + +def java_net_socketexception_handler(exc): + if exc.message.startswith("Address family not supported by protocol family"): + return error(errno.EAFNOSUPPORT, 'Address family not supported by protocol family: See http://wiki.python.org/jython/NewSocketModule#IPV6addresssupport') + return _unmapped_exception(exc) + +def would_block_error(exc=None): + return error(errno.EWOULDBLOCK, 'The socket operation could not complete without blocking') + ALL = None _exception_map = { -# (<javaexception>, <circumstance>) : lambda: <code that raises the python equivalent>, or None to stub out as unmapped +# (<javaexception>, <circumstance>) : callable that raises the python equivalent exception, or None to stub out as unmapped -(java.io.IOException, ALL) : lambda: error(errno.ECONNRESET, 'Software caused connection abort'), -(java.io.InterruptedIOException, ALL) : lambda: timeout('timed out'), +(java.io.IOException, ALL) : lambda x: error(errno.ECONNRESET, 'Software caused connection abort'), +(java.io.InterruptedIOException, ALL) : lambda x: timeout('timed out'), -(java.net.BindException, ALL) : lambda: error(errno.EADDRINUSE, 'Address already in use'), -(java.net.ConnectException, ALL) : lambda: error(errno.ECONNREFUSED, 'Connection refused'), +(java.net.BindException, ALL) : lambda x: error(errno.EADDRINUSE, 'Address already in use'), +(java.net.ConnectException, ALL) : lambda x: error(errno.ECONNREFUSED, 'Connection refused'), (java.net.NoRouteToHostException, ALL) : None, (java.net.PortUnreachableException, ALL) : None, (java.net.ProtocolException, ALL) : None, -(java.net.SocketException, ALL) : None, -(java.net.SocketTimeoutException, ALL) : lambda: timeout('timed out'), -(java.net.UnknownHostException, ALL) : lambda: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'), +(java.net.SocketException, ALL) : java_net_socketexception_handler, +(java.net.SocketTimeoutException, ALL) : lambda x: timeout('timed out'), +(java.net.UnknownHostException, ALL) : lambda x: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'), -(java.nio.channels.AlreadyConnectedException, ALL) : lambda: error(errno.EISCONN, 'Socket is already connected'), +(java.nio.channels.AlreadyConnectedException, ALL) : lambda x: error(errno.EISCONN, 'Socket is already connected'), (java.nio.channels.AsynchronousCloseException, ALL) : None, (java.nio.channels.CancelledKeyException, ALL) : None, (java.nio.channels.ClosedByInterruptException, ALL) : None, -(java.nio.channels.ClosedChannelException, ALL) : lambda: error(errno.EPIPE, 'Socket closed'), +(java.nio.channels.ClosedChannelException, ALL) : lambda x: error(errno.EPIPE, 'Socket closed'), (java.nio.channels.ClosedSelectorException, ALL) : None, (java.nio.channels.ConnectionPendingException, ALL) : None, (java.nio.channels.IllegalBlockingModeException, ALL) : None, @@ -126,28 +137,25 @@ (java.nio.channels.NonWritableChannelException, ALL) : None, (java.nio.channels.NotYetBoundException, ALL) : None, (java.nio.channels.NotYetConnectedException, ALL) : None, -(java.nio.channels.UnresolvedAddressException, ALL) : lambda: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'), +(java.nio.channels.UnresolvedAddressException, ALL) : lambda x: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'), (java.nio.channels.UnsupportedAddressTypeException, ALL) : None, # These error codes are currently wrong: getting them correct is going to require # some investigation. Cpython 2.6 introduced extensive SSL support. -(javax.net.ssl.SSLException, ALL) : lambda: sslerror(-1, 'SSL exception'), -(javax.net.ssl.SSLHandshakeException, ALL) : lambda: sslerror(-1, 'SSL handshake exception'), -(javax.net.ssl.SSLKeyException, ALL) : lambda: sslerror(-1, 'SSL key exception'), -(javax.net.ssl.SSLPeerUnverifiedException, ALL) : lambda: sslerror(-1, 'SSL peer unverified exception'), -(javax.net.ssl.SSLProtocolException, ALL) : lambda: sslerror(-1, 'SSL protocol exception'), +(javax.net.ssl.SSLException, ALL) : lambda x: sslerror(-1, 'SSL exception'), +(javax.net.ssl.SSLHandshakeException, ALL) : lambda x: sslerror(-1, 'SSL handshake exception'), +(javax.net.ssl.SSLKeyException, ALL) : lambda x: sslerror(-1, 'SSL key exception'), +(javax.net.ssl.SSLPeerUnverifiedException, ALL) : lambda x: sslerror(-1, 'SSL peer unverified exception'), +(javax.net.ssl.SSLProtocolException, ALL) : lambda x: sslerror(-1, 'SSL protocol exception'), } -def would_block_error(exc=None): - return error(errno.EWOULDBLOCK, 'The socket operation could not complete without blocking') - def _map_exception(exc, circumstance=ALL): # print "Mapping exception: %s" % exc mapped_exception = _exception_map.get((exc.__class__, circumstance)) if mapped_exception: - exception = mapped_exception() + exception = mapped_exception(exc) else: exception = error(-1, 'Unmapped exception: %s' % exc) exception.java_exception = exc @@ -588,7 +596,7 @@ return Protocol.getProtocolByName(protocol_name).getProto() def _realsocket(family = AF_INET, type = SOCK_STREAM, protocol=0): - assert family == AF_INET, "Only AF_INET sockets are currently supported on jython" + assert family in (AF_INET, AF_INET6), "Only AF_INET and AF_INET6 sockets are currently supported on jython" assert type in (SOCK_DGRAM, SOCK_STREAM), "Only SOCK_STREAM and SOCK_DGRAM sockets are currently supported on jython" if type == SOCK_STREAM: if protocol != 0: @@ -599,16 +607,25 @@ assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets" return _udpsocket() +_ipv4_addresses_only = False + +def _use_ipv4_addresses_only(value): + global _ipv4_addresses_only + _ipv4_addresses_only = value + def getaddrinfo(host, port, family=AF_INET, socktype=None, proto=0, flags=None): try: if not family in [AF_INET, AF_INET6, AF_UNSPEC]: raise gaierror(errno.EIO, 'ai_family not supported') filter_fns = [] - filter_fns.append({ - AF_INET: lambda x: isinstance(x, java.net.Inet4Address), - AF_INET6: lambda x: isinstance(x, java.net.Inet6Address), - AF_UNSPEC: lambda x: isinstance(x, java.net.InetAddress), - }[family]) + if _ipv4_addresses_only: + filter_fns.append( lambda x: isinstance(x, java.net.Inet4Address) ) + else: + filter_fns.append({ + AF_INET: lambda x: isinstance(x, java.net.Inet4Address), + AF_INET6: lambda x: isinstance(x, java.net.Inet6Address), + AF_UNSPEC: lambda x: isinstance(x, java.net.InetAddress), + }[family]) if host == "": host = java.net.InetAddress.getLocalHost().getHostName() passive_mode = flags is not None and flags & AI_PASSIVE @@ -617,18 +634,16 @@ for a in java.net.InetAddress.getAllByName(host): if len([f for f in filter_fns if f(a)]): family = {java.net.Inet4Address: AF_INET, java.net.Inet6Address: AF_INET6}[a.getClass()] - # bug 1697: exclude IPv6 addresses from being returned - if family != AF_INET6: - if passive_mode and not canonname_mode: - canonname = "" - else: - canonname = asPyString(a.getCanonicalHostName()) - if host is None and passive_mode and not canonname_mode: - sockname = INADDR_ANY - else: - sockname = asPyString(a.getHostAddress()) - # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses - results.append((family, socktype, proto, canonname, (sockname, port))) + if passive_mode and not canonname_mode: + canonname = "" + else: + canonname = asPyString(a.getCanonicalHostName()) + if host is None and passive_mode and not canonname_mode: + sockname = INADDR_ANY + else: + sockname = asPyString(a.getHostAddress()) + # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses + results.append((family, socktype, proto, canonname, (sockname, port))) return results except java.lang.Exception, jlx: raise _map_exception(jlx) Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2011-01-23 15:58:55 UTC (rev 7190) +++ trunk/jython/Lib/test/test_socket.py 2011-01-25 23:46:27 UTC (rev 7191) @@ -1493,6 +1493,15 @@ self.failUnlessEqual(expected_canonname, canonname, "For hostname '%s' and flags %d, canonname '%s' != '%s'" % (host_param, flags, expected_canonname, canonname) ) self.failUnlessEqual(expected_sockaddr, sockaddr[0], "For hostname '%s' and flags %d, sockaddr '%s' != '%s'" % (host_param, flags, expected_sockaddr, sockaddr[0]) ) + def testIPV4AddressesOnly(self): + socket._use_ipv4_addresses_only(True) + def doAddressTest(addrinfos): + for family, socktype, proto, canonname, sockaddr in addrinfos: + self.failIf(":" in sockaddr[0], "Incorrectly received IPv6 address '%s'" % (sockaddr[0]) ) + doAddressTest(socket.getaddrinfo("localhost", 0, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)) + doAddressTest(socket.getaddrinfo("localhost", 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, 0)) + socket._use_ipv4_addresses_only(False) + class TestExceptions(unittest.TestCase): def testExceptionTree(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |