blob: 2012e16d41e13b742cffdb4d8bf2abd7920c3076 [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 Rossum2fc4d581998-02-19 21:19:48 +0000191 self.msg("send %s", `buffer`)
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000192 self.sock.send(buffer)
193
194 def read_until(self, match, timeout=None):
195 """Read until a given string is encountered or until timeout.
196
197 When no match is found, return whatever is available instead,
198 possibly the empty string. Raise EOFError if the connection
199 is closed and no cooked data is available.
200
201 """
202 n = len(match)
203 self.process_rawq()
204 i = string.find(self.cookedq, match)
205 if i >= 0:
206 i = i+n
207 buf = self.cookedq[:i]
208 self.cookedq = self.cookedq[i:]
209 return buf
210 s_reply = ([self], [], [])
211 s_args = s_reply
212 if timeout is not None:
213 s_args = s_args + (timeout,)
214 while not self.eof and apply(select.select, s_args) == s_reply:
215 i = max(0, len(self.cookedq)-n)
216 self.fill_rawq()
217 self.process_rawq()
218 i = string.find(self.cookedq, match, i)
219 if i >= 0:
220 i = i+n
221 buf = self.cookedq[:i]
222 self.cookedq = self.cookedq[i:]
223 return buf
224 return self.read_very_lazy()
225
226 def read_all(self):
227 """Read all data until EOF; block until connection closed."""
228 self.process_rawq()
229 while not self.eof:
230 self.fill_rawq()
231 self.process_rawq()
232 buf = self.cookedq
233 self.cookedq = ''
234 return buf
235
236 def read_some(self):
237 """Read at least one byte of cooked data unless EOF is hit.
238
239 Return '' if EOF is hit. Block if no data is immediately
240 available.
241
242 """
243 self.process_rawq()
244 while not self.cookedq and not self.eof:
245 self.fill_rawq()
246 self.process_rawq()
247 buf = self.cookedq
248 self.cookedq = ''
249 return buf
250
251 def read_very_eager(self):
252 """Read everything that's possible without blocking in I/O (eager).
253
254 Raise EOFError if connection closed and no cooked data
255 available. Return '' if no cooked data available otherwise.
256 Don't block unless in the midst of an IAC sequence.
257
258 """
259 self.process_rawq()
260 while not self.eof and self.sock_avail():
261 self.fill_rawq()
262 self.process_rawq()
263 return self.read_very_lazy()
264
265 def read_eager(self):
266 """Read readily available data.
267
268 Raise EOFError if connection closed and no cooked data
269 available. Return '' if no cooked data available otherwise.
270 Don't block unless in the midst of an IAC sequence.
271
272 """
273 self.process_rawq()
274 while not self.cookedq and not self.eof and self.sock_avail():
275 self.fill_rawq()
276 self.process_rawq()
277 return self.read_very_lazy()
278
279 def read_lazy(self):
280 """Process and return data that's already in the queues (lazy).
281
282 Raise EOFError if connection closed and no data available.
283 Return '' if no cooked data available otherwise. Don't block
284 unless in the midst of an IAC sequence.
285
286 """
287 self.process_rawq()
288 return self.read_very_lazy()
289
290 def read_very_lazy(self):
291 """Return any data available in the cooked queue (very lazy).
292
293 Raise EOFError if connection closed and no data available.
294 Return '' if no cooked data available otherwise. Don't block.
295
296 """
297 buf = self.cookedq
298 self.cookedq = ''
299 if not buf and self.eof and not self.rawq:
300 raise EOFError, 'telnet connection closed'
301 return buf
302
303 def process_rawq(self):
304 """Transfer from raw queue to cooked queue.
305
306 Set self.eof when connection is closed. Don't block unless in
307 the midst of an IAC sequence.
308
309 """
310 buf = ''
311 try:
312 while self.rawq:
313 c = self.rawq_getchar()
314 if c == theNULL:
315 continue
316 if c == "\021":
317 continue
318 if c != IAC:
319 buf = buf + c
320 continue
321 c = self.rawq_getchar()
322 if c == IAC:
323 buf = buf + c
324 elif c in (DO, DONT):
325 opt = self.rawq_getchar()
326 self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
327 self.sock.send(IAC + WONT + opt)
328 elif c in (WILL, WONT):
329 opt = self.rawq_getchar()
330 self.msg('IAC %s %d',
331 c == WILL and 'WILL' or 'WONT', ord(c))
332 else:
333 self.msg('IAC %s not recognized' % `c`)
334 except EOFError: # raised by self.rawq_getchar()
335 pass
336 self.cookedq = self.cookedq + buf
337
338 def rawq_getchar(self):
339 """Get next char from raw queue.
340
341 Block if no data is immediately available. Raise EOFError
342 when connection is closed.
343
344 """
345 if not self.rawq:
346 self.fill_rawq()
347 if self.eof:
348 raise EOFError
349 c = self.rawq[self.irawq]
350 self.irawq = self.irawq + 1
351 if self.irawq >= len(self.rawq):
352 self.rawq = ''
353 self.irawq = 0
354 return c
355
356 def fill_rawq(self):
357 """Fill raw queue from exactly one recv() system call.
358
359 Block if no data is immediately available. Set self.eof when
360 connection is closed.
361
362 """
363 if self.irawq >= len(self.rawq):
364 self.rawq = ''
365 self.irawq = 0
366 # The buffer size should be fairly small so as to avoid quadratic
367 # behavior in process_rawq() above
368 buf = self.sock.recv(50)
Guido van Rossum2fc4d581998-02-19 21:19:48 +0000369 self.msg("recv %s", `buf`)
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000370 self.eof = (not buf)
371 self.rawq = self.rawq + buf
372
373 def sock_avail(self):
374 """Test whether data is available on the socket."""
375 return select.select([self], [], [], 0) == ([self], [], [])
376
377 def interact(self):
378 """Interaction function, emulates a very dumb telnet client."""
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000379 while 1:
380 rfd, wfd, xfd = select.select([self, sys.stdin], [], [])
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000381 if self in rfd:
382 try:
383 text = self.read_eager()
384 except EOFError:
385 print '*** Connection closed by remote host ***'
386 break
387 if text:
388 sys.stdout.write(text)
389 sys.stdout.flush()
Guido van Rossum5baf4bc1997-12-29 20:05:45 +0000390 if sys.stdin in rfd:
391 line = sys.stdin.readline()
392 if not line:
393 break
394 self.write(line)
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000395
Guido van Rossumccb5ec61997-12-24 22:24:19 +0000396 def expect(self, list, timeout=None):
397 """Read until one from a list of a regular expressions matches.
398
399 The first argument is a list of regular expressions, either
400 compiled (re.RegexObject instances) or uncompiled (strings).
401 The optional second argument is a timeout, in seconds; default
402 is no timeout.
403
404 Return a tuple of three items: the index in the list of the
405 first regular expression that matches; the match object
406 returned; and the text read up till and including the match.
407
408 If EOF is read and no text was read, raise EOFError.
409 Otherwise, when nothing matches, return (-1, None, text) where
410 text is the text received so far (may be the empty string if a
411 timeout happened).
412
413 If a regular expression ends with a greedy match (e.g. '.*')
414 or if more than one expression can match the same input, the
415 results are undeterministic, and may depend on the I/O timing.
416
417 """
418 re = None
419 list = list[:]
420 indices = range(len(list))
421 for i in indices:
422 if not hasattr(list[i], "search"):
423 if not re: import re
424 list[i] = re.compile(list[i])
425 while 1:
426 self.process_rawq()
427 for i in indices:
428 m = list[i].search(self.cookedq)
429 if m:
430 e = m.end()
431 text = self.cookedq[:e]
432 self.cookedq = self.cookedq[e:]
433 return (i, m, text)
434 if self.eof:
435 break
436 if timeout is not None:
437 r, w, x = select.select([self.fileno()], [], [], timeout)
438 if not r:
439 break
440 self.fill_rawq()
441 text = self.read_very_lazy()
442 if not text and self.eof:
443 raise EOFError
444 return (-1, None, text)
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000445
446
447def test():
448 """Test program for telnetlib.
449
450 Usage: python telnetlib.py [-d] ... [host [port]]
451
452 Default host is localhost; default port is 23.
453
454 """
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000455 debuglevel = 0
456 while sys.argv[1:] and sys.argv[1] == '-d':
457 debuglevel = debuglevel+1
458 del sys.argv[1]
459 host = 'localhost'
460 if sys.argv[1:]:
461 host = sys.argv[1]
462 port = 0
463 if sys.argv[2:]:
464 portstr = sys.argv[2]
465 try:
466 port = int(portstr)
467 except ValueError:
468 port = socket.getservbyname(portstr, 'tcp')
469 tn = Telnet()
470 tn.set_debuglevel(debuglevel)
471 tn.open(host, port)
472 tn.interact()
473 tn.close()
474
475if __name__ == '__main__':
476 test()