Skip to content

Instantly share code, notes, and snippets.

@jimbaker
Created November 13, 2015 22:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jimbaker/72a44fd7c54d26bcc4b0 to your computer and use it in GitHub Desktop.
Save jimbaker/72a44fd7c54d26bcc4b0 to your computer and use it in GitHub Desktop.
Diff for socket.connect_ex to returning EALREADY when a socket connection is already in progress
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment