class BluetoothReceive: def __init__(self, port=3, size=1024): self.port = port self.size = size self.client_socket = None self.stopped = False @inlineCallbacks def find_key(self, bt_mac, mac): self.client_socket = BluetoothSocket(RFCOMM) message = b"" try: self.client_socket.setblocking(False) try: self.client_socket.connect((bt_mac, self.port)) except BluetoothError as be: if be.args[0] == "(115, 'Operation now in progress')": pass else: raise be success = False while not self.stopped and not success: r, w, e = yield threads.deferToThread(select.select, [self.client_socket], [], [], 0.5) if r: log.info("Connection established") self.client_socket.setblocking(True) success = True # try to receive until the sender closes the connection try: while True: part_message = self.client_socket.recv(self.size) message += part_message except BluetoothError as be: if be.args[0] == "(104, 'Connection reset by peer')": log.info("Bluetooth connection closed, let's check if we downloaded the key") else: raise be mac_key = fingerprint_from_keydata(message) verified = None if mac: verified = mac_verify(mac_key.encode('ascii'), message, mac) if verified: success = True else: log.info("MAC validation failed: %r", verified) success = False message = b"" except BluetoothError as be: if be.args[0] == "(16, 'Device or resource busy')": log.info("Probably has been provided a partial bt mac") elif be.args[0] == "(111, 'Connection refused')": log.info("The sender refused our connection attempt") elif be.args[0] == "(112, 'Host is down')": log.info("The sender's Bluetooth is not available") elif be.args[0] == "(113, 'No route to host')": log.info("An error occurred with Bluetooth, if present probably the device is not powered") else: log.info("An unknown bt error occurred: %s" % be.args[0]) key_data = None success = False returnValue((key_data, success, be)) except Exception as e: log.error("An error occurred connecting or receiving: %s" % e) key_data = None success = False returnValue((key_data, success, e)) if self.client_socket: self.client_socket.close() returnValue((message.decode("utf-8"), success, None)) def stop(self): self.stopped = True if self.client_socket: try: self.client_socket.shutdown(socket.SHUT_RDWR) self.client_socket.close() except BluetoothError as be: if be.args[0] == "(9, 'Bad file descriptor')": log.info("The old Bluetooth connection was already closed") else: log.warning("An unknown bt error occurred: %s" % be.args[0])
class BluetoothOffer: def __init__(self, key, port=3, size=1024): self.key = key self.port = port self.size = size self.server_socket = None self.message_def = None self.stopped = False @inlineCallbacks def start(self): self.stopped = False message = "Back" success = False try: while not self.stopped and not success: # server_socket.accept() is not stoppable. So with select we can call accept() # only when we are sure that there is already a waiting connection ready_to_read, ready_to_write, in_error = yield threads.deferToThread( select.select, [self.server_socket], [], [], 0.5) if ready_to_read: # We are sure that a connection is available, so we can call # accept() without deferring it to a thread client_socket, address = self.server_socket.accept() key_data = get_public_key_data(self.key.fingerprint) kd_decoded = key_data.decode('utf-8') yield threads.deferToThread(client_socket.sendall, kd_decoded) log.info("Key has been sent") client_socket.shutdown(socket.SHUT_RDWR) client_socket.close() success = True message = None except Exception as e: log.error("An error occurred: %s" % e) success = False message = e returnValue((success, message)) def allocate_code(self): """Acquires and returns a string suitable for finding the key via Bluetooth. Returns None if no powered on adapter could be found.""" # TODO: when we have magic-wormhole we should perform this operation in async # and show the loading spinning wheel bt_data = None try: code = get_local_bt_address().upper() except NoBluezDbus as e: log.debug("Bluetooth service seems to be unavailable: %s", e) except NoAdapter as e: log.debug("Bluetooth adapter is not available: %s", e) except UnpoweredAdapter as e: log.debug("Bluetooth adapter is turned off: %s", e) else: if self.server_socket is None: self.server_socket = BluetoothSocket(RFCOMM) # We create a bind with the Bluetooth address we have in the system self.server_socket.bind((code, PORT_ANY)) # Number of unaccepted connections that the system will allow before refusing new connections backlog = 1 self.server_socket.listen(backlog) log.info("sockname: %r", self.server_socket.getsockname()) port = self.server_socket.getsockname()[1] log.info("BT Code: %s %s", code, port) bt_data = "BT={0};PT={1}".format(code, port) return bt_data def stop(self): log.debug("Stopping bt receive") self.stopped = True if self.server_socket: self.server_socket.shutdown(socket.SHUT_RDWR) self.server_socket.close() self.server_socket = None
class BluetoothOffer: def __init__(self, key, port=3, size=1024): self.key = key self.port = port self.size = size self.server_socket = None self.message_def = None self.stopped = False self.code = None @inlineCallbacks def start(self): self.stopped = False message = "Back" success = False try: while not self.stopped and not success: # server_socket.accept() is not stoppable. So with select we can call accept() # only when we are sure that there is already a waiting connection ready_to_read, ready_to_write, in_error = yield threads.deferToThread( select.select, [self.server_socket], [], [], 0.5) if ready_to_read: # We are sure that a connection is available, so we can call # accept() without deferring it to a thread client_socket, address = self.server_socket.accept() key_data = get_public_key_data(self.key.fingerprint) kd_decoded = key_data.decode('utf-8') yield threads.deferToThread(client_socket.sendall, kd_decoded) log.info("Key has been sent") client_socket.shutdown(socket.SHUT_RDWR) client_socket.close() success = True message = None except Exception as e: log.error("An error occurred: %s" % e) success = False message = e returnValue((success, message)) def allocate_code(self): try: code = get_local_bt_address().upper() except dbus.exceptions.DBusException as e: if e.get_dbus_name() == "org.freedesktop.systemd1.NoSuchUnit": log.info("No Bluetooth devices found, probably the bluetooth service is not running") elif e.get_dbus_name() == "org.freedesktop.DBus.Error.UnknownObject": log.info("No Bluetooth devices available") else: log.error("An unexpected error occurred %s", e.get_dbus_name()) self.code = None return None if self.server_socket is None: self.server_socket = BluetoothSocket(RFCOMM) # We can also bind only the mac found with get_local_bt_address(), anyway # even with multiple bt in a single system BDADDR_ANY is not a problem self.server_socket.bind((socket.BDADDR_ANY, PORT_ANY)) # Number of unaccepted connections that the system will allow before refusing new connections backlog = 1 self.server_socket.listen(backlog) log.info("sockname: %r", self.server_socket.getsockname()) port = self.server_socket.getsockname()[1] log.info("BT Code: %s %s", code, port) bt_data = "BT={0};PT={1}".format(code, port) return bt_data def stop(self): log.debug("Stopping bt receive") self.stopped = True if self.server_socket: self.server_socket.shutdown(socket.SHUT_RDWR) self.server_socket.close() self.server_socket = None
class BluetoothReceive: def __init__(self, port=3, size=1024): self.port = port self.size = size self.client_socket = None self.stopped = False @inlineCallbacks def find_key(self, bt_mac, mac): self.client_socket = BluetoothSocket(RFCOMM) message = b"" try: self.client_socket.setblocking(False) try: self.client_socket.connect((bt_mac, self.port)) except BluetoothError as be: if be.args[0] == "(115, 'Operation now in progress')": pass else: raise be success = False while not self.stopped and not success: r, w, e = yield threads.deferToThread(select.select, [self.client_socket], [], [], 0.5) if r: log.info("Connection established") self.client_socket.setblocking(True) success = True # try to receive until the sender closes the connection try: while True: part_message = self.client_socket.recv(self.size) log.debug("Read %d bytes: %r", len(part_message), part_message) message += part_message except BluetoothError as be: if be.args[0] == "(104, 'Connection reset by peer')": log.info("Bluetooth connection closed, let's check if we downloaded the key") else: raise be mac_key = fingerprint_from_keydata(message) verified = None if mac: verified = mac_verify(mac_key.encode('ascii'), message, mac) if verified: success = True else: log.info("MAC validation failed: %r", verified) success = False message = b"" except BluetoothError as be: if be.args[0] == "(16, 'Device or resource busy')": log.info("Probably has been provided a partial bt mac") elif be.args[0] == "(111, 'Connection refused')": log.info("The sender refused our connection attempt") elif be.args[0] == "(112, 'Host is down')": log.info("The sender's Bluetooth is not available") elif be.args[0] == "(113, 'No route to host')": log.info("An error occurred with Bluetooth, if present probably the device is not powered") else: log.info("An unknown bt error occurred: %s" % be.args[0]) key_data = None success = False returnValue((key_data, success, be)) except Exception as e: log.error("An error occurred connecting or receiving: %s" % e) key_data = None success = False returnValue((key_data, success, e)) if self.client_socket: self.client_socket.close() returnValue((message.decode("utf-8"), success, None)) def stop(self): self.stopped = True if self.client_socket: try: self.client_socket.shutdown(socket.SHUT_RDWR) self.client_socket.close() except BluetoothError as be: if be.args[0] == "(9, 'Bad file descriptor')": log.info("The old Bluetooth connection was already closed") else: log.exception("An unknown bt error occurred")