From 2e645039c2ea7a7e0684e46799db2a901a5d3cae Mon Sep 17 00:00:00 2001 From: Arturo FilastoĢ€ Date: Tue, 23 Aug 2011 01:33:13 +0200 Subject: Fix #3790 Add a daemon class and make tor web ui run as such. --- packages/torouter-web/src/daemon.py | 129 ++++++++++++++++++++++++++++++++++++ packages/torouter-web/src/runui.py | 63 ++++++++++++------ 2 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 packages/torouter-web/src/daemon.py diff --git a/packages/torouter-web/src/daemon.py b/packages/torouter-web/src/daemon.py new file mode 100644 index 0000000..4ccc15c --- /dev/null +++ b/packages/torouter-web/src/daemon.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +import sys, os, time, atexit +from signal import SIGTERM + +class Daemon: + """ + A generic daemon class. + + Usage: subclass the Daemon class and override the run() method + """ + def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): + self.stdin = stdin + self.stdout = stdout + self.stderr = stderr + self.pidfile = pidfile + + def daemonize(self): + """ + do the UNIX double-fork magic, see Stevens' "Advanced + Programming in the UNIX Environment" for details (ISBN 0201563177) + http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + """ + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # decouple from parent environment + #os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file(self.stdin, 'r') + so = file(self.stdout, 'a+') + se = file(self.stderr, 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + # write pidfile + atexit.register(self.delpid) + pid = str(os.getpid()) + file(self.pidfile,'w+').write("%s\n" % pid) + + def delpid(self): + os.remove(self.pidfile) + + def start(self): + """ + Start the daemon + """ + # Check for a pidfile to see if the daemon already runs + try: + pf = file(self.pidfile,'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid: + message = "pidfile %s already exist. Daemon already running?\n" + sys.stderr.write(message % self.pidfile) + sys.exit(1) + + # Start the daemon + self.daemonize() + self.run() + + def stop(self): + """ + Stop the daemon + """ + # Get the pid from the pidfile + try: + pf = file(self.pidfile,'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if not pid: + message = "pidfile %s does not exist. Daemon not running?\n" + sys.stderr.write(message % self.pidfile) + return # not an error in a restart + + # Try killing the daemon process + try: + while 1: + os.kill(pid, SIGTERM) + time.sleep(0.1) + except OSError, err: + err = str(err) + if err.find("No such process") > 0: + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + else: + print str(err) + sys.exit(1) + + def restart(self): + """ + Restart the daemon + """ + self.stop() + self.start() + + def run(self): + """ + You should override this method when you subclass Daemon. It will be called after the process has been + daemonized by start() or restart(). + """ diff --git a/packages/torouter-web/src/runui.py b/packages/torouter-web/src/runui.py index d5c7c9e..488c483 100644 --- a/packages/torouter-web/src/runui.py +++ b/packages/torouter-web/src/runui.py @@ -3,6 +3,8 @@ # by Arturo Filasto' # +import sys, time, os +from daemon import Daemon import web from tui import config import tui.controllers @@ -10,27 +12,50 @@ import tui.controllers from tui.utils import session from tui.view import render - # This is the main structure of URLs urls = ( - '/', 'tui.controllers.main.index', -# '/config/(tor|router)', 'tui.controllers.main.config', - '/network', 'tui.controllers.network.main', - '/network/firewall', 'tui.controllers.network.firewall', - '/network/wireless', 'tui.controllers.network.wireless', - '/network/wired', 'tui.controllers.network.wired', - '/network/status', 'tui.controllers.network.status', - '/tor', 'tui.controllers.tor.status', - '/tor/config', 'tui.controllers.tor.torrc', - '/logout', 'tui.controllers.main.logout' - ) -# '/wizard/([0-9a-f]{1,2})?', 'tui.controllers.wizard.step', -# '/status', 'tui.controllers.status') + '/', 'tui.controllers.main.index', +# '/config/(tor|router)', 'tui.controllers.main.config', + '/network', 'tui.controllers.network.main', + '/network/firewall', 'tui.controllers.network.firewall', + '/network/wireless', 'tui.controllers.network.wireless', + '/network/wired', 'tui.controllers.network.wired', + '/network/status', 'tui.controllers.network.status', + '/tor', 'tui.controllers.tor.status', + '/tor/config', 'tui.controllers.tor.torrc', + '/logout', 'tui.controllers.main.logout' + ) +# '/wizard/([0-9a-f]{1,2})?', 'tui.controllers.wizard.step', +# '/status', 'tui.controllers.status') + +app = web.application(urls, globals()) +# add session management to the app +session.add_session_to_app(app) +app.internalerror = web.debugerror +class TorWebDaemon(Daemon): + def run(self): + app.run() + +DEBUG = False if __name__ == "__main__": - app = web.application(urls, globals()) - # Add session management to the app - session.add_session_to_app(app) - app.internalerror = web.debugerror - app.run() + if DEBUG: + app.run() + service = TorWebDaemon(os.path.join(os.getcwd(),'tui.pid')) + if len(sys.argv) == 2: + if 'start' == sys.argv[1]: + sys.argv[1] = '8080' + service.start() + elif 'stop' == sys.argv[1]: + service.stop() + elif 'restart' == sys.argv[1]: + service.restart() + else: + print "Unknown command" + sys.exit(2) + sys.exit(0) + else: + print "usage: %s start|stop|restart" % sys.argv[0] + sys.exit(2) + -- cgit v1.2.3