1 """TELNET client class.
3 Based on RFC 854: TELNET Protocol Specification, by J. Postel and
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()
12 Login Name TTY Idle When Where
13 guido Guido van Rossum pts/2 <Dec 2 11:10> snag.cnri.reston..
17 Note 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.
20 It is possible to pass a Telnet object to select.select() in order to
21 wait until more data is available. Note that in this case,
22 read_eager() may return '' even if there was data on the socket,
23 because the protocol negotiation may have eaten the data. This is why
24 EOFError is needed in some cases to distinguish between "no data" and
25 "connection closed" (since the socket also appears ready for reading
29 - may hang when connection is slow in the middle of an IAC sequence
33 - timeout should be intrinsic to the connection object instead of an
34 option on one of the read calls only
49 # Telnet protocol defaults
52 # Telnet protocol characters (don't change)
53 IAC
= chr(255) # "Interpret As Command"
63 """Telnet interface class.
65 An instance of this class represents a connection to a telnet
66 server. The instance is initially not connected; the open()
67 method must be used to establish a connection. Alternatively, the
68 host name and optional port number can be passed to the
71 Don't try to reopen an already connected instance.
73 This class has many read_*() methods. Note that some of them
74 raise EOFError when the end of the connection is read, because
75 they can return an empty string for other reasons. See the
76 individual doc strings.
78 read_until(expected, [timeout])
79 Read until the expected string has been seen, or a timeout is
80 hit (default is no timeout); may block.
83 Read all data until EOF; may block.
86 Read at least one byte or EOF; may block.
89 Read all data available already queued or on the socket,
93 Read either data already queued or some data available on the
94 socket, without blocking.
97 Read all data in the raw queue (processing it first), without
101 Reads all data in the cooked queue, without doing any socket
106 def __init__(self
, host
=None, port
=0):
109 When called without arguments, create an unconnected instance.
110 With a hostname argument, it connects the instance; a port
114 self
.debuglevel
= DEBUGLEVEL
123 self
.open(host
, port
)
125 def open(self
, host
, port
=0):
126 """Connect to a host.
128 The optional second argument is the port number, which
129 defaults to the standard telnet port (23).
131 Don't try to reopen an already connected instance.
139 msg
= "getaddrinfo returns an empty list"
140 for res
in socket
.getaddrinfo(host
, port
, 0, socket
.SOCK_STREAM
):
141 af
, socktype
, proto
, canonname
, sa
= res
143 self
.sock
= socket
.socket(af
, socktype
, proto
)
144 self
.sock
.connect(sa
)
145 except socket
.error
, msg
:
151 raise socket
.error
, msg
154 """Destructor -- close the connection."""
157 def msg(self
, msg
, *args
):
158 """Print a debug message, when the debug level is > 0.
160 If extra arguments are present, they are substituted in the
161 message using the standard string formatting operator.
164 if self
.debuglevel
> 0:
165 print 'Telnet(%s,%d):' % (self
.host
, self
.port
),
171 def set_debuglevel(self
, debuglevel
):
172 """Set the debug level.
174 The higher it is, the more debug output you get (on sys.stdout).
177 self
.debuglevel
= debuglevel
180 """Close the connection."""
186 def get_socket(self
):
187 """Return the socket object used internally."""
191 """Return the fileno() of the socket object used internally."""
192 return self
.sock
.fileno()
194 def write(self
, buffer):
195 """Write a string to the socket, doubling any IAC characters.
197 Can block if the connection is blocked. May raise
198 socket.error if the connection is closed.
202 buffer = buffer.replace(IAC
, IAC
+IAC
)
203 self
.msg("send %s", `
buffer`
)
204 self
.sock
.send(buffer)
206 def read_until(self
, match
, timeout
=None):
207 """Read until a given string is encountered or until timeout.
209 When no match is found, return whatever is available instead,
210 possibly the empty string. Raise EOFError if the connection
211 is closed and no cooked data is available.
216 i
= self
.cookedq
.find(match
)
219 buf
= self
.cookedq
[:i
]
220 self
.cookedq
= self
.cookedq
[i
:]
222 s_reply
= ([self
], [], [])
224 if timeout
is not None:
225 s_args
= s_args
+ (timeout
,)
226 while not self
.eof
and apply(select
.select
, s_args
) == s_reply
:
227 i
= max(0, len(self
.cookedq
)-n
)
230 i
= self
.cookedq
.find(match
, i
)
233 buf
= self
.cookedq
[:i
]
234 self
.cookedq
= self
.cookedq
[i
:]
236 return self
.read_very_lazy()
239 """Read all data until EOF; block until connection closed."""
249 """Read at least one byte of cooked data unless EOF is hit.
251 Return '' if EOF is hit. Block if no data is immediately
256 while not self
.cookedq
and not self
.eof
:
263 def read_very_eager(self
):
264 """Read everything that's possible without blocking in I/O (eager).
266 Raise EOFError if connection closed and no cooked data
267 available. Return '' if no cooked data available otherwise.
268 Don't block unless in the midst of an IAC sequence.
272 while not self
.eof
and self
.sock_avail():
275 return self
.read_very_lazy()
277 def read_eager(self
):
278 """Read readily available data.
280 Raise EOFError if connection closed and no cooked data
281 available. Return '' if no cooked data available otherwise.
282 Don't block unless in the midst of an IAC sequence.
286 while not self
.cookedq
and not self
.eof
and self
.sock_avail():
289 return self
.read_very_lazy()
292 """Process and return data that's already in the queues (lazy).
294 Raise EOFError if connection closed and no data available.
295 Return '' if no cooked data available otherwise. Don't block
296 unless in the midst of an IAC sequence.
300 return self
.read_very_lazy()
302 def read_very_lazy(self
):
303 """Return any data available in the cooked queue (very lazy).
305 Raise EOFError if connection closed and no data available.
306 Return '' if no cooked data available otherwise. Don't block.
311 if not buf
and self
.eof
and not self
.rawq
:
312 raise EOFError, 'telnet connection closed'
315 def process_rawq(self
):
316 """Transfer from raw queue to cooked queue.
318 Set self.eof when connection is closed. Don't block unless in
319 the midst of an IAC sequence.
325 c
= self
.rawq_getchar()
333 c
= self
.rawq_getchar()
336 elif c
in (DO
, DONT
):
337 opt
= self
.rawq_getchar()
338 self
.msg('IAC %s %d', c
== DO
and 'DO' or 'DONT', ord(c
))
339 self
.sock
.send(IAC
+ WONT
+ opt
)
340 elif c
in (WILL
, WONT
):
341 opt
= self
.rawq_getchar()
342 self
.msg('IAC %s %d',
343 c
== WILL
and 'WILL' or 'WONT', ord(c
))
344 self
.sock
.send(IAC
+ DONT
+ opt
)
346 self
.msg('IAC %s not recognized' % `c`
)
347 except EOFError: # raised by self.rawq_getchar()
349 self
.cookedq
= self
.cookedq
+ buf
351 def rawq_getchar(self
):
352 """Get next char from raw queue.
354 Block if no data is immediately available. Raise EOFError
355 when connection is closed.
362 c
= self
.rawq
[self
.irawq
]
363 self
.irawq
= self
.irawq
+ 1
364 if self
.irawq
>= len(self
.rawq
):
370 """Fill raw queue from exactly one recv() system call.
372 Block if no data is immediately available. Set self.eof when
373 connection is closed.
376 if self
.irawq
>= len(self
.rawq
):
379 # The buffer size should be fairly small so as to avoid quadratic
380 # behavior in process_rawq() above
381 buf
= self
.sock
.recv(50)
382 self
.msg("recv %s", `buf`
)
384 self
.rawq
= self
.rawq
+ buf
386 def sock_avail(self
):
387 """Test whether data is available on the socket."""
388 return select
.select([self
], [], [], 0) == ([self
], [], [])
391 """Interaction function, emulates a very dumb telnet client."""
392 if sys
.platform
== "win32":
396 rfd
, wfd
, xfd
= select
.select([self
, sys
.stdin
], [], [])
399 text
= self
.read_eager()
401 print '*** Connection closed by remote host ***'
404 sys
.stdout
.write(text
)
407 line
= sys
.stdin
.readline()
412 def mt_interact(self
):
413 """Multithreaded version of interact()."""
415 thread
.start_new_thread(self
.listener
, ())
417 line
= sys
.stdin
.readline()
423 """Helper for mt_interact() -- this executes in the other thread."""
426 data
= self
.read_eager()
428 print '*** Connection closed by remote host ***'
431 sys
.stdout
.write(data
)
435 def expect(self
, list, timeout
=None):
436 """Read until one from a list of a regular expressions matches.
438 The first argument is a list of regular expressions, either
439 compiled (re.RegexObject instances) or uncompiled (strings).
440 The optional second argument is a timeout, in seconds; default
443 Return a tuple of three items: the index in the list of the
444 first regular expression that matches; the match object
445 returned; and the text read up till and including the match.
447 If EOF is read and no text was read, raise EOFError.
448 Otherwise, when nothing matches, return (-1, None, text) where
449 text is the text received so far (may be the empty string if a
452 If a regular expression ends with a greedy match (e.g. '.*')
453 or if more than one expression can match the same input, the
454 results are undeterministic, and may depend on the I/O timing.
459 indices
= range(len(list))
461 if not hasattr(list[i
], "search"):
463 list[i
] = re
.compile(list[i
])
467 m
= list[i
].search(self
.cookedq
)
470 text
= self
.cookedq
[:e
]
471 self
.cookedq
= self
.cookedq
[e
:]
475 if timeout
is not None:
476 r
, w
, x
= select
.select([self
.fileno()], [], [], timeout
)
480 text
= self
.read_very_lazy()
481 if not text
and self
.eof
:
483 return (-1, None, text
)
487 """Test program for telnetlib.
489 Usage: python telnetlib.py [-d] ... [host [port]]
491 Default host is localhost; default port is 23.
495 while sys
.argv
[1:] and sys
.argv
[1] == '-d':
496 debuglevel
= debuglevel
+1
503 portstr
= sys
.argv
[2]
507 port
= socket
.getservbyname(portstr
, 'tcp')
509 tn
.set_debuglevel(debuglevel
)
514 if __name__
== '__main__':