summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2013-03-08 11:09:23 -0300
committerTomás Touceda <chiiph@leap.se>2013-03-08 11:09:23 -0300
commit01a7faa2033ef3ce85bc5a346eca3601f0f4f7c5 (patch)
treefd3da99f8d1bec4c4d086583a461e77477dfd8b9 /src
parentcaba70c5cee5e772761f9bbb2e4a9c5beab0be1e (diff)
Migrate VPN process to QProcess
Also: - Add a new tray icon for the whole app and a VPN specific one - Add a way to start/stop EIP independently - Improve reaction to the process dying
Diffstat (limited to 'src')
-rw-r--r--src/leap/gui/mainwindow.py98
-rw-r--r--src/leap/gui/ui/mainwindow.ui63
-rw-r--r--src/leap/services/eip/vpn.py29
3 files changed, 142 insertions, 48 deletions
diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py
index 50a03fb9..df21a2bb 100644
--- a/src/leap/gui/mainwindow.py
+++ b/src/leap/gui/mainwindow.py
@@ -56,6 +56,9 @@ class MainWindow(QtGui.QMainWindow):
self.CONNECTED_ICON = QtGui.QPixmap(":/images/conn_connected.png")
self.ERROR_ICON = QtGui.QPixmap(":/images/conn_error.png")
+ self.LOGGED_OUT_ICON = QtGui.QPixmap(":/images/leap-gray-big.png")
+ self.LOGGED_IN_ICON = QtGui.QPixmap(":/images/leap-color-big.png")
+
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
@@ -67,6 +70,10 @@ class MainWindow(QtGui.QMainWindow):
self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX)
+ self.ui.btnEipStartStop.setEnabled(False)
+ self.ui.btnEipStartStop.clicked.connect(
+ self._stop_eip)
+
# This is loaded only once, there's a bug when doing that more
# than once
self._provider_config = ProviderConfig()
@@ -105,11 +112,13 @@ class MainWindow(QtGui.QMainWindow):
self._eip_bootstrapper.download_config.connect(
self._intermediate_stage)
self._eip_bootstrapper.download_client_certificate.connect(
- self._start_eip)
+ self._finish_eip_bootstrap)
self._vpn = VPN()
self._vpn.state_changed.connect(self._update_vpn_state)
self._vpn.status_changed.connect(self._update_vpn_status)
+ self._vpn.process_finished.connect(
+ self._eip_finished)
QtCore.QCoreApplication.instance().connect(
QtCore.QCoreApplication.instance(),
@@ -130,6 +139,22 @@ class MainWindow(QtGui.QMainWindow):
self._really_quit = False
self._systray = None
+ self._vpn_systray = None
+
+ self._action_eip_status = QtGui.QAction("Encryption is OFF", self)
+ self._action_eip_status.setEnabled(False)
+ self._action_eip_stop = QtGui.QAction("Stop", self)
+ self._action_eip_stop.triggered.connect(
+ self._stop_eip)
+ self._action_eip_write = QtGui.QAction(
+ QtGui.QIcon(":/images/Arrow-Up-32.png"),
+ "0.0 Kb", self)
+ self._action_eip_write.setEnabled(False)
+ self._action_eip_read = QtGui.QAction(
+ QtGui.QIcon(":/images/Arrow-Down-32.png"),
+ "0.0 Kb", self)
+ self._action_eip_read.setEnabled(False)
+
self._action_visible = QtGui.QAction("Hide", self)
self._action_visible.triggered.connect(self._toggle_visible)
@@ -179,10 +204,20 @@ class MainWindow(QtGui.QMainWindow):
systrayMenu.addAction(self.ui.action_quit)
self._systray = QtGui.QSystemTrayIcon(self)
self._systray.setContextMenu(systrayMenu)
- self._systray.setIcon(QtGui.QIcon(self.ERROR_ICON))
+ self._systray.setIcon(QtGui.QIcon(self.LOGGED_OUT_ICON))
self._systray.setVisible(True)
self._systray.activated.connect(self._toggle_visible)
+ vpn_systrayMenu = QtGui.QMenu(self)
+ vpn_systrayMenu.addAction(self._action_eip_status)
+ vpn_systrayMenu.addAction(self._action_eip_stop)
+ vpn_systrayMenu.addAction(self._action_eip_read)
+ vpn_systrayMenu.addAction(self._action_eip_write)
+ self._vpn_systray = QtGui.QSystemTrayIcon(self)
+ self._vpn_systray.setContextMenu(vpn_systrayMenu)
+ self._vpn_systray.setIcon(QtGui.QIcon(self.ERROR_ICON))
+ self._vpn_systray.setVisible(False)
+
def _toggle_visible(self):
"""
SLOT
@@ -455,8 +490,33 @@ class MainWindow(QtGui.QMainWindow):
triggers the eip bootstrapping
"""
self.ui.stackedWidget.setCurrentIndex(self.EIP_STATUS_INDEX)
+ self._systray.setIcon(self.LOGGED_IN_ICON)
self._download_eip_config()
+ def _start_eip(self):
+ self._vpn.start(eipconfig=self._eip_config,
+ providerconfig=self._provider_config,
+ socket_host="/home/chiiph/vpnsock",
+ socket_port="unix")
+ self._vpn_systray.setVisible(True)
+ self.ui.btnEipStartStop.setEnabled(True)
+ self.ui.btnEipStartStop.setText("Stop EIP")
+ self.ui.btnEipStartStop.clicked.disconnect(
+ self._start_eip)
+ self.ui.btnEipStartStop.clicked.connect(
+ self._stop_eip)
+
+ def _stop_eip(self):
+ self._vpn.set_should_quit()
+ self._vpn_systray.setVisible(False)
+ self._set_eip_status("EIP has stopped")
+ self._set_eip_status_icon("error")
+ self.ui.btnEipStartStop.setText("Start EIP")
+ self.ui.btnEipStartStop.clicked.disconnect(
+ self._stop_eip)
+ self.ui.btnEipStartStop.clicked.connect(
+ self._start_eip)
+
def _download_eip_config(self):
"""
Starts the EIP bootstrapping sequence
@@ -483,13 +543,16 @@ class MainWindow(QtGui.QMainWindow):
@type status: str
"""
selected_pixmap = self.ERROR_ICON
+ tray_message = "Encryption is OFF"
if status in ("AUTH", "GET_CONFIG"):
selected_pixmap = self.CONNECTING_ICON
elif status in ("CONNECTED"):
+ tray_message = "Encryption is ON"
selected_pixmap = self.CONNECTED_ICON
self.ui.lblVPNStatusIcon.setPixmap(selected_pixmap)
- self._systray.setIcon(QtGui.QIcon(selected_pixmap))
+ self._vpn_systray.setIcon(QtGui.QIcon(selected_pixmap))
+ self._action_eip_status.setText(tray_message)
def _update_vpn_state(self, data):
"""
@@ -520,12 +583,16 @@ class MainWindow(QtGui.QMainWindow):
"""
upload = float(data[self._vpn.TUNTAP_WRITE_KEY])
upload = upload / 1000.0
- self.ui.lblUpload.setText("%s Kb" % (upload,))
+ upload_str = "%s Kb" % (upload,)
+ self.ui.lblUpload.setText(upload_str)
+ self._action_eip_write.setText(upload_str)
download = float(data[self._vpn.TUNTAP_READ_KEY])
download = download / 1000.0
- self.ui.lblDownload.setText("%s Kb" % (download,))
+ download_str = "%s Kb" % (download,)
+ self.ui.lblDownload.setText(download_str)
+ self._action_eip_read.setText(download_str)
- def _start_eip(self, data):
+ def _finish_eip_bootstrap(self, data):
"""
SLOT
TRIGGER: self._eip_bootstrapper.download_client_certificate
@@ -542,10 +609,7 @@ class MainWindow(QtGui.QMainWindow):
self._provider_config
.get_domain(),
"eip-service.json")):
- self._vpn.start(eipconfig=self._eip_config,
- providerconfig=self._provider_config,
- socket_host="/home/chiiph/vpnsock",
- socket_port="unix")
+ self._start_eip()
# TODO: display a message if the EIP configuration cannot be
# loaded
@@ -569,12 +633,14 @@ class MainWindow(QtGui.QMainWindow):
logging out
"""
self._set_status(message)
+ self._vpn_systray.setIcon(self.LOGGED_OUT_ICON)
self.ui.action_sign_out.setEnabled(False)
self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX)
self.ui.lnPassword.setText("")
self._login_set_enabled(True)
self._set_status("")
self._vpn.set_should_quit()
+ self._vpn_systray.setVisible(False)
def _intermediate_stage(self, data):
"""
@@ -594,6 +660,18 @@ class MainWindow(QtGui.QMainWindow):
self._login_set_enabled(True)
self._set_status(data[self._provider_bootstrapper.ERROR_KEY])
+ def _eip_finished(self, exitCode):
+ """
+ SLOT
+ TRIGGERS:
+ self._vpn.process_finished
+
+ Triggered when the EIP/VPN process finishes to set the UI
+ accordingly
+ """
+ logger.debug("Finished VPN with exitCode %s" % (exitCode,))
+ self._stop_eip()
+
if __name__ == "__main__":
import signal
from functools import partial
diff --git a/src/leap/gui/ui/mainwindow.ui b/src/leap/gui/ui/mainwindow.ui
index a527eaf6..d8a6d37d 100644
--- a/src/leap/gui/ui/mainwindow.ui
+++ b/src/leap/gui/ui/mainwindow.ui
@@ -171,16 +171,6 @@
</widget>
<widget class="QWidget" name="page_2">
<layout class="QGridLayout" name="gridLayout_3">
- <item row="1" column="0" colspan="6">
- <widget class="QLabel" name="lblEIPStatus">
- <property name="text">
- <string>Disconnected</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
<item row="0" column="0" colspan="6">
<widget class="QLabel" name="lblVPNStatusIcon">
<property name="text">
@@ -194,20 +184,7 @@
</property>
</widget>
</item>
- <item row="2" column="0">
- <spacer name="horizontalSpacer_5">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="2">
+ <item row="3" column="2">
<widget class="QLabel" name="lblUpload">
<property name="minimumSize">
<size>
@@ -220,7 +197,7 @@
</property>
</widget>
</item>
- <item row="2" column="4">
+ <item row="3" column="4">
<widget class="QLabel" name="lblDownload">
<property name="minimumSize">
<size>
@@ -233,7 +210,7 @@
</property>
</widget>
</item>
- <item row="2" column="5">
+ <item row="3" column="5">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -246,7 +223,7 @@
</property>
</spacer>
</item>
- <item row="2" column="3">
+ <item row="3" column="3">
<widget class="QLabel" name="label_7">
<property name="text">
<string/>
@@ -256,7 +233,7 @@
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string/>
@@ -266,6 +243,36 @@
</property>
</widget>
</item>
+ <item row="3" column="0">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" colspan="6">
+ <widget class="QLabel" name="lblEIPStatus">
+ <property name="text">
+ <string>Disconnected</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="4">
+ <widget class="QPushButton" name="btnEipStartStop">
+ <property name="text">
+ <string>Start EIP</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</widget>
diff --git a/src/leap/services/eip/vpn.py b/src/leap/services/eip/vpn.py
index 88692442..71944f50 100644
--- a/src/leap/services/eip/vpn.py
+++ b/src/leap/services/eip/vpn.py
@@ -22,7 +22,6 @@ import logging
import sys
from PySide import QtCore, QtGui
-from subprocess import Popen, PIPE
from functools import partial
from leap.config.providerconfig import ProviderConfig
@@ -46,6 +45,8 @@ class VPN(QtCore.QThread):
state_changed = QtCore.Signal(dict)
status_changed = QtCore.Signal(dict)
+ process_finished = QtCore.Signal(int)
+
CONNECTION_RETRY_TIME = 1000
POLL_TIME = 100
@@ -69,7 +70,6 @@ class VPN(QtCore.QThread):
self._launcher = get_platform_launcher()
self._subp = None
- self._started = False
self._tn = None
self._host = None
@@ -100,15 +100,14 @@ class VPN(QtCore.QThread):
return
try:
- self._disconnect()
+ self._send_command("signal SIGTERM")
+ self._tn.close()
self._subp.terminate()
except Exception as e:
logger.debug("Could not terminate process, trying command " +
"signal SIGNINT: %r" % (e,))
- self._send_command("signal SIGINT")
- self._subp.wait()
- self.wait()
- self._started = False
+ finally:
+ self._tn = None
def start(self, eipconfig, providerconfig, socket_host, socket_port):
"""
@@ -128,7 +127,7 @@ class VPN(QtCore.QThread):
leap_assert_type(eipconfig, EIPConfig)
leap_assert(providerconfig, "We need a provider config")
leap_assert_type(providerconfig, ProviderConfig)
- leap_assert(not self._started, "Starting process more than once!")
+ leap_assert(not self.isRunning(), "Starting process more than once!")
logger.debug("Starting VPN...")
@@ -140,8 +139,12 @@ class VPN(QtCore.QThread):
socket_host=socket_host,
socket_port=socket_port)
try:
- self._subp = Popen(command, stdout=PIPE, stderr=PIPE,
- bufsize=1, close_fds=ON_POSIX)
+ self._subp = QtCore.QProcess()
+ self._subp.finished.connect(self.process_finished)
+ self._subp.start(command[:1][0], command[1:])
+ logger.debug("Waiting for started...")
+ self._subp.waitForStarted()
+ logger.debug("Started!")
self._host = socket_host
self._port = socket_port
@@ -296,12 +299,18 @@ class VPN(QtCore.QThread):
logger.debug("Quitting VPN thread")
return
+ if self._subp and self._subp.state() != QtCore.QProcess.Running:
+ QtCore.QThread.msleep(self.CONNECTION_RETRY_TIME)
+
if self._tn is None:
self._connect(self._host, self._port)
QtCore.QThread.msleep(self.CONNECTION_RETRY_TIME)
else:
self._parse_state_and_notify(self._send_command("state"))
self._parse_status_and_notify(self._send_command("status"))
+ output_sofar = self._subp.readAllStandardOutput()
+ if len(output_sofar) > 0:
+ logger.debug(output_sofar)
QtCore.QThread.msleep(self.POLL_TIME)