Changeset 14

Show
Ignore:
Timestamp:
02/01/04 19:07:42 (5 years ago)
Author:
jajcus
Message:

- error handling improvements (still a lot to do here)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/jjigw.py

    r13 r14  
    1111import string 
    1212import random 
     13import signal 
    1314 
    1415from pyxmpp import ClientStream,JID,Iq,Presence,Message,StreamError 
     
    348349            pass 
    349350 
    350     def irc_cmd_324(self,prefix,command,params): 
     351    def irc_cmd_324(self,prefix,command,params): # RPL_CHANNELMODEIS 
    351352        for m in self.toggle_modes: 
    352353            try: 
     
    496497        self.nick=nick 
    497498        self.thread=threading.Thread(name=u"%s on %s as %s" % (jid,config.network.jid,nick), 
    498                 target=self.thread_loop) 
    499         self.exit=0 
     499                target=self.thread_run) 
     500        self.thread.setDaemon(1) 
     501        self.exit=None 
     502        self.exited=0 
    500503        self.socket=None 
    501504        self.lock=threading.RLock() 
    502505        self.cond=threading.Condition(self.lock) 
    503506        self.servers_left=self.network.get_servers() 
    504         self.thread.setDaemon(1) 
    505         self.thread.start() 
    506507        self.input_buffer="" 
    507508        self.used_for=[] 
    508509        self.server="" 
     510        self.join_requests=[] 
     511        self.messages_to_channel=[] 
     512        self.messages_to_user=[] 
    509513        self.ready=0 
    510514        self.channels={} 
    511515        self.users={} 
    512516        self.user=IRCUser(self,nick) 
     517        self.thread.start() 
    513518 
    514519    def register_user(self,user): 
     
    562567 
    563568    def thread_run(self): 
     569        clean_exit=1 
    564570        try: 
    565571            self.thread_loop() 
    566572        except: 
     573            clean_exit=0 
    567574            self.print_exception() 
    568575        self.lock.acquire() 
    569576        try: 
     577            if not self.exited and self.socket: 
     578                if clean_exit and self.component.shutdown: 
     579                    self._send("QUIT :JJIGW shutdown") 
     580                elif clean_exit and self.exit: 
     581                    self._send("QUIT :%s" % (self.exit.encode(self.default_encoding,"replace"))) 
     582                else: 
     583                    self._send("QUIT :Internal JJIGW error") 
     584                self.exited=1 
    570585            if self.socket: 
    571586                try: 
     
    580595        finally: 
    581596            self.lock.release() 
     597        for j in self.used_for: 
     598            p=Presence(fr=j,to=self.jid,type="unavailable") 
     599            self.component.send(p) 
     600        self.used_for=[] 
    582601     
    583602    def thread_loop(self): 
    584603        self.debug("thread_loop()") 
    585         while not self.exit
     604        while not self.exit and not self.component.shutdown
    586605            self.lock.acquire() 
    587606            try: 
     
    598617                    while self.input_buffer.find("\r\n")>-1: 
    599618                        input,self.input_buffer=self.input_buffer.split("\r\n",1) 
    600                         self._process_input(input) 
     619                        self._safe_process_input(input) 
    601620            finally: 
    602621                self.lock.release() 
     
    612631        if not self.servers_left: 
    613632            self.debug("No servers left, quitting") 
    614             self.exit=1 
     633            self.exit="No servers left, quitting" 
    615634            return 
    616635        if self.socket: 
     
    635654        self._send("USER %s 0 * :JJIGW User %s" % (user,user)) 
    636655        self.server=server[0] 
    637         self.ready=1 
    638656        self.cond.notify() 
    639657 
    640658    def _send(self,str): 
    641         self.debug("IRC OUT: %r" % (str,)) 
    642         self.socket.send(str+"\r\n") 
     659        if self.socket and not self.exited: 
     660            self.debug("IRC OUT: %r" % (str,)) 
     661            self.socket.send(str+"\r\n") 
     662        else: 
     663            self.debug("ignoring out: %r" % (str,)) 
    643664 
    644665    def send(self,str): 
     
    649670            self.lock.release() 
    650671 
     672    def _safe_process_input(self,input): 
     673        try: 
     674            self._process_input(input) 
     675        except: 
     676            self.print_exception() 
     677     
    651678    def _process_input(self,input): 
    652679        self.debug("Server message: %r" % (input,)) 
     
    724751        m=Message(type=typ,fr=fr,to=self.jid,body=remove_evil_characters(strip_colors(body))) 
    725752        self.component.send(m) 
     753 
     754    def login_error(self,join_condition,message_condition): 
     755        self.lock.acquire() 
     756        try: 
     757            if join_condition: 
     758                for s in self.join_requests: 
     759                    p=s.make_error_response(join_condition) 
     760                    self.component.send(p) 
     761                    try: 
     762                        self.used_for.remove(s.get_to()) 
     763                    except ValueError: 
     764                        pass 
     765                self.join_requests=[] 
     766            if message_condition: 
     767                for s in self.messages_to_user+self.messages_to_channel: 
     768                    p=s.make_error_response(message_condition) 
     769                    self.component.send(p) 
     770                self.messages_to_user=[] 
     771                self.messages_to_channel=[] 
     772            self.exit="IRC user registration failed" 
     773        finally: 
     774            self.lock.release() 
     775 
     776    def irc_cmd_001(self,prefix,command,params): # RPL_WELCOME 
     777        self.lock.acquire() 
     778        try: 
     779            self.debug("Connected successfully") 
     780            self.ready=1 
     781            for s in self.join_requests: 
     782                self.join(s) 
     783            for s in self.messages_to_user: 
     784                self.message_to_user(s) 
     785            for s in self.messages_to_channel: 
     786                self.message_to_channel(s) 
     787        finally: 
     788            self.lock.release() 
     789 
     790    def irc_cmd_431(self,prefix,command,params): # ERR_NONICKNAMEGIVEN 
     791        if self.ready: 
     792            return 
     793        self.login_error("undefined-condition","not-authorized") 
     794  
     795    def irc_cmd_432(self,prefix,command,params): # ERR_ERRONEUSNICKNAME 
     796        if self.ready: 
     797            return 
     798        self.login_error("bad-request","not-authorized") 
     799  
     800    def irc_cmd_433(self,prefix,command,params): # ERR_NICKNAMEINUSE 
     801        if self.ready: 
     802            return 
     803        self.login_error("conflict","not-authorized") 
     804  
     805    def irc_cmd_436(self,prefix,command,params): # ERR_NICKCOLLISION 
     806        if self.ready: 
     807            return 
     808        self.login_error("conflict","not-authorized") 
     809  
     810    def irc_cmd_437(self,prefix,command,params): # ERR_UNAVAILRESOURCE 
     811        if self.ready: 
     812            return 
     813        self.login_error("resource-constraint","not-authorized") 
     814  
     815    def irc_cmd_437(self,prefix,command,params): # ERR_RESTRICTED 
     816        if self.ready: 
     817            return 
     818        pass 
    726819  
    727820    def irc_cmd_QUIT(self,prefix,command,params): 
     
    730823        self.unregister_user(user) 
    731824 
    732     def irc_cmd_352(self,prefix,command,params): 
     825    def irc_cmd_352(self,prefix,command,params): # RPL_WHOREPLY 
    733826        self.debug("WHO reply received") 
    734827        if len(params)<7: 
     
    766859 
    767860    def join(self,stanza): 
     861        self.cond.acquire() 
     862        try: 
     863            if not self.ready: 
     864                self.join_requests.append(stanza) 
     865                return 
     866        finally: 
     867            self.cond.release() 
    768868        to=stanza.get_to() 
    769869        channel=node_to_channel(to.node,self.default_encoding) 
    770870        if self.channels.has_key(normalize(channel)): 
    771871            return 
    772         self.cond.acquire() 
    773         try: 
    774             # FIXME: may hang the main thread 
    775             while not self.ready and not self.exit: 
    776                 self.cond.wait() 
    777         finally: 
    778             self.cond.release() 
    779         if self.exit: 
    780             return 
    781872        channel=Channel(self,channel) 
    782873        channel.join(stanza) 
     
    784875 
    785876    def message_to_channel(self,stanza): 
    786         if not self.ready: 
    787             return 
     877        self.cond.acquire() 
     878        try: 
     879            if not self.ready: 
     880                self.messages_to_channel.append(stanza) 
     881                return 
     882        finally: 
     883            self.cond.release() 
    788884        channel=stanza.get_to().node 
    789885        channel=node_to_channel(channel,self.default_encoding) 
     
    801897 
    802898    def message_to_user(self,stanza): 
    803         if not self.ready: 
    804             return 
     899        self.cond.acquire() 
     900        try: 
     901            if not self.ready: 
     902                self.messages_to_user.append(stanza) 
     903                return 
     904        finally: 
     905            self.cond.release() 
    805906        to=stanza.get_to() 
    806907        if to.resource and (to.node[0] in "#+!" or to.node.startswith(",amp,")): 
     
    827928            reason="Unknown reason" 
    828929        self.send("QUIT :%s" % (reason,)) 
    829         self.exit=1 
     930        self.exit=reason 
     931        self.exited=1 
    830932 
    831933    def debug(self,msg): 
     
    840942                config.connect.secret,config.connect.host,config.connect.port, 
    841943                category="gateway",type="irc") 
    842         self.exit=0 
     944        self.shutdown=0 
     945        signal.signal(signal.SIGINT,self.signal_handler) 
     946        signal.signal(signal.SIGTERM,self.signal_handler) 
    843947        self.irc_sessions={} 
    844948        self.config=config 
     949 
     950    def signal_handler(self,signum,frame): 
     951        self.debug("Signal %i received, shutting down..." % (signum,)) 
     952        self.shutdown=1 
     953 
     954    def run(self,timeout): 
     955        self.connect() 
     956        while (not self.shutdown and self.stream  
     957                and not self.stream.eof and self.stream.socket is not None): 
     958            self.stream.loop_iter(timeout) 
     959        if self.shutdown: 
     960            for sess in self.irc_sessions.values(): 
     961                sess.disconnect("JJIGW shutdown") 
     962        threads=threading.enumerate() 
     963        for th in threads: 
     964            try: 
     965                th.join(10*timeout) 
     966            except: 
     967                pass 
     968        for th in threads: 
     969            try: 
     970                th.join(timeout) 
     971            except: 
     972                pass 
     973        self.disconnect() 
     974        self.debug("Exitting normally") 
    845975 
    846976    def send(self,stanza): 
     
    10401170c=Component(config) 
    10411171 
    1042 print "connecting..." 
    1043 c.connect() 
    1044  
    1045 print "looping..." 
    1046 try: 
    1047     c.loop(1) 
    1048 except KeyboardInterrupt: 
    1049     print "disconnecting..." 
    1050     c.disconnect() 
    1051     pass 
    1052  
    1053 print "exiting..." 
     1172print "starting..." 
     1173c.run(1) 
    10541174 
    10551175# vi: sw=4 ts=8 sts=4