[Jython-checkins] jython: Perform SSL handshake, regardless if original socket is wrapped. Fixes #2462

jim.baker jython-checkins at python.org
Wed Aug 17 00:38:39 EDT 2016


https://hg.python.org/jython/rev/aea64acc5e47
changeset:   7927:aea64acc5e47
user:        Jim Baker <jim.baker at rackspace.com>
date:        Tue Aug 16 22:03:56 2016 -0600
summary:
  Perform SSL handshake, regardless if original socket is wrapped. Fixes #2462

files:
  Lib/_socket.py             |  139 +++++++++++++++---------
  Lib/_sslcerts.py           |    5 +-
  Lib/ssl.py                 |  140 +++++++++++++++++-------
  Lib/test/regrtest.py       |   17 +-
  Lib/test/test_socket_jy.py |    7 +-
  5 files changed, 197 insertions(+), 111 deletions(-)


diff --git a/Lib/_socket.py b/Lib/_socket.py
--- a/Lib/_socket.py
+++ b/Lib/_socket.py
@@ -21,7 +21,7 @@
 
 import java
 from java.io import IOException, InterruptedIOException
-from java.lang import Thread, IllegalStateException
+from java.lang import Thread, ArrayIndexOutOfBoundsException, IllegalStateException
 from java.net import InetAddress, InetSocketAddress
 from java.nio.channels import ClosedChannelException
 from java.security.cert import CertificateException
@@ -41,6 +41,8 @@
     from org.python.netty.channel.nio import NioEventLoopGroup
     from org.python.netty.channel.socket import DatagramPacket
     from org.python.netty.channel.socket.nio import NioDatagramChannel, NioSocketChannel, NioServerSocketChannel
+    from org.python.netty.handler.ssl import NotSslRecordException
+
 except ImportError:
     # dev version from extlibs
     from io.netty.bootstrap import Bootstrap, ChannelFactory, ServerBootstrap
@@ -49,7 +51,7 @@
     from io.netty.channel.nio import NioEventLoopGroup
     from io.netty.channel.socket import DatagramPacket
     from io.netty.channel.socket.nio import NioDatagramChannel, NioSocketChannel, NioServerSocketChannel
-
+    from io.netty.handler.ssl import NotSslRecordException
 
 log = logging.getLogger("_socket")
 log.setLevel(level=logging.WARNING)
@@ -248,7 +250,7 @@
 class herror(error): pass
 class gaierror(error): pass
 class timeout(error): pass
-class SSLError(error): pass
+class SSLError(error): pass   # FIXME import from ssl, solving the usual mutual import schema
 
 SSL_ERROR_SSL = 1
 SSL_ERROR_WANT_READ = 2
@@ -259,6 +261,7 @@
 SSL_ERROR_WANT_CONNECT = 7
 SSL_ERROR_EOF = 8
 SSL_ERROR_INVALID_ERROR_CODE = 9
+SSL_UNKNOWN_PROTOCOL = 10   # FIXME check code from OpenSSL
 
 
 def _add_exception_attrs(exc):
@@ -321,6 +324,12 @@
     java.nio.channels.UnsupportedAddressTypeException : None,
 
     SSLPeerUnverifiedException: lambda x: SSLError(SSL_ERROR_SSL, x.message),
+    # FIXME
+    # CPython wraps with a message like so:
+    #   ssl.SSLError: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:590)
+    # Currently this error handler produces this message:
+    #   _socket.SSLError: [Errno 1] not an SSL/TLS record: 48692c2049276d206120636c69656e7421
+    NotSslRecordException: lambda x: SSLError(SSL_UNKNOWN_PROTOCOL, x.message),
 }
 
 
@@ -605,10 +614,11 @@
         child.proto = IPPROTO_TCP
         child._init_client_mode(child_channel)
 
-        # Get most current options from the parent. This enables any subsequent divergence.
+        # Get most current options from the parent. This enables any
+        # subsequent divergence.
         #
