From 19c90e02a65d1d6fe30e6915cd2a9440878aef83 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 24 Jun 2013 02:57:26 +0900 Subject: Improve OpenVPN Process Control * Disable toggle button until we get "connected" status. #2956 * Catch abnormal termination and update UI accordingly. #2890 --- src/leap/gui/mainwindow.py | 54 ++++++++++++++++++++++++++++++++----- src/leap/gui/statuspanel.py | 1 - src/leap/gui/ui/statuspanel.ui | 3 +++ src/leap/services/eip/vpnprocess.py | 30 ++++++++++++++++++--- 4 files changed, 78 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py index b0bf8a44..94343292 100644 --- a/src/leap/gui/mainwindow.py +++ b/src/leap/gui/mainwindow.py @@ -90,6 +90,9 @@ class MainWindow(QtGui.QMainWindow): new_updates = QtCore.Signal(object) raise_window = QtCore.Signal([]) + # We use this flag to detect abnormal terminations + user_stopped_eip = False + def __init__(self, quit_callback, standalone=False, bypass_checks=False): """ @@ -951,6 +954,7 @@ class MainWindow(QtGui.QMainWindow): Starts EIP """ self._status_panel.eip_pre_up() + self.user_stopped_eip = False provider_config = self._get_best_provider_config() try: @@ -1007,8 +1011,6 @@ class MainWindow(QtGui.QMainWindow): else: self._already_started_eip = True - #self._status_panel.set_startstop_enabled(True) - def _set_eipstatus_off(self): """ Sets eip status to off @@ -1016,11 +1018,16 @@ class MainWindow(QtGui.QMainWindow): self._status_panel.set_eip_status(self.tr("OFF"), error=True) self._status_panel.set_startstop_enabled(True) - def _stop_eip(self): + def _stop_eip(self, abnormal=False): """ 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 = True self._vpn.terminate() self._status_panel.set_eip_status(self.tr("OFF")) @@ -1036,6 +1043,8 @@ class MainWindow(QtGui.QMainWindow): self._status_panel.set_provider( "%s@%s" % (self._logged_user, self._get_best_provider_config().get_domain())) + if abnormal: + self._status_panel.set_startstop_enabled(True) def _get_best_provider_config(self): """ @@ -1188,10 +1197,43 @@ class MainWindow(QtGui.QMainWindow): self._vpn.process_finished Triggered when the EIP/VPN process finishes to set the UI - accordingly + accordingly. """ - logger.debug("Finished VPN with exitCode %s" % (exitCode,)) - self._stop_eip() + logger.info("VPN process finished with exitCode %s..." + % (exitCode,)) + + # 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. + + # TODO we should have a way of parsing the latest lines in the vpn + # log buffer so we can have a more precise idea of which type + # of error did we have (server side, local problem, etc) + abnormal = True + + # XXX check if these exitCodes are pkexec/cocoasudo specific + if exitCode in (126, 127): + self._status_panel.set_global_status( + self.tr("Encrypted Internet could not be launched " + "because you did not authenticate properly."), + error=True) + self._vpn.killit() + elif exitCode != 0 or not self.user_stopped_eip: + self._status_panel.set_global_status( + self.tr("Encrypted Internet finished in an " + "unexpected manner!"), error=True) + else: + abnormal = False + if exitCode == 0: + # XXX remove this warning after I fix cocoasudo. + logger.warning("The above exit code MIGHT BE WRONG.") + self._stop_eip(abnormal) def _on_raise_window_event(self, req): """ diff --git a/src/leap/gui/statuspanel.py b/src/leap/gui/statuspanel.py index de913f09..3e5a5093 100644 --- a/src/leap/gui/statuspanel.py +++ b/src/leap/gui/statuspanel.py @@ -171,7 +171,6 @@ class StatusPanelWidget(QtGui.QWidget): """ self.hide_status_box() self.set_startstop_enabled(False) - logger.debug('disabling buton.....................') def eip_started(self): """ diff --git a/src/leap/gui/ui/statuspanel.ui b/src/leap/gui/ui/statuspanel.ui index 502ba78a..1a2c77ad 100644 --- a/src/leap/gui/ui/statuspanel.ui +++ b/src/leap/gui/ui/statuspanel.ui @@ -208,6 +208,9 @@ ... + + true + diff --git a/src/leap/services/eip/vpnprocess.py b/src/leap/services/eip/vpnprocess.py index d9fa85a6..0ec56ae7 100644 --- a/src/leap/services/eip/vpnprocess.py +++ b/src/leap/services/eip/vpnprocess.py @@ -142,6 +142,14 @@ class VPN(object): # after running out of patience, we try a killProcess logger.debug("Process did not died. Sending a SIGKILL.") + self.killit() + + def killit(self): + """ + Sends a kill signal to the process. + """ + self._stop_pollers() + self._vpnproc.aborted = True self._vpnproc.killProcess() def terminate(self, shutdown=False): @@ -225,11 +233,20 @@ class VPNManager(object): self._reactor = reactor self._tn = None self._qtsigs = qtsigs + self._aborted = False @property def qtsigs(self): return self._qtsigs + @property + def aborted(self): + return self._aborted + + @aborted.setter + def aborted(self, value): + self._aborted = value + def _seek_to_eof(self): """ Read as much as available. Position seek pointer to end of stream @@ -378,7 +395,7 @@ class VPNManager(object): """ # TODO decide about putting a max_lim to retries and signaling # an error. - if not self.is_connected(): + if not self.aborted and not self.is_connected(): self.connect_to_management(self._socket_host, self._socket_port) self._reactor.callLater( self.CONNECTION_RETRY_TIME, @@ -611,6 +628,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): self._last_state = None self._last_status = None + self._alive = False # processProtocol methods @@ -620,6 +638,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): .. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa """ + self._alive = True + self.aborted = False self.try_to_connect_to_management() def outReceived(self, data): @@ -643,6 +663,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): exit_code = reason.value.exitCode if isinstance(exit_code, int): logger.debug("processExited, status %d" % (exit_code,)) + self.qtsigs.process_finished.emit(exit_code) + self._alive = False def processEnded(self, reason): """ @@ -661,13 +683,15 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): """ Polls connection status. """ - self.get_status() + if self._alive: + self.get_status() def pollState(self): """ Polls connection state. """ - self.get_state() + if self._alive: + self.get_state() # launcher -- cgit v1.2.3