[Twisted-Python] twisted.conch.telnet example?

Hello all. :) I'm trying to learn Twisted, and to replace irritating telnetlib code for a simple telnet client application to do so. The problem is I'm slightly lost as to where to start with the twisted.conch.telnet library, so was wondering if anyone could point me to a simple example. So far, I understand the whole client factory thing-- but where I start getting lost is where we get to the "protocol" point (I know I know-- so early to get confused!). Specifically, in the buildProtocol method of a ReconnectingClientFactory instance.. what should I be returning a subclass of? There's a telnet.Telnet, which /looks/ like it would be handling all of the telnet negotiation nicely, but it has methods like "def enableRemote" that call "self.protocol.enableRemote".. and I'm not sure what should be put there, or how that should have been handled. My best success so far was to have it return a subclass of telnet.StatefulTelnetProtocol. It does the "basis" of what I want: a line-oriented output from the telnet protocol connection. However, it also returns all the negotiation characters, so it seems like it's not actually implementing the telnet negotiation part itself. Then there's telnet.TelnetBootstrapProtocol which looks very interesting but looks like its mostly handling telnet features I'm not interested in (various line modes, screen size negotiation, etc) yet... and a telnet.TelnetProtocol that I'm very confused by.. it's inheriting from ITelnetProtocol which appears to define the basic negotiation methods, but it doesn't appear to -do- anything. (And telnet.Telnet, which does notinherit from that interface, does appear to support -doing- the negotiation) This might all be a lot of babbling, and if so-- sorry! I'm just not sure where to get started on understanding what's going on in this module to make use of it. :) I tried googling around to see if I could find a simple display of gluing the conch modules together to produce a line-oriented telnet client connection that appeared to handle the negotiation ... just to get started-- and I can't find one. Does anyone know of one? (Or, if I give you $0.25, could you throw one together? :)) Thanks in advance. --S

On Tue, 26 Jun 2007 10:03:26 -0700, Stephen Hansen <apt.shansen@gmail.com> wrote:
Hello all. :)
Hey!
Cool. :)
The documentation for this part of Twisted is basically completely missing. That'd be my fault, I really should have written some, either when telnet was implemented or some time in the two years since. ;) So, to start, I'll try to give a high-level overview. Then there's t.c.telnet.
Yep. t.c.telnet.Telnet is a Protocol subclass and so implements IProtocol: it is the class which actually implements the telnet protocol. It goes right on top of an ITCPTransport and its dataReceived knows about telnet escapes and the other features of the telnet protocol. When it gets bytes which represent some telnet protocol action, a Telnet instance calls either negotiate or commandReceived on itself. The default implementation of these methods dispatches the event to handlers defined by negotiationMap and enableLocal/disableLocal/enableRemote/disableRemote, respectively. In turn, {enable,disable}{Local,Remote} dispatch to another object, self.protocol, as you noticed. There's also a subclass of Telnet, TelnetTransport. TelnetTransport takes a protocol class and some arguments to its initializer. When TelnetTransport is connected to an ITCPTransport, it instantiates the class it was given and saves the instance as self.protocol. As a Telnet subclass, this means that the protocol class passed to TelnetTransport's initializer can now control how negotiations happen and how to respond to commands.
StatefulTelnetProtocol is a TelnetProtocol. TelnetProtocol is the intended base class for anything which is passed to TelnetTransport. TelnetProtocol is an ITelnetProtocol, so actually anywhere a TelnetProtocol class will work, so will any other class which implements ITelnetProtocol. TelnetProtocol doesn't know anything about the actual telnet protocol - its name attempts to convey that it /is/ a protocol /for/ telnet: it can receive application level bytes (dataReceived, inherited from IProtocol/Protocol), but it can also handle events which can only happen when you're using telnet: those four enable/disable methods, plus some catch-alls for negotiation about options which aren't recognized. Since TelnetProtocol doesn't know the telnet protocol, if you hook it directly up to an ITCPTransport, it'll just think everything it gets is application data, even telnet negotiation sequences.
TelnetBootstrapProtocol is another one like StatefulTelnetProtocol - it adds some features which may or may not be interesting, but it won't work by itself, it needs TelnetTransport to actually parse the protocol.
Hopefully the above has given you a better idea of what all the pieces are supposed to be doing. Here's an example of how you might hook them up to each other, by way of a client which prints all application data it receives: from twisted.internet import reactor from twisted.internet.protocol import ClientFactory from twisted.conch.telnet import TelnetTransport, TelnetProtocol class TelnetPrinter(TelnetProtocol): def dataReceived(self, bytes): print 'Received:', repr(bytes) class TelnetFactory(ClientFactory): def buildProtocol(self, addr): return TelnetTransport(TelnetPrinter) reactor.connectTCP(host, port, TelnetFactory()) For something line oriented, you might mix in LineReceiver (as StatefulTelnetProtocol does) or instantiate one directly yourself in a TelnetProtocol subclass and feed it bytes in your dataReceived implementation. Hope this helps, Jean-Paul