-        # It's OK that this copy could occur without a mutex, given that such iteration
-        # is guaranteed to be weakly consistent
+        # It's OK that this copy could occur without a mutex, given
+        # that such iteration is guaranteed to be weakly consistent
         child.options = dict(((option, value) for option, value in self.parent_socket.options.iteritems()))
         if child.options:
             log.debug("Setting inherited options %s", child.options, extra={"sock": child})
@@ -616,29 +626,51 @@
             for option, value in child.options.iteritems():
                 _set_option(config.setOption, option, value)
 
-        log.debug("Notifing listeners of parent socket %s", self.parent_socket, extra={"sock": child})
-        self.parent_socket.child_queue.put(child)
-        self.parent_socket._notify_selectors()
-        log.debug("Notified listeners of parent socket %s with queue %s",
-                  self.parent_socket, self.parent_socket.child_queue, extra={"sock": child})
+        # Ensure that this handler will not block if the channel is
+        # closed, otherwise this handler will simply sit idly as a
+        # pending task in the Netty thread pool
+        child_channel.closeFuture().addListener(child._make_active)
 
-        # Must block until the child socket is actually "used". This is
-        # because there may be some additional setup required, such as
-        # wrapping the socket, before the child is ready to read.
+        # Parent socket is wrapping, so we know intent and we can
+        # return as soon as handshaking is completed, if any
+        if hasattr(self.parent_socket, "ssl_wrap_child_socket"):
+            log.debug("Wrapping child socket for a wrapped parent=%s", self.parent_socket, extra={"sock": self})
+            child._wrapper_socket = self.parent_socket.ssl_wrap_child_socket(child)
+            child._handshake_future.sync()
+            child._post_connect()
+            self.parent_socket.child_queue.put(child)
+            log.debug("Notifing listeners of parent socket %s", self.parent_socket, extra={"sock": child})
+            self.parent_socket._notify_selectors()
+            log.debug("Notified listeners of parent socket %s with queue %s",
+                      self.parent_socket, self.parent_socket.child_queue, extra={"sock": child})
+            return
 
-        def unlatch_child(_):
-            # FIXME when bound methods are supported for single method interfaces
-            child._unlatch()
+        # Otherwise, must wait on this barrier until the child socket
+        # is activated, as demonstrated by use or other setup
+        # info. This is because the child may still be OPTIONALLY
+        # wrapped with an SSL socket. Not blocking here will cause
+        # corruption in send/recv data because it will overlap with
+        # the handshaking in that case.
+        with child._activation_cv:
+            def wait_for_barrier():
+                with child._activation_cv:
+                    self.parent_socket.child_queue.put(child)
+                    log.debug("Notifing listeners of parent socket %s", self.parent_socket, extra={"sock": child})
+                    self.parent_socket._notify_selectors()
+                    log.debug("Notified listeners of parent socket %s with queue %s",
+                          self.parent_socket, self.parent_socket.child_queue, extra={"sock": child})
+            self.parent_socket.parent_group.submit(wait_for_barrier)
+            while not child._activated:
+                log.debug("Waiting for optional wrapping", extra={"sock": child})
+                child._activation_cv.wait()
 
-        # Ensure that this handler will not block if the channel is closed,
-        # otherwise this handler will simply sit idly as a pending task in the Netty
-        # thread pool
-        child_channel.closeFuture().addListener(unlatch_child)
-
-        if self.parent_socket.timeout is None:
-            child._ensure_post_connect()
-        child._wait_on_latch()
-        log.debug("Socket initChannel completed waiting on latch", extra={"sock": child})
+        log.debug("Completed waiting for optional wrapping", extra={"sock": child})
+        if hasattr(child, "ssl_wrap_self"):
+            log.debug("Wrapping self", extra={"sock": child})
+            child.ssl_wrap_self()
+        log.debug("Activating child socket by adding inbound handler", extra={"sock": child})
+        child._post_connect()
+        child._channel_is_initialized = True
 
 
 # FIXME raise exceptions for ops not permitted on client socket, server socket
