--- socket.py 2005-05-27 20:47:53.420411200 +0100 +++ jytimeoutsocket.py 2005-05-29 16:16:18.113148800 +0100 @@ -6,9 +6,10 @@ - No asynchronous behavior - No socket options - Can't do a very good gethostbyaddr() right... - +- 20050527: updated by Alan Kennedy to support socket timeouts. """ +import java.io import java.net import org.python.core import jarray @@ -20,6 +21,7 @@ 'gethostbyname', 'gethostname', 'socket', 'getaddrinfo'] error = IOError +class timeout(error): pass AF_INET = 2 @@ -69,7 +71,7 @@ return (names[0], names, addrs) -def socket(family, type, flags=0): +def socket(family = AF_INET, type = SOCK_STREAM, flags=0): assert family == AF_INET assert type in (SOCK_DGRAM, SOCK_STREAM) assert flags == 0 @@ -81,8 +83,36 @@ def getaddrinfo(host, port, family=0, socktype=SOCK_STREAM, proto=0, flags=0): return ( (AF_INET, socktype, 0, "", (gethostbyname(host), port)), ) +_defaulttimeout = None +def getdefaulttimeout(): + return _defaulttimeout +def _get_timeout_value(value): + if value is None: + return None + try: + floatval = float(value) + except ValueError: + raise TypeError('A float is required') + if floatval < 0: + raise ValueError('Timeout value out of range') + if floatval < 0.001: # 1 millisecond + # java interprets a zero timeout as an infinite timeout + # python interprets a zero timeout as equivalent to non-blocking + # we cannot represent python semantics for a zero timeout on + # java (if we want it to work on pre 1.4 JVMs) + # so we use the shortest timeout possible, 1.1 millisecond + return 0.0011 + return floatval + +def setdefaulttimeout(timeout): + try: + global _defaulttimeout + _defaulttimeout = _get_timeout_value(timeout) + finally: + _tcpsocket.timeout = _defaulttimeout + class _tcpsocket: sock = None @@ -93,6 +123,9 @@ file_count = 0 reuse_addr = 0 + def __init__(self): + self.timeout = _defaulttimeout + def bind(self, addr, port=None): if port is not None: addr = (addr, port) @@ -122,7 +155,12 @@ if not self.sock: self.listen() assert self.server - sock = self.sock.accept() + if self.timeout: + self.sock.setSoTimeout(int(self.timeout*1000)) + try: + sock = self.sock.accept() + except java.net.SocketTimeoutException, jnste: + raise timeout('timed out') host = sock.getInetAddress().getHostName() port = sock.getPort() conn = _tcpsocket() @@ -137,7 +175,16 @@ host, port = addr if host == "": host = java.net.InetAddress.getLocalHost() - self._setup(java.net.Socket(host, port)) + try: + cli_sock = java.net.Socket() + addr = java.net.InetSocketAddress(host, port) + if self.timeout: + cli_sock.connect(addr, int(self.timeout*1000)) + else: + cli_sock.connect(addr) + self._setup(cli_sock) + except java.net.SocketTimeoutException, jnste: + raise timeout('timed out') def _setup(self, sock): self.sock = sock @@ -149,7 +196,10 @@ def recv(self, n): assert self.sock data = jarray.zeros(n, 'b') - m = self.istream.read(data) + try: + m = self.istream.read(data) + except java.io.InterruptedIOException , jiiie: + raise timeout('timed out') if m <= 0: return "" if m < n: @@ -270,6 +320,13 @@ if sock: sock.close() + def gettimeout(self): + return self.timeout + + def settimeout(self, timeout): + self.timeout = _get_timeout_value(timeout) + if self.timeout and self.sock: + self.sock.setSoTimeout(int(self.timeout*1000)) class _udpsocket: