From df160c0d44e8d0439d54313f097b2a4d9ada7357 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 24 Jul 2014 12:54:12 -0300 Subject: Allow frontend and backend to be run separately. Add the 'check_online' method to check whether the backend is accessible or not. Reduce the wait for running threads timeout on quit. Add retry feature to the backend requests send. --- src/leap/bitmask/app.py | 31 +++++++++++++++++++++---------- src/leap/bitmask/backend/backend.py | 2 +- src/leap/bitmask/backend/backend_proxy.py | 30 ++++++++++++++++++++++++++++-- src/leap/bitmask/backend/signaler.py | 1 + src/leap/bitmask/backend_app.py | 13 +++++++++++-- src/leap/bitmask/frontend_app.py | 2 +- src/leap/bitmask/gui/app.py | 1 + 7 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 87f22d88..ef156671 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -44,6 +44,7 @@ import os import sys +from leap.bitmask.backend.backend_proxy import BackendProxy from leap.bitmask.backend.utils import generate_certificates from leap.bitmask import __version__ as VERSION @@ -178,19 +179,29 @@ def start_app(): logger.info('Starting app') - generate_certificates() + backend = BackendProxy() + backend_running = backend.check_online() - flags_dict = flags_to_dict() + logger.debug("Backend online: {0}".format(backend_running)) + + if not backend_running: + generate_certificates() - frontend_pid = os.getpid() - backend = lambda: run_backend(opts.danger, flags_dict, frontend_pid) - backend_process = multiprocessing.Process(target=backend, name='Backend') - # we don't set the 'daemon mode' since we need to start child processes in - # the backend - # backend_process.daemon = True - backend_process.start() + flags_dict = flags_to_dict() - run_frontend(options, flags_dict, backend_pid=backend_process.pid) + backend_pid = None + if not backend_running: + frontend_pid = os.getpid() + backend = lambda: run_backend(opts.danger, flags_dict, frontend_pid) + backend_process = multiprocessing.Process(target=backend, + name='Backend') + # we don't set the 'daemon mode' since we need to start child processes + # in the backend + # backend_process.daemon = True + backend_process.start() + backend_pid = backend_process.pid + + run_frontend(options, flags_dict, backend_pid=backend_pid) if __name__ == "__main__": diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py index 37535f37..75eff8a9 100644 --- a/src/leap/bitmask/backend/backend.py +++ b/src/leap/bitmask/backend/backend.py @@ -135,7 +135,7 @@ class Backend(object): i.e.: use threads.deferToThread(this_method) instead of this_method() """ - wait_max = 5 # seconds + wait_max = 3 # seconds wait_step = 0.5 wait = 0 while self._ongoing_defers and wait < wait_max: diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py index e2611251..9de3501e 100644 --- a/src/leap/bitmask/backend/backend_proxy.py +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -67,6 +67,7 @@ class BackendProxy(object): socket.curve_serverkey = public socket.setsockopt(zmq.RCVTIMEO, 1000) + socket.setsockopt(zmq.LINGER, 0) # Terminate early socket.connect(self.SERVER) self._socket = socket @@ -75,8 +76,23 @@ class BackendProxy(object): self._call_queue = Queue.Queue() self._worker_caller = threading.Thread(target=self._worker) + + def start(self): self._worker_caller.start() + def check_online(self): + """ + Return whether the backend is accessible or not. + You don't need to do `run` in order to use this. + + :rtype: bool + """ + # we use a small timeout in order to response quickly if the backend is + # offline + self._send_request(PING_REQUEST, retry=False, timeout=500) + self._socket.close() + return self.online + def _worker(self): """ Worker loop that processes the Queue of pending requests to do. @@ -150,7 +166,7 @@ class BackendProxy(object): if api_method == STOP_REQUEST: self._call_queue.put(STOP_REQUEST) - def _send_request(self, request): + def _send_request(self, request, retry=True, timeout=None): """ Send the given request to the server. This is used from a thread safe loop in order to avoid sending a @@ -158,6 +174,10 @@ class BackendProxy(object): :param request: the request to send. :type request: str + :param retry: whether we should retry or not in case of timeout. + :type retry: bool + :param timeout: a custom timeout (milliseconds) to wait for a response. + :type timeout: int """ # logger.debug("Sending request to backend: {0}".format(request)) self._socket.send(request) @@ -166,10 +186,16 @@ class BackendProxy(object): poll.register(self._socket, zmq.POLLIN) reply = None + tries = 0 + if not retry: + tries = self.POLL_TRIES + 1 # this means: no retries left + + if timeout is None: + timeout = self.POLL_TIMEOUT while True: - socks = dict(poll.poll(self.POLL_TIMEOUT)) + socks = dict(poll.poll(timeout)) if socks.get(self._socket) == zmq.POLLIN: reply = self._socket.recv() break diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py index 574bfa71..43cba994 100644 --- a/src/leap/bitmask/backend/signaler.py +++ b/src/leap/bitmask/backend/signaler.py @@ -60,6 +60,7 @@ class Signaler(object): socket.curve_serverkey = public socket.setsockopt(zmq.RCVTIMEO, 1000) + socket.setsockopt(zmq.LINGER, 0) # Terminate early socket.connect(self.SERVER) self._socket = socket diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py index 716ae4a7..ce75dc80 100644 --- a/src/leap/bitmask/backend_app.py +++ b/src/leap/bitmask/backend_app.py @@ -22,6 +22,8 @@ import multiprocessing import signal from leap.bitmask.backend.leapbackend import LeapBackend +from leap.bitmask.backend.utils import generate_certificates +from leap.bitmask.logs.utils import create_logger from leap.bitmask.util import dict_to_flags logger = logging.getLogger(__name__) @@ -44,7 +46,7 @@ def signal_handler(signum, frame): logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum)) -def run_backend(bypass_checks, flags_dict, frontend_pid=None): +def run_backend(bypass_checks=False, flags_dict=None, frontend_pid=None): """ Run the backend for the application. @@ -57,8 +59,15 @@ def run_backend(bypass_checks, flags_dict, frontend_pid=None): signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal_handler) - dict_to_flags(flags_dict) + if flags_dict is not None: + dict_to_flags(flags_dict) backend = LeapBackend(bypass_checks=bypass_checks, frontend_pid=frontend_pid) backend.run() + + +if __name__ == '__main__': + logger = create_logger(debug=True) + generate_certificates() + run_backend() diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 909005f0..b0a149f9 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -54,7 +54,7 @@ def signal_handler(window, pid, signum, frame): window.quit() -def run_frontend(options, flags_dict, backend_pid): +def run_frontend(options, flags_dict, backend_pid=None): """ Run the GUI for the application. diff --git a/src/leap/bitmask/gui/app.py b/src/leap/bitmask/gui/app.py index eb1a58d5..75dc4a38 100644 --- a/src/leap/bitmask/gui/app.py +++ b/src/leap/bitmask/gui/app.py @@ -41,6 +41,7 @@ class App(QtGui.QWidget): self.settings = LeapSettings() self.backend = BackendProxy() + self.backend.start() self.signaler = LeapSignaler() self.signaler.start() -- cgit v1.2.3