@@ -651,8 +683,6 @@
 }
 
 
-
-
 def _identity(value):
     return value
 
@@ -725,7 +755,6 @@
         self.timeout = _defaulttimeout
         self.channel = None
         self.bind_addr = _EPHEMERAL_ADDRESS
-        self.bind_timestamp = None   # Handle Netty race condition on bound addresses
         self.selectors = CopyOnWriteArrayList()
         self.options = {}  # deferred options until bootstrap
         self.peer_closed = False
@@ -748,10 +777,11 @@
         return "<_realsocket at {:#x} type={} open_count={} channel={} timeout={}>".format(
             id(self), _socket_types[self.socket_type], self.open_count, self.channel, self.timeout)
 
-    def _unlatch(self):
-        pass  # no-op once mutated from ChildSocket to normal _socketobject
+    def _make_active(self):
+        pass
 
     def _register_selector(self, selector):
+        self._make_active()  # attempting to poll/select on a socket means waiting for wrap intent is done
         self.selectors.addIfAbsent(selector)
 
     def _unregister_selector(self, selector):
@@ -759,6 +789,8 @@
             return self.selectors.remove(selector)
         except ValueError:
             return None
+        except ArrayIndexOutOfBoundsException:
+            return None
 
     def _notify_selectors(self, exception=None, hangup=False):
         for selector in self.selectors:
@@ -867,7 +899,6 @@
 
         self.connect_future = self.channel.connect(addr)
         self._handle_channel_future(self.connect_future, "connect")
-        self.bind_timestamp = time.time()
 
     def _post_connect(self):
         # Post-connect step is necessary to handle SSL setup,
@@ -882,6 +913,7 @@
             self.incoming.put(_PEER_CLOSED)
             self._notify_selectors(hangup=True)
 
+        log.debug("Add _peer_closed to channel close", extra={"sock": self}) 
         self.channel.closeFuture().addListener(_peer_closed)
 
     def connect(self, addr):
@@ -906,7 +938,7 @@
             if was_connecting:
                 try:
                     # Timing is based on CPython and was empirically
-                    # guestimated. Of course this means user code is
+                    # guesstimated. Of course this means user code is
                     # polling, so the the best we can do is wait like
                     # this in supposedly nonblocking mode without
                     # completely busy waiting!
@@ -961,7 +993,6 @@
 
         self.bind_future = b.bind(self.bind_addr.getAddress(), self.bind_addr.getPort())
         self._handle_channel_future(self.bind_future, "listen")
-        self.bind_timestamp = time.time()
         self.channel = self.bind_future.channel()
         log.debug("Bound server socket to %s", self.bind_addr, extra={"sock": self})
 
@@ -1157,6 +1188,7 @@
     sendall = send   # FIXME see note above!
 
     def _get_incoming_msg(self, reason):
+        log.debug("head=%s incoming=%s" % (self.incoming_head, self.incoming), extra={"sock": self})
         if self.incoming_head is None:
             if self.timeout is None:
                 if self.peer_closed:
@@ -1403,28 +1435,25 @@
 socket = SocketType = _socketobject
 
 
+# FIXME handshake_future - gates all requests. should be cheap (comparable to the old self.active)
+
 class ChildSocket(_realsocket):
     
     def __init__(self, parent_socket):
         super(ChildSocket, self).__init__(type=parent_socket.type)
         self.parent_socket = parent_socket
-        self.active = AtomicBoolean()
-        self.active_latch = CountDownLatch(1)
+        self._activation_cv = Condition()
+        self._activated = False
         self.accepted = False
         self.timeout = parent_socket.timeout
 
