1 # A TELNET client class. Based on RFC 854: TELNET Protocol
2 # Specification, by J. Postel and J. Reynolds
7 # >>> from telnetlib import Telnet
8 # >>> tn = Telnet('voorn.cwi.nl', 79) # connect to finger port
9 # >>> tn.write('guido\r\n')
10 # >>> print tn.read_all()
11 # Login name: guido In real life: Guido van Rossum
12 # Office: M353, x4127 Home phone: 020-6225521
13 # Directory: /ufs/guido Shell: /usr/local/bin/esh
14 # On since Oct 28 11:02:16 on ttyq1
15 # Project: Multimedia Kernel Systems
19 # Note that read() won't read until eof -- it just reads some data
20 # (but it guarantees to read at least one byte unless EOF is hit).
22 # It is possible to pass a Telnet object to select.select() in order
23 # to wait until more data is available. Note that in this case,
24 # read_eager() may return '' even if there was data on the socket,
25 # because the protocol negotiation may have eaten the data.
26 # This is why EOFError is needed to distinguish between "no data"
27 # and "connection closed" (since the socket also appears ready for
28 # reading when it is closed).
31 # - may hang when connection is slow in the middle of an IAC sequence
34 # - option negotiation
46 # Telnet protocol defaults
49 # Telnet protocol characters (don't change)
50 IAC
= chr(255) # "Interpret As Command"
57 # Telnet interface class
62 def __init__(self
, host
, *args
):
66 if len(args
) > 1: raise TypeError, 'too many args'
68 if not port
: port
= TELNET_PORT
69 self
.debuglevel
= DEBUGLEVEL
72 self
.sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
73 self
.sock
.connect((self
.host
, self
.port
))
84 def msg(self
, msg
, *args
):
85 if self
.debuglevel
> 0:
86 print 'Telnet(%s,%d):' % (self
.host
, self
.port
), msg
% args
89 def set_debuglevel(self
, debuglevel
):
90 self
.debuglevel
= debuglevel
99 # Return socket (e.g. for select)
100 def get_socket(self
):
103 # Return socket's fileno (e.g. for select)
105 return self
.sock
.fileno()
107 # Write a string to the socket, doubling any IAC characters
108 # Might block if the connection is blocked
109 # May raise socket.error if the connection is closed
110 def write(self
, buffer):
112 buffer = regsub
.gsub(IAC
, IAC
+IAC
, buffer)
113 self
.sock
.send(buffer)
115 # The following read_* methods exist:
117 # - read_until() reads until a string is encountered or a timeout is hit
119 # - read_all() reads all data until EOF
120 # - read_some() reads at least one byte until EOF
121 # These may do I/O but won't block doing it:
122 # - read_very_eager() reads all data available on the socket
123 # - read_eager() reads either data already queued or some data
124 # available on the socket
125 # These don't do I/O:
126 # - read_lazy() reads all data in the raw queue (processing it first)
127 # - read_very_lazy() reads all data in the cooked queue
129 # Read until a given string is encountered or until timeout
130 # Raise EOFError if connection closed and no cooked data available
131 # Return '' if no cooked data available otherwise
132 def read_until(self
, match
, *args
):
136 if len(args
) > 1: raise TypeError, 'too many args'
140 i
= string
.find(self
.cookedq
, match
)
143 buf
= self
.cookedq
[:i
]
144 self
.cookedq
= self
.cookedq
[i
:]
146 s_reply
= ([self
], [], [])
148 if timeout
is not None:
149 s_args
= s_args
+ (timeout
,)
150 while not self
.eof
and apply(select
.select
, s_args
) == s_reply
:
151 i
= max(0, len(self
.cookedq
)-n
)
154 i
= string
.find(self
.cookedq
, match
, i
)
157 buf
= self
.cookedq
[:i
]
158 self
.cookedq
= self
.cookedq
[i
:]
160 return self
.read_very_lazy()
162 # Read all data until EOF
163 # Block until connection closed
173 # Read at least one byte of cooked data unless EOF is hit
174 # Return '' if EOF is hit
175 # Block if no data is immediately available
178 while not self
.cookedq
and not self
.eof
:
185 # Read everything that's possible without blocking in I/O (eager)
186 # Raise EOFError if connection closed and no cooked data available
187 # Return '' if no cooked data available otherwise
188 # Don't block unless in the midst of an IAC sequence
189 def read_very_eager(self
):
191 while not self
.eof
and self
.sock_avail():
194 return self
.read_very_lazy()
196 # Read readily available data
197 # Raise EOFError if connection closed and no cooked data available
198 # Return '' if no cooked data available otherwise
199 # Don't block unless in the midst of an IAC sequence
200 def read_eager(self
):
202 while not self
.cookedq
and not self
.eof
and self
.sock_avail():
205 return self
.read_very_lazy()
207 # Process and return data that's already in the queues (lazy)
208 # Raise EOFError if connection closed and no data available
209 # Return '' if no cooked data available otherwise
210 # Don't block unless in the midst of an IAC sequence
213 return self
.read_very_lazy()
215 # Return any data available in the cooked queue (very lazy)
216 # Raise EOFError if connection closed and no data available
217 # Return '' if no cooked data available otherwise
219 def read_very_lazy(self
):
222 if not buf
and self
.eof
and not self
.rawq
:
223 raise EOFError, 'telnet connection closed'
226 # Transfer from raw queue to cooked queue
227 # Set self.eof when connection is closed
228 # Don't block unless in the midst of an IAC sequence
229 def process_rawq(self
):
233 c
= self
.rawq_getchar()
237 c
= self
.rawq_getchar()
240 elif c
in (DO
, DONT
):
241 opt
= self
.rawq_getchar()
242 self
.msg('IAC %s %d', c
== DO
and 'DO' or 'DONT', ord(c
))
243 self
.sock
.send(IAC
+ WONT
+ opt
)
244 elif c
in (WILL
, WONT
):
245 opt
= self
.rawq_getchar()
246 self
.msg('IAC %s %d',
247 c
== WILL
and 'WILL' or 'WONT', ord(c
))
249 self
.msg('IAC %s not recognized' % `c`
)
250 except EOFError: # raised by self.rawq_getchar()
252 self
.cookedq
= self
.cookedq
+ buf
254 # Get next char from raw queue
255 # Block if no data is immediately available
256 # Raise EOFError when connection is closed
257 def rawq_getchar(self
):
262 c
= self
.rawq
[self
.irawq
]
263 self
.irawq
= self
.irawq
+ 1
264 if self
.irawq
>= len(self
.rawq
):
269 # Fill raw queue from exactly one recv() system call
270 # Block if no data is immediately available
271 # Set self.eof when connection is closed
273 if self
.irawq
>= len(self
.rawq
):
276 # The buffer size should be fairly small so as to avoid quadratic
277 # behavior in process_rawq() above
278 buf
= self
.sock
.recv(50)
280 self
.rawq
= self
.rawq
+ buf
282 # Test whether data is available on the socket
283 def sock_avail(self
):
284 return select
.select([self
], [], [], 0) == ([self
], [], [])
288 # Usage: test [-d] ... [host [port]]
290 import sys
, string
, socket
, select
292 while sys
.argv
[1:] and sys
.argv
[1] == '-d':
293 debuglevel
= debuglevel
+1
300 portstr
= sys
.argv
[2]
302 port
= string
.atoi(portstr
)
303 except string
.atoi_error
:
304 port
= socket
.getservbyname(portstr
, 'tcp')
305 tn
= Telnet(host
, port
)
306 tn
.set_debuglevel(debuglevel
)
308 rfd
, wfd
, xfd
= select
.select([tn
, sys
.stdin
], [], [])
310 line
= sys
.stdin
.readline()
314 text
= tn
.read_eager()
316 print '*** Connection closed by remote host ***'
319 sys
.stdout
.write(text
)