blob: 1a1c75edfdeb249dcd6d9959e81e7027dc2eb8bd [file] [log] [blame]
Guido van Rossumb9b50eb1997-12-24 21:07:04 +00001"""TELNET client class.
2
3Based on RFC 854: TELNET Protocol Specification, by J. Postel and
4J. Reynolds
5
6Example:
7
8>>> from telnetlib import Telnet
9>>> tn = Telnet('www.python.org', 79) # connect to finger port
10>>> tn.write('guido\r\n')
11>>> print tn.read_all()
12Login Name TTY Idle When Where
13guido Guido van Rossum pts/2 <Dec 2 11:10> snag.cnri.reston..
14
15>>>
16
17Note that read_all() won't read until eof -- it just reads some data
18-- but it guarantees to read at least one byte unless EOF is hit.
19
20It is possible to pass a Telnet object to select.select() in order to
21wait until more data is available. Note that in this case,
22read_eager() may return '' even if there was data on the socket,
23because the protocol negotiation may have eaten the data. This is why
24EOFError is needed in some cases to distinguish between "no data" and
25"connection closed" (since the socket also appears ready for reading
26when it is closed).
27
28Bugs:
29- may hang when connection is slow in the middle of an IAC sequence
30
31To do:
32- option negotiation
Guido van Rossumccb5ec61997-12-24 22:24:19 +000033- timeout should be intrinsic to the connection object instead of an
34 option on one of the read calls only
Guido van Rossumb9b50eb1997-12-24 21:07:04 +000035
36"""
37
38
39# Imported modules
Guido van Rossumccb5ec61997-12-24 22:24:19 +000040import sys
Guido van Rossumb9b50eb1997-12-24 21:07:04 +000041import socket
42import select
43import string
Guido van Rossumb9b50eb1997-12-24 21:07:04 +000044
45# Tunable parameters
46DEBUGLEVEL = 0
47
48# Telnet protocol defaults
49TELNET_PORT = 23
50
51# Telnet protocol characters (don't change)
52IAC = chr(255) # "Interpret As Command"
53DONT = chr(254)
54DO = chr(253)
55WONT = chr(252)
56WILL = chr(251)
57theNULL = chr(0)
58
59
60class Telnet:
61
62 """Telnet interface class.
63
64 An instance of this class represents a connection to a telnet
65 server. The instance is initially not connected; the open()
66 method must be used to establish a connection. Alternatively, the
67 host name and optional port number can be passed to the
68 constructor, too.
69
70 Don't try to reopen an already connected instance.
71
72 This class has many read_*() methods. Note that some of them
73 raise EOFError when the end of the connection is read, because
74 they can return an empty string for other reasons. See the
75 individual doc strings.
76
77 read_until(expected, [timeout])
78 Read until the expected string has been seen, or a timeout is
79 hit (default is no timeout); may block.
80
81 read_all()
82 Read all data until EOF; may block.
83
84 read_some()
85 Read at least one byte or EOF; may block.
86
87 read_very_eager()
88 Read all data available already queued or on the socket,
89 without blocking.
90
91 read_eager()
92 Read either data already queued or some data available on the
93 socket, without blocking.
94
95 read_lazy()
96 Read all data in the raw queue (processing it first), without
97 doing any socket I/O.
98
99 read_very_lazy()
100 Reads all data in the cooked queue, without doing any socket
101 I/O.
102
103 """
104
105 def __init__(self, host=None, port=0):
106 """Constructor.
107
108 When called without arguments, create an unconnected instance.
109 With a hostname argument, it connects the instance; a port
110 number is optional.
111
112 """
113 self.debuglevel = DEBUGLEVEL
114 self.host = host
115 self.port = port
116 self.sock = None
117 self.rawq = ''
118 self.irawq = 0
119 self.cookedq = ''
120 self.eof = 0
121 if host:
122 self.open(host, port)
123
124 def open(self, host, port=0):
125 """Connect to a host.
126
127 The optional second argument is the port number, which
128 defaults to the standard telnet port (23).
129
130 Don't try to reopen an already connected instance.
131
132 """
133 self.eof = 0
134 if not port:
135 port = TELNET_PORT
136 self.host = host
137 self.port = port
138 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
139 self.sock.connect((self.host, self.port))
140
141 def __del__(self):
142 """Destructor -- close the connection."""
143 self.close()
144
145 def msg(self, msg, *args):
146 """Print a debug message, when the debug level is > 0.
147
148 If extra arguments are present, they are substituted in the
149 message using the standard string formatting operator.
150
151 """
152 if self.debuglevel > 0:
153 print 'Telnet(%s,%d):' % (self.host, self.port),
154 if args:
155 print msg % args
156 else:
157 print msg
158
159 def set_debuglevel(self, debuglevel):
160 """Set the debug level.
161
162 The higher it is, the more debug output you get (on sys.stdout).
163
164 """
165 self.debuglevel = debuglevel
166
167 def close(self):
168 """Close the connection."""
169 if self.sock:
170 self.sock.close()
171 self.sock = 0
172 self.eof = 1
173
174 def get_socket(self):
175 """Return the socket object used internally."""
176 return self.sock
177
178 def fileno(self):
179 """Return the fileno() of the socket object used internally."""
180 return self.sock.fileno()
181
182 def write(self, buffer):
183 """Write a string to the socket, doubling any IAC characters.
184
185 Can block if the connection is blocked. May raise
186 socket.error if the connection is closed.
187
188 """
189 if IAC in buffer:
Guido van Rossum00f9fea1997-12-24 21:18:41 +0000190 buffer = string.replace(buffer, IAC, IAC+IAC)
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000191 self.sock.send(buffer)
192
193 def read_until(self, match, timeout=None):
194 """Read until a given string is encountered or until timeout.
195
196 When no match is found, return whatever is available instead,
197 possibly the empty string. Raise EOFError if the connection
198 is closed and no cooked data is available.
199
200 """
201 n = len(match)
202 self.process_rawq()
203 i = string.find(self.cookedq, match)
204 if i >= 0:
205 i = i+n
206 buf = self.cookedq[:i]
207 self.cookedq = self.cookedq[i:]
208 return buf
209 s_reply = ([self], [], [])
210 s_args = s_reply
211 if timeout is not None:
212 s_args = s_args + (timeout,)
213 while not self.eof and apply(select.select, s_args) == s_reply:
214 i = max(0, len(self.cookedq)-n)
215 self.fill_rawq()
216 self.process_rawq()
217 i = string.find(self.cookedq, match, i)
218 if i >= 0:
219 i = i+n
220 buf = self.cookedq[:i]
221 self.cookedq = self.cookedq[i:]
222 return buf
223 return self.read_very_lazy()
224
225 def read_all(self):
226 """Read all data until EOF; block until connection closed."""
227 self.process_rawq()
228 while not self.eof:
229 self.fill_rawq()
230 self.process_rawq()
231 buf = self.cookedq
232 self.cookedq = ''
233 return buf
234
235 def read_some(self):
236 """Read at least one byte of cooked data unless EOF is hit.
237
238 Return '' if EOF is hit. Block if no data is immediately
239 available.
240
241 """
242 self.process_rawq()
243 while not self.cookedq and not self.eof:
244 self.fill_rawq()
245 self.process_rawq()
246 buf = self.cookedq
247 self.cookedq = ''
248 return buf
249
250 def read_very_eager(self):
251 """Read everything that's possible without blocking in I/O (eager).
252
253 Raise EOFError if connection closed and no cooked data
254 available. Return '' if no cooked data available otherwise.
255 Don't block unless in the midst of an IAC sequence.
256
257 """
258 self.process_rawq()
259 while not self.eof and self.sock_avail():
260 self.fill_rawq()
261 self.process_rawq()
262 return self.read_very_lazy()
263
264 def read_eager(self):
265 """Read readily available data.
266
267 Raise EOFError if connection closed and no cooked data
268 available. Return '' if no cooked data available otherwise.
269 Don't block unless in the midst of an IAC sequence.
270
271 """
272 self.process_rawq()
273 while not self.cookedq and not self.eof and self.sock_avail():
274 self.fill_rawq()
275 self.process_rawq()
276 return self.read_very_lazy()
277
278 def read_lazy(self):
279 """Process and return data that's already in the queues (lazy).
280
281 Raise EOFError if connection closed and no data available.
282 Return '' if no cooked data available otherwise. Don't block
283 unless in the midst of an IAC sequence.
284
285 """
286 self.process_rawq()
287 return self.read_very_lazy()
288
289 def read_very_lazy(self):
290 """Return any data available in the cooked queue (very lazy).
291
292 Raise EOFError if connection closed and no data available.
293 Return '' if no cooked data available otherwise. Don't block.
294
295 """
296 buf = self.cookedq
297 self.cookedq = ''
298 if not buf and self.eof and not self.rawq:
299 raise EOFError, 'telnet connection closed'
300 return buf
301
302 def process_rawq(self):
303 """Transfer from raw queue to cooked queue.
304
305 Set self.eof when connection is closed. Don't block unless in
306 the midst of an IAC sequence.
307
308 """
309 buf = ''
310 try:
311 while self.rawq:
312 c = self.rawq_getchar()
313 if c == theNULL:
314 continue
315 if c == "\021":
316 continue
317 if c != IAC:
318 buf = buf + c
319 continue
320 c = self.rawq_getchar()
321 if c == IAC:
322 buf = buf + c
323 elif c in (DO, DONT):
324 opt = self.rawq_getchar()
325 self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
326 self.sock.send(IAC + WONT + opt)
327 elif c in (WILL, WONT):
328 opt = self.rawq_getchar()
329 self.msg('IAC %s %d',
330 c == WILL and 'WILL' or 'WONT', ord(c))
331 else:
332 self.msg('IAC %s not recognized' % `c`)
333 except EOFError: # raised by self.rawq_getchar()
334 pass
335 self.cookedq = self.cookedq + buf
336
337 def rawq_getchar(self):
338 """Get next char from raw queue.
339
340 Block if no data is immediately available. Raise EOFError
341 when connection is closed.
342
343 """
344 if not self.rawq:
345 self.fill_rawq()
346 if self.eof:
347 raise EOFError
348 c = self.rawq[self.irawq]
349 self.irawq = self.irawq + 1
350 if self.irawq >= len(self.rawq):
351 self.rawq = ''
352 self.irawq = 0
353 return c
354
355 def fill_rawq(self):
356 """Fill raw queue from exactly one recv() system call.
357
358 Block if no data is immediately available. Set self.eof when
359 connection is closed.
360
361 """
362 if self.irawq >= len(self.rawq):
363 self.rawq = ''
364 self.irawq = 0
365 # The buffer size should be fairly small so as to avoid quadratic
366 # behavior in process_rawq() above
367 buf = self.sock.recv(50)
368 self.eof = (not buf)
369 self.rawq = self.rawq + buf
370
371 def sock_avail(self):
372 """Test whether data is available on the socket."""
373 return select.select([self], [], [], 0) == ([self], [], [])
374
375 def interact(self):
376 """Interaction function, emulates a very dumb telnet client."""
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000377 while 1:
378 rfd, wfd, xfd = select.select([self, sys.stdin], [], [])
379 if sys.stdin in rfd:
380 line = sys.stdin.readline()
381 self.write(line)
382 if self in rfd:
383 try:
384 text = self.read_eager()
385 except EOFError:
386 print '*** Connection closed by remote host ***'
387 break
388 if text:
389 sys.stdout.write(text)
390 sys.stdout.flush()
391 self.close()
392
Guido van Rossumccb5ec61997-12-24 22:24:19 +0000393 def expect(self, list, timeout=None):
394 """Read until one from a list of a regular expressions matches.
395
396 The first argument is a list of regular expressions, either
397 compiled (re.RegexObject instances) or uncompiled (strings).
398 The optional second argument is a timeout, in seconds; default
399 is no timeout.
400
401 Return a tuple of three items: the index in the list of the
402 first regular expression that matches; the match object
403 returned; and the text read up till and including the match.
404
405 If EOF is read and no text was read, raise EOFError.
406 Otherwise, when nothing matches, return (-1, None, text) where
407 text is the text received so far (may be the empty string if a
408 timeout happened).
409
410 If a regular expression ends with a greedy match (e.g. '.*')
411 or if more than one expression can match the same input, the
412 results are undeterministic, and may depend on the I/O timing.
413
414 """
415 re = None
416 list = list[:]
417 indices = range(len(list))
418 for i in indices:
419 if not hasattr(list[i], "search"):
420 if not re: import re
421 list[i] = re.compile(list[i])
422 while 1:
423 self.process_rawq()
424 for i in indices:
425 m = list[i].search(self.cookedq)
426 if m:
427 e = m.end()
428 text = self.cookedq[:e]
429 self.cookedq = self.cookedq[e:]
430 return (i, m, text)
431 if self.eof:
432 break
433 if timeout is not None:
434 r, w, x = select.select([self.fileno()], [], [], timeout)
435 if not r:
436 break
437 self.fill_rawq()
438 text = self.read_very_lazy()
439 if not text and self.eof:
440 raise EOFError
441 return (-1, None, text)
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000442
443
444def test():
445 """Test program for telnetlib.
446
447 Usage: python telnetlib.py [-d] ... [host [port]]
448
449 Default host is localhost; default port is 23.
450
451 """
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000452 debuglevel = 0
453 while sys.argv[1:] and sys.argv[1] == '-d':
454 debuglevel = debuglevel+1
455 del sys.argv[1]
456 host = 'localhost'
457 if sys.argv[1:]:
458 host = sys.argv[1]
459 port = 0
460 if sys.argv[2:]:
461 portstr = sys.argv[2]
462 try:
463 port = int(portstr)
464 except ValueError:
465 port = socket.getservbyname(portstr, 'tcp')
466 tn = Telnet()
467 tn.set_debuglevel(debuglevel)
468 tn.open(host, port)
469 tn.interact()
470 tn.close()
471
472if __name__ == '__main__':
473 test()