-    def _ensure_post_connect(self):
-        do_post_connect = not self.active.getAndSet(True)
-        if do_post_connect:
-            if hasattr(self.parent_socket, "ssl_wrap_child_socket"):
-                self.parent_socket.ssl_wrap_child_socket(self)
-            self._post_connect()
-            self.active_latch.countDown()
-
-    def _wait_on_latch(self):
-        log.debug("Waiting for activity", extra={"sock": self})
-        self.active_latch.await()
-        log.debug("Latch released, can now proceed", extra={"sock": self})
+    def _make_active(self, *ignore):  # ignore result arg when used as a listener on a future
+        if self._activated:
+            return
+        with self._activation_cv:
+            self._activated = True
+            self._activation_cv.notify()
+        log.debug("Child socket is now activated", extra={"sock": self})
 
     # FIXME raise exception for accept, listen, bind, connect, connect_ex
 
@@ -1434,25 +1463,25 @@
     # connection, not metadata.
 
     def send(self, data):
-        self._ensure_post_connect()
+        self._make_active()
         return super(ChildSocket, self).send(data)
 
     sendall = send
 
     def recv(self, bufsize, flags=0):
-        self._ensure_post_connect()
+        self._make_active()
         return super(ChildSocket, self).recv(bufsize, flags)
 
     def recvfrom(self, bufsize, flags=0):
-        self._ensure_post_connect()
+        self._make_active()
         return super(ChildSocket, self).recvfrom(bufsize, flags)
 
     def setblocking(self, mode):
-        self._ensure_post_connect()
+        self._make_active()
         return super(ChildSocket, self).setblocking(mode)
 
     def close(self):
-        self._ensure_post_connect()
+        self._make_active()
         super(ChildSocket, self).close()
         if self.open_count > 0:
             return
@@ -1465,7 +1494,7 @@
                     self.parent_socket.child_group.shutdownGracefully(0, 100, TimeUnit.MILLISECONDS)
 
     def shutdown(self, how):
-        self._ensure_post_connect()
+        self._make_active()
         super(ChildSocket, self).shutdown(how)
 
     def __del__(self):
@@ -1474,7 +1503,7 @@
         # handler is released when a GC happens, not necessarily
         # before shutdown of course.  Naturally no extra work will be
         # done in setting up the channel.
-        self.active_latch.countDown()
+        self._make_active()
         self.close()
 
 
diff --git a/Lib/_sslcerts.py b/Lib/_sslcerts.py
--- a/Lib/_sslcerts.py
+++ b/Lib/_sslcerts.py
@@ -24,8 +24,9 @@
     # http://bugs.jython.org/issue2469, due to the fact that jarjar-ed
     # jars - like other shading - lose their signatures. For most jars
     # this is not an issue, and we have been removing signature files
-    # since 2.7.0, but it causes conflicts Java's security provider
-    # model.
+    # since 2.7.0. But in this specific case, removing signatures then
+    # causes conflicts with Java's security provider model, because it
+    # requires signing.
     from org.bouncycastle.asn1.pkcs import PrivateKeyInfo
     from org.bouncycastle.cert import X509CertificateHolder
     from org.bouncycastle.cert.jcajce import JcaX509CertificateConverter
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -52,6 +52,7 @@
 from java.util import ArrayList, Locale, TimeZone, NoSuchElementException
 from java.util.concurrent import CountDownLatch
 from javax.naming.ldap import LdapName
+from javax.net.ssl import SSLException, SSLHandshakeException
 from javax.security.auth.x500 import X500Principal
 from org.ietf.jgss import Oid
 
@@ -393,7 +394,7 @@
 
     All Python stdlib modules shall use this function to create SSLContext
     objects in order to keep common settings in one place. The configuration
