From 421e7c82fae639e848104650fd4a44b99ef48ae0 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 8 Feb 2013 10:36:57 +0100 Subject: [PATCH 1/3] Put get_all_ips onto a thread. Cache the result when we get it. --- .../devices/smart_device_app/driver.py | 10 +++- src/calibre/gui2/actions/device.py | 1 + src/calibre/utils/mdns.py | 49 +++++++++++++------ 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/calibre/devices/smart_device_app/driver.py b/src/calibre/devices/smart_device_app/driver.py index b925909c50..285cd14680 100644 --- a/src/calibre/devices/smart_device_app/driver.py +++ b/src/calibre/devices/smart_device_app/driver.py @@ -54,6 +54,8 @@ def synchronous(tlockname): class ConnectionListener (Thread): + all_ip_addresses = dict() + NOT_SERVICED_COUNT = 6 def __init__(self, driver): @@ -61,6 +63,7 @@ class ConnectionListener (Thread): self.daemon = True self.driver = driver self.keep_running = True + all_ip_addresses = dict() def stop(self): self.keep_running = False @@ -78,6 +81,11 @@ class ConnectionListener (Thread): if not self.keep_running: break + if not self.all_ip_addresses: + self.all_ip_addresses = get_all_ips() + if self.all_ip_addresses: + self.driver._debug("All IP addresses", self.all_ip_addresses) + if not self.driver.connection_queue.empty(): queue_not_serviced_count += 1 if queue_not_serviced_count >= self.NOT_SERVICED_COUNT: @@ -1287,8 +1295,6 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin): self.client_can_stream_metadata = False self.client_wants_uuid_file_names = False - self._debug("All IP addresses", get_all_ips()) - message = None try: self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py index 9be0aaaf0c..d95da00369 100644 --- a/src/calibre/gui2/actions/device.py +++ b/src/calibre/gui2/actions/device.py @@ -182,6 +182,7 @@ class ConnectShareAction(InterfaceAction): def genesis(self): self.share_conn_menu = ShareConnMenu(self.gui) + self.share_conn_menu.aboutToShow.connect(self.set_smartdevice_action_state) self.share_conn_menu.toggle_server.connect(self.toggle_content_server) self.share_conn_menu.control_smartdevice.connect(self.control_smartdevice) self.share_conn_menu.config_email.connect(partial( diff --git a/src/calibre/utils/mdns.py b/src/calibre/utils/mdns.py index 63112036fd..225cc90748 100644 --- a/src/calibre/utils/mdns.py +++ b/src/calibre/utils/mdns.py @@ -5,29 +5,46 @@ __docformat__ = 'restructuredtext en' import socket, time, atexit from collections import defaultdict +from threading import Thread from calibre.utils.filenames import ascii_text from calibre import force_unicode _server = None +_all_ip_addresses = dict() + +class AllIpAddressesGetter (Thread): + + def get_all_ips(self): + ''' Return a mapping of interface names to the configuration of the + interface, which includes the ip address, netmask and broadcast addresses + ''' + import netifaces + all_ips = defaultdict(list) + if hasattr(netifaces, 'AF_INET'): + for x in netifaces.interfaces(): + try: + for c in netifaces.ifaddresses(x).get(netifaces.AF_INET, []): + all_ips[x].append(c) + except ValueError: + from calibre import prints + prints('Failed to get IP addresses for interface', x) + import traceback + traceback.print_exc() + return dict(all_ips) + + def run(self): + global _all_ip_addresses +# print 'sleeping' +# time.sleep(10) +# print 'slept' + _all_ip_addresses = self.get_all_ips() + +AllIpAddressesGetter().start() + def get_all_ips(): - ''' Return a mapping of interface names to the configuration of the - interface, which includes the ip address, netmask and broadcast addresses - ''' - import netifaces - all_ips = defaultdict(list) - if hasattr(netifaces, 'AF_INET'): - for x in netifaces.interfaces(): - try: - for c in netifaces.ifaddresses(x).get(netifaces.AF_INET, []): - all_ips[x].append(c) - except ValueError: - from calibre import prints - prints('Failed to get IP addresses for interface', x) - import traceback - traceback.print_exc() - return dict(all_ips) + return _all_ip_addresses def _get_external_ip(): 'Get IP address of interface used to connect to the outside world' From 82550e6ace5e8c4c121fa95a88523bab2c99c1aa Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 8 Feb 2013 10:46:38 +0100 Subject: [PATCH 2/3] Improve message in connect/share when waiting for IP addresses --- src/calibre/gui2/actions/device.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py index d95da00369..0f97553dcb 100644 --- a/src/calibre/gui2/actions/device.py +++ b/src/calibre/gui2/actions/device.py @@ -259,7 +259,10 @@ class ConnectShareAction(InterfaceAction): show_port = True else: all_ips = get_all_ip_addresses() - if len(all_ips) > 3: + if len(all_ips) == 0: + formatted_addresses = _('Still looking for IP addresses') + show_port = False + elif len(all_ips) > 3: formatted_addresses = _('Many IP addresses. See Start/Stop dialog.') show_port = False else: From 6914cdec1367f5bc161cfa2a8a62ba753db8dbaa Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 8 Feb 2013 12:09:09 +0100 Subject: [PATCH 3/3] Get the IP addresses again when restarting the smartdevice driver. --- src/calibre/devices/smart_device_app/driver.py | 2 ++ src/calibre/utils/mdns.py | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/calibre/devices/smart_device_app/driver.py b/src/calibre/devices/smart_device_app/driver.py index 285cd14680..b8bf50aba7 100644 --- a/src/calibre/devices/smart_device_app/driver.py +++ b/src/calibre/devices/smart_device_app/driver.py @@ -71,6 +71,8 @@ class ConnectionListener (Thread): def run(self): queue_not_serviced_count = 0 device_socket = None + get_all_ips(reinitialize=True) + while self.keep_running: try: time.sleep(1) diff --git a/src/calibre/utils/mdns.py b/src/calibre/utils/mdns.py index 225cc90748..aebb2b2e09 100644 --- a/src/calibre/utils/mdns.py +++ b/src/calibre/utils/mdns.py @@ -14,7 +14,7 @@ _server = None _all_ip_addresses = dict() -class AllIpAddressesGetter (Thread): +class AllIpAddressesGetter(Thread): def get_all_ips(self): ''' Return a mapping of interface names to the configuration of the @@ -37,13 +37,20 @@ class AllIpAddressesGetter (Thread): def run(self): global _all_ip_addresses # print 'sleeping' -# time.sleep(10) +# time.sleep(15) # print 'slept' _all_ip_addresses = self.get_all_ips() -AllIpAddressesGetter().start() +_ip_address_getter_thread = None -def get_all_ips(): +def get_all_ips(reinitialize=False): + global _all_ip_addresses, _ip_address_getter_thread + if not _ip_address_getter_thread or (reinitialize and not + _ip_address_getter_thread.is_alive()): + _all_ip_addresses = dict() + _ip_address_getter_thread = AllIpAddressesGetter() + _ip_address_getter_thread.setDaemon(True) + _ip_address_getter_thread.start() return _all_ip_addresses def _get_external_ip():