Merge pull request #3635 from a-rodian-jedi/memleaks

fixing memory leaks
This commit is contained in:
Griatch 2024-10-21 20:55:48 +02:00 committed by GitHub
commit 78e6683991
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 99 additions and 88 deletions

View file

@ -15,6 +15,7 @@ This protocol is implemented by the telnet protocol importing
mccp_compress and calling it from its write methods. mccp_compress and calling it from its write methods.
""" """
import weakref
import zlib import zlib
# negotiations for v1 and v2 of the protocol # negotiations for v1 and v2 of the protocol
@ -57,10 +58,10 @@ class Mccp:
""" """
self.protocol = protocol self.protocol = weakref.ref(protocol)
self.protocol.protocol_flags["MCCP"] = False self.protocol().protocol_flags["MCCP"] = False
# ask if client will mccp, connect callbacks to handle answer # ask if client will mccp, connect callbacks to handle answer
self.protocol.will(MCCP).addCallbacks(self.do_mccp, self.no_mccp) self.protocol().will(MCCP).addCallbacks(self.do_mccp, self.no_mccp)
def no_mccp(self, option): def no_mccp(self, option):
""" """
@ -70,10 +71,10 @@ class Mccp:
option (Option): Option dict (not used). option (Option): Option dict (not used).
""" """
if hasattr(self.protocol, "zlib"): if hasattr(self.protocol(), "zlib"):
del self.protocol.zlib del self.protocol().zlib
self.protocol.protocol_flags["MCCP"] = False self.protocol().protocol_flags["MCCP"] = False
self.protocol.handshake_done() self.protocol().handshake_done()
def do_mccp(self, option): def do_mccp(self, option):
""" """
@ -84,7 +85,7 @@ class Mccp:
option (Option): Option dict (not used). option (Option): Option dict (not used).
""" """
self.protocol.protocol_flags["MCCP"] = True self.protocol().protocol_flags["MCCP"] = True
self.protocol.requestNegotiation(MCCP, b"") self.protocol().requestNegotiation(MCCP, b"")
self.protocol.zlib = zlib.compressobj(9) self.protocol().zlib = zlib.compressobj(9)
self.protocol.handshake_done() self.protocol().handshake_done()

View file

@ -11,6 +11,7 @@ active players and so on.
""" """
import weakref
from django.conf import settings from django.conf import settings
from evennia.utils import utils from evennia.utils import utils
@ -39,8 +40,8 @@ class Mssp:
protocol (Protocol): The active protocol instance. protocol (Protocol): The active protocol instance.
""" """
self.protocol = protocol self.protocol = weakref.ref(protocol)
self.protocol.will(MSSP).addCallbacks(self.do_mssp, self.no_mssp) self.protocol().will(MSSP).addCallbacks(self.do_mssp, self.no_mssp)
def get_player_count(self): def get_player_count(self):
""" """
@ -50,7 +51,7 @@ class Mssp:
count (int): The number of players in the MUD. count (int): The number of players in the MUD.
""" """
return str(self.protocol.sessionhandler.count_loggedin()) return str(self.protocol().sessionhandler.count_loggedin())
def get_uptime(self): def get_uptime(self):
""" """
@ -60,7 +61,7 @@ class Mssp:
uptime (int): Number of seconds of uptime. uptime (int): Number of seconds of uptime.
""" """
return str(self.protocol.sessionhandler.uptime) return str(self.protocol().sessionhandler.uptime)
def no_mssp(self, option): def no_mssp(self, option):
""" """
@ -71,7 +72,7 @@ class Mssp:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.handshake_done() self.protocol().handshake_done()
def do_mssp(self, option): def do_mssp(self, option):
""" """
@ -132,5 +133,5 @@ class Mssp:
) )
# send to crawler by subnegotiation # send to crawler by subnegotiation
self.protocol.requestNegotiation(MSSP, varlist) self.protocol().requestNegotiation(MSSP, varlist)
self.protocol.handshake_done() self.protocol().handshake_done()

View file

