[Twisted-Python] Telnet negotiation with Twisted

Patrick Mylund Nielsen twisted at patrickmylund.com
Sat Dec 3 09:48:04 EST 2011


Pardon my double-posting. Here it is, a little less confusing:

#!/usr/bin/env python
from twisted.internet.protocol import Factory
from twisted.conch.telnet import TelnetProtocol, TelnetTransport
from twisted.conch.telnet import WILL

# More info: http://www.faqs.org/rfcs/rfc1184.html

LINEMODE = chr(34)
LINEMODE_EDIT = chr(1) + chr(1)
LINEMODE_TRAPSIG = chr(1) + chr(2)
LINEMODE_MODEACK = chr(1) + chr(4)
LINEMODE_SOFTTAB = chr(1) + chr(8)
LINEMODE_LITECHO = chr(1) + chr(16)

class LinemodeProtocol(TelnetProtocol):

    def dataReceived(self, data):
        if self.transport.lines:
            line = data.rstrip()
            print("data received (normal): " + line)
            if line == "gounbuffered":
                self.transport.requestNegotiation(LINEMODE,
LINEMODE_TRAPSIG) # Client should only trap signals locally
                self.transport.lines = False
        else:
            # manually buffer data here
            print("data received (unbuffered): " + data)
            if data == "n":
                self.transport.requestNegotiation(LINEMODE,
LINEMODE_EDIT) # Go back to buffered
                self.transport.lines = True

class LinemodeTransport(TelnetTransport):

    def connectionMade(self):
        self.lines = True
        self.do(LINEMODE) # Ask client to begin sub-negotation of linemode
        TelnetTransport.connectionMade(self)

    def commandReceived(self, command, argument):
        if argument == LINEMODE:
            if command == WILL: # Client said OK to our DO; let's... do it
                self.requestNegotiation(LINEMODE, LINEMODE_EDIT) # Buffered mode
        else:
            TelnetTransport.commandReceived(self, command, argument)

class LinemodeFactory(Factory):

    def buildProtocol(self, addr):
        return LinemodeTransport(LinemodeProtocol)

if __name__ == '__main__':
    from twisted.internet import reactor

    port = 2222
    factory = LinemodeFactory()

    reactor.listenTCP(port, factory)
    reactor.run()



On Sat, Dec 3, 2011 at 15:22, Patrick Mylund Nielsen
<twisted at patrickmylund.com> wrote:
> Hi Lee,
>
> Here is a complete example that works with Twisted 11.0. LINEMODE
> itself is enabled at connect, but it has different modes that
> determine what is sent when by the client. (See section 2.2 of
> http://www.faqs.org/rfcs/rfc1184.html)
>
> #####
>
> #!/usr/bin/env python
> from twisted.internet.protocol import Factory
> from twisted.conch.telnet import TelnetProtocol,
> StatefulTelnetProtocol, TelnetTransport
> from twisted.conch.telnet import DO, DONT, WILL, WONT
>
> LINEMODE = chr(34)
> LINEMODE_EDIT = chr(1) + chr(1)
> LINEMODE_TRAPSIG = chr(1) + chr(2)
> LINEMODE_MODEACK = chr(1) + chr(4)
> LINEMODE_SOFTTAB = chr(1) + chr(8)
> LINEMODE_LITECHO = chr(1) + chr(16)
>
> class LineModeProtocol(TelnetProtocol):
>
>    def connectionMade(self):
>        print("Connection made!")
>
>    def connectionLost(self, reason):
>        print("Connection lost!")
>
>    def dataReceived(self, data):
>        if self.transport.lines:
>            line = data.rstrip()
>            print("data received (normal): " + line)
>            if line == "gounbuffered":
>                self.transport.requestNegotiation(LINEMODE,
> LINEMODE_TRAPSIG) # Only trap signals locally
>                self.transport.lines = False
>        else:
>            # manually buffer data here
>            print("data received (linemode): " + data)
>            if data == "n":
>                self.transport.requestNegotiation(LINEMODE,
> LINEMODE_EDIT) # Change to edit mode
>                self.transport.lines = True
>
> class LineModeTransport(TelnetTransport):
>
>    def connectionMade(self):
>        self.lines = True
>        self.do(LINEMODE) # Ask client to begin sub-negotation of linemode
>        TelnetTransport.connectionMade(self)
>
>    def commandReceived(self, command, argument):
>        if argument == LINEMODE:
>            if command == WILL: # Client said OK to our DO; let's... do it
>                self.requestNegotiation(LINEMODE, LINEMODE_EDIT) # The
> normal (buffered) mode
>        else:
>            TelnetTransport.commandReceived(self, command, argument)
>
> class LineModeFactory(Factory):
>
>    def buildProtocol(self, addr):
>        return LineModeTransport(LineModeProtocol)
>
> if __name__ == '__main__':
>    from twisted.internet import reactor
>
>    port = 2222
>    factory = LineModeFactory()
>
>    reactor.listenTCP(port, factory)
>    reactor.run()
>
> #####
>
> There is probably an easier way to check the state of LINEMODE, e.g.
> with getOptionState, but it works.
>
> Example:
>
> Client:
> # telnet localhost 2222
> Trying 127.0.0.1...
> Connected to localhost.
> Escape character is '^]'.
> How are you?
> gounbuffered
> testnback again
>
> Server:
> # ./linemode.py
> Connection made!
> data received (normal): How are you?
> data received (normal): gounbuffered
> data received (linemode): t
> data received (linemode): e
> data received (linemode): s
> data received (linemode): t
> data received (linemode): n
> data received (normal): back again
>
> Best,
> Patrick
>
> On Sat, Dec 3, 2011 at 14:59,  <exarkun at twistedmatrix.com> wrote:
>> On 03:53 am, lmorsino at gmail.com wrote:
>>>Jean-Paul,
>>>
>>>Thanks for your response. I still can't get self.will(LINEMODE) to work
>>>but
>>>I did get self.telnet_WILL(LINEMODE) to run without throwing an Error.
>>>Can
>>>you elaborate on what needs to happen in the enableRemote? My
>>>impression
>>>was that once I send the negotiation WILL command from server to the
>>>client, the client will respond with either a DO or a DONT. What
>>>further
>>>logic is necessary?
>>
>> I can't say what further logic is necessary, because I don't know what
>> logic you have now.  The description of your code you gave above is a
>> good introduction to an actual code listing (<http://sscce.org/>), but
>> it's not sufficient on its own.
>>
>> Jean-Paul
>>
>> _______________________________________________
>> Twisted-Python mailing list
>> Twisted-Python at twistedmatrix.com
>> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python



More information about the Twisted-Python mailing list