summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/leap/bitmask/app.py2
-rw-r--r--src/leap/bitmask/backend.py62
-rw-r--r--src/leap/bitmask/gui/mainwindow.py98
-rw-r--r--src/leap/bitmask/util/leap_argparse.py10
4 files changed, 103 insertions, 69 deletions
diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index 374c91d2..6a7d6ff1 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -121,7 +121,7 @@ def main():
Starts the main event loop and launches the main window.
"""
# Parse arguments and store them
- _, opts = leap_argparse.init_leapc_args()
+ opts = leap_argparse.get_options()
do_display_version(opts)
bypass_checks = opts.danger
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py
index f7200dd7..5748c4c6 100644
--- a/src/leap/bitmask/backend.py
+++ b/src/leap/bitmask/backend.py
@@ -19,6 +19,7 @@ Backend for everything
"""
import logging
import os
+import socket
import time
from functools import partial
@@ -653,6 +654,45 @@ class EIP(object):
if self._signaler is not None:
self._signaler.signal(self._signaler.EIP_CANNOT_START)
+ def check_dns(self, domain):
+ """
+ Check if we can resolve the given domain name.
+
+ :param domain: the domain to check.
+ :type domain: str
+ """
+ def do_check():
+ """
+ Try to resolve the domain name.
+ """
+ socket.gethostbyname(domain.encode('idna'))
+
+ def check_ok(_):
+ """
+ Callback handler for `do_check`.
+ """
+ self._signaler.signal(self._signaler.EIP_DNS_OK)
+ logger.debug("DNS check OK")
+
+ def check_err(failure):
+ """
+ Errback handler for `do_check`.
+
+ :param failure: the failure that triggered the errback.
+ :type failure: twisted.python.failure.Failure
+ """
+ logger.debug("Can't resolve hostname. {0!r}".format(failure))
+
+ self._signaler.signal(self._signaler.EIP_DNS_ERROR)
+
+ # python 2.7.4 raises socket.error
+ # python 2.7.5 raises socket.gaierror
+ failure.trap(socket.gaierror, socket.error)
+
+ d = threads.deferToThread(do_check)
+ d.addCallback(check_ok)
+ d.addErrback(check_err)
+
class Soledad(object):
"""
@@ -1177,6 +1217,9 @@ class Signaler(QtCore.QObject):
eip_connection_aborted = QtCore.Signal(object)
eip_stopped = QtCore.Signal(object)
+ eip_dns_ok = QtCore.Signal(object)
+ eip_dns_error = QtCore.Signal(object)
+
# EIP problems
eip_no_polkit_agent_error = QtCore.Signal(object)
eip_no_tun_kext_error = QtCore.Signal(object)
@@ -1308,6 +1351,9 @@ class Signaler(QtCore.QObject):
EIP_CAN_START = "eip_can_start"
EIP_CANNOT_START = "eip_cannot_start"
+ EIP_DNS_OK = "eip_dns_ok"
+ EIP_DNS_ERROR = "eip_dns_error"
+
SOLEDAD_BOOTSTRAP_FAILED = "soledad_bootstrap_failed"
SOLEDAD_BOOTSTRAP_FINISHED = "soledad_bootstrap_finished"
SOLEDAD_OFFLINE_FAILED = "soledad_offline_failed"
@@ -1395,6 +1441,9 @@ class Signaler(QtCore.QObject):
self.EIP_CAN_START,
self.EIP_CANNOT_START,
+ self.EIP_DNS_OK,
+ self.EIP_DNS_ERROR,
+
self.SRP_AUTH_OK,
self.SRP_AUTH_ERROR,
self.SRP_AUTH_SERVER_ERROR,
@@ -1840,6 +1889,19 @@ class Backend(object):
self._call_queue.put(("eip", "can_start",
None, domain))
+ def eip_check_dns(self, domain):
+ """
+ Check if we can resolve the given domain name.
+
+ :param domain: the domain for the provider to check
+ :type domain: str
+
+ Signals:
+ eip_dns_ok
+ eip_dns_error
+ """
+ self._call_queue.put(("eip", "check_dns", None, domain))
+
def tear_fw_down(self):
"""
Signal the need to tear the fw down.
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 885cb792..03c29d0e 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -18,12 +18,10 @@
Main window for Bitmask.
"""
import logging
-import socket
from datetime import datetime
from PySide import QtCore, QtGui
-from twisted.internet import reactor, threads
from leap.bitmask import __version__ as VERSION
from leap.bitmask import __version_hash__ as VERSION_HASH
@@ -177,8 +175,8 @@ class MainWindow(QtGui.QMainWindow):
# Set used to track the services being stopped and need wait.
self._services_being_stopped = {}
- # timeout object used to trigger quit
- self._quit_timeout_callater = None
+ # used to know if we are in the final steps of quitting
+ self._finally_quitting = False
self._backend_connected_signals = []
self._backend_connect()
@@ -403,6 +401,8 @@ class MainWindow(QtGui.QMainWindow):
sig.eip_can_start.connect(self._backend_can_start_eip)
sig.eip_cannot_start.connect(self._backend_cannot_start_eip)
+ sig.eip_dns_error.connect(self._eip_dns_error)
+
# ==================================================================
# Soledad signals
@@ -897,7 +897,7 @@ class MainWindow(QtGui.QMainWindow):
self.tr('Hello!'),
self.tr('Bitmask has started in the tray.'))
# we wait for the systray to be ready
- reactor.callLater(1, hello)
+ QtDelayedCall(1, hello)
@QtCore.Slot(int)
def _tray_activated(self, reason=None):
@@ -1461,55 +1461,25 @@ class MainWindow(QtGui.QMainWindow):
self._already_started_eip = True
# check for connectivity
- # we might want to leave a little time here...
- self._check_name_resolution(domain)
-
- def _check_name_resolution(self, domain):
- # FIXME this has to be moved to backend !!!
- # Should move to netchecks module.
- # and separate qt from reactor...
- """
- Check if we can resolve the given domain name.
-
- :param domain: the domain to check.
- :type domain: str
- """
- def do_check():
- """
- Try to resolve the domain name.
- """
- socket.gethostbyname(domain.encode('idna'))
-
- def check_err(failure):
- """
- Errback handler for `do_check`.
-
- :param failure: the failure that triggered the errback.
- :type failure: twisted.python.failure.Failure
- """
- logger.error(repr(failure))
- logger.error("Can't resolve hostname.")
-
- msg = self.tr(
- "The server at {0} can't be found, because the DNS lookup "
- "failed. DNS is the network service that translates a "
- "website's name to its Internet address. Either your computer "
- "is having trouble connecting to the network, or you are "
- "missing some helper files that are needed to securely use "
- "DNS while {1} is active. To install these helper files, quit "
- "this application and start it again."
- ).format(domain, self._eip_conductor.eip_name)
-
- show_err = lambda: QtGui.QMessageBox.critical(
- self, self.tr("Connection Error"), msg)
- reactor.callLater(0, show_err)
-
- # python 2.7.4 raises socket.error
- # python 2.7.5 raises socket.gaierror
- failure.trap(socket.gaierror, socket.error)
-
- d = threads.deferToThread(do_check)
- d.addErrback(check_err)
+ self._backend.eip_check_dns(domain)
+
+ @QtCore.Slot()
+ def _eip_dns_error(self):
+ """
+ Trigger this if we don't have a working DNS resolver.
+ """
+ domain = self._login_widget.get_selected_provider()
+ msg = self.tr(
+ "The server at {0} can't be found, because the DNS lookup "
+ "failed. DNS is the network service that translates a "
+ "website's name to its Internet address. Either your computer "
+ "is having trouble connecting to the network, or you are "
+ "missing some helper files that are needed to securely use "
+ "DNS while {1} is active. To install these helper files, quit "
+ "this application and start it again."
+ ).format(domain, self._eip_conductor.eip_name)
+
+ QtGui.QMessageBox.critical(self, self.tr("Connection Error"), msg)
def _try_autostart_eip(self):
"""
@@ -1768,8 +1738,7 @@ class MainWindow(QtGui.QMainWindow):
# call final quit when all the services are stopped
self.all_services_stopped.connect(self.final_quit)
# or if we reach the timeout
- self._quit_timeout_callater = reactor.callLater(
- self.SERVICES_STOP_TIMEOUT, self.final_quit)
+ QtDelayedCall(self.SERVICES_STOP_TIMEOUT, self.final_quit)
@QtCore.Slot()
def _remove_service(self, service):
@@ -1795,16 +1764,13 @@ class MainWindow(QtGui.QMainWindow):
"""
logger.debug('Final quit...')
- try:
- # disconnect signal if we get here due a timeout.
- self.all_services_stopped.disconnect(self.final_quit)
- except RuntimeError:
- pass # Signal was not connected
+ # We can reach here because all the services are stopped or because a
+ # timeout was triggered. Since we want to run this only once, we exit
+ # if this is called twice.
+ if self._finally_quitting:
+ return
- # Cancel timeout to avoid being called if we reached here through the
- # signal
- if self._quit_timeout_callater.active():
- self._quit_timeout_callater.cancel()
+ self._finally_quitting = True
# Remove lockfiles on a clean shutdown.
logger.debug('Cleaning pidfiles')
@@ -1814,4 +1780,4 @@ class MainWindow(QtGui.QMainWindow):
self._backend.stop()
self.close()
- reactor.callLater(1, twisted_main.quit)
+ QtDelayedCall(1, twisted_main.quit)
diff --git a/src/leap/bitmask/util/leap_argparse.py b/src/leap/bitmask/util/leap_argparse.py
index 84af4e8d..0717aea5 100644
--- a/src/leap/bitmask/util/leap_argparse.py
+++ b/src/leap/bitmask/util/leap_argparse.py
@@ -123,7 +123,13 @@ def build_parser():
return parser
-def init_leapc_args():
+def get_options():
+ """
+ Get the command line options used when the app was started.
+
+ :return: the command options
+ :rtype: argparse.Namespace
+ """
parser = build_parser()
opts, unknown = parser.parse_known_args()
- return parser, opts
+ return opts