@ -15,6 +15,7 @@ http://www.gammon.com.au/mushclient/addingservermxp.htm
""" """
import re import re
import weakref
from django.conf import settings from django.conf import settings
@ -61,10 +62,10 @@ class Mxp:
protocol (Protocol): The active protocol instance. protocol (Protocol): The active protocol instance.
""" """
self.protocol = protocol self.protocol = weakref.ref(protocol)
self.protocol.protocol_flags["MXP"] = False self.protocol().protocol_flags["MXP"] = False
if settings.MXP_ENABLED: if settings.MXP_ENABLED:
self.protocol.will(MXP).addCallbacks(self.do_mxp, self.no_mxp) self.protocol().will(MXP).addCallbacks(self.do_mxp, self.no_mxp)
def no_mxp(self, option): def no_mxp(self, option):
""" """
@ -74,8 +75,8 @@ class Mxp:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.protocol_flags["MXP"] = False self.protocol().protocol_flags["MXP"] = False
self.protocol.handshake_done() self.protocol().handshake_done()
def do_mxp(self, option): def do_mxp(self, option):
""" """
@ -86,8 +87,8 @@ class Mxp:
""" """
if settings.MXP_ENABLED: if settings.MXP_ENABLED:
self.protocol.protocol_flags["MXP"] = True self.protocol().protocol_flags["MXP"] = True
self.protocol.requestNegotiation(MXP, b"") self.protocol().requestNegotiation(MXP, b"")
else: else:
self.protocol.wont(MXP) self.protocol().wont(MXP)
self.protocol.handshake_done() self.protocol().handshake_done()

View file

