X-Git-Url: https://code.delx.au/pymsnt/blobdiff_plain/2cff639a5cb807ae8de8ca942054b5c147a93916..cbe38882237ba2dff9191c266ddc04a5e78ebba4:/src/main.py diff --git a/src/main.py b/src/main.py index 598d245..6be4c74 100644 --- a/src/main.py +++ b/src/main.py @@ -6,17 +6,42 @@ reload(sys) sys.setdefaultencoding("utf-8") sys.stdout = codecs.lookup('utf-8')[-1](sys.stdout) +# Find the best reactor +selectWarning = "Unable to install any good reactors (kqueue, epoll, poll).\nWe fell back to using select. You may have scalability problems.\nThis reactor will not support more than 1024 connections at a time." +try: + from twisted.internet import epollreactor as bestreactor +except: + try: + from twisted.internet import kqreactor as bestreactor + except: + try: + from twisted.internet import pollreactor as bestreactor + except: + try: + from twisted.internet import selectreactor as bestreactor + print selectWarning + except: + try: + from twisted.internet import default as bestreactor + print selectWarning + except: + print "Unable to find a reactor.\nExiting..." + sys.exit(1) +bestreactor.install() + + + # Must load config before everything else import config import xmlconfig configFile = "config.xml" configOptions = {} -opts, args = getopt.getopt(sys.argv[1:], "bc:o:dDgtl:h", ["background", "config=", "option=", "debug", "Debug", "garbage", "traceback", "log=", "help"]) +opts, args = getopt.getopt(sys.argv[1:], "bc:o:dDgtlp:h", ["background", "config=", "option=", "debug", "Debug", "garbage", "traceback", "log=", "pid=", "help"]) for o, v in opts: if o in ("-c", "--config"): configFile = v elif o in ("-b", "--background"): - config.daemonise = True + config.background = True elif o in ("-d", "--debug"): config.debugLevel = "2" elif o in ("-D", "--Debug"): @@ -28,6 +53,8 @@ for o, v in opts: config.debugLevel = "1" elif o in ("-l", "--log"): config.debugFile = v + elif o in ("-p", "--pid"): + config.pid = v elif o in ("-o", "--option"): var, setting = v.split("=", 2) configOptions[var] = setting @@ -41,24 +68,26 @@ for o, v in opts: print " -g print garbage collection output" print " -t print debugging only on traceback" print " -l write debugging output to file" + print " -p write process ID to file" print " -o = set config var to setting" sys.exit(0) xmlconfig.reloadConfig(configFile, configOptions) -del sys.modules["twisted.internet.reactor"] -# Choose a reactor -if config.reactor == "epoll": - from twisted.internet import epollreactor - epollreactor.install() -elif config.reactor == "poll": - from twisted.internet import pollreactor - pollreactor.install() -elif config.reactor == "kqueue": - from twisted.internet import kqreactor - kqreactor.install() -elif len(config.reactor) > 0: - print "Unknown reactor: ", config.reactor, ". Using default, select(), reactor." +if config.reactor: + # They picked their own reactor. Lets install it. + del sys.modules["twisted.internet.reactor"] + if config.reactor == "epoll": + from twisted.internet import epollreactor + epollreactor.install() + elif config.reactor == "poll": + from twisted.internet import pollreactor + pollreactor.install() + elif config.reactor == "kqueue": + from twisted.internet import kqreactor + kqreactor.install() + elif len(config.reactor) > 0: + print "Unknown reactor: ", config.reactor, ". Using select(), reactor." from twisted.internet import reactor, task @@ -67,6 +96,7 @@ from tlib.xmlw import Element, jid, component from debug import LogEvent, INFO, WARN, ERROR import debug +import svninfo import utils import xdb import avatar @@ -85,13 +115,18 @@ import housekeep class PyTransport(component.Service): def __init__(self): LogEvent(INFO) + try: + LogEvent(INFO, msg="SVN r" + svninfo.getSVNVersion()) + except: + pass # Discovery, as well as some builtin features self.discovery = disco.ServerDiscovery(self) - self.discovery.addIdentity("gateway", legacy.id, legacy.name, config.jid) - self.discovery.addIdentity("conference", "text", legacy.name + " Chatrooms", config.jid) + self.discovery.addIdentity("gateway", legacy.id, config.discoName, config.jid) + self.discovery.addIdentity("conference", "text", config.discoName + " Chatrooms", config.jid) self.discovery.addFeature(disco.XCONFERENCE, None, config.jid) # So that clients know you can create groupchat rooms on the server self.discovery.addFeature("jabber:iq:conference", None, config.jid) # We don't actually support this, but Psi has a bug where it looks for this instead of the above + self.discovery.addIdentity("client", "pc", "MSN Messenger", "USER") self.xdb = xdb.XDB(config.jid, legacy.mangle) self.avatarCache = avatar.AvatarCache() @@ -122,8 +157,8 @@ class PyTransport(component.Service): # Message IDs self.messageID = 0 - self.loopCall = task.LoopingCall(self.loopCall) - self.loopCall.start(60.0) + self.loopTask = task.LoopingCall(self.loopFunc) + self.loopTask.start(60.0) def removeMe(self): LogEvent(INFO) @@ -146,7 +181,7 @@ class PyTransport(component.Service): def reserveID(self, ID): self.reservedIDs.append(ID) - def loopCall(self): + def loopFunc(self): numsessions = len(self.sessions) #if config.debugOn and numsessions > 0: @@ -161,12 +196,12 @@ class PyTransport(component.Service): oldDict = self.sessions.copy() self.sessions = {} for key in oldDict: - session = oldDict[key] - if not session.alive: + s = oldDict[key] + if not s.alive: LogEvent(WARN, "", "Ghost session found.") # Don't add it to the new dictionary. Effectively removing it else: - self.sessions[key] = session + self.sessions[key] = s def componentConnected(self, xmlstream): LogEvent(INFO) @@ -210,8 +245,12 @@ class PyTransport(component.Service): LogEvent(WARN, "", "Failed stringprep.") return mtype = el.getAttribute("type") - if self.sessions.has_key(froj.userhost()): - self.sessions[froj.userhost()].onMessage(el) + s = self.sessions.get(froj.userhost(), None) + if mtype == "error" and s: + LogEvent(INFO, s.jabberID, "Removing session because of message type=error") + s.removeMe() + elif s: + s.onMessage(el) elif mtype != "error": to = el.getAttribute("to") ulang = utils.getLang(el) @@ -232,8 +271,13 @@ class PyTransport(component.Service): LogEvent(WARN, "", "Failed stringprep.") return - if self.sessions.has_key(froj.userhost()): - self.sessions[froj.userhost()].onPresence(el) + ptype = el.getAttribute("type") + s = self.sessions.get(froj.userhost()) + if ptype == "error" and s: + LogEvent(INFO, s.jabberID, "Removing session because of message type=error") + s.removeMe() + elif s: + s.onPresence(el) else: ulang = utils.getLang(el) ptype = el.getAttribute("type") @@ -278,15 +322,17 @@ class PyTransport(component.Service): class App: def __init__(self): # Check for any other instances + if config.pid and os.name != "posix": + config.pid = "" if config.pid: - self.checkPID() + twistd.checkPID(config.pid) # Do any auto-update stuff housekeep.init() # Daemonise the process and write the PID file - if config.background: - self.daemonise() + if config.background and os.name == "posix": + twistd.daemonize() if config.pid: self.writePID() @@ -304,21 +350,6 @@ class App: self.c.startService() reactor.addSystemEventTrigger('before', 'shutdown', self.shuttingDown) - def checkPID(self): - # Check that we're not already running - if os.path.isfile(config.pid): - if os.name == "posix": - pf = open(config.pid) - pid = int(str(pf.readline().strip())) - pf.close() - try: - os.kill(pid, signal.SIGHUP) - self.alreadyRunning() - except OSError: - pass - else: - self.alreadyRunning() - def writePID(self): # Create a PID file pid = str(os.getpid()) @@ -326,25 +357,12 @@ class App: pf.write("%s\n" % pid) pf.close() - def alreadyRunning(self): - sys.__stdout__.write("There is already a transport instance running with this configuration.\nExiting...\n\n") - sys.exit(1) - - def daemonise(self): - try: - pid = os.fork() - if pid > 0: - sys.exit(0) - except OSError, e: - sys.stderr.write("Daemonise failed: (%d) %s\n" % (e.errno, e.strerror)) - sys.exit(1) - def shuttingDown(self): self.transportSvc.removeMe() # Keep the transport running for another 3 seconds def cb(ignored=None): if config.pid: - os.remove(config.pid) + twistd.removePID(config.pid) d = Deferred() d.addCallback(cb) reactor.callLater(3.0, d.callback, None) @@ -355,6 +373,8 @@ class App: def SIGHUPstuff(*args): global configFile, configOptions xmlconfig.reloadConfig(configFile, configOptions) + if config.pid and os.name != "posix": + config.pid = "" debug.reloadConfig() legacy.reloadConfig() @@ -362,6 +382,8 @@ if os.name == "posix": import signal # Set SIGHUP to reload the config file & close & open debug file signal.signal(signal.SIGHUP, SIGHUPstuff) + # Load some scripts for PID and daemonising + from twisted.scripts import twistd def main():