diff options
Diffstat (limited to 'src/leap/bitmask/vpn/_control.py')
-rw-r--r-- | src/leap/bitmask/vpn/_control.py | 185 |
1 files changed, 0 insertions, 185 deletions
diff --git a/src/leap/bitmask/vpn/_control.py b/src/leap/bitmask/vpn/_control.py deleted file mode 100644 index ff39db8d..00000000 --- a/src/leap/bitmask/vpn/_control.py +++ /dev/null @@ -1,185 +0,0 @@ -import os - -from twisted.internet import reactor, defer -from twisted.logger import Logger - -from .process import VPNProcess -from .constants import IS_LINUX - - -# TODO -# TODO merge these classes with service. -# [ ] register change state listener -# emit_async(catalog.VPN_STATUS_CHANGED) -# [ ] catch ping-restart -# 'NETWORK_UNREACHABLE': ( -# 'Network is unreachable (code=101)',), -# 'PROCESS_RESTART_TLS': ( -# "SIGTERM[soft,tls-error]",), - - -class VPNControl(object): - - """ - This is the high-level object that the service knows about. - It exposes the start and terminate methods. - - On start, it spawns a VPNProcess instance that will use a vpnlauncher - suited for the running platform and connect to the management interface - opened by the openvpn process, executing commands over that interface on - demand. - """ - - TERMINATE_MAXTRIES = 10 - TERMINATE_WAIT = 1 # secs - RESTART_WAIT = 2 # secs - - log = Logger() - - def __init__(self, remotes, vpnconfig, - providerconfig, socket_host, socket_port): - self._vpnproc = None - self._user_stopped = False - - self._remotes = remotes - self._vpnconfig = vpnconfig - self._providerconfig = providerconfig - self._host = socket_host - self._port = socket_port - - def start(self): - self.log.debug('VPN: start') - - self._user_stopped = False - - args = [self._vpnconfig, self._providerconfig, self._host, - self._port] - kwargs = {'openvpn_verb': 4, 'remotes': self._remotes, - 'restartfun': self.restart} - - vpnproc = VPNProcess(*args, **kwargs) - - # TODO -- restore - # if get_openvpn_process(): - # self.log.info( - # 'Another vpn process is running. Will try to stop it.') - # vpnproc.stop_if_already_running() - - try: - vpnproc.preUp() - except Exception as e: - self.log.error('Error on vpn pre-up {0!r}'.format(e)) - raise - try: - cmd = vpnproc.getCommand() - except Exception as e: - self.log.error( - 'Error while getting vpn command... {0!r}'.format(e)) - raise - - env = os.environ - - try: - runningproc = reactor.spawnProcess(vpnproc, cmd[0], cmd, env) - except Exception as e: - self.log.error( - 'Error while spawning vpn process... {0!r}'.format(e)) - return False - - # TODO get pid from management instead - vpnproc.pid = runningproc.pid - self._vpnproc = vpnproc - - return True - - @defer.inlineCallbacks - def restart(self): - yield self.stop(shutdown=False, restart=True) - reactor.callLater( - self.RESTART_WAIT, self.start) - - def stop(self, shutdown=False, restart=False): - """ - Stops the openvpn subprocess. - - Attempts to send a SIGTERM first, and after a timeout - it sends a SIGKILL. - - :param shutdown: whether this is the final shutdown - :type shutdown: bool - :param restart: whether this stop is part of a hard restart. - :type restart: bool - """ - # We assume that the only valid stops are initiated - # by an user action, not hard restarts - self._user_stopped = not restart - if self._vpnproc is not None: - self._vpnproc.restarting = restart - - try: - if self._vpnproc is not None: - self._vpnproc.preDown() - except Exception as e: - self.log.error('Error on vpn pre-down {0!r}'.format(e)) - raise - - d = defer.succeed(True) - if IS_LINUX: - # TODO factor this out to a linux-only launcher mechanism. - # First we try to be polite and send a SIGTERM... - if self._vpnproc is not None: - self._sentterm = True - self._vpnproc.terminate() - - # we trigger a countdown to be unpolite - # if strictly needed. - d = defer.Deferred() - reactor.callLater( - self.TERMINATE_WAIT, self._kill_if_left_alive, d) - return d - - # TODO -- remove indirection - @property - def status(self): - if not self._vpnproc: - return {'status': 'off', 'error': None} - return self._vpnproc.status - - @property - def traffic_status(self): - return self._vpnproc.traffic_status - - def _killit(self): - if self._vpnproc is None: - self.log.debug("There's no vpn process running to kill.") - else: - self._vpnproc.aborted = True - self._vpnproc.kill() - - def _kill_if_left_alive(self, deferred, tries=0): - """ - Check if the process is still alive, and send a - SIGKILL after a timeout period. - - :param tries: counter of tries, used in recursion - :type tries: int - """ - if tries < self.TERMINATE_MAXTRIES: - if self._vpnproc.transport.pid is None: - deferred.callback(True) - return - else: - self.log.debug('Process did not die, waiting...') - - tries += 1 - reactor.callLater(self.TERMINATE_WAIT, - self._kill_if_left_alive, deferred, tries) - return - - # after running out of patience, we try a killProcess - self.log.debug('Process did not die. Sending a SIGKILL.') - try: - self._killit() - except OSError: - self.log.error('Could not kill process!') - deferred.callback(True) |