From b314c73432da0797fc00e7a6d270b783929d4c08 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 23 Aug 2017 00:34:22 -0400 Subject: [refactor] re-add retries for connecting to management --- src/leap/bitmask/vpn/process.py | 29 +++++++++++++++++++++-------- src/leap/bitmask/vpn/tunnel.py | 25 ++++++++++++++++--------- tests/e2e/TODO | 4 ++++ 3 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 tests/e2e/TODO diff --git a/src/leap/bitmask/vpn/process.py b/src/leap/bitmask/vpn/process.py index 48d3f1ad..4ef9fd98 100644 --- a/src/leap/bitmask/vpn/process.py +++ b/src/leap/bitmask/vpn/process.py @@ -89,6 +89,7 @@ class _VPNProcess(protocol.ProcessProtocol): self._restartfun = restartfun self.restarting = True + self.failed = False self.proto = None self._remotes = remotes @@ -106,18 +107,28 @@ class _VPNProcess(protocol.ProcessProtocol): except Exception as exc: print('[!] Error: %s' % exc) - def _connect_to_management(self): - # TODO -- add retries, twisted style, to this. - # this sometimes raises 'file not found' error + def _connect_to_management(self, retries=30): + if retries == 0: + self.log.error('Timeout whilte connecting to management') + self.failed = True + return + + def retry(retries): + ctr = retries - 1 + self.log.warn( + 'Error connecting to management, retrying. Retries left: %s' % ctr) + reactor.callLater( + 0.1, self._connect_to_management, ctr) + self._d = connectProtocol( self._management_endpoint, ManagementProtocol(verbose=True)) - self._d.addCallback(self._got_management_protocol) - self._d.addErrback(self.log.error) + self._d.addCallbacks( + self._got_management_protocol, + lambda f: retry(retries)) def connectionMade(self): - # TODO cut this wait time when retries are done - reactor.callLater(0.5, self._connect_to_management) + reactor.callLater(0.1, self._connect_to_management) def processExited(self, failure): err = failure.trap( @@ -143,7 +154,9 @@ class _VPNProcess(protocol.ProcessProtocol): Called when the child process exits and all file descriptors associated with it have been closed. """ + self.proto = None exit_code = reason.value.exitCode + if isinstance(exit_code, int): self.log.debug('processEnded, status %d' % (exit_code,)) if self.restarting: @@ -174,6 +187,7 @@ class _VPNProcess(protocol.ProcessProtocol): if not self.proto: status = {'status': 'off', 'error': None} return status + status = {'status': self.proto.state.simple.lower(), 'error': None} if self.proto.traffic: @@ -230,7 +244,6 @@ class _VPNProcess(protocol.ProcessProtocol): self.log.debug('Process Exited Already') def terminate_or_kill(self): - # XXX this returns a deferred return self._launcher.terminate_or_kill( self.terminate, self.kill, self) diff --git a/src/leap/bitmask/vpn/tunnel.py b/src/leap/bitmask/vpn/tunnel.py index d05a50e2..d9a8be3d 100644 --- a/src/leap/bitmask/vpn/tunnel.py +++ b/src/leap/bitmask/vpn/tunnel.py @@ -76,11 +76,15 @@ class ConfiguredTunnel(object): self._port = port self._vpnproc = None + @defer.inlineCallbacks def start(self): - return self._start_vpn() + started = yield self._start_vpn() + defer.returnValue(started) + @defer.inlineCallbacks def stop(self): - return self._stop_vpn(restart=False) + stopped = yield self._stop_vpn(restart=False) + defer.returnValue(stopped) # status @@ -96,6 +100,7 @@ class ConfiguredTunnel(object): # VPN Control + @defer.inlineCallbacks def _start_vpn(self): self.log.debug('VPN: start') args = [self._vpnconfig, self._providerconfig, self._host, @@ -105,15 +110,15 @@ class ConfiguredTunnel(object): vpnproc = VPNProcess(*args, **kwargs) self._vpnproc = vpnproc - self._start_pre_up(vpnproc) + self.__start_pre_up(vpnproc) cmd = self.__start_get_cmd(vpnproc) - # XXX this should be a deferred - running = self.__start_spawn_proc(vpnproc, cmd) + + running = yield self.__start_spawn_proc(vpnproc, cmd) if running: vpnproc.pid = running.pid - return True + defer.returnValue(True) else: - return False + defer.returnValue(False) def __start_pre_up(self, proc): try: @@ -147,6 +152,7 @@ class ConfiguredTunnel(object): reactor.callLater( self.RESTART_WAIT, self.start) + @defer.inlineCallbacks def _stop_vpn(self, restart=False): """ Stops the openvpn subprocess. @@ -162,11 +168,12 @@ class ConfiguredTunnel(object): if self._vpnproc is None: self.log.debug('Tried to stop VPN but no process found') - return + defer.returnValue(False) self._vpnproc.restarting = restart self.__stop_pre_down(self._vpnproc) - self._vpnproc.terminate_or_kill() + stopped = yield self._vpnproc.terminate_or_kill() + defer.returnValue(stopped) def __stop_pre_down(self, proc): try: diff --git a/tests/e2e/TODO b/tests/e2e/TODO new file mode 100644 index 00000000..5cec6267 --- /dev/null +++ b/tests/e2e/TODO @@ -0,0 +1,4 @@ +VPN +--------- +[ ] status when killed (fail-close) +[ ] kill previously running vpn when launching one -- cgit v1.2.3