-    is less restrict than create_default_context()'s to increase backward
+    is less restricted than create_default_context()'s to increase backward
     compatibility.
     """
     if not isinstance(purpose, _ASN1Object):
@@ -443,17 +444,6 @@
         pipeline = ch.pipeline()
         pipeline.addFirst("ssl", self.ssl_handler)
 
-class RaceFreeSslHandler(SslHandler):
-    """
-    This is a temporary workaround to solve a race condition that is present in
-    Netty 4.0.33. The race condition causes an NPE because 'this.ctx' isn't set when
-    calling channelActive. Once we upgrade to a version of Netty that fixes the race
-    condition, we should remove this.
-    """
-
-    def channelActive(self, ctx):
-        self.ctx = ctx
-        SslHandler.channelActive(self)
 
 class SSLSocket(object):
 
@@ -465,6 +455,14 @@
         self.sock = sock
         self.do_handshake_on_connect = do_handshake_on_connect
         self._sock = sock._sock  # the real underlying socket
+
+        # FIXME in CPython, a check like so is performed - but this is
+        # not quite correct, based on tests. We should revisit to see
+        # if we can make this work as desired.
+
+        # if do_handshake_on_connect and self._sock.timeout == 0:
+        #     raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
+
         self._connected = False
         if _context:
             self._context = _context
@@ -507,30 +505,72 @@
 
         self.ssl_handler = None
         # We use _sslobj here to support the CPython convention that
-        # an object means we have handshaked, as used by existing code
-        # in the wild that looks at this ostensibly internal attribute
-        self._sslobj = None
-        self.handshake_count = 0
+        # an object means we have handshaked. It is used by existing code
+        # in the wild that looks at this ostensibly internal attribute.
+        
+        # FIXME CPython uses _sslobj to track the OpenSSL wrapper
+        # object that's implemented in C, with the following
+        # properties:
+        #
+        # 'cipher', 'compression', 'context', 'do_handshake',
+        # 'peer_certificate', 'pending', 'read', 'shutdown',
+        # 'tls_unique_cb', 'version', 'write'
+        self._sslobj = self   # setting to self is not quite right
 
         self.engine = None
 
         if self.do_handshake_on_connect and self._sock.connected:
+            log.debug("Handshaking socket on connect", extra={"sock": self._sock})
             if isinstance(self._sock, ChildSocket):
-                log.debug("Child socket - do not handshake! type=%s parent=%s", type(self._sock), self._sock.parent_socket,
-                          extra={"sock": self._sock})
+                # Need to handle child sockets differently depending
+                # on whether the parent socket is wrapped or not.
+                #
+                # In either case, we cannot handshake here in this
+                # thread - it must be done in the child pool and
+                # before the child is activated.
+                #
+                # 1. If wrapped, this is going through SSLSocket.accept
+
+                if isinstance(self._sock.parent_socket, SSLSocket):
+                    # already wrapped, via `wrap_child` function a few lines below
+                    log.debug(
+                        "Child socket - will handshake in child loop type=%s parent=%s",
+                        type(self._sock), self._sock.parent_socket,
+                        extra={"sock": self._sock})
+                    self._sock._make_active()
+
+                # 2. If not, using code will be calling SSLContext.wrap_socket
+                #    *after* accept from an unwrapped socket
+
+                else:
+                    log.debug("Child socket will wrap self with handshake", extra={"sock": self._sock})
+                    setup_handshake_latch = CountDownLatch(1)
+
+                    def setup_handshake():
+                        handshake_future = self.do_handshake()
+                        setup_handshake_latch.countDown()
+                        return handshake_future
+
+                    self._sock.ssl_wrap_self = setup_handshake
+                    self._sock._make_active()
+                    setup_handshake_latch.await()
+                    log.debug("Child socket waiting on handshake=%s", self._handshake_future, extra={"sock": self._sock})
+                    self._sock._handle_channel_future(self._handshake_future, "SSL handshake")
             else:
                 self.do_handshake()
 
         if hasattr(self._sock, "accepted_children"):
             def wrap_child(child):
-                log.debug("Wrapping child socket - about to handshake! parent=%s", self._sock, extra={"sock": child})
+                log.debug(
+                    "Wrapping child socket - about to handshake! parent=%s",
+                    self._sock, extra={"sock": child})
                 child._wrapper_socket = self.context.wrap_socket(
                     _socketobject(_sock=child),
                     do_handshake_on_connect=self.do_handshake_on_connect,
                     suppress_ragged_eofs=self.suppress_ragged_eofs,
                     server_side=True)
-
                 if self.do_handshake_on_connect:
+                    # this handshake will be done in the child pool - initChannel will block on it
                     child._wrapper_socket.do_handshake()
             self._sock.ssl_wrap_child_socket = wrap_child
 
@@ -583,15 +623,21 @@
         SSL channel, and the address of the remote client."""
         child, addr = self._sock.accept()
         if self.do_handshake_on_connect:
