summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2014-05-29 16:23:23 -0300
committerTomás Touceda <chiiph@leap.se>2014-05-29 16:23:23 -0300
commit5eba0d4173ef352ad30d3f04e7d103bce2c202ed (patch)
treebd5ddcec4ed93c79a8b40942151ea672db6fb9f0
parent7b7e1357fc1e9e64e7c2ee08f762389d7128efc3 (diff)
parentefea398e18f806ad5bb7cec4aa0dcef5f94319bc (diff)
Merge remote-tracking branch 'refs/remotes/kali/bug/eip-restarts-refactor' into develop
-rw-r--r--src/leap/bitmask/backend.py14
-rw-r--r--src/leap/bitmask/gui/eip_status.py186
-rw-r--r--src/leap/bitmask/gui/mainwindow.py428
-rw-r--r--src/leap/bitmask/gui/statemachines.py13
-rw-r--r--src/leap/bitmask/services/eip/conductor.py302
-rw-r--r--src/leap/bitmask/services/eip/vpnprocess.py17
6 files changed, 593 insertions, 367 deletions
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py
index 5e22a8c4..1ab5b40d 100644
--- a/src/leap/bitmask/backend.py
+++ b/src/leap/bitmask/backend.py
@@ -434,8 +434,12 @@ class EIP(object):
except Exception as e:
logger.error("Unexpected problem: {0!r}".format(e))
else:
+ logger.debug('EIP: no errors')
# TODO: are we connected here?
- signaler.signal(signaler.EIP_CONNECTED)
+ # kali -- no, we are not! CONNECTED should be passed only
+ # by the vpn observer. Currently handled by the state updater
+ # in eip_status
+ #signaler.signal(signaler.EIP_CONNECTED)
def _do_stop(self, shutdown=False, restart=False):
"""
@@ -470,9 +474,9 @@ class EIP(object):
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)
+ #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... "
@@ -1714,7 +1718,7 @@ class Backend(object):
"""
self._call_queue.put(("eip", "start", None))
- def eip_stop(self, shutdown=False, restart=False):
+ def eip_stop(self, shutdown=False, restart=False, failed=False):
"""
Stop the EIP service.
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index ca28b8bf..04acc167 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -24,7 +24,6 @@ from functools import partial
from PySide import QtCore, QtGui
-from leap.bitmask.services.eip.connection import EIPConnection
from leap.bitmask.services import get_service_display_name, EIP_SERVICE
from leap.bitmask.platform_init import IS_LINUX
from leap.bitmask.util.averages import RateMovingAverage
@@ -43,9 +42,14 @@ class EIPStatusWidget(QtGui.QWidget):
RATE_STR = "%1.2f KB/s"
TOTAL_STR = "%1.2f Kb"
- eip_connection_connected = QtCore.Signal()
+ def __init__(self, parent=None, eip_conductor=None):
+ """
+ :param parent: the parent of the widget.
+ :type parent: QObject
- def __init__(self, parent=None):
+ :param eip_conductor: an EIPConductor object.
+ :type eip_conductor: EIPConductor
+ """
QtGui.QWidget.__init__(self, parent)
self._systray = None
@@ -54,7 +58,8 @@ class EIPStatusWidget(QtGui.QWidget):
self.ui = Ui_EIPStatus()
self.ui.setupUi(self)
- self.eipconnection = EIPConnection()
+ self.eip_conductor = eip_conductor
+ self.eipconnection = eip_conductor.eip_connection
# set systray tooltip status
self._eip_status = ""
@@ -75,11 +80,36 @@ class EIPStatusWidget(QtGui.QWidget):
self._make_status_clickable()
self._provider = ""
+ self.is_restart = False
# Action for the systray
self._eip_disabled_action = QtGui.QAction(
"{0} is {1}".format(self._service_name, self.tr("disabled")), self)
+ def connect_backend_signals(self):
+ """
+ Connect backend signals.
+ """
+ signaler = self.eip_conductor._backend.signaler
+
+ signaler.eip_openvpn_already_running.connect(
+ self._on_eip_openvpn_already_running)
+ signaler.eip_alien_openvpn_already_running.connect(
+ self._on_eip_alien_openvpn_already_running)
+ signaler.eip_openvpn_not_found_error.connect(
+ self._on_eip_openvpn_not_found_error)
+ signaler.eip_vpn_launcher_exception.connect(
+ self._on_eip_vpn_launcher_exception)
+ signaler.eip_no_polkit_agent_error.connect(
+ self._on_eip_no_polkit_agent_error)
+ signaler.eip_no_pkexec_error.connect(self._on_eip_no_pkexec_error)
+ signaler.eip_no_tun_kext_error.connect(self._on_eip_no_tun_kext_error)
+
+ signaler.eip_state_changed.connect(self.update_vpn_state)
+ signaler.eip_status_changed.connect(self.update_vpn_status)
+ signaler.eip_network_unreachable.connect(
+ self._on_eip_network_unreachable)
+
def _make_status_clickable(self):
"""
Makes upload and download figures clickable.
@@ -238,7 +268,7 @@ class EIPStatusWidget(QtGui.QWidget):
def eip_pre_up(self):
"""
Triggered when the app activates eip.
- Hides the status box and disables the start/stop button.
+ Disables the start/stop button.
"""
self.set_startstop_enabled(False)
@@ -248,7 +278,7 @@ class EIPStatusWidget(QtGui.QWidget):
Triggered when a default provider_config has not been found.
Disables the start button and adds instructions to the user.
"""
- #logger.debug('Hiding EIP start button')
+ logger.debug('Hiding EIP start button')
# you might be tempted to change this for a .setEnabled(False).
# it won't work. it's under the claws of the state machine.
# probably the best thing would be to make a conditional
@@ -326,30 +356,51 @@ class EIPStatusWidget(QtGui.QWidget):
Sets the state of the widget to how it should look after EIP
has started
"""
- self.ui.btnEipStartStop.setText(self.tr("Turn OFF"))
self.ui.btnEipStartStop.disconnect(self)
self.ui.btnEipStartStop.clicked.connect(
self.eipconnection.qtsigs.do_connect_signal)
- # XXX disable -----------------------------
- def eip_stopped(self):
+ @QtCore.Slot(dict)
+ def eip_stopped(self, restart=False, failed=False):
"""
+ TRIGGERS:
+ EIPConductor.qtsigs.disconnected_signal
+
Sets the state of the widget to how it should look after EIP
has stopped
"""
- # XXX should connect this to EIPConnection.disconnected_signal
self._reset_traffic_rates()
- # XXX disable -----------------------------
- self.ui.btnEipStartStop.setText(self.tr("Turn ON"))
- self.ui.btnEipStartStop.disconnect(self)
- self.ui.btnEipStartStop.clicked.connect(
- self.eipconnection.qtsigs.do_disconnect_signal)
-
self.ui.eip_bandwidth.hide()
- self.ui.lblEIPMessage.setText(
- self.tr("Traffic is being routed in the clear"))
+
+ # XXX FIXME ! ----------------------- this needs to
+ # accomodate the messages about firewall status. Right now
+ # we're assuming it works correctly, but we should test fw
+ # status positively.
+ # Or better call it from the conductor...
+
+ clear_traffic = self.tr("Traffic is being routed in the clear.")
+ unreachable_net = self.tr("Network is unreachable.")
+ failed_msg = self.tr("Cannot start Encrypted Proxy.")
+
+ if restart:
+ msg = unreachable_net
+ elif failed:
+ msg = failed_msg
+ else:
+ msg = clear_traffic
+ self.ui.lblEIPMessage.setText(msg)
self.ui.lblEIPStatus.show()
+ def eip_failed_to_restart(self):
+ """
+ Update EIP messages.
+ """
+ msg = self.tr("Could not restart Encrypted Proxy")
+ self.ui.lblEIPMessage.setText(msg)
+ self.ui.lblEIPStatus.show()
+
+ self.set_eip_status(self.tr("You can start the service manually."))
+
@QtCore.Slot(dict)
def update_vpn_status(self, data=None):
"""
@@ -407,7 +458,8 @@ class EIPStatusWidget(QtGui.QWidget):
self.ui.lblEIPStatus.hide()
# XXX should be handled by the state machine too.
- self.eip_connection_connected.emit()
+ # --- is this currently being sent?
+ self.eipconnection.qtsigs.connected_signal.emit()
# XXX should lookup vpn_state map in EIPConnection
elif vpn_state == "AUTH":
@@ -423,8 +475,9 @@ class EIPStatusWidget(QtGui.QWidget):
elif vpn_state == "ALREADYRUNNING":
# Put the following calls in Qt's event queue, otherwise
# the UI won't update properly
+ #self.send_disconnect_signal()
QtCore.QTimer.singleShot(
- 0, self.eipconnection.qtsigs.do_disconnect_signal)
+ 0, self.eipconnection.qtsigns.do_disconnect_signal.emit)
msg = self.tr("Unable to start VPN, it's already running.")
QtCore.QTimer.singleShot(0, partial(self.set_eip_status, msg))
else:
@@ -470,3 +523,96 @@ class EIPStatusWidget(QtGui.QWidget):
self._provider = provider
self.ui.lblEIPMessage.setText(
self.tr("Route traffic through: {0}").format(self._provider))
+
+ #
+ # Slots for signals
+ #
+
+ @QtCore.Slot()
+ def _on_eip_connection_aborted(self):
+ """
+ TRIGGERS:
+ Signaler.eip_connection_aborted
+ """
+ logger.error("Tried to start EIP but cannot find any "
+ "available provider!")
+
+ eip_status_label = self.tr("Could not load {0} configuration.")
+ eip_status_label = eip_status_label.format(
+ self._eip_conductor.eip_name)
+ self.set_eip_status(eip_status_label, error=True)
+
+ # signal connection_aborted to state machine:
+ qtsigs = self._eipconnection.qtsigs
+ qtsigs.connection_aborted_signal.emit()
+
+ def _on_eip_openvpn_already_running(self):
+ self.set_eip_status(
+ self.tr("Another openvpn instance is already running, and "
+ "could not be stopped."),
+ error=True)
+ self.set_eipstatus_off()
+
+ def _on_eip_alien_openvpn_already_running(self):
+ self.set_eip_status(
+ self.tr("Another openvpn instance is already running, and "
+ "could not be stopped because it was not launched by "
+ "Bitmask. Please stop it and try again."),
+ error=True)
+ self.set_eipstatus_off()
+
+ def _on_eip_openvpn_not_found_error(self):
+ self.set_eip_status(
+ self.tr("We could not find openvpn binary."),
+ error=True)
+ self.set_eipstatus_off()
+
+ def _on_eip_vpn_launcher_exception(self):
+ # XXX We should implement again translatable exceptions so
+ # we can pass a translatable string to the panel (usermessage attr)
+ self.set_eip_status("VPN Launcher error.", error=True)
+ self.set_eipstatus_off()
+
+ def _on_eip_no_polkit_agent_error(self):
+ self.set_eip_status(
+ # XXX this should change to polkit-kde where
+ # applicable.
+ self.tr("We could not find any authentication agent in your "
+ "system.<br/>Make sure you have"
+ "<b>polkit-gnome-authentication-agent-1</b> running and"
+ "try again."),
+ error=True)
+ self.set_eipstatus_off()
+
+ def _on_eip_no_pkexec_error(self):
+ self.set_eip_status(
+ self.tr("We could not find <b>pkexec</b> in your system."),
+ error=True)
+ self.set_eipstatus_off()
+
+ def _on_eip_no_tun_kext_error(self):
+ self.set_eip_status(
+ self.tr("{0} cannot be started because the tuntap extension is "
+ "not installed properly in your "
+ "system.").format(self._eip_conductor.eip_name))
+ self.set_eipstatus_off()
+
+ @QtCore.Slot()
+ def _on_eip_network_unreachable(self):
+ """
+ TRIGGERS:
+ self._eip_connection.qtsigs.network_unreachable
+
+ Displays a "network unreachable" error in the EIP status panel.
+ """
+ self.set_eip_status(self.tr("Network is unreachable"),
+ error=True)
+ self.set_eip_status_icon("error")
+
+ def set_eipstatus_off(self, error=True):
+ # XXX this should be handled by the state machine.
+ """
+ Sets eip status to off
+ """
+ self.set_eip_status("", error=error)
+ self.set_eip_status_icon("error")
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index fd9a70ac..1d467e60 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -30,7 +30,6 @@ from leap.bitmask import __version_hash__ as VERSION_HASH
from leap.bitmask.config import flags
from leap.bitmask.config.leapsettings import LeapSettings
-from leap.bitmask.gui import statemachines
from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement
from leap.bitmask.gui.eip_preferenceswindow import EIPPreferencesWindow
from leap.bitmask.gui.eip_status import EIPStatusWidget
@@ -46,12 +45,10 @@ from leap.bitmask.platform_init.initializers import init_platform
from leap.bitmask import backend
-from leap.bitmask.services import get_service_display_name
-
+from leap.bitmask.services.eip import conductor as eip_conductor
from leap.bitmask.services.mail import conductor as mail_conductor
from leap.bitmask.services import EIP_SERVICE, MX_SERVICE
-from leap.bitmask.services.eip.connection import EIPConnection
from leap.bitmask.util import make_address
from leap.bitmask.util.keyring_helpers import has_keyring
@@ -68,6 +65,7 @@ from leap.mail.imap.service.imap import IMAP_PORT
from ui_mainwindow import Ui_MainWindow
+QtDelayedCall = QtCore.QTimer.singleShot
logger = logging.getLogger(__name__)
@@ -131,11 +129,16 @@ class MainWindow(QtGui.QMainWindow):
self._settings = LeapSettings()
+ # Login Widget
self._login_widget = LoginWidget(
self._settings,
self)
self.ui.loginLayout.addWidget(self._login_widget)
+ # Mail Widget
+ self._mail_status = MailStatusWidget(self)
+ self.ui.mailLayout.addWidget(self._mail_status)
+
# Qt Signal Connections #####################################
# TODO separate logic from ui signals.
@@ -144,34 +147,29 @@ class MainWindow(QtGui.QMainWindow):
self._login_widget.show_wizard.connect(self._launch_wizard)
self._login_widget.logout.connect(self._logout)
- self._eip_status = EIPStatusWidget(self)
- self.ui.eipLayout.addWidget(self._eip_status)
- self._login_widget.logged_in_signal.connect(
- self._eip_status.enable_eip_start)
- self._login_widget.logged_in_signal.connect(
- self._enable_eip_start_action)
+ # EIP Control redux #########################################
+ self._eip_conductor = eip_conductor.EIPConductor(
+ self._settings, self._backend)
+ self._eip_status = EIPStatusWidget(self, self._eip_conductor)
- self._mail_status = MailStatusWidget(self)
- self.ui.mailLayout.addWidget(self._mail_status)
-
- self._eip_connection = EIPConnection()
-
- # XXX this should be handled by EIP Conductor
- self._eip_connection.qtsigs.connecting_signal.connect(
- self._start_EIP)
- self._eip_connection.qtsigs.disconnecting_signal.connect(
- self._stop_eip)
+ self.ui.eipLayout.addWidget(self._eip_status)
+ self._eip_conductor.add_eip_widget(self._eip_status)
- self._eip_status.eip_connection_connected.connect(
+ self._eip_conductor.connect_signals()
+ self._eip_conductor.qtsigs.connected_signal.connect(
self._on_eip_connection_connected)
- self._eip_status.eip_connection_connected.connect(
+ self._eip_conductor.qtsigs.disconnected_signal.connect(
+ self._on_eip_connection_disconnected)
+ self._eip_conductor.qtsigs.connected_signal.connect(
self._maybe_run_soledad_setup_checks)
+
self.offline_mode_bypass_login.connect(
self._maybe_run_soledad_setup_checks)
self.eip_needs_login.connect(self._eip_status.disable_eip_start)
self.eip_needs_login.connect(self._disable_eip_start_action)
+ self._already_started_eip = False
self._trying_to_start_eip = False
self._already_started_eip = False
@@ -215,8 +213,7 @@ class MainWindow(QtGui.QMainWindow):
self._systray = None
- # XXX separate actions into a different
- # module.
+ # XXX separate actions into a different module.
self._action_mail_status = QtGui.QAction(self.tr("Mail is OFF"), self)
self._mail_status.set_action_mail_status(self._action_mail_status)
@@ -280,20 +277,19 @@ class MainWindow(QtGui.QMainWindow):
# the EIPConductor or some other clever component that we will
# instantiate from here.
- self.eip_machine = None
# start event machines
- self.start_eip_machine()
+ # TODO should encapsulate all actions into one object
+ self._eip_conductor.start_eip_machine(
+ action=self._action_eip_startstop)
self._mail_conductor.start_mail_machine()
- self._eip_name = get_service_display_name(EIP_SERVICE)
-
if self._first_run():
self._wizard_firstrun = True
self._disconnect_and_untrack()
self._wizard = Wizard(backend=self._backend,
bypass_checks=bypass_checks)
# Give this window time to finish init and then show the wizard
- QtCore.QTimer.singleShot(1, self._launch_wizard)
+ QtDelayedCall(1, self._launch_wizard)
self._wizard.accepted.connect(self._finish_init)
self._wizard.rejected.connect(self._rejected_wizard)
else:
@@ -351,67 +347,50 @@ class MainWindow(QtGui.QMainWindow):
:type only_tracked: bool
"""
sig = self._backend.signaler
+ conntrack = self._connect_and_track
+ auth_err = self._authentication_error
- self._connect_and_track(sig.prov_name_resolution,
- self._intermediate_stage)
- self._connect_and_track(sig.prov_https_connection,
- self._intermediate_stage)
- self._connect_and_track(sig.prov_download_ca_cert,
- self._intermediate_stage)
-
- self._connect_and_track(sig.prov_download_provider_info,
- self._load_provider_config)
- self._connect_and_track(sig.prov_check_api_certificate,
- self._provider_config_loaded)
+ conntrack(sig.prov_name_resolution, self._intermediate_stage)
+ conntrack(sig.prov_https_connection, self._intermediate_stage)
+ conntrack(sig.prov_download_ca_cert, self._intermediate_stage)
+ conntrack(sig.prov_download_provider_info, self._load_provider_config)
+ conntrack(sig.prov_check_api_certificate, self._provider_config_loaded)
- self._connect_and_track(sig.prov_problem_with_provider,
- self._login_problem_provider)
-
- self._connect_and_track(sig.prov_cancelled_setup,
- self._set_login_cancelled)
+ conntrack(sig.prov_problem_with_provider, self._login_problem_provider)
+ conntrack(sig.prov_cancelled_setup, self._set_login_cancelled)
self._connect_and_track(sig.prov_get_details,
self._provider_get_details)
# Login signals
- self._connect_and_track(sig.srp_auth_ok, self._authentication_finished)
+ conntrack(sig.srp_auth_ok, self._authentication_finished)
- auth_error = (
- lambda: self._authentication_error(self.tr("Unknown error.")))
- self._connect_and_track(sig.srp_auth_error, auth_error)
+ auth_error = lambda: auth_err(self.tr("Unknown error."))
+ conntrack(sig.srp_auth_error, auth_error)
- auth_server_error = (
- lambda: self._authentication_error(
- self.tr("There was a server problem with authentication.")))
- self._connect_and_track(sig.srp_auth_server_error, auth_server_error)
+ auth_server_error = lambda: auth_err(self.tr(
+ "There was a server problem with authentication."))
+ conntrack(sig.srp_auth_server_error, auth_server_error)
- auth_connection_error = (
- lambda: self._authentication_error(
- self.tr("Could not establish a connection.")))
- self._connect_and_track(sig.srp_auth_connection_error,
- auth_connection_error)
+ auth_connection_error = lambda: auth_err(self.tr(
+ "Could not establish a connection."))
+ conntrack(sig.srp_auth_connection_error, auth_connection_error)
- auth_bad_user_or_password = (
- lambda: self._authentication_error(
- self.tr("Invalid username or password.")))
- self._connect_and_track(sig.srp_auth_bad_user_or_password,
- auth_bad_user_or_password)
+ auth_bad_user_or_password = lambda: auth_err(self.tr(
+ "Invalid username or password."))
+ conntrack(sig.srp_auth_bad_user_or_password, auth_bad_user_or_password)
# Logout signals
- self._connect_and_track(sig.srp_logout_ok, self._logout_ok)
- self._connect_and_track(sig.srp_logout_error, self._logout_error)
-
- self._connect_and_track(sig.srp_not_logged_in_error,
- self._not_logged_in_error)
+ conntrack(sig.srp_logout_ok, self._logout_ok)
+ conntrack(sig.srp_logout_error, self._logout_error)
+ conntrack(sig.srp_not_logged_in_error, self._not_logged_in_error)
# EIP bootstrap signals
- self._connect_and_track(sig.eip_config_ready,
- self._eip_intermediate_stage)
- self._connect_and_track(sig.eip_client_certificate_ready,
- self._finish_eip_bootstrap)
+ conntrack(sig.eip_config_ready, self._eip_intermediate_stage)
+ conntrack(sig.eip_client_certificate_ready, self._finish_eip_bootstrap)
###################################################
- # Add tracked signals above this, untracked bellow!
+ # Add tracked signals above this, untracked below!
###################################################
if only_tracked:
return
@@ -421,38 +400,20 @@ class MainWindow(QtGui.QMainWindow):
sig.backend_bad_call.connect(self._backend_bad_call)
sig.prov_check_api_certificate.connect(self._get_provider_details)
-
sig.prov_unsupported_client.connect(self._needs_update)
sig.prov_unsupported_api.connect(self._incompatible_api)
+ sig.prov_get_all_services.connect(self._provider_get_all_services)
- sig.prov_get_all_services.connect(
- self._provider_get_all_services)
-
- # EIP start signals
- sig.eip_openvpn_already_running.connect(
- self._on_eip_openvpn_already_running)
- sig.eip_alien_openvpn_already_running.connect(
- self._on_eip_alien_openvpn_already_running)
- sig.eip_openvpn_not_found_error.connect(
- self._on_eip_openvpn_not_found_error)
- sig.eip_vpn_launcher_exception.connect(
- self._on_eip_vpn_launcher_exception)
- sig.eip_no_polkit_agent_error.connect(
- self._on_eip_no_polkit_agent_error)
- sig.eip_no_pkexec_error.connect(self._on_eip_no_pkexec_error)
- sig.eip_no_tun_kext_error.connect(self._on_eip_no_tun_kext_error)
-
- sig.eip_state_changed.connect(self._eip_status.update_vpn_state)
- sig.eip_status_changed.connect(self._eip_status.update_vpn_status)
- sig.eip_process_finished.connect(self._eip_finished)
- sig.eip_network_unreachable.connect(self._on_eip_network_unreachable)
- sig.eip_process_restart_tls.connect(self._do_eip_restart)
- sig.eip_process_restart_ping.connect(self._do_eip_restart)
+ # EIP start signals ==============================================
+ self._eip_conductor.connect_backend_signals()
sig.eip_can_start.connect(self._backend_can_start_eip)
sig.eip_cannot_start.connect(self._backend_cannot_start_eip)
+ # ==================================================================
+
# Soledad signals
+ # TODO delegate connection to soledad bootstrapper
sig.soledad_bootstrap_failed.connect(
self._mail_status.set_soledad_failed)
sig.soledad_bootstrap_finished.connect(self._on_soledad_ready)
@@ -919,7 +880,8 @@ class MainWindow(QtGui.QMainWindow):
systrayMenu.addAction(self._action_visible)
systrayMenu.addSeparator()
- eip_status_label = "{0}: {1}".format(self._eip_name, self.tr("OFF"))
+ eip_status_label = "{0}: {1}".format(
+ self._eip_conductor.eip_name, self.tr("OFF"))
self._eip_menu = eip_menu = systrayMenu.addMenu(eip_status_label)
eip_menu.addAction(self._action_eip_startstop)
self._eip_status.set_eip_status_menu(eip_menu)
@@ -1001,7 +963,7 @@ class MainWindow(QtGui.QMainWindow):
# Wait a bit until the window visibility has changed so
# the menu is set with the correct value.
- QtCore.QTimer.singleShot(500, self._update_hideshow_menu)
+ QtDelayedCall(500, self._update_hideshow_menu)
def _center_window(self):
"""
@@ -1398,7 +1360,7 @@ class MainWindow(QtGui.QMainWindow):
"""
# TODO split.
if not self._provides_mx_and_enabled() and not flags.OFFLINE:
- logger.debug("Does not provides and enabled MX")
+ logger.debug("Provider does not offer MX, but it is enabled.")
return
username = self._login_widget.get_user()
@@ -1473,21 +1435,6 @@ class MainWindow(QtGui.QMainWindow):
###################################################################
# Service control methods: eip
- def start_eip_machine(self):
- """
- Initializes and starts the EIP state machine
- """
- button = self._eip_status.eip_button
- action = self._action_eip_startstop
- label = self._eip_status.eip_label
- builder = statemachines.ConnectionMachineBuilder(self._eip_connection)
- eip_machine = builder.make_machine(button=button,
- action=action,
- label=label)
- self.eip_machine = eip_machine
- self.eip_machine.start()
- logger.debug('eip machine started')
-
@QtCore.Slot()
def _disable_eip_start_action(self):
"""
@@ -1506,17 +1453,14 @@ class MainWindow(QtGui.QMainWindow):
def _on_eip_connection_connected(self):
"""
TRIGGERS:
- self._eip_status.eip_connection_connected
-
- Emits the EIPConnection.qtsigs.connected_signal
+ self._eip_conductor.qtsigs.connected_signal
This is a little workaround for connecting the vpn-connected
signal that currently is beeing processed under status_panel.
After the refactor to EIPConductor this should not be necessary.
"""
- self._eip_connection.qtsigs.connected_signal.emit()
-
domain = self._login_widget.get_selected_provider()
+
self._eip_status.set_provider(domain)
self._settings.set_defaultprovider(domain)
self._already_started_eip = True
@@ -1524,7 +1468,29 @@ class MainWindow(QtGui.QMainWindow):
# check for connectivity
self._check_name_resolution(domain)
+ @QtCore.Slot()
+ def _on_eip_connection_disconnected(self):
+ """
+ TRIGGERS:
+ self._eip_conductor.qtsigs.disconnected_signal
+
+ Workaround for updating the eip_status widget with
+ the provider when the eip connection disconnects.
+ """
+ # TODO
+ # We should move this to the conductor<->widget interface.
+ # To do that, we need to subscribe to logged_user,
+ # for example by using the observer pattern or a proxy object.
+ user = self._logged_user
+ if user:
+ domain = self._login_widget.get_selected_provider()
+ full_user_id = make_address(user, domain)
+ self._eip_status.set_provider(full_user_id)
+
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.
@@ -1555,7 +1521,7 @@ class MainWindow(QtGui.QMainWindow):
"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_name)
+ ).format(domain, self._eip_conductor.eip_name)
show_err = lambda: QtGui.QMessageBox.critical(
self, self.tr("Connection Error"), msg)
@@ -1580,211 +1546,6 @@ class MainWindow(QtGui.QMainWindow):
if settings.get_autostart_eip():
self._maybe_start_eip(autostart=True)
- @QtCore.Slot()
- def _start_EIP(self):
- """
- Starts EIP
- """
- self._eip_status.eip_pre_up()
- self.user_stopped_eip = False
-
- # Until we set an option in the preferences window, we'll assume that
- # by default we try to autostart. If we switch it off manually, it
- # won't try the next time.
- self._settings.set_autostart_eip(True)
-
- self._backend.eip_start()
-
- @QtCore.Slot()
- def _on_eip_connection_aborted(self):
- """
- TRIGGERS:
- Signaler.eip_connection_aborted
- """
- logger.error("Tried to start EIP but cannot find any "
- "available provider!")
-
- eip_status_label = self.tr("Could not load {0} configuration.")
- eip_status_label = eip_status_label.format(self._eip_name)
- self._eip_status.set_eip_status(eip_status_label, error=True)
-
- # signal connection_aborted to state machine:
- qtsigs = self._eip_connection.qtsigs
- qtsigs.connection_aborted_signal.emit()
-
- def _on_eip_openvpn_already_running(self):
- self._eip_status.set_eip_status(
- self.tr("Another openvpn instance is already running, and "
- "could not be stopped."),
- error=True)
- self._set_eipstatus_off()
-
- def _on_eip_alien_openvpn_already_running(self):
- self._eip_status.set_eip_status(
- self.tr("Another openvpn instance is already running, and "
- "could not be stopped because it was not launched by "
- "Bitmask. Please stop it and try again."),
- error=True)
- self._set_eipstatus_off()
-
- def _on_eip_openvpn_not_found_error(self):
- self._eip_status.set_eip_status(
- self.tr("We could not find openvpn binary."),
- error=True)
- self._set_eipstatus_off()
-
- def _on_eip_vpn_launcher_exception(self):
- # XXX We should implement again translatable exceptions so
- # we can pass a translatable string to the panel (usermessage attr)
- self._eip_status.set_eip_status("VPN Launcher error.", error=True)
- self._set_eipstatus_off()
-
- def _on_eip_no_polkit_agent_error(self):
- self._eip_status.set_eip_status(
- # XXX this should change to polkit-kde where
- # applicable.
- self.tr("We could not find any authentication agent in your "
- "system.<br/>Make sure you have"
- "<b>polkit-gnome-authentication-agent-1</b> running and"
- "try again."),
- error=True)
- self._set_eipstatus_off()
-
- def _on_eip_no_pkexec_error(self):
- self._eip_status.set_eip_status(
- self.tr("We could not find <b>pkexec</b> in your system."),
- error=True)
- self._set_eipstatus_off()
-
- def _on_eip_no_tun_kext_error(self):
- self._eip_status.set_eip_status(
- self.tr("{0} cannot be started because the tuntap extension is "
- "not installed properly in your "
- "system.").format(self._eip_name))
- self._set_eipstatus_off()
-
- @QtCore.Slot()
- def _stop_eip(self, restart=False):
- """
- TRIGGERS:
- self._eip_connection.qtsigs.do_disconnect_signal (via state machine)
-
- Stops vpn process and makes gui adjustments to reflect
- the change of state.
-
- :param abnormal: whether this was an abnormal termination.
- :type abnormal: bool
- """
- self.user_stopped_eip = not restart
- self._backend.eip_stop(restart=restart)
-
- self._set_eipstatus_off(False)
- self._already_started_eip = False
-
- logger.debug('Setting autostart to: False')
- self._settings.set_autostart_eip(False)
-
- user = self._logged_user
- if user:
- domain = self._login_widget.get_selected_provider()
- full_user_id = make_address(user, domain)
- self._eip_status.set_provider(full_user_id)
-
- self._eip_status.eip_stopped()
-
- @QtCore.Slot()
- def _on_eip_network_unreachable(self):
- # XXX Should move to EIP Conductor
- """
- TRIGGERS:
- self._eip_connection.qtsigs.network_unreachable
-
- Displays a "network unreachable" error in the EIP status panel.
- """
- self._eip_status.set_eip_status(self.tr("Network is unreachable"),
- error=True)
- self._eip_status.set_eip_status_icon("error")
-
- @QtCore.Slot()
- def _do_eip_restart(self):
- # XXX Should move to EIP Conductor
- """
- TRIGGERS:
- self._eip_connection.qtsigs.process_restart
-
- Restart the connection.
- """
- # for some reason, emitting the do_disconnect/do_connect
- # signals hangs the UI.
- self._stop_eip(restart=True)
- QtCore.QTimer.singleShot(2000, self._start_EIP)
-
- def _set_eipstatus_off(self, error=True):
- """
- Sets eip status to off
- """
- # XXX this should be handled by the state machine.
- self._eip_status.set_eip_status("", error=error)
- self._eip_status.set_eip_status_icon("error")
-
- @QtCore.Slot(int)
- def _eip_finished(self, exitCode):
- """
- TRIGGERS:
- Signaler.eip_process_finished
-
- Triggered when the EIP/VPN process finishes to set the UI
- accordingly.
-
- Ideally we would have the right exit code here,
- but the use of different wrappers (pkexec, cocoasudo) swallows
- the openvpn exit code so we get zero exit in some cases where we
- shouldn't. As a workaround we just use a flag to indicate
- a purposeful switch off, and mark everything else as unexpected.
-
- In the near future we should trigger a native notification from here,
- since the user really really wants to know she is unprotected asap.
- And the right thing to do will be to fail-close.
-
- :param exitCode: the exit code of the eip process.
- :type exitCode: int
- """
- # TODO move to EIPConductor.
- # TODO Add error catching to the openvpn log observer
- # so we can have a more precise idea of which type
- # of error did we have (server side, local problem, etc)
-
- logger.info("VPN process finished with exitCode %s..."
- % (exitCode,))
-
- qtsigs = self._eip_connection.qtsigs
- signal = qtsigs.disconnected_signal
-
- # XXX check if these exitCodes are pkexec/cocoasudo specific
- if exitCode in (126, 127):
- eip_status_label = self.tr(
- "{0} could not be launched "
- "because you did not authenticate properly.")
- eip_status_label = eip_status_label.format(self._eip_name)
- self._eip_status.set_eip_status(eip_status_label, error=True)
- signal = qtsigs.connection_aborted_signal
- self._backend.eip_terminate()
-
- elif exitCode != 0 or not self.user_stopped_eip:
- eip_status_label = self.tr("{0} finished in an unexpected manner!")
- eip_status_label = eip_status_label.format(self._eip_name)
- self._eip_status.eip_stopped()
- self._eip_status.set_eip_status_icon("error")
- self._eip_status.set_eip_status(eip_status_label, error=True)
- signal = qtsigs.connection_died_signal
-
- if exitCode == 0 and IS_MAC:
- # XXX remove this warning after I fix cocoasudo.
- logger.warning("The above exit code MIGHT BE WRONG.")
-
- # We emit signals to trigger transitions in the state machine:
- signal.emit()
-
# eip boostrapping, config etc...
def _maybe_start_eip(self, autostart=False):
@@ -1812,9 +1573,8 @@ class MainWindow(QtGui.QMainWindow):
self._already_started_eip = True
# we want to start soledad anyway after a certain timeout if eip
# fails to come up
- QtCore.QTimer.singleShot(
- self.EIP_START_TIMEOUT,
- self._maybe_run_soledad_setup_checks)
+ QtDelayedCall(self.EIP_START_TIMEOUT,
+ self._maybe_run_soledad_setup_checks)
else:
if not self._already_started_eip:
if EIP_SERVICE in self._enabled_services:
@@ -1833,8 +1593,8 @@ class MainWindow(QtGui.QMainWindow):
TRIGGERS:
self._backend.signaler.eip_client_certificate_ready
- Starts the VPN thread if the eip configuration is properly
- loaded
+ Start the VPN thread if the eip configuration is properly
+ loaded.
"""
passed = data[self._backend.PASSED_KEY]
@@ -1846,11 +1606,11 @@ class MainWindow(QtGui.QMainWindow):
return
# DO START EIP Connection!
- self._eip_connection.qtsigs.do_connect_signal.emit()
+ self._eip_conductor.do_connect()
@QtCore.Slot(dict)
def _eip_intermediate_stage(self, data):
- # TODO missing param
+ # TODO missing param documentation
"""
TRIGGERS:
self._backend.signaler.eip_config_ready
@@ -2004,7 +1764,7 @@ class MainWindow(QtGui.QMainWindow):
if self._systray is not None:
self._systray.showMessage(
self.tr('Quitting...'),
- self.tr('The app is quitting, please wait.'))
+ self.tr('Bitmask is quitting, please wait.'))
# explicitly process events to display tooltip immediately
QtCore.QCoreApplication.processEvents(0, 10)
diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py
index 31938a70..f8e5479d 100644
--- a/src/leap/bitmask/gui/statemachines.py
+++ b/src/leap/bitmask/gui/statemachines.py
@@ -504,6 +504,11 @@ class ConnectionMachineBuilder(object):
conn.qtsigs.connection_died_signal,
states[_OFF])
+ # XXX adding this---------------------
+ states[_ON].addTransition(
+ conn.qtsigs.do_disconnect_signal,
+ states[_DIS])
+
# * If we receive the connection_aborted, we transition
# from connecting to the off state
states[_CON].addTransition(
@@ -551,7 +556,8 @@ class ConnectionMachineBuilder(object):
# TODO add tooltip
# OFF State ----------------------
- off = QState()
+ off = SignallingState(
+ None, name=conn.name)
off_label = _tr("Turn {0}").format(
conn.Connected.short_label)
if button:
@@ -587,7 +593,10 @@ class ConnectionMachineBuilder(object):
states[_CON] = connecting
# ON State ------------------------
- on = QState()
+ on = SignallingState(
+ None, name=conn.name)
+ on_label = _tr("Turn {0}").format(
+ conn.Disconnected.short_label)
if button:
on.assignProperty(
button, 'text', on_label)
diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py
new file mode 100644
index 00000000..0cd4c95c
--- /dev/null
+++ b/src/leap/bitmask/services/eip/conductor.py
@@ -0,0 +1,302 @@
+# -*- coding: utf-8 -*-
+# conductor.py
+# Copyright (C) 2014 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+EIP Conductor module.
+"""
+import logging
+
+from PySide import QtCore
+
+from leap.bitmask.gui import statemachines
+from leap.bitmask.services import EIP_SERVICE
+from leap.bitmask.services import get_service_display_name
+from leap.bitmask.services.eip.connection import EIPConnection
+from leap.bitmask.platform_init import IS_MAC
+from leap.bitmask.util import make_address
+
+QtDelayedCall = QtCore.QTimer.singleShot
+logger = logging.getLogger(__name__)
+
+
+class EIPConductor(object):
+
+ def __init__(self, settings, backend, **kwargs):
+ """
+ Initializes EIP Conductor.
+
+ :param settings:
+ :type settings:
+
+ :param backend:
+ :type backend:
+ """
+ self.eip_connection = EIPConnection()
+ self.eip_name = get_service_display_name(EIP_SERVICE)
+ self._settings = settings
+ self._backend = backend
+
+ self._eip_status = None
+
+ @property
+ def qtsigs(self):
+ return self.eip_connection.qtsigs
+
+ def add_eip_widget(self, widget):
+ """
+ Keep a reference to the passed eip status widget.
+
+ :param widget: the EIP Status widget.
+ :type widget: QWidget
+ """
+ self._eip_status = widget
+
+ def connect_signals(self):
+ """
+ Connect signals.
+ """
+ self.qtsigs.connecting_signal.connect(self._start_eip)
+
+ self.qtsigs.disconnecting_signal.connect(self._stop_eip)
+ self.qtsigs.disconnected_signal.connect(self._eip_status.eip_stopped)
+
+ def connect_backend_signals(self):
+ """
+ Connect to backend signals.
+ """
+ signaler = self._backend.signaler
+
+ # for conductor
+ signaler.eip_process_restart_tls.connect(self._do_eip_restart)
+ signaler.eip_process_restart_tls.connect(self._do_eip_failed)
+ signaler.eip_process_restart_ping.connect(self._do_eip_restart)
+ signaler.eip_process_finished.connect(self._eip_finished)
+
+ # for widget
+ self._eip_status.connect_backend_signals()
+
+ def start_eip_machine(self, action):
+ """
+ Initializes and starts the EIP state machine.
+ Needs the reference to the eip_status widget not to be empty.
+
+ :action: QtAction
+ """
+ action = action
+ button = self._eip_status.eip_button
+ label = self._eip_status.eip_label
+
+ builder = statemachines.ConnectionMachineBuilder(self.eip_connection)
+ eip_machine = builder.make_machine(button=button,
+ action=action,
+ label=label)
+ self.eip_machine = eip_machine
+ self.eip_machine.start()
+ logger.debug('eip machine started')
+
+ def do_connect(self):
+ """
+ Start the connection procedure.
+ Emits a signal that triggers the OFF -> Connecting sequence.
+ This will call _start_eip via the state machine.
+ """
+ self.qtsigs.do_connect_signal.emit()
+
+ @QtCore.Slot()
+ def _start_eip(self):
+ """
+ Starts EIP.
+ """
+ # FIXME --- pass is_restart parameter to here ???
+ is_restart = self._eip_status and self._eip_status.is_restart
+
+ def reconnect():
+ self.qtsigs.disconnecting_signal.connect(self._stop_eip)
+
+ if is_restart:
+ QtDelayedCall(0, reconnect)
+ else:
+ self._eip_status.eip_pre_up()
+ self.user_stopped_eip = False
+
+ # Until we set an option in the preferences window, we'll assume that
+ # by default we try to autostart. If we switch it off manually, it
+ # won't try the next time.
+ self._settings.set_autostart_eip(True)
+ self._eip_status.is_restart = False
+
+ # DO the backend call!
+ self._backend.eip_start()
+
+ @QtCore.Slot()
+ def _stop_eip(self, restart=False, failed=False):
+ """
+ TRIGGERS:
+ self.qsigs.do_disconnect_signal (via state machine)
+
+ Stops vpn process and makes gui adjustments to reflect
+ the change of state.
+
+ :param restart: whether this is part of a eip restart.
+ :type restart: bool
+
+ :param failed: whether this is the final step of a retry sequence
+ :type failed: bool
+ """
+ self._eip_status.is_restart = restart
+ self.user_stopped_eip = not restart and not failed
+
+ def on_disconnected_do_restart():
+ # hard restarts
+ logger.debug("HARD RESTART")
+ eip_status_label = self._eip_status.tr("{0} is restarting")
+ eip_status_label = eip_status_label.format(self.eip_name)
+ self._eip_status.eip_stopped(restart=True)
+ self._eip_status.set_eip_status(eip_status_label, error=False)
+
+ QtDelayedCall(2000, self.do_connect)
+
+ def plug_restart_on_disconnected():
+ self.qtsigs.disconnected_signal.connect(on_disconnected_do_restart)
+
+ def reconnect_disconnected_signal():
+ self.qtsigs.disconnected_signal.disconnect(
+ on_disconnected_do_restart)
+
+ def do_stop(*args):
+ self._stop_eip(restart=False)
+
+ def reconnect_stop_signal():
+ self.qtsigs.disconnecting_signal.disconnect()
+ self.qtsigs.disconnecting_signal.connect(do_stop)
+
+ if restart:
+ # we bypass the on_eip_disconnected here
+ plug_restart_on_disconnected()
+ self.qtsigs.disconnected_signal.emit()
+ #QtDelayedCall(0, self.qtsigs.disconnected_signal.emit)
+ # ...and reconnect the original signal again, after having used the
+ # diversion
+ QtDelayedCall(500, reconnect_disconnected_signal)
+
+ elif failed:
+ self.qtsigs.disconnected_signal.emit()
+
+ else:
+ logger.debug('Setting autostart to: False')
+ self._settings.set_autostart_eip(False)
+
+ # Call to the backend.
+ self._backend.eip_stop(restart=restart)
+
+ # ... and inform the status widget
+ self._eip_status.set_eipstatus_off(False)
+ self._eip_status.eip_stopped(restart=restart, failed=failed)
+
+ self._already_started_eip = False
+
+ # XXX needed?
+ if restart:
+ QtDelayedCall(3000, reconnect_stop_signal)
+
+ @QtCore.Slot()
+ def _do_eip_restart(self):
+ """
+ TRIGGERS:
+ self._eip_connection.qtsigs.process_restart
+
+ Restart the connection.
+ """
+ if self._eip_status is not None:
+ self._eip_status.is_restart = True
+
+ def do_stop(*args):
+ self._stop_eip(restart=True)
+
+ try:
+ self.qtsigs.disconnecting_signal.disconnect()
+ except Exception:
+ logger.error("cannot disconnect signals")
+
+ self.qtsigs.disconnecting_signal.connect(do_stop)
+ self.qtsigs.do_disconnect_signal.emit()
+
+ @QtCore.Slot()
+ def _do_eip_failed(self):
+ """
+ Stop EIP after a failure to start.
+
+ TRIGGERS
+ signaler.eip_process_restart_tls
+ """
+ logger.debug("TLS Error: eip_stop (failed)")
+ self.qtsigs.connection_died_signal.emit()
+ QtDelayedCall(1000, self._eip_status.eip_failed_to_restart)
+
+ @QtCore.Slot(int)
+ def _eip_finished(self, exitCode):
+ """
+ TRIGGERS:
+ Signaler.eip_process_finished
+
+ Triggered when the EIP/VPN process finishes to set the UI
+ accordingly.
+
+ Ideally we would have the right exit code here,
+ but the use of different wrappers (pkexec, cocoasudo) swallows
+ the openvpn exit code so we get zero exit in some cases where we
+ shouldn't. As a workaround we just use a flag to indicate
+ a purposeful switch off, and mark everything else as unexpected.
+
+ :param exitCode: the exit code of the eip process.
+ :type exitCode: int
+ """
+ # TODO Add error catching to the openvpn log observer
+ # so we can have a more precise idea of which type
+ # of error did we have (server side, local problem, etc)
+
+ logger.info("VPN process finished with exitCode %s..."
+ % (exitCode,))
+
+ signal = self.qtsigs.disconnected_signal
+
+ # XXX check if these exitCodes are pkexec/cocoasudo specific
+ if exitCode in (126, 127):
+ eip_status_label = self._eip_status.tr(
+ "{0} could not be launched "
+ "because you did not authenticate properly.")
+ eip_status_label = eip_status_label.format(self.eip_name)
+ self._eip_status.set_eip_status(eip_status_label, error=True)
+ signal = self.qtsigs.connection_aborted_signal
+ self._backend.eip_terminate()
+
+ # XXX FIXME --- check exitcode is != 0 really
+ if exitCode != 0 and not self.user_stopped_eip:
+ eip_status_label = self._eip_status.tr(
+ "{0} finished in an unexpected manner!")
+ eip_status_label = eip_status_label.format(self.eip_name)
+ self._eip_status.eip_stopped()
+ self._eip_status.set_eip_status_icon("error")
+ self._eip_status.set_eip_status(eip_status_label,
+ error=True)
+ signal = self.qtsigs.connection_died_signal
+
+ if exitCode == 0 and IS_MAC:
+ # XXX remove this warning after I fix cocoasudo.
+ logger.warning("The above exit code MIGHT BE WRONG.")
+
+ # We emit signals to trigger transitions in the state machine:
+ signal.emit()
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index b068066f..098619be 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -70,7 +70,7 @@ class VPNObserver(object):
'NETWORK_UNREACHABLE': (
'Network is unreachable (code=101)',),
'PROCESS_RESTART_TLS': (
- "SIGUSR1[soft,tls-error]",),
+ "SIGTERM[soft,tls-error]",),
'PROCESS_RESTART_PING': (
"SIGTERM[soft,ping-restart]",),
'INITIALIZATION_COMPLETED': (
@@ -116,10 +116,12 @@ class VPNObserver(object):
:returns: a Signaler signal or None
:rtype: str or None
"""
+ sig = self._signaler
signals = {
- "network_unreachable": self._signaler.EIP_NETWORK_UNREACHABLE,
- "process_restart_tls": self._signaler.EIP_PROCESS_RESTART_TLS,
- "process_restart_ping": self._signaler.EIP_PROCESS_RESTART_PING,
+ "network_unreachable": sig.EIP_NETWORK_UNREACHABLE,
+ "process_restart_tls": sig.EIP_PROCESS_RESTART_TLS,
+ "process_restart_ping": sig.EIP_PROCESS_RESTART_PING,
+ "initialization_completed": sig.EIP_CONNECTED
}
return signals.get(event.lower())
@@ -318,6 +320,7 @@ class VPN(object):
# We assume that the only valid stops are initiated
# by an user action, not hard restarts
self._user_stopped = not restart
+ self._vpnproc.is_restart = restart
# First we try to be polite and send a SIGTERM...
if self._vpnproc:
@@ -755,7 +758,7 @@ class VPNManager(object):
# However, that should be a rare case right now.
self._send_command("signal SIGTERM")
self._close_management_socket(announce=True)
- except Exception as e:
+ except (Exception, AssertionError) as e:
logger.warning("Problem trying to terminate OpenVPN: %r"
% (e,))
else:
@@ -824,6 +827,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
self._openvpn_verb = openvpn_verb
self._vpn_observer = VPNObserver(signaler)
+ self.is_restart = False
# processProtocol methods
@@ -859,7 +863,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
exit_code = reason.value.exitCode
if isinstance(exit_code, int):
logger.debug("processExited, status %d" % (exit_code,))
- self._signaler.signal(self._signaler.EIP_PROCESS_FINISHED, exit_code)
+ self._signaler.signal(
+ self._signaler.EIP_PROCESS_FINISHED, exit_code)
self._alive = False
def processEnded(self, reason):