On Tue, 26 Jun 2007 10:03:26 -0700, Stephen Hansen <apt.shansen@gmail.com> wrote:
Hello all. :)
Hey!
Cool. :)
The documentation for this part of Twisted is basically completely missing. That'd be my fault, I really should have written some, either when telnet was implemented or some time in the two years since. ;) So, to start, I'll try to give a high-level overview. Then there's t.c.telnet.
Yep. t.c.telnet.Telnet is a Protocol subclass and so implements IProtocol: it is the class which actually implements the telnet protocol. It goes right on top of an ITCPTransport and its dataReceived knows about telnet escapes and the other features of the telnet protocol. When it gets bytes which represent some telnet protocol action, a Telnet instance calls either negotiate or commandReceived on itself. The default implementation of these methods dispatches the event to handlers defined by negotiationMap and enableLocal/disableLocal/enableRemote/disableRemote, respectively. In turn, {enable,disable}{Local,Remote} dispatch to another object, self.protocol, as you noticed. There's also a subclass of Telnet, TelnetTransport. TelnetTransport takes a protocol class and some arguments to its initializer. When TelnetTransport is connected to an ITCPTransport, it instantiates the class it was given and saves the instance as self.protocol. As a Telnet subclass, this means that the protocol class passed to TelnetTransport's initializer can now control how negotiations happen and how to respond to commands.
StatefulTelnetProtocol is a TelnetProtocol. TelnetProtocol is the intended base class for anything which is passed to TelnetTransport. TelnetProtocol is an ITelnetProtocol, so actually anywhere a TelnetProtocol class will work, so will any other class which implements ITelnetProtocol. TelnetProtocol doesn't know anything about the actual telnet protocol - its name attempts to convey that it /is/ a protocol /for/ telnet: it can receive application level bytes (dataReceived, inherited from IProtocol/Protocol), but it can also handle events which can only happen when you're using telnet: those four enable/disable methods, plus some catch-alls for negotiation about options which aren't recognized. Since TelnetProtocol doesn't know the telnet protocol, if you hook it directly up to an ITCPTransport, it'll just think everything it gets is application data, even telnet negotiation sequences.
TelnetBootstrapProtocol is another one like StatefulTelnetProtocol - it adds some features which may or may not be interesting, but it won't work by itself, it needs TelnetTransport to actually parse the protocol.
Hopefully the above has given you a better idea of what all the pieces are supposed to be doing. Here's an example of how you might hook them up to each other, by way of a client which prints all application data it receives: from twisted.internet import reactor from twisted.internet.protocol import ClientFactory from twisted.conch.telnet import TelnetTransport, TelnetProtocol class TelnetPrinter(TelnetProtocol): def dataReceived(self, bytes): print 'Received:', repr(bytes) class TelnetFactory(ClientFactory): def buildProtocol(self, addr): return TelnetTransport(TelnetPrinter) reactor.connectTCP(host, port, TelnetFactory()) For something line oriented, you might mix in LineReceiver (as StatefulTelnetProtocol does) or instantiate one directly yourself in a TelnetProtocol subclass and feed it bytes in your dataReceived implementation. Hope this helps, Jean-Paul
participants (2)
-
Jean-Paul Calderone
-
Stephen Hansen