def close (self): try: coro.with_timeout (1, self.shutdown) except (openssl.Error, coro.TimeoutError): pass finally: coro.sock.close (self)
def get_connected(self): if self.state == self.UNCONNECTED: self.state = self.CONNECTING for i in range(self._num_retries): try: coro.with_timeout(self._retry_timeout, self._connect) except coro.TimeoutError: coro.sleep_relative(self._retry_timeout) except OSError as e: # wait a bit, maybe it'll come back up... coro.sleep_relative(self._retry_timeout) except: self.state = self.UNCONNECTED raise else: return # ok, we give up! # fail any pending requests self.state = self.UNCONNECTED for thread in self.pending_requests.values(): # avoid a race: if the thread is already scheduled, then # it's about to be awakened with the result it was looking # for, so don't bother trying to interrupt it - this will # cause the latent interrupt to show up at a later and # bizarre point in the code. [see bug 5322 and others] if not thread.scheduled: thread.raise_exception(RPC_Server_Unreachable) # fail anyone waiting on connect self.connection_cv.raise_all(RPC_Server_Unreachable)
def go(self): try: if G.connection_map.has_key(self.other_addr): return else: G.connection_map[self.other_addr] = self LOG('connect', self.direction, self.my_addr, self.other_addr) try: if self.direction == 'outgoing': coro.with_timeout(30, self.connect) self.send_version() while 1: command, payload = self.get_packet() if command is None: break self.do_command(command, payload) self.last_packet = coro.now except OSError: # XXX collect data on errnos LOG('connection', 'oserror', self.other_addr) except EOFError: LOG('connection', 'eoferror', self.other_addr) except coro.TimeoutError: LOG('connection', 'timeout', self.other_addr) finally: LOG('stopped', self.direction, self.my_addr, self.other_addr) del G.connection_map[self.other_addr] if self.direction == 'incoming': G.in_conn_sem.release(1) else: G.out_conn_sem.release(1)
def go (self): try: if G.connection_map.has_key (self.other_addr): return else: G.connection_map[self.other_addr] = self LOG ('connect', self.direction, self.my_addr, self.other_addr) try: if self.direction == 'outgoing': coro.with_timeout (30, self.connect) self.send_version() while 1: command, payload = self.get_packet() if command is None: break self.do_command (command, payload) self.last_packet = coro.now except OSError: # XXX collect data on errnos LOG ('connection', 'oserror', self.other_addr) except EOFError: LOG ('connection', 'eoferror', self.other_addr) except coro.TimeoutError: LOG ('connection', 'timeout', self.other_addr) finally: LOG ('stopped', self.direction, self.my_addr, self.other_addr) del G.connection_map[self.other_addr] if self.direction == 'incoming': G.in_conn_sem.release (1) else: G.out_conn_sem.release (1)
def go(self): try: if G.connection_map.has_key(self.other_addr): return else: G.connection_map[self.other_addr] = self G.log('connect', self.direction, self.my_addr, self.other_addr) try: if self.direction == 'outgoing': coro.with_timeout(30, self.connect) self.send_version() for command, payload in self.gen_packets(): self.do_command(command, payload) self.last_packet = coro.now except OSError: # XXX collect data on errnos G.log('connection', 'oserror', self.other_addr) except coro.TimeoutError: G.log('connection', 'timeout', self.other_addr) finally: G.log('stopped', self.direction, self.my_addr, self.other_addr) del G.connection_map[self.other_addr] if self.direction == 'incoming': G.in_conn_sem.release(1) else: G.out_conn_sem.release(1)
def shutdown(self, timeout): """shutdown(timeout) -> None Shuts down the server and all the children within timeout seconds. Rudely terminates sessions if they don't exit within timeout seconds. """ # Shut down the main accept loop if self.thread_id: try: my_thread = coro.get_thread_by_id (self.thread_id) except KeyError: # thread already exited return my_thread.shutdown() # Shut down all the children if self.clients: for c in self.clients: c.shutdown() # wait for all the children to finish try: coro.with_timeout(timeout, self.shutdown_cv.wait) except coro.TimeoutError: # kill hard for c in self.clients: c.shutdown(rudely=1)
def close(self): try: coro.with_timeout(1, self.shutdown) except (openssl.Error, coro.TimeoutError): pass finally: coro.sock.close(self)
def get_result(self, timeout): """Get query result waiting up to timeout seconds. If the query completes within the timeout, it will be returned. If the query raises an exception, the same exception will be raised by this call. If the query times out, this call will raise coro.TimeoutError. """ # See if the query has completed already; if not # wait for a result up to the timeout. if self._res is None: try: coro.with_timeout(timeout, self._cv.wait) except coro.TimeoutError: # Timeout, cancel the request. self._client.cancel() # The request may or may not be cancelled. Either way, # wait for the other thread to post a result and finish # using the db connection. while self._res is None: self._cv.wait() if isinstance(self._res, Exception): if (isinstance(self._res, BackendError) and self._res.error_code() == PG_ERROR_QUERY_CANCELLED): raise coro.TimeoutError # really did time out else: raise self._res # Fall through if we got an actual result return self._res
def send_with_producer (self, s, p): while 1: block = p.more() if block: coro.with_timeout (self.send_timeout, s.send, block) else: break
def go (self): try: if G.connection_map.has_key (self.other_addr): return else: G.connection_map[self.other_addr] = self G.log ('connect', self.direction, self.my_addr, self.other_addr) try: if self.direction == 'outgoing': coro.with_timeout (30, self.connect) self.send_version() for command, payload in self.gen_packets(): self.do_command (command, payload) self.last_packet = coro.now except OSError: # XXX collect data on errnos G.log ('connection', 'oserror', self.other_addr) except coro.TimeoutError: G.log ('connection', 'timeout', self.other_addr) finally: G.log ('stopped', self.direction, self.my_addr, self.other_addr) del G.connection_map[self.other_addr] if self.direction == 'incoming': G.in_conn_sem.release (1) else: G.out_conn_sem.release (1)
def get_connected (self): if self.state == self.UNCONNECTED: self.state = self.CONNECTING for i in range (self._num_retries): try: coro.with_timeout (self._retry_timeout, self._connect) except coro.TimeoutError: coro.sleep_relative (self._retry_timeout) except OSError as e: # wait a bit, maybe it'll come back up... coro.sleep_relative (self._retry_timeout) except: self.state = self.UNCONNECTED raise else: return # ok, we give up! # fail any pending requests self.state = self.UNCONNECTED for thread in self.pending_requests.values(): # avoid a race: if the thread is already scheduled, then # it's about to be awakened with the result it was looking # for, so don't bother trying to interrupt it - this will # cause the latent interrupt to show up at a later and # bizarre point in the code. [see bug 5322 and others] if not thread.scheduled: thread.raise_exception (RPC_Server_Unreachable) # fail anyone waiting on connect self.connection_cv.raise_all (RPC_Server_Unreachable)
def testit(family, address, block_sends, block_receives, expected_results): s = coro.make_socket(family, socket.SOCK_STREAM) server.block_sends = block_sends coro.with_timeout(5, s.connect, (address, server.port)) blocks = coro.with_timeout(5, s.readv, block_receives) self.assertEqual(len(blocks), len(expected_results)) for block, expected_block in zip(blocks, expected_results): self.assertEqual(block, expected_block)
def send_file (self, s, f): while 1: # use a big block size, since this is likely to be on a fast network block = f.read (32768) if block: coro.with_timeout(self.send_timeout, s.send, block) else: break
def test_with_timeout(): try: coro.print_stderr(' Should be a 1 second pause:\n') coro.with_timeout(1, coro.sleep_relative, 5) except coro.TimeoutError: pass else: raise ValueError('Timeout didn\'t happen as expected!')
def connect(): s = coro.make_socket (coro.AF.INET, socket.SOCK_STREAM) coro.with_timeout (5, s.connect, ('127.0.0.1', server.port)) howdy = coro.with_timeout (5, s.recv, 100) self.assertEqual (howdy, 'howdy!\r\n') count -= 1 if count == 0: server_thread.raise_exception(coro.Shutdown)
def test_with_timeout_with_interrupt(): coro.spawn(_test_with_timeout_with_interrupt, coro.current()) try: coro.print_stderr(' Should be no pause:\n') coro.with_timeout(1, coro.sleep_relative, 5) except coro.Interrupted, why: if why != 'foobar': raise ValueError('Interrupt value is not foobar!')
def join(self, timeout=None): if timeout is None: self.__co.join() else: try: coro.with_timeout(timeout, self.__co.join) except coro.TimeoutError: pass
def wait(self, timeout=None): if not self.__flag: if timeout is None: self.__cond.wait() else: try: coro.with_timeout(timeout, self.__cond.wait) except coro.TimeoutError: pass
def serve (port): s = coro.tcp_sock() s.bind (('', port)) s.listen (5) with self.assertRaises(coro.TimeoutError): conn, addr = coro.with_timeout(1, s.accept) # do this a second time to make sure no SimultaneousErrors occur with self.assertRaises(coro.TimeoutError): conn, addr = coro.with_timeout(1, s.accept)
def serve(port): s = coro.tcp_sock() s.bind(("", port)) s.listen(5) with self.assertRaises(coro.TimeoutError): conn, addr = coro.with_timeout(1, s.accept) # do this a second time to make sure no SimultaneousErrors occur with self.assertRaises(coro.TimeoutError): conn, addr = coro.with_timeout(1, s.accept)
def connect(self): """Connect to the host and port specified in __init__.""" self.sock = coro.tcp_sock() if self.timeout: coro.with_timeout(self.timeout, self.sock.connect, (self.host, self.port)) else: self.sock.connect((self.host, self.port)) if self._tunnel_host: self._tunnel()
def write_to_data_channel (self, dc, block_writer): global send_timeout try: while 1: block = block_writer() if not block: break else: coro.with_timeout (send_timeout, dc.send, block) finally: dc.close()
def testit(family, address, block_sends, expected_buffer_result, expected_return): global finished finished = coro.condition_variable() s = coro.make_socket(family, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, send_buffer_size) coro.with_timeout(5, s.connect, (address, server.port)) blocks = [ big_block[:size] for size in block_sends ] rc = coro.with_timeout(5, s.writev, blocks) s.close() if finished is not None: coro.with_timeout(5, finished.wait) self.assertEqual(expected_buffer_result, current_buffer) self.assertEqual(expected_return, rc)
def connect (self, host): global connect_timeout if not self.ip_re.match (host): ip = dnsqr.query(host,'A') if ip: # pull out the ip of the first entry ip = ip[0][1] else: # no results found for this entry raise dns_exceptions.DNS_Hard_Error else: ip = host coro.with_timeout (connect_timeout, self.s.connect, (ip, self.ftp_port)) self.read_response ('2')
def make_data_channel (self): global connect_timeout if self.pasv_mode: reply = self.command ('PASV', '2') ip, port = self.parse_pasv_reply (reply) dc = coro.make_socket (socket.AF_INET, socket.SOCK_STREAM) if self.local_ip: dc.bind((self.local_ip, 0)) if self.debug: coro.print_stderr ('connecting to %s:%s\n' % (ip, port)) coro.with_timeout (connect_timeout, dc.connect, (ip, port)) return dc else: raise ftp_error, "non-pasv transfers not yet implemented"
def testit(family, address, block_sends, expected_buffer_result, expected_return): global finished finished = coro.condition_variable() s = coro.make_socket(family, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, send_buffer_size) coro.with_timeout(5, s.connect, (address, server.port)) blocks = [big_block[:size] for size in block_sends] rc = coro.with_timeout(5, s.writev, blocks) s.close() if finished is not None: coro.with_timeout(5, finished.wait) self.assertEqual(expected_buffer_result, current_buffer) self.assertEqual(expected_return, rc)
def getheaders (self, hashes=None): # on this connection only, download the entire chain of headers from our # tip to the other side's tip. if hashes is None: hashes = G.block_db.set_for_getblocks() if not hashes: hashes = [network.genesis_block_hash] hashes.append (ZERO_NAME) chain = [hashes[0]] while 1: # getheaders and getblocks have identical args/layout. self.send_packet ('getheaders', pack_getblocks (self.version, hashes)) _, data = coro.with_timeout (30, self.wait_for, 'headers') blocks = unpack_headers (data) if len(blocks) == 0: break else: for block in blocks: if block.prev_block == chain[-1]: chain.append (block.name) else: G.log ('getheaders', 'nochain') return [] hashes[0] = chain[-1] return chain
def lookup (self, qname, qtype, timeout=10, retries=3, port=53): m = new_packer() while 1: qid = random.randrange (65536) # avoid collisions if qid not in self.inflight_ids: break m.addHeader(qid, 0, packet.OPCODE.QUERY, 0, 0, 1, 0, 0,0,1,0, 0, 0) m.addQuestion (qname, qtype, packet.CLASS.IN) p = m.getbuf() for addr in self.nameservers: for i in range (retries): self.inflight.acquire (1) self.inflight_ids.add (qid) try: s = coro.udp_sock() s.connect ((addr, port)) s.send (p) try: reply = coro.with_timeout (timeout, s.recv, 3000) if not reply: continue r = unpack_reply(reply) if r.id != qid: raise QueryFailed ("bad id in reply") else: return r except coro.TimeoutError: pass finally: self.inflight.release (1) self.inflight_ids.remove (qid) raise QueryFailed ("no reply from nameservers")
def with_timeout(timeout, function, *args, **kwargs): """Call a function with a timeout. This version supports running even if the coro event loop isn't running by using SIGALRM. See `coro._coro.sched.with_timeout` for more detail. :Parameters: - `timeout`: The number of seconds to wait before raising the timeout. May be a floating point number. - `function`: The function to call. :Return: Returns the return value of the function. :Exceptions: - `coro.TimeoutError`: The timeout expired. """ if coro.coro_is_running(): return coro.with_timeout(timeout, function, *args, **kwargs) else: # Use sigalarm to do the magic. old_sigalrm_handler = signal.signal(signal.SIGALRM, _shutdown_sigalrm_handler) try: try: signal.alarm(timeout) return function(*args, **kwargs) except _shutdown_sigalrm_exc: raise coro.TimeoutError finally: signal.alarm(0) signal.signal(signal.SIGALRM, old_sigalrm_handler)
def read_body(self): """Read the message body, if any, so that it's cleared from the input stream. This avoids problems with keep-alives if the request handler doesn't read the body itself. This used to be done in the __init__method, but that can lead to a fatal error in the Python interpreter (see bug 3367). The ultimate solution is to fix the way connections are handled to ensure that we don't reuse the connection if the body wasn't fully read by the request handler.""" self._body = '' clen = self.get_request_header('Content-Length') if clen: try: clen = int(clen) self._body = coro.with_timeout(60, self._client.read, clen) if len(self._body) < clen: qlog.write('WEBUI.CONN_ERROR', 'http', id(self), 'Truncated body (%d<%d) (req:%s)' % \ (len(self._body), clen, self._request)) self._error = 1 # didn't get the body we were promised except coro.TimeoutError: qlog.write('WEBUI.CONN_ERROR', 'http', id(self), 'Body read timeout (req:%s)' % self._request) self._error = 1 except ValueError: qlog.write('WEBUI.CONN_ERROR', 'http', id(self), 'Invalid Content-Length (%s) (req:%s)' % \ (clen, self._request) ) self._error = 1
def session (sid, fifo): i = 0 while 1: try: # wait a half hour for a new hit request = coro.with_timeout (1800, fifo.pop) except coro.TimeoutError: break else: request['content-type'] = 'text/html' if i == 10: request.push ( '<html><h1>Session Over! Bye!</h1>' '<a href="session">start over</a>' '</html>' ) request.done() break else: request.push ( '<html><h1>Session Demo</h1><br><h2>Hit=%d</h2>' '<a href="session">hit me!</a>' '</html>' % (i,) ) request.done() i += 1
def recv_loop(self): try: try: while 1: while len(self.buffer): self.unpack_frame() if self.heartbeat: block = coro.with_timeout(self.heartbeat * 2, self.s.recv, self.buffer_size) else: block = self.s.recv(self.buffer_size) if not block: break else: self.buffer += block if self.heartbeat and self.secs_since_send( ) > self.heartbeat: self.send_frame(spec.FRAME_HEARTBEAT, 0, '') except coro.TimeoutError: # two heartbeat periods have expired with no data, so we let the # connection close. XXX Should we bother trying to call connection.close()? pass finally: self.notify_channels_of_close() self.closed_cv.wake_all() self.s.close()
def recv_loop (self): try: try: while 1: while len (self.buffer): self.unpack_frame() self._s_recv_sema.acquire(1) try: if self.heartbeat: block = coro.with_timeout (self.heartbeat * 2, self.s.recv, self.buffer_size) else: block = self.s.recv (self.buffer_size) finally: self._s_recv_sema.release(1) if not block: break else: self.buffer += block if self.heartbeat and self.secs_since_send() > self.heartbeat: self.send_frame (spec.FRAME_HEARTBEAT, 0, '') except coro.TimeoutError: # two heartbeat periods have expired with no data, so we let the # connection close. XXX Should we bother trying to call connection.close()? pass except Exception, e: if self._exception_handler: self._exception_handler(e) finally: self.notify_channels_of_close()
def _with_timeout(self, func, *args, **kwargs): if self.timeout: try: return coro.with_timeout(self.timeout, func, *args, **kwargs) except coro.TimeoutError: raise timeout('Timed out') else: return func(*args, **kwargs)
def read_from_data_channel (self, dc, block_reader): global recv_timeout while 1: block = coro.with_timeout (recv_timeout, dc.recv, 8192) if not block: break else: block_reader (block)
def wait(self, timeout=None): # This API is a little on the bizarre side. Probably due to some # preemption race conditions we don't have in shrapnel. # XXX: This is not emulating the "save/restore" logic of the Python # version. We could probably do that without too much difficulty # if self.lock == RLock. self.__lock.release() try: if timeout is None: self.__cv.wait() else: try: coro.with_timeout(timeout, self.__cv.wait) except coro.TimeoutError: # Seems dumb not to return an indication it timed out. pass finally: self.__lock.acquire()
def get_packet(self, timeout=1800): data = coro.with_timeout(timeout, self.conn.recv_exact, 24) if not data: self.log('closed', self.other_addr) return None, None magic, command, length, checksum = struct.unpack('<I12sII', data) command = command.strip('\x00') if self.verbose and command not in ('ping', 'pong'): LOG('<=', command) self.packet_count += 1 self.header = magic, command, length if length: payload = coro.with_timeout(30, self.conn.recv_exact, length) else: payload = '' if self.packet: self.log('recv', self.other_addr, command, payload) return (command, payload)
def get_packet (self, timeout=1800): data = coro.with_timeout (timeout, self.conn.recv_exact, 24) if not data: self.log ('closed', self.other_addr) return None, None magic, command, length, checksum = struct.unpack ('<I12sII', data) command = command.strip ('\x00') if self.verbose and command not in ('ping', 'pong'): LOG ('<=', command) self.packet_count += 1 self.header = magic, command, length if length: payload = coro.with_timeout (30, self.conn.recv_exact, length) else: payload = '' if self.packet: self.log ('recv', self.other_addr, command, payload) return (command, payload)
def send_message(self, msg): msgid = self.msgid self.msgid += 1 self.sock.send(SEQUENCE(INTEGER(msgid), msg)) try: self.pending[msgid] = me = coro.current() reply = coro.with_timeout(self.default_timeout, me._yield) return reply finally: del self.pending[msgid]
def send_message (self, msg): msgid = self.msgid self.msgid += 1 self.sock.send (SEQUENCE (INTEGER (msgid), msg)) try: self.pending[msgid] = me = coro.current() reply = coro.with_timeout (self.default_timeout, me._yield) return reply finally: del self.pending[msgid]
def go(self): rnd = open('/dev/urandom', 'rb') try: try: coro.with_timeout(30, self.connect) self.send_version() while 1: try: command, payload = coro.with_timeout( 60, self.get_packet) if command is None: break self.do_command(command, payload) except coro.TimeoutError: self.last_nonce = rnd.read(8) self.send_packet('ping', self.last_nonce) except (OSError, EOFError, coro.TimeoutError): pass finally: self.conn.close()