@ -11,6 +11,7 @@ client and update it when the size changes
""" """
from codecs import encode as codecs_encode from codecs import encode as codecs_encode
import weakref
from django.conf import settings from django.conf import settings
@ -41,13 +42,13 @@ class Naws:
""" """
self.naws_step = 0 self.naws_step = 0
self.protocol = protocol self.protocol = weakref.ref(protocol)
self.protocol.protocol_flags["SCREENWIDTH"] = { self.protocol().protocol_flags["SCREENWIDTH"] = {
0: DEFAULT_WIDTH 0: DEFAULT_WIDTH
} # windowID (0 is root):width } # windowID (0 is root):width
self.protocol.protocol_flags["SCREENHEIGHT"] = {0: DEFAULT_HEIGHT} # windowID:width self.protocol().protocol_flags["SCREENHEIGHT"] = {0: DEFAULT_HEIGHT} # windowID:width
self.protocol.negotiationMap[NAWS] = self.negotiate_sizes self.protocol().negotiationMap[NAWS] = self.negotiate_sizes
self.protocol.do(NAWS).addCallbacks(self.do_naws, self.no_naws) self.protocol().do(NAWS).addCallbacks(self.do_naws, self.no_naws)
def no_naws(self, option): def no_naws(self, option):
""" """
@ -58,8 +59,8 @@ class Naws:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.protocol_flags["AUTORESIZE"] = False self.protocol().protocol_flags["AUTORESIZE"] = False
self.protocol.handshake_done() self.protocol().handshake_done()
def do_naws(self, option): def do_naws(self, option):
""" """
@ -69,8 +70,8 @@ class Naws:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.protocol_flags["AUTORESIZE"] = True self.protocol().protocol_flags["AUTORESIZE"] = True
self.protocol.handshake_done() self.protocol().handshake_done()
def negotiate_sizes(self, options): def negotiate_sizes(self, options):
""" """
@ -83,6 +84,6 @@ class Naws:
if len(options) == 4: if len(options) == 4:
# NAWS is negotiated with 16bit words # NAWS is negotiated with 16bit words
width = options[0] + options[1] width = options[0] + options[1]
self.protocol.protocol_flags["SCREENWIDTH"][0] = int(codecs_encode(width, "hex"), 16) self.protocol().protocol_flags["SCREENWIDTH"][0] = int(codecs_encode(width, "hex"), 16)
height = options[2] + options[3] height = options[2] + options[3]
self.protocol.protocol_flags["SCREENHEIGHT"][0] = int(codecs_encode(height, "hex"), 16) self.protocol().protocol_flags["SCREENHEIGHT"][0] = int(codecs_encode(height, "hex"), 16)

View file

@ -14,6 +14,8 @@ http://www.faqs.org/rfcs/rfc858.html
""" """
import weakref
SUPPRESS_GA = bytes([3]) # b"\x03" SUPPRESS_GA = bytes([3]) # b"\x03"
# default taken from telnet specification # default taken from telnet specification
@ -36,14 +38,14 @@ class SuppressGA:
protocol (Protocol): The active protocol instance. protocol (Protocol): The active protocol instance.
""" """
self.protocol = protocol self.protocol = weakref.ref(protocol)
self.protocol.protocol_flags["NOGOAHEAD"] = True self.protocol().protocol_flags["NOGOAHEAD"] = True
self.protocol.protocol_flags["NOPROMPTGOAHEAD"] = ( self.protocol().protocol_flags["NOPROMPTGOAHEAD"] = (
True # Used to send a GA after a prompt line only, set in TTYPE (per client) True # Used to send a GA after a prompt line only, set in TTYPE (per client)
) )
# tell the client that we prefer to suppress GA ... # tell the client that we prefer to suppress GA ...
self.protocol.will(SUPPRESS_GA).addCallbacks(self.will_suppress_ga, self.wont_suppress_ga) self.protocol().will(SUPPRESS_GA).addCallbacks(self.will_suppress_ga, self.wont_suppress_ga)
def wont_suppress_ga(self, option): def wont_suppress_ga(self, option):
""" """
@ -53,8 +55,8 @@ class SuppressGA:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.protocol_flags["NOGOAHEAD"] = False self.protocol().protocol_flags["NOGOAHEAD"] = False
self.protocol.handshake_done() self.protocol().handshake_done()
def will_suppress_ga(self, option): def will_suppress_ga(self, option):
""" """
@ -64,5 +66,5 @@ class SuppressGA:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.protocol_flags["NOGOAHEAD"] = True self.protocol().protocol_flags["NOGOAHEAD"] = True
self.protocol.handshake_done() self.protocol().handshake_done()

View file

@ -306,6 +306,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
""" """
self.sessionhandler.disconnect(self) self.sessionhandler.disconnect(self)
if self.nop_keep_alive and self.nop_keep_alive.running:
self.toggle_nop_keepalive()
self.transport.loseConnection() self.transport.loseConnection()
def applicationDataReceived(self, data): def applicationDataReceived(self, data):

View file

@ -26,6 +26,7 @@ This implements the following telnet OOB communication protocols:
import json import json
import re import re
import weakref
# General Telnet # General Telnet
from twisted.conch.telnet import IAC, SB, SE from twisted.conch.telnet import IAC, SB, SE
@ -84,16 +85,16 @@ class TelnetOOB:
protocol (Protocol): The active protocol. protocol (Protocol): The active protocol.
""" """
self.protocol = protocol self.protocol = weakref.ref(protocol)
self.protocol.protocol_flags["OOB"] = False self.protocol().protocol_flags["OOB"] = False
self.MSDP = False self.MSDP = False
self.GMCP = False self.GMCP = False
# ask for the available protocols and assign decoders # ask for the available protocols and assign decoders
# (note that handshake_done() will be called twice!) # (note that handshake_done() will be called twice!)
self.protocol.negotiationMap[MSDP] = self.decode_msdp self.protocol().negotiationMap[MSDP] = self.decode_msdp
self.protocol.negotiationMap[GMCP] = self.decode_gmcp self.protocol().negotiationMap[GMCP] = self.decode_gmcp
self.protocol.will(MSDP).addCallbacks(self.do_msdp, self.no_msdp) self.protocol().will(MSDP).addCallbacks(self.do_msdp, self.no_msdp)
self.protocol.will(GMCP).addCallbacks(self.do_gmcp, self.no_gmcp) self.protocol().will(GMCP).addCallbacks(self.do_gmcp, self.no_gmcp)
self.oob_reported = {} self.oob_reported = {}
def no_msdp(self, option): def no_msdp(self, option):
@ -105,7 +106,7 @@ class TelnetOOB:
""" """
# no msdp, check GMCP # no msdp, check GMCP
self.protocol.handshake_done() self.protocol().handshake_done()
def do_msdp(self, option): def do_msdp(self, option):
""" """
@ -116,8 +117,8 @@ class TelnetOOB:
""" """
self.MSDP = True self.MSDP = True
self.protocol.protocol_flags["OOB"] = True self.protocol().protocol_flags["OOB"] = True
self.protocol.handshake_done() self.protocol().handshake_done()
def no_gmcp(self, option): def no_gmcp(self, option):
""" """
@ -128,7 +129,7 @@ class TelnetOOB:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.handshake_done() self.protocol().handshake_done()
def do_gmcp(self, option): def do_gmcp(self, option):
""" """
@ -139,8 +140,8 @@ class TelnetOOB:
""" """
self.GMCP = True self.GMCP = True
self.protocol.protocol_flags["OOB"] = True self.protocol().protocol_flags["OOB"] = True
self.protocol.handshake_done() self.protocol().handshake_done()
# encoders # encoders
@ -375,7 +376,7 @@ class TelnetOOB:
cmds["msdp_{}".format(remap)] = cmds.pop(lower_case[remap]) cmds["msdp_{}".format(remap)] = cmds.pop(lower_case[remap])
# print("msdp data in:", cmds) # DEBUG # print("msdp data in:", cmds) # DEBUG
self.protocol.data_in(**cmds) self.protocol().data_in(**cmds)
def decode_gmcp(self, data): def decode_gmcp(self, data):
""" """
@ -424,7 +425,7 @@ class TelnetOOB:
if cmdname.lower().startswith(b"core_"): if cmdname.lower().startswith(b"core_"):
# if Core.cmdname, then use cmdname # if Core.cmdname, then use cmdname
cmdname = cmdname[5:] cmdname = cmdname[5:]
self.protocol.data_in(**{cmdname.lower().decode(): [args, kwargs]}) self.protocol().data_in(**{cmdname.lower().decode(): [args, kwargs]})
# access methods # access methods
@ -441,8 +442,8 @@ class TelnetOOB:
if self.MSDP: if self.MSDP:
encoded_oob = self.encode_msdp(cmdname, *args, **kwargs) encoded_oob = self.encode_msdp(cmdname, *args, **kwargs)
self.protocol._write(IAC + SB + MSDP + encoded_oob + IAC + SE) self.protocol()._write(IAC + SB + MSDP + encoded_oob + IAC + SE)
if self.GMCP: if self.GMCP:
encoded_oob = self.encode_gmcp(cmdname, *args, **kwargs) encoded_oob = self.encode_gmcp(cmdname, *args, **kwargs)
self.protocol._write(IAC + SB + GMCP + encoded_oob + IAC + SE) self.protocol()._write(IAC + SB + GMCP + encoded_oob + IAC + SE)

View file

@ -12,6 +12,8 @@ under the 'TTYPE' key.
""" """
import weakref
# telnet option codes # telnet option codes
TTYPE = bytes([24]) # b"\x18" TTYPE = bytes([24]) # b"\x18"
IS = bytes([0]) # b"\x00" IS = bytes([0]) # b"\x00"
@ -55,16 +57,16 @@ class Ttype:
""" """
self.ttype_step = 0 self.ttype_step = 0
self.protocol = protocol self.protocol = weakref.ref(protocol)
# we set FORCEDENDLINE for clients not supporting ttype # we set FORCEDENDLINE for clients not supporting ttype
self.protocol.protocol_flags["FORCEDENDLINE"] = True self.protocol().protocol_flags["FORCEDENDLINE"] = True
self.protocol.protocol_flags["TTYPE"] = False self.protocol().protocol_flags["TTYPE"] = False
# is it a safe bet to assume ANSI is always supported? # is it a safe bet to assume ANSI is always supported?
self.protocol.protocol_flags["ANSI"] = True self.protocol().protocol_flags["ANSI"] = True
# setup protocol to handle ttype initialization and negotiation # setup protocol to handle ttype initialization and negotiation
self.protocol.negotiationMap[TTYPE] = self.will_ttype self.protocol().negotiationMap[TTYPE] = self.will_ttype
# ask if client will ttype, connect callback if it does. # ask if client will ttype, connect callback if it does.
self.protocol.do(TTYPE).addCallbacks(self.will_ttype, self.wont_ttype) self.protocol().do(TTYPE).addCallbacks(self.will_ttype, self.wont_ttype)
def wont_ttype(self, option): def wont_ttype(self, option):
""" """
@ -74,8 +76,8 @@ class Ttype:
option (Option): Not used. option (Option): Not used.
""" """
self.protocol.protocol_flags["TTYPE"] = False self.protocol().protocol_flags["TTYPE"] = False
self.protocol.handshake_done() self.protocol().handshake_done()
def will_ttype(self, option): def will_ttype(self, option):
""" """
@ -91,7 +93,7 @@ class Ttype:
stored on protocol.protocol_flags under the TTYPE key. stored on protocol.protocol_flags under the TTYPE key.
""" """
options = self.protocol.protocol_flags options = self.protocol().protocol_flags
if options and options.get("TTYPE", False) or self.ttype_step > 3: if options and options.get("TTYPE", False) or self.ttype_step > 3:
return return
@ -104,7 +106,7 @@ class Ttype:
if self.ttype_step == 0: if self.ttype_step == 0:
# just start the request chain # just start the request chain
self.protocol.requestNegotiation(TTYPE, SEND) self.protocol().requestNegotiation(TTYPE, SEND)
elif self.ttype_step == 1: elif self.ttype_step == 1:
# this is supposed to be the name of the client/terminal. # this is supposed to be the name of the client/terminal.
@ -125,9 +127,9 @@ class Ttype:
xterm256 = clientname.split("MUDLET", 1)[1].strip() >= "1.1" xterm256 = clientname.split("MUDLET", 1)[1].strip() >= "1.1"
# Mudlet likes GA's on a prompt line for the prompt trigger to # Mudlet likes GA's on a prompt line for the prompt trigger to
# match, if it's not wanting NOGOAHEAD. # match, if it's not wanting NOGOAHEAD.
if not self.protocol.protocol_flags["NOGOAHEAD"]: if not self.protocol().protocol_flags["NOGOAHEAD"]:
self.protocol.protocol_flags["NOGOAHEAD"] = True self.protocol().protocol_flags["NOGOAHEAD"] = True
self.protocol.protocol_flags["NOPROMPTGOAHEAD"] = False self.protocol().protocol_flags["NOPROMPTGOAHEAD"] = False
if ( if (
clientname.startswith("XTERM") clientname.startswith("XTERM")
@ -153,11 +155,11 @@ class Ttype:
truecolor = True truecolor = True
# all clients supporting TTYPE at all seem to support ANSI # all clients supporting TTYPE at all seem to support ANSI
self.protocol.protocol_flags["ANSI"] = True self.protocol().protocol_flags["ANSI"] = True
self.protocol.protocol_flags["XTERM256"] = xterm256 self.protocol().protocol_flags["XTERM256"] = xterm256
self.protocol.protocol_flags["TRUECOLOR"] = truecolor self.protocol().protocol_flags["TRUECOLOR"] = truecolor
self.protocol.protocol_flags["CLIENTNAME"] = clientname self.protocol().protocol_flags["CLIENTNAME"] = clientname
self.protocol.requestNegotiation(TTYPE, SEND) self.protocol().requestNegotiation(TTYPE, SEND)
elif self.ttype_step == 2: elif self.ttype_step == 2:
# this is a term capabilities flag # this is a term capabilities flag
@ -170,11 +172,11 @@ class Ttype:
and not tupper.endswith("-COLOR") # old Tintin, Putty and not tupper.endswith("-COLOR") # old Tintin, Putty
) )
if xterm256: if xterm256:
self.protocol.protocol_flags["ANSI"] = True self.protocol().protocol_flags["ANSI"] = True
self.protocol.protocol_flags["XTERM256"] = xterm256 self.protocol().protocol_flags["XTERM256"] = xterm256
self.protocol.protocol_flags["TERM"] = term self.protocol().protocol_flags["TERM"] = term
# request next information # request next information
self.protocol.requestNegotiation(TTYPE, SEND) self.protocol().requestNegotiation(TTYPE, SEND)
elif self.ttype_step == 3: elif self.ttype_step == 3:
# the MTTS bitstring identifying term capabilities # the MTTS bitstring identifying term capabilities
@ -186,12 +188,12 @@ class Ttype:
support = dict( support = dict(
(capability, True) for bitval, capability in MTTS if option & bitval > 0 (capability, True) for bitval, capability in MTTS if option & bitval > 0
) )
self.protocol.protocol_flags.update(support) self.protocol().protocol_flags.update(support)
else: else:
# some clients send erroneous MTTS as a string. Add directly. # some clients send erroneous MTTS as a string. Add directly.
self.protocol.protocol_flags[option.upper()] = True self.protocol().protocol_flags[option.upper()] = True
self.protocol.protocol_flags["TTYPE"] = True self.protocol().protocol_flags["TTYPE"] = True
# we must sync ttype once it'd done # we must sync ttype once it'd done
self.protocol.handshake_done() self.protocol().handshake_done()
self.ttype_step += 1 self.ttype_step += 1