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()