import socket import threading import logging from core.peer import BankPeer class BankScanner(threading.Thread): def __init__(self, host: str, port: str, result_peer: BankPeer, bank_found_event: threading.Event, lock: threading.Lock, timeout: int): super().__init__(name="BankScannerThread-{self.host}:{port}") self.logger = logging.getLogger(__name__) self.host = host self.port = port self.result_peer = result_peer self.bank_found_event = bank_found_event self.lock = lock self.timeout = timeout def run(self): if self.bank_found_event.is_set(): return self.__probe_for_open_ports(self.host, self.port) def __probe_for_open_ports(self, host: str, port: int): try: connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connection.settimeout(self.timeout) connection.connect((host, port)) self.__scan_for_bank(connection) except socket.timeout: self.logger.debug("Connection for port %d timed out", port) except socket.error as e: if e.errno == 111: # Connection refused self.logger.debug("Port %d not open", port) else: self.logger.debug("Unknown error occurred when probing port: %s", e) def __scan_for_bank(self, connection: socket.socket): ping_command = "BC" connection.sendall(ping_command.encode("utf-8")) response = connection.recv(1024).decode("utf-8") if response.strip() == f"BC {self.host}": self.logger.debug("Bank application found on %s:%s", self.host, self.port) with self.lock: if not self.bank_found_event.is_set(): self.result_peer.port = self.port self.result_peer.bank_socket = connection self.bank_found_event.set() else: self.logger.debug("Port is open, but no bank application found")