def run(self): cov_files = glob.glob('.coverage*') try: import coverage omitted_files = ['*site-packages*'] cov = coverage.Coverage(data_file='.coverage.%s' % (len(cov_files) + 1), omit=omitted_files) cov.start() except ImportError: cov = None suite = unittest.TestSuite() import stomp.test if self.test == '*': logging.info('Running all tests') tests = stomp.test.__all__ else: tests = self.test.split(',') for tst in tests: suite.addTests(unittest.TestLoader().loadTestsFromName( 'stomp.test.%s' % tst)) runner = unittest.TextTestRunner(verbosity=2) res = runner.run(suite) if cov: cov.stop() cov.save()
def transmit(self, frame): """ Convert a frame object to a frame string and transmit to the server. :param Frame frame: the Frame object to transmit """ with self.__listeners_change_condition: listeners = sorted(self.listeners.items()) for (_, listener) in listeners: if not listener: continue try: listener.on_send(frame) except AttributeError: continue if frame.cmd == CMD_DISCONNECT and HDR_RECEIPT in frame.headers: self.__disconnect_receipt = frame.headers[HDR_RECEIPT] lines = convert_frame(frame) packed_frame = pack(lines) if logging.isEnabledFor(logging.DEBUG): logging.debug("Sending frame: %s", clean_lines(lines)) else: logging.info("Sending frame: %r", frame.cmd or "heartbeat") self.send(packed_frame)
def __heartbeat_loop(self): """ Main loop for sending (and monitoring received) heartbeats. """ logging.info('Starting heartbeat loop') now = monotonic() # Setup the initial due time for the outbound heartbeat if self.send_sleep != 0: self.next_outbound_heartbeat = now + self.send_sleep while self.running: now = monotonic() next_events = [] if self.next_outbound_heartbeat is not None: next_events.append(self.next_outbound_heartbeat - now) if self.receive_sleep != 0: t = self.received_heartbeat + self.receive_sleep - now if t > 0: next_events.append(t) sleep_time = min(next_events) if sleep_time > 0: terminate = self.heartbeat_terminate_event.wait(sleep_time) if terminate: break now = monotonic() if not self.transport.is_connected(): time.sleep(self.send_sleep) continue if self.send_sleep != 0 and now > self.next_outbound_heartbeat: logging.debug("Sending a heartbeat message at %s", now) try: self.transport.transmit(utils.Frame(None, {}, None)) except exception.NotConnectedException: logging.debug("Lost connection, unable to send heartbeat") except Exception: _, e, _ = sys.exc_info() logging.debug("Unable to send heartbeat, due to: %s", e) if self.receive_sleep != 0: diff_receive = now - self.received_heartbeat if diff_receive > self.receive_sleep: # heartbeat timeout logging.warning( "Heartbeat timeout: diff_receive=%s, time=%s, lastrec=%s", diff_receive, now, self.received_heartbeat) self.transport.set_connected(False) self.transport.disconnect_socket() self.transport.stop() for listener in self.transport.listeners.values(): listener.on_heartbeat_timeout() self.heartbeat_thread = None self.heartbeat_terminate_event.clear() logging.info('Heartbeat loop ended')
def on_connecting(self, host_and_port): """ Increment the connection count. See :py:meth:`ConnectionListener.on_connecting` :param (str,int) host_and_port: the host and port as a tuple """ logging.info("connecting %s %s (x %s)", host_and_port[0], host_and_port[1], self.connections) self.connections += 1
def try_setsockopt(sock, name, fam, opt, val): if val is None: return True # no value to set always works try: sock.setsockopt(fam, opt, val) logging.info("keepalive: set %r option to %r on socket", name, val) except: logging.error("keepalive: unable to set %r option to %r on socket", name, val) return False return True
def on_error(self, headers, body): """ Increment the error count. See :py:meth:`ConnectionListener.on_error` :param dict headers: headers in the message :param body: the message content """ if logging.isEnabledFor(logging.DEBUG): logging.debug("received an error %s [%s]", body, headers) else: logging.info("received an error %s", body) self.errors += 1
def start(self): """ Start the connection. This should be called after all listeners have been registered. If this method is not called, no frames will be received by the connection and no SSL/TLS handshake will occur. """ self.running = True self.attempt_connection() receiver_thread = self.create_thread_fc(self.__receiver_loop) logging.info("Created thread %s using func %s", receiver_thread, self.create_thread_fc) self.notify("connecting")
def start(self): logging.info("Starting stomp server") self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.s.bind((self.host, self.port)) self.s.listen(1) self.running = True thread = threading.Thread(None, self.run) thread.daemon = True thread.start() self.stopped = False logging.info("Stomp server started")
def stop(self): logging.info("Stopping test server") if self.conn: try: self.conn.shutdown(socket.SHUT_WR) except Exception: pass self.conn.close() if self.s: self.s.close() self.running = False self.conn = None self.s = None self.stopped = True logging.info("Connection stopped")
def process_frame(self, f, frame_str): """ :param Frame f: Frame object :param bytes frame_str: raw frame content """ frame_type = f.cmd.lower() if frame_type in ["connected", "message", "receipt", "error", "heartbeat"]: if frame_type == "message": self.notify("before_message", f) if logging.isEnabledFor(logging.DEBUG): logging.debug("Received frame: %r, headers=%r, body=%r", f.cmd, f.headers, f.body) else: logging.info("Received frame: %r, len(body)=%r", f.cmd, length(f.body)) self.notify(frame_type, f) else: logging.warning("Unknown response frame type: '%s' (frame length was %d)", frame_type, length(frame_str))
def __receiver_loop(self): """ Main loop listening for incoming data. """ logging.info("Starting receiver loop (%s)", threading.current_thread()) notify_disconnected = True try: while self.running: try: while self.running: frames = self.__read() for frame in frames: if self.__is_eol(frame): f = HEARTBEAT_FRAME else: f = parse_frame(frame) if f is None: continue if self.__auto_decode: f.body = decode(f.body) self.process_frame(f, frame) except exception.ConnectionClosedException: if self.running: # # Clear out any half-received messages after losing connection # self.__recvbuf = b'' self.running = False notify_disconnected = True break finally: self.cleanup() finally: with self.__receiver_thread_exit_condition: self.__receiver_thread_exited = True self.__receiver_thread_exit_condition.notifyAll() logging.info("Receiver loop ended") self.notify("receiver_loop_completed") if notify_disconnected and not self.__notified_on_disconnect: self.notify("disconnected") with self.__connect_wait_condition: self.__connect_wait_condition.notifyAll()
def __enable_keepalive(self): def try_setsockopt(sock, name, fam, opt, val): if val is None: return True # no value to set always works try: sock.setsockopt(fam, opt, val) logging.info("keepalive: set %r option to %r on socket", name, val) except: logging.error( "keepalive: unable to set %r option to %r on socket", name, val) return False return True ka = self.__keepalive if not ka: return if ka is True: ka_sig = 'auto' ka_args = () else: try: ka_sig = ka[0] ka_args = ka[1:] except Exception: logging.error("keepalive: bad specification %r", ka) return if ka_sig == 'auto': if LINUX_KEEPALIVE_AVAIL: ka_sig = 'linux' ka_args = None logging.info("keepalive: autodetected linux-style support") else: logging.error( "keepalive: unable to detect any implementation, DISABLED!" ) return if ka_sig == 'linux': logging.info("keepalive: activating linux-style support") if ka_args is None: logging.info("keepalive: using system defaults") ka_args = (None, None, None) lka_idle, lka_intvl, lka_cnt = ka_args if try_setsockopt(self.socket, 'enable', SOL_SOCKET, SO_KEEPALIVE, 1): try_setsockopt(self.socket, 'idle time', SOL_TCP, TCP_KEEPIDLE, lka_idle) try_setsockopt(self.socket, 'interval', SOL_TCP, TCP_KEEPINTVL, lka_intvl) try_setsockopt(self.socket, 'count', SOL_TCP, TCP_KEEPCNT, lka_cnt) else: logging.error( "keepalive: implementation %r not recognized or not supported", ka_sig)
def run(self): self.conn, _ = self.s.accept() while self.running: try: _ = self.conn.recv(1024) frame = self.get_next_frame() if self.conn is None: break if frame is not None: logging.info("Stompserver sending frame %s", frame) self.conn.send(encode(frame)) except Exception: _, e, _ = sys.exc_info() logging.debug(e) break time.sleep(0.1) try: self.conn.close() except: pass self.stopped = True logging.info("Run loop completed")
def __print(self, msg, *args): if self.print_to_log: logging.info(msg, *args) else: print(msg % args)
def attempt_connection(self): """ Try connecting to the (host, port) tuples specified at construction time. """ self.connection_error = False sleep_exp = 1 connect_count = 0 while self.running and self.socket is None and ( connect_count < self.__reconnect_attempts_max or self.__reconnect_attempts_max == -1): for host_and_port in self.__host_and_ports: try: logging.info("Attempting connection to host %s, port %s", host_and_port[0], host_and_port[1]) self.socket = socket.create_connection( host_and_port, self.__timeout) self.__enable_keepalive() need_ssl = self.__need_ssl(host_and_port) if need_ssl: # wrap socket ssl_params = self.get_ssl(host_and_port) if ssl_params['ca_certs']: cert_validation = ssl.CERT_REQUIRED else: cert_validation = ssl.CERT_NONE try: tls_context = ssl.create_default_context( cafile=ssl_params['ca_certs']) except AttributeError: tls_context = None if tls_context: # Wrap the socket for TLS certfile = ssl_params['cert_file'] keyfile = ssl_params['key_file'] password = ssl_params.get('password') if certfile and not keyfile: keyfile = certfile if certfile: tls_context.load_cert_chain( certfile, keyfile, password) if cert_validation is None or cert_validation == ssl.CERT_NONE: tls_context.check_hostname = False tls_context.verify_mode = cert_validation self.socket = tls_context.wrap_socket( self.socket, server_hostname=host_and_port[0]) else: # Old-style wrap_socket where we don't have a modern SSLContext (so no SNI) self.socket = ssl.wrap_socket( self.socket, keyfile=ssl_params['key_file'], certfile=ssl_params['cert_file'], cert_reqs=cert_validation, ca_certs=ssl_params['ca_certs'], ssl_version=ssl_params['ssl_version']) self.socket.settimeout(self.__timeout) if self.blocking is not None: self.socket.setblocking(self.blocking) # # Validate server cert # if need_ssl and ssl_params['cert_validator']: cert = self.socket.getpeercert() (ok, errmsg) = ssl_params['cert_validator']( cert, host_and_port[0]) if not ok: raise SSLError( "Server certificate validation failed: %s", errmsg) self.current_host_and_port = host_and_port logging.info("Established connection to host %s, port %s", host_and_port[0], host_and_port[1]) break except socket.error: self.socket = None connect_count += 1 logging.warning("Could not connect to host %s, port %s", host_and_port[0], host_and_port[1], exc_info=1) if self.socket is None: sleep_duration = (min(self.__reconnect_sleep_max, ( (self.__reconnect_sleep_initial / (1.0 + self.__reconnect_sleep_increase)) * math.pow(1.0 + self.__reconnect_sleep_increase, sleep_exp) )) * (1.0 + random.random() * self.__reconnect_sleep_jitter)) sleep_end = monotonic() + sleep_duration logging.debug( "Sleeping for %.1f seconds before attempting reconnect", sleep_duration) while self.running and monotonic() < sleep_end: time.sleep(0.2) if sleep_duration < self.__reconnect_sleep_max: sleep_exp += 1 if not self.socket: raise exception.ConnectFailedException()
def on_disconnected(self): """ Increment the disconnect count. See :py:meth:`ConnectionListener.on_disconnected` """ self.disconnects += 1 logging.info("disconnected (x %s)", self.disconnects)
def is_inside_travis(): if os.environ.get("TRAVIS", "false") == "true": logging.info("Not running test inside travis") return True return False