-            child.active_latch.await()
-
-        log.debug("accepted sock=%s wrapped=%s addr=%s", child, child._wrapper_socket, addr, extra={"sock": self._sock})
-        wrapped_child_socket = child._wrapper_socket
-        del child._wrapper_socket
-        return wrapped_child_socket, addr
+            wrapped_child_socket = child._wrapper_socket
+            del child._wrapper_socket
+            return wrapped_child_socket, addr
+        else:
+            return self.context.wrap_socket(
+                _socketobject(_sock=child),
+                do_handshake_on_connect=self.do_handshake_on_connect,
+                suppress_ragged_eofs=self.suppress_ragged_eofs,
+                server_side=True)
 
     def unwrap(self):
-        self._sock.channel.pipeline().remove("ssl")
+        try:
+            self._sock.channel.pipeline().remove("ssl")
+        except NoSuchElementException:
+            pass
         self.ssl_handler.close()
         return self._sock
 
@@ -601,16 +647,10 @@
 
         def handshake_step(result):
             log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
-
-            if not hasattr(self._sock, "active_latch"):
-                log.debug("Post connect step", extra={"sock": self._sock})
-                self._sock._post_connect()
-                self._sock._unlatch()
-            self._sslobj = object()  # we have now handshaked
             self._notify_selectors()
 
         if self.ssl_handler is None:
-            self.ssl_handler = RaceFreeSslHandler(self.engine)
+            self.ssl_handler = SslHandler(self.engine)
             self.ssl_handler.handshakeFuture().addListener(handshake_step)
 
             if hasattr(self._sock, "connected") and self._sock.connected:
@@ -621,38 +661,52 @@
                 log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                 self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))
 
-        handshake = self.ssl_handler.handshakeFuture()
-        time.sleep(0.001)  # Necessary apparently for the handler to get into a good state
+        self._handshake_future = self.ssl_handler.handshakeFuture()
         if isinstance(self._sock, ChildSocket):
+            pass
             # see
             # http://stackoverflow.com/questions/24628271/exception-in-netty-io-netty-util-concurrent-blockingoperationexception
-            # - we are doing this in the handler thread!
-            return
-
-        self._sock._handle_channel_future(handshake, "SSL handshake")
+            # - handshake in the child thread pool
+        else:
+            self._sock._handle_channel_future(self._handshake_future, "SSL handshake")
 
     def dup(self):
         raise NotImplemented("Can't dup() %s instances" %
                              self.__class__.__name__)
 
+    @raises_java_exception
+    def _ensure_handshake(self):
+        log.debug("Ensure handshake", extra={"sock": self}) 
+        self._sock._make_active()
+        # nonblocking code should never wait here, but only attempt to
+        # come to this point when notified via a selector
+        if not hasattr(self, "_handshake_future"):
+            self.do_handshake()
+        # additional synchronization guard if this is a child socket
+        self._handshake_future.sync()
+        log.debug("Completed post connect", extra={"sock": self})
+
     # Various pass through methods to the wrapped socket
 
     def send(self, data):
+        self._ensure_handshake()
         return self.sock.send(data)
 
     write = send
 
     def sendall(self, data):
