summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/leap/bitmask/app.py2
-rw-r--r--src/leap/bitmask/backend.py29
-rw-r--r--src/leap/bitmask/gui/mainwindow.py69
-rw-r--r--src/leap/bitmask/services/eip/vpnprocess.py12
4 files changed, 77 insertions, 35 deletions
diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index e413ab4c..05f81f0b 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -76,6 +76,7 @@ def sigint_handler(*args, **kwargs):
mainwindow = args[0]
mainwindow.quit()
+
def sigterm_handler(*args, **kwargs):
"""
Signal handler for SIGTERM.
@@ -87,6 +88,7 @@ def sigterm_handler(*args, **kwargs):
mainwindow = args[0]
mainwindow.quit()
+
def add_logger_handlers(debug=False, logfile=None, replace_stdout=True):
"""
Create the logger and attach the handlers.
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py
index 9661bda0..b138fd8d 100644
--- a/src/leap/bitmask/backend.py
+++ b/src/leap/bitmask/backend.py
@@ -17,7 +17,6 @@
"""
Backend for everything
"""
-import commands
import logging
import os
import time
@@ -391,14 +390,20 @@ class EIP(object):
# TODO: are we connected here?
signaler.signal(signaler.EIP_CONNECTED)
- def stop(self, shutdown=False):
+ def _do_stop(self, shutdown=False):
"""
- Stop the service.
+ Stop the service. This is run in a thread to avoid blocking.
"""
self._vpn.terminate(shutdown)
if IS_LINUX:
self._wait_for_firewall_down()
+ def stop(self, shutdown=False):
+ """
+ Stop the service.
+ """
+ return threads.deferToThread(self._do_stop, shutdown)
+
def _wait_for_firewall_down(self):
"""
Wait for the firewall to come down.
@@ -411,15 +416,16 @@ class EIP(object):
MAX_FW_WAIT_RETRIES = 25
FW_WAIT_STEP = 0.5
- retry = 0
-
- fw_up_cmd = "pkexec /usr/sbin/bitmask-root firewall isup"
- fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256
+ retry = 1
- while retry < MAX_FW_WAIT_RETRIES:
- if fw_is_down():
+ while retry <= MAX_FW_WAIT_RETRIES:
+ if self._vpn.is_fw_down():
+ self._signaler.signal(self._signaler.EIP_STOPPED)
return
else:
+ msg = "Firewall is not down yet, waiting... {0} of {1}"
+ msg = msg.format(retry, MAX_FW_WAIT_RETRIES)
+ logger.debug(msg)
time.sleep(FW_WAIT_STEP)
retry += 1
logger.warning("After waiting, firewall is not down... "
@@ -953,6 +959,7 @@ class Signaler(QtCore.QObject):
eip_disconnected = QtCore.Signal(object)
eip_connection_died = QtCore.Signal(object)
eip_connection_aborted = QtCore.Signal(object)
+ eip_stopped = QtCore.Signal(object)
# EIP problems
eip_no_polkit_agent_error = QtCore.Signal(object)
@@ -1040,6 +1047,8 @@ class Signaler(QtCore.QObject):
EIP_DISCONNECTED = "eip_disconnected"
EIP_CONNECTION_DIED = "eip_connection_died"
EIP_CONNECTION_ABORTED = "eip_connection_aborted"
+ EIP_STOPPED = "eip_stopped"
+
EIP_NO_POLKIT_AGENT_ERROR = "eip_no_polkit_agent_error"
EIP_NO_TUN_KEXT_ERROR = "eip_no_tun_kext_error"
EIP_NO_PKEXEC_ERROR = "eip_no_pkexec_error"
@@ -1110,6 +1119,8 @@ class Signaler(QtCore.QObject):
self.EIP_DISCONNECTED,
self.EIP_CONNECTION_DIED,
self.EIP_CONNECTION_ABORTED,
+ self.EIP_STOPPED,
+
self.EIP_NO_POLKIT_AGENT_ERROR,
self.EIP_NO_TUN_KEXT_ERROR,
self.EIP_NO_PKEXEC_ERROR,
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 557f3828..7cc88c1f 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -19,7 +19,6 @@ Main window for Bitmask.
"""
import logging
import socket
-import time
from datetime import datetime
@@ -87,6 +86,7 @@ class MainWindow(QtGui.QMainWindow):
raise_window = QtCore.Signal([])
soledad_ready = QtCore.Signal([])
logout = QtCore.Signal([])
+ all_services_stopped = QtCore.Signal()
# We use this flag to detect abnormal terminations
user_stopped_eip = False
@@ -195,6 +195,12 @@ class MainWindow(QtGui.QMainWindow):
self._logged_user = None
self._logged_in_offline = False
+ # 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
+
self._backend_connected_signals = {}
self._backend_connect()
@@ -1996,6 +2002,14 @@ class MainWindow(QtGui.QMainWindow):
self._cancel_ongoing_defers()
+ self._services_being_stopped = {'imap', 'eip'}
+
+ imap_stopped = lambda: self._remove_service('imap')
+ self._backend.signaler.imap_stopped.connect(imap_stopped)
+
+ eip_stopped = lambda: self._remove_service('eip')
+ self._backend.signaler.eip_stopped.connect(eip_stopped)
+
logger.debug('Stopping mail services')
self._backend.stop_imap_service()
self._backend.stop_smtp_service()
@@ -2007,27 +2021,6 @@ class MainWindow(QtGui.QMainWindow):
logger.debug('Terminating vpn')
self._backend.stop_eip(shutdown=True)
- # We need to give some time to the ongoing signals for shutdown
- # to come into action. This needs to be solved using
- # back-communication from backend.
- # TODO: handle this, I commented this fix to merge 'cleanly'
- # QtCore.QTimer.singleShot(3000, self._shutdown)
-
- def _shutdown(self):
- """
- Actually shutdown.
- """
- self._cancel_ongoing_defers()
-
- # TODO missing any more cancels?
-
- logger.debug('Cleaning pidfiles')
- self._cleanup_pidfiles()
- if self._quit_callback:
- self._quit_callback()
-
- logger.debug('Bye.')
-
def quit(self):
"""
Start the quit sequence and wait for services to finish.
@@ -2060,10 +2053,27 @@ class MainWindow(QtGui.QMainWindow):
self._really_quit = True
- # call final_quit when imap is stopped
- self._backend.signaler.imap_stopped.connect(self.final_quit)
+ # call final quit when all the services are stopped
+ self.all_services_stopped.connect(self.final_quit)
# or if we reach the timeout
- reactor.callLater(self.SERVICES_STOP_TIMEOUT, self._backend.stop)
+ self._quit_timeout_callater = reactor.callLater(
+ self.SERVICES_STOP_TIMEOUT, self.final_quit)
+
+ @QtCore.Slot()
+ def _remove_service(self, service):
+ """
+ Remove the given service from the waiting list and check if we have
+ running services that we need to wait until we quit.
+ Emit self.all_services_stopped signal if we don't need to keep waiting.
+
+ :param service: the service that we want to remove
+ :type service: str
+ """
+ self._services_being_stopped.discard(service)
+
+ if not self._services_being_stopped:
+ logger.debug("All services stopped.")
+ self.all_services_stopped.emit()
@QtCore.Slot()
def final_quit(self):
@@ -2075,10 +2085,15 @@ class MainWindow(QtGui.QMainWindow):
try:
# disconnect signal if we get here due a timeout.
- self._backend.signaler.imap_stopped.disconnect(self.final_quit)
+ self.all_services_stopped.disconnect(self.final_quit)
except RuntimeError:
pass # Signal was not connected
+ # Cancel timeout to avoid being called if we reached here through the
+ # signal
+ if self._quit_timeout_callater.active():
+ self._quit_timeout_callater.cancel()
+
# Remove lockfiles on a clean shutdown.
logger.debug('Cleaning pidfiles')
if IS_WIN:
@@ -2086,3 +2101,5 @@ class MainWindow(QtGui.QMainWindow):
self._backend.stop()
self.close()
+
+ reactor.callLater(1, self._quit_callback)
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index 734b88df..81eac6d9 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -17,6 +17,7 @@
"""
VPN Manager, spawned in a custom processProtocol.
"""
+import commands
import logging
import os
import shutil
@@ -232,6 +233,17 @@ class VPN(object):
BM_ROOT, "firewall", "start"] + gateways)
return True if exitCode is 0 else False
+ def is_fw_down(self):
+ """
+ Return whether the firewall is down or not.
+
+ :rtype: bool
+ """
+ BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT
+ fw_up_cmd = "pkexec {0} firewall isup".format(BM_ROOT)
+ fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256
+ return fw_is_down()
+
def _tear_down_firewall(self):
"""
Tear the firewall down using the privileged wrapper.