Closed
Description
The Stream class is supposed to use the lib.compat layer, in order to make use of poll() or select() depending on the OS. But the Stream.poll() method actually uses the builtin select() function straight, thus being prone to the select limitation of not handling file descriptors higher than 1024.
To prove this, you can try the following code (on Linux):
import rpyc
import traceback
import time
# make sure we open enough fd and keep them to go beyond 1024
c = []
for i in range(1030):
c.append(open('/dev/null'))
# establish an RPyC connection
rpcconn = rpyc.connect('yourserver.org', YOURPORT)
remote_root_ref = rpcconn.async_request(rpyc.core.consts.HANDLE_GETROOT)
remote_root_ref.set_expiry(1.0)
c.append(rpcconn)
try:
# use it - this calls Stream.poll(), which actually is a select() ...
rpcconn._remote_root = remote_root_ref.value
print 'Successfully connected, waiting 10 secs before terminating...'
time.sleep(10)
except Exception, e:
print i, e
traceback.print_exc()
The stack trace includes the following error:
error: filedescriptor out of range in select()
The following is a simple patch to fix this bug, can you please review it? Thanks!
diff --git a/rpyc/core/stream.py b/rpyc/core/stream.py
index eed2d87..1e680a7 100644
--- a/rpyc/core/stream.py
+++ b/rpyc/core/stream.py
@@ -8,7 +8,7 @@ import socket
import time
import errno
from rpyc.lib import safe_import
-from rpyc.lib.compat import select, select_error, BYTES_LITERAL, get_exc_errno, maxint
+from rpyc.lib.compat import poll, select_error, BYTES_LITERAL, get_exc_errno, maxint
win32file = safe_import("win32file")
win32pipe = safe_import("win32pipe")
msvcrt = safe_import("msvcrt")
@@ -36,9 +36,11 @@ class Stream(object):
"""indicates whether the stream has data to read (within *timeout*
seconds)"""
try:
+ p = poll() # from lib.compat, it may be a select object on non-Unix platforms
+ p.register(self.fileno(), "r")
while True:
try:
- rl, _, _ = select([self], [], [], timeout)
+ rl = p.poll(timeout)
except select_error:
ex = sys.exc_info()[1]
if ex.args[0] == errno.EINTR:
@@ -48,8 +50,10 @@ class Stream(object):
else:
break
except ValueError:
- # i get this some times: "ValueError: file descriptor cannot be a negative integer (-1)"
- # let's translate it to select.error
+ # if the underlying call is a select(), then the following errors may happen:
+ # - "ValueError: filedescriptor cannot be a negative integer (-1)"
+ # - "ValueError: filedescriptor out of range in select()"
+ # let's translate them to select.error
ex = sys.exc_info()[1]
raise select_error(str(ex))
return bool(rl)
Metadata
Metadata
Assignees
Labels
No labels