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