Example #1
0
class IRCProtocol(irc.IRC):
    def __init__(self, ip):
        self.dead = False
        self.type = None
        self.secure = False
        self.data = 0
        self.data_checker = LoopingCall(self.checkData)
        self.pinger = LoopingCall.withCount(self.ping)
        self.connection_expire = reactor.callLater(15, self.connectionLost, None)
        self.ip = ip
    
    def connectionMade(self):
        self.connection_expire.cancel()
        self.type = IRCUser(self)
        tryagain = []
        for function in self.factory.actions["connect"]:
            result = function(self.type)
            if result == "again":
                tryagain.append(function)
            elif not result:
                self.transport.loseConnection()
                self.type = None
                break
        if self.type:
            for function in tryagain:
                if not function(self.type):
                    self.transport.loseConnection()
                    self.type = None
                    break
        if self.type:
            self.secure = ISSLTransport(self.transport, None) is not None
            self.data_checker.start(5)
            self.pinger.start(self.factory.servconfig["client_ping_interval"], now=False)
            for server in self.factory.servers.itervalues():
                if server.nearHop == self.factory.name:
                    server.callRemote(ConnectUser, uuid=self.type.uuid, ip=self.type.ip, server=self.factory.name, secure=self.secure, signon=epoch(self.type.signon))

    def dataReceived(self, data):
        if self.dead:
            return
        # Get and store the peer certificate if the client is using SSL and providing a client certificate
        # I don't like handling this here, but twisted does not provide a hook to process it in a better place (e.g.
        # when the SSL handshake is complete); see http://twistedmatrix.com/trac/ticket/6024
        # This will be moved in the future when we can.
        if self.secure and self.transport:
            certificate = self.transport.getPeerCertificate()
            if certificate is not None:
                self.type.setMetadata("server", "certfp", certificate.digest("md5").lower().replace(":", ""))
        # Handle the received data
        for modfunc in self.factory.actions["recvdata"]:
            modfunc(self.type, data)
        self.data += len(data)
        if self.pinger.running:
            self.pinger.reset()
        irc.IRC.dataReceived(self, data)
    
    def checkData(self):
        if self.type:
            self.type.checkData(self.data)
        self.data = 0
    
    def ping(self, intervals):
        timeout = self.factory.servconfig["client_timeout_delay"] + self.factory.servconfig["client_ping_interval"] * (intervals - 1)
        if (now() - self.type.lastpong).total_seconds() > timeout:
            log.msg("Client has stopped responding to PING and is now disconnecting.")
            self.transport.loseConnection()
            self.connectionLost(None)
        elif self.type.lastactivity > self.type.lastpong:
            self.type.lastpong = now()
        else:
            self.sendMessage("PING",":{}".format(self.factory.name))
    
    def handleCommand(self, command, prefix, params):
        log.msg("handleCommand: {!r} {!r} {!r}".format(command, prefix, params))
        return self.type.handleCommand(command, prefix, params)
    
    def sendLine(self, line):
        if self.dead:
            return
        for modfunc in self.factory.actions["senddata"]:
            modfunc(self.type, line)
        log.msg("sendLine: {!r}".format(line))
        return irc.IRC.sendLine(self, line)
        
    def connectionLost(self, reason):
        if self.dead:
            return
        self.dead = True
        self.factory.unregisterProtocol(self)
        if self.type:
            self.type.connectionLost(reason)
        if self.data_checker.running:
            self.data_checker.stop()
        if self.pinger.running:
            self.pinger.stop()