diff -r 03f797ecd7ea Lib/_socket.py --- a/Lib/_socket.py Thu Nov 12 13:47:41 2015 +1100 +++ b/Lib/_socket.py Fri Nov 13 15:08:47 2015 -0700 @@ -28,7 +28,8 @@ from java.util import NoSuchElementException from java.util.concurrent import ( ArrayBlockingQueue, CopyOnWriteArrayList, CountDownLatch, LinkedBlockingQueue, - RejectedExecutionException, ThreadFactory, TimeUnit) + ExecutionException, RejectedExecutionException, ThreadFactory, + TimeoutException, TimeUnit) from java.util.concurrent.atomic import AtomicBoolean, AtomicLong from javax.net.ssl import SSLPeerUnverifiedException, SSLException @@ -852,7 +853,7 @@ if self.bind_addr: log.debug("Connect %s to %s", self.bind_addr, addr, extra={"sock": self}) - bind_future = bootstrap.bind(self.bind_addr) + bind_future = bootstrap.bind(self.bind_addr).sync() self._handle_channel_future(bind_future, "local bind") self.channel = bind_future.channel() else: @@ -888,16 +889,39 @@ log.debug("Completed connection to %s", addr, extra={"sock": self}) def connect_ex(self, addr): + was_connecting = self.connected # actually means self.connecting if + # not blocking if not self.connected: try: self.connect(addr) except error as e: return e.errno if not self.connect_future.isDone(): - return errno.EINPROGRESS + if was_connecting: + try: + # Timing is based on CPython and was empirically + # guestimated. 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! + self.connect_future.get(1500, TimeUnit.MICROSECONDS) + except ExecutionException: + # generally raised if closed; pick up the state + # when testing for success + pass + except TimeoutException: + # more than 1.5ms, will report EALREADY below + pass + + if not self.connect_future.isDone(): + if was_connecting: + return errno.EALREADY + else: + return errno.EINPROGRESS elif self.connect_future.isSuccess(): return errno.EISCONN else: + print self.connect_future.cause() return errno.ENOTCONN # SERVER METHODS