139 lines
4.2 KiB
Python
139 lines
4.2 KiB
Python
![]() |
|
||
|
# -------------------------------------------------------------
|
||
|
# select.py: Emulation of Python select module.
|
||
|
# -------------------------------------------------------------
|
||
|
|
||
|
"""
|
||
|
I2P Python API - Emulation of Python select module.
|
||
|
"""
|
||
|
|
||
|
import time
|
||
|
|
||
|
import i2p.socket
|
||
|
from i2p.pylib import select as pyselect # Import Python select
|
||
|
|
||
|
# --------------------------------------------------
|
||
|
# Poll and select
|
||
|
# --------------------------------------------------
|
||
|
|
||
|
POLLIN = 1 # There is data to read
|
||
|
POLLPRI = 1 # Same as POLLIN
|
||
|
POLLOUT = 4 # Ready for output
|
||
|
POLLERR = 8 # Wait for error condition
|
||
|
POLLHUP = 16 # Not implemented
|
||
|
POLLNVAL = 32 # Not implemented
|
||
|
|
||
|
class Poll:
|
||
|
"""Class implementing poll interface. Works for Python sockets
|
||
|
and SAM sockets."""
|
||
|
def __init__(self):
|
||
|
self.fds = {} # Maps _hash() -> (socket, mask)
|
||
|
def _hash(self, fd):
|
||
|
"""Get a unique number for each object."""
|
||
|
if isinstance(fd, int):
|
||
|
return fd # Use the fd itself if integer.
|
||
|
else:
|
||
|
return id(fd) # Use object address (no copies!)
|
||
|
def register(self, fd, eventmask=POLLIN|POLLOUT|POLLERR):
|
||
|
self.fds[self._hash(fd)] = (fd, eventmask)
|
||
|
def unregister(self, fd):
|
||
|
del self.fds[self._hash(fd)]
|
||
|
def poll(self, timeout=None):
|
||
|
readlist, writelist, errlist = [], [], []
|
||
|
for F, mask in self.fds:
|
||
|
if mask & POLLIN: readlist += [F]
|
||
|
if mask & POLLOUT: writelist += [F]
|
||
|
if mask & POLLERR: errlist += [F]
|
||
|
(Rs, Ws, Es) = select(readlist, writelist, errlist,
|
||
|
timeout=timeout)
|
||
|
ans = []
|
||
|
for R in Rs: ans.append((R, POLLIN))
|
||
|
for W in Ws: ans.append((W, POLLOUT))
|
||
|
for E in Es: ans.append((E, POLLERR))
|
||
|
return ans
|
||
|
|
||
|
def poll():
|
||
|
"""Returns a polling object. Works on SAM sockets and Python
|
||
|
sockets. See select.poll() in the Python library for more
|
||
|
information.
|
||
|
|
||
|
Polling flags specified in this module:
|
||
|
- POLLIN
|
||
|
- POLLOUT
|
||
|
- POLLERR
|
||
|
- POLLHUP
|
||
|
- POLLNVAL
|
||
|
- POLLPRI
|
||
|
"""
|
||
|
return Poll()
|
||
|
|
||
|
def select(readlist, writelist, errlist, timeout=None):
|
||
|
"""Performs a select call. Works on SAM sockets and Python
|
||
|
sockets. See select.select() in the Python library for more
|
||
|
information."""
|
||
|
Rans = []
|
||
|
Wans = []
|
||
|
Eans = []
|
||
|
if timeout != None: end = time.clock() + timeout
|
||
|
while True:
|
||
|
# FIXME: Check performance.
|
||
|
# Use pyselect.poll for Python sockets, if needed for speed.
|
||
|
|
||
|
# Check for read availability.
|
||
|
for R in readlist:
|
||
|
if isinstance(R, int) or hasattr(R, 'fileno'):
|
||
|
# Python socket
|
||
|
if len(pyselect.select([R], [], [], 0.0)[0]) > 0:
|
||
|
Rans.append(R)
|
||
|
else:
|
||
|
# SAM Socket
|
||
|
if R.type == i2p.socket.SOCK_STREAM:
|
||
|
try:
|
||
|
R._verify_connected()
|
||
|
Rans.append(R)
|
||
|
except:
|
||
|
pass
|
||
|
else:
|
||
|
if len(R) > 0: Rans.append(R)
|
||
|
|
||
|
# Check for write availability.
|
||
|
for W in writelist:
|
||
|
if isinstance(W, int) or hasattr(W, 'fileno'):
|
||
|
# Python socket
|
||
|
if len(pyselect.select([], [W], [], 0.0)[1]) > 0:
|
||
|
Wans.append(W)
|
||
|
else:
|
||
|
# SAM Socket
|
||
|
if W.type == i2p.socket.SOCK_STREAM:
|
||
|
try:
|
||
|
W._verify_connected()
|
||
|
Wans.append(W)
|
||
|
except:
|
||
|
pass
|
||
|
else:
|
||
|
Wans.append(W)
|
||
|
|
||
|
# Check for error conditions.
|
||
|
# These can only be stream errors.
|
||
|
for E in errlist:
|
||
|
if isinstance(E, int) or hasattr(E, 'fileno'):
|
||
|
# Python socket
|
||
|
if len(pyselect.select([], [], [E], 0.0)[2]) > 0:
|
||
|
Eans.append(E)
|
||
|
else:
|
||
|
if E.type == i2p.socket.SOCK_STREAM:
|
||
|
try:
|
||
|
# FIXME: Use a ._get_error() function for errors.
|
||
|
# Socket can only have an error if it connected.
|
||
|
E._verify_connected()
|
||
|
if E.sessobj.err != None:
|
||
|
Eans.append(E)
|
||
|
except:
|
||
|
pass
|
||
|
if timeout != None and time.clock() >= end: break
|
||
|
if len(Rans) != 0 or len(Wans) != 0 or len(Eans) != 0: break
|
||
|
|
||
|
time.sleep(0.01)
|
||
|
|
||
|
return (Rans, Wans, Eans)
|