+        self._ensure_handshake()
         return self.sock.sendall(data)
 
     def recv(self, bufsize, flags=0):
+        self._ensure_handshake()
         return self.sock.recv(bufsize, flags)
 
     def read(self, len=0, buffer=None):
         """Read up to LEN bytes and return them.
         Return zero-length string on EOF."""
-
         self._checkClosed()
+        self._ensure_handshake()
         # FIXME? breaks test_smtpnet.py
         # if not self._sslobj:
         #     raise ValueError("Read on closed or unwrapped SSL socket.")
@@ -672,17 +726,21 @@
                 raise
 
     def recvfrom(self, bufsize, flags=0):
+        self._ensure_handshake()
         return self.sock.recvfrom(bufsize, flags)
 
     def recvfrom_into(self, buffer, nbytes=0, flags=0):
+        self._ensure_handshake()
         return self.sock.recvfrom_into(buffer, nbytes, flags)
 
     def recv_into(self, buffer, nbytes=0, flags=0):
+        self._ensure_handshake()
         return self.sock.recv_into(buffer, nbytes, flags)
 
     def sendto(self, string, arg1, arg2=None):
         # as observed on CPython, sendto when wrapped ignores the
         # destination address, thereby behaving just like send
+        self._ensure_handshake()
         return self.sock.send(string)
 
     def close(self):
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -1313,7 +1313,6 @@
 
         # fails on Windows standalone, probably shouldn't
         test_netrc             # KeyError: 'foo.domain.com'
-        test_shutil            # Operation not permitted errors
         test_zipfile
 
         # fails on Windows standalone too, but more embarassing as java specific
@@ -1336,18 +1335,16 @@
 
         # Unreliable tests 
         test_asynchat
-        test_gc                # Rare failures depending on timing of Java gc
-        test_logging
-        test_select_new
-        test_socket            # flakey (Windows)
+        # test_gc                # Rare failures depending on timing of Java gc
+        # test_logging
         test_tarfile           # flakey (Windows)
-        test_threading
-        test_urllib2net        # unexpected output makes this a failure to regrtest.py
+        # test_urllib2net        # unexpected output makes this a failure to regrtest.py
 
-        # Tests that should work with socket-reboot, but currently fail/hang
-        test_ftplib            # NoSuchElementException ssl
+        # Failing tests here are because of lack of STARTTLS; see http://bugs.jython.org/issue2447
+        # (which produces "'NoneType' is not iterable" in the server accept loop)
+        test_ftplib
         test_httplib
-        test_poplib            # 'NoneType' is not iterable
+        test_poplib
         test_smtplib
 
         # Problems with the latest JSR 223 changes; see http://bugs.jython.org/issue2154
diff --git a/Lib/test/test_socket_jy.py b/Lib/test/test_socket_jy.py
--- a/Lib/test/test_socket_jy.py
+++ b/Lib/test/test_socket_jy.py
@@ -51,11 +51,11 @@
         connect_errno = 0
         connect_attempt = 0
 
-        while connect_errno != errno.EISCONN and connect_attempt < 5000:
+        while connect_errno != errno.EISCONN and connect_attempt < 10000:
             connect_attempt += 1
             connect_errno = sock.connect_ex(self.address)
             results[index].append(connect_errno)
-            time.sleep(0.001)
+            time.sleep(0.01)
         sock.close()
 
     def do_workout(self, num_threads=10):
@@ -108,10 +108,11 @@
         connect_attempt = 0
         sock = ssl.wrap_socket(sock, certfile=CERTFILE, do_handshake_on_connect=True)
 
-        while connect_errno != errno.EISCONN and connect_attempt < 500:
+        while connect_errno != errno.EISCONN and connect_attempt < 10000:
             connect_attempt += 1
             connect_errno = sock.connect_ex(self.address)
             results[index].append(connect_errno)
+            time.sleep(0.01)
         sock.close()
 
     def do_workout(self, num_threads=10):

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list