blob: 0f20fb4cc0d9a277ba3e0ce471e77a3ff48679ca [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
33
34"""
35
36
37# Imported modules
38import socket
39import select
40import string
Guido van Rossumb9b50eb1997-12-24 21:07:04 +000041
42# Tunable parameters
43DEBUGLEVEL = 0
44
45# Telnet protocol defaults
46TELNET_PORT = 23
47
48# Telnet protocol characters (don't change)
49IAC = chr(255) # "Interpret As Command"
50DONT = chr(254)
51DO = chr(253)
52WONT = chr(252)
53WILL = chr(251)
54theNULL = chr(0)
55
56
57class Telnet:
58
59 """Telnet interface class.
60
61 An instance of this class represents a connection to a telnet
62 server. The instance is initially not connected; the open()
63 method must be used to establish a connection. Alternatively, the
64 host name and optional port number can be passed to the
65 constructor, too.
66
67 Don't try to reopen an already connected instance.
68
69 This class has many read_*() methods. Note that some of them
70 raise EOFError when the end of the connection is read, because
71 they can return an empty string for other reasons. See the
72 individual doc strings.
73
74 read_until(expected, [timeout])
75 Read until the expected string has been seen, or a timeout is
76 hit (default is no timeout); may block.
77
78 read_all()
79 Read all data until EOF; may block.
80
81 read_some()
82 Read at least one byte or EOF; may block.
83
84 read_very_eager()
85 Read all data available already queued or on the socket,
86 without blocking.
87
88 read_eager()
89 Read either data already queued or some data available on the
90 socket, without blocking.
91
92 read_lazy()
93 Read all data in the raw queue (processing it first), without
94 doing any socket I/O.
95
96 read_very_lazy()
97 Reads all data in the cooked queue, without doing any socket
98 I/O.
99
100 """
101
102 def __init__(self, host=None, port=0):
103 """Constructor.
104
105 When called without arguments, create an unconnected instance.
106 With a hostname argument, it connects the instance; a port
107 number is optional.
108
109 """
110 self.debuglevel = DEBUGLEVEL
111 self.host = host
112 self.port = port
113 self.sock = None
114 self.rawq = ''
115 self.irawq = 0
116 self.cookedq = ''
117 self.eof = 0
118 if host:
119 self.open(host, port)
120
121 def open(self, host, port=0):
122 """Connect to a host.
123
124 The optional second argument is the port number, which
125 defaults to the standard telnet port (23).
126
127 Don't try to reopen an already connected instance.
128
129 """
130 self.eof = 0
131 if not port:
132 port = TELNET_PORT
133 self.host = host
134 self.port = port
135 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
136 self.sock.connect((self.host, self.port))
137
138 def __del__(self):
139 """Destructor -- close the connection."""
140 self.close()
141
142 def msg(self, msg, *args):
143 """Print a debug message, when the debug level is > 0.
144
145 If extra arguments are present, they are substituted in the
146 message using the standard string formatting operator.
147
148 """
149 if self.debuglevel > 0:
150 print 'Telnet(%s,%d):' % (self.host, self.port),
151 if args:
152 print msg % args
153 else:
154 print msg
155
156 def set_debuglevel(self, debuglevel):
157 """Set the debug level.
158
159 The higher it is, the more debug output you get (on sys.stdout).
160
161 """
162 self.debuglevel = debuglevel
163
164 def close(self):
165 """Close the connection."""
166 if self.sock:
167 self.sock.close()
168 self.sock = 0
169 self.eof = 1
170
171 def get_socket(self):
172 """Return the socket object used internally."""
173 return self.sock
174
175 def fileno(self):
176 """Return the fileno() of the socket object used internally."""
177 return self.sock.fileno()
178
179 def write(self, buffer):
180 """Write a string to the socket, doubling any IAC characters.
181
182 Can block if the connection is blocked. May raise
183 socket.error if the connection is closed.
184
185 """
186 if IAC in buffer:
Guido van Rossum00f9fea1997-12-24 21:18:41 +0000187 buffer = string.replace(buffer, IAC, IAC+IAC)
Guido van Rossumb9b50eb1997-12-24 21:07:04 +0000188 self.sock.send(buffer)
189
190 def read_until(self, match, timeout=None):
191 """Read until a given string is encountered or until timeout.
192
193 When no match is found, return whatever is available instead,
194 possibly the empty string. Raise EOFError if the connection
195 is closed and no cooked data is available.
196
197 """
198 n = len(match)
199 self.process_rawq()
200 i = string.find(self.cookedq, match)
201 if i >= 0:
202 i = i+n
203 buf = self.cookedq[:i]
204 self.cookedq = self.cookedq[i:]
205 return buf
206 s_reply = ([self], [], [])
207 s_args = s_reply
208 if timeout is not None:
209 s_args = s_args + (timeout,)
210 while not self.eof and apply(select.select, s_args) == s_reply:
211 i = max(0, len(self.cookedq)-n)
212 self.fill_rawq()
213 self.process_rawq()
214 i = string.find(self.cookedq, match, i)
215 if i >= 0:
216 i = i+n
217 buf = self.cookedq[:i]
218 self.cookedq = self.cookedq[i:]
219 return buf
220 return self.read_very_lazy()
221
222 def read_all(self):
223 """Read all data until EOF; block until connection closed."""
224 self.process_rawq()
225 while not self.eof:
226 self.fill_rawq()
227 self.process_rawq()
228 buf = self.cookedq
229 self.cookedq = ''
230 return buf
231
232 def read_some(self):
233 """Read at least one byte of cooked data unless EOF is hit.
234
235 Return '' if EOF is hit. Block if no data is immediately
236 available.
237
238 """
239 self.process_rawq()
240 while not self.cookedq and not self.eof:
241 self.fill_rawq()
242 self.process_rawq()
243 buf = self.cookedq
244 self.cookedq = ''
245 return buf
246
247 def read_very_eager(self):
248 """Read everything that's possible without blocking in I/O (eager).
249
250 Raise EOFError if connection closed and no cooked data
251 available. Return '' if no cooked data available otherwise.
252 Don't block unless in the midst of an IAC sequence.
253
254 """
255 self.process_rawq()
256 while not self.eof and self.sock_avail():
257 self.fill_rawq()
258 self.process_rawq()
259 return self.read_very_lazy()
260
261 def read_eager(self):
262 """Read readily available data.
263
264 Raise EOFError if connection closed and no cooked data
265 available. Return '' if no cooked data available otherwise.
266 Don't block unless in the midst of an IAC sequence.
267
268 """
269 self.process_rawq()
270 while not self.cookedq and not self.eof and self.sock_avail():
271 self.fill_rawq()
272 self.process_rawq()
273 return self.read_very_lazy()
274
275 def read_lazy(self):
276 """Process and return data that's already in the queues (lazy).
277
278 Raise EOFError if connection closed and no data available.
279 Return '' if no cooked data available otherwise. Don't block
280 unless in the midst of an IAC sequence.
281
282 """
283 self.process_rawq()
284 return self.read_very_lazy()
285
286 def read_very_lazy(self):
287 """Return any data available in the cooked queue (very lazy).
288
289 Raise EOFError if connection closed and no data available.
290 Return '' if no cooked data available otherwise. Don't block.
291
292 """
293 buf = self.cookedq
294 self.cookedq = ''
295 if not buf and self.eof and not self.rawq:
296 raise EOFError, 'telnet connection closed'
297 return buf
298
299 def process_rawq(self):
300 """Transfer from raw queue to cooked queue.
301
302 Set self.eof when connection is closed. Don't block unless in
303 the midst of an IAC sequence.
304
305 """
306 buf = ''
307 try:
308 while self.rawq:
309 c = self.rawq_getchar()
310 if c == theNULL:
311 continue
312 if c == "\021":
313 continue
314 if c != IAC:
315 buf = buf + c
316 continue
317 c = self.rawq_getchar()
318 if c == IAC:
319 buf = buf + c
320 elif c in (DO, DONT):
321 opt = self.rawq_getchar()
322 self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
323 self.sock.send(IAC + WONT + opt)
324 elif c in (WILL, WONT):
325 opt = self.rawq_getchar()
326 self.msg('IAC %s %d',
327 c == WILL and 'WILL' or 'WONT', ord(c))
328 else:
329 self.msg('IAC %s not recognized' % `c`)
330 except EOFError: # raised by self.rawq_getchar()
331 pass
332 self.cookedq = self.cookedq + buf
333
334 def rawq_getchar(self):
335 """Get next char from raw queue.
336
337 Block if no data is immediately available. Raise EOFError
338 when connection is closed.
339
340 """
341 if not self.rawq:
342 self.fill_rawq()
343 if self.eof:
344 raise EOFError
345 c = self.rawq[self.irawq]
346 self.irawq = self.irawq + 1
347 if self.irawq >= len(self.rawq):
348 self.rawq = ''
349 self.irawq = 0
350 return c
351
352 def fill_rawq(self):
353 """Fill raw queue from exactly one recv() system call.
354
355 Block if no data is immediately available. Set self.eof when
356 connection is closed.
357
358 """
359 if self.irawq >= len(self.rawq):
360 self.rawq = ''
361 self.irawq = 0
362 # The buffer size should be fairly small so as to avoid quadratic
363 # behavior in process_rawq() above
364 buf = self.sock.recv(50)
365 self.eof = (not buf)
366 self.rawq = self.rawq + buf
367
368 def sock_avail(self):
369 """Test whether data is available on the socket."""
370 return select.select([self], [], [], 0) == ([self], [], [])
371
372 def interact(self):
373 """Interaction function, emulates a very dumb telnet client."""
374 import sys, select
375 while 1:
376 rfd, wfd, xfd = select.select([self, sys.stdin], [], [])
377 if sys.stdin in rfd:
378 line = sys.stdin.readline()
379 self.write(line)
380 if self in rfd:
381 try:
382 text = self.read_eager()
383 except EOFError:
384 print '*** Connection closed by remote host ***'
385 break
386 if text:
387 sys.stdout.write(text)
388 sys.stdout.flush()
389 self.close()
390
391
392
393def test():
394 """Test program for telnetlib.
395
396 Usage: python telnetlib.py [-d] ... [host [port]]
397
398 Default host is localhost; default port is 23.
399
400 """
401 import sys
402 debuglevel = 0
403 while sys.argv[1:] and sys.argv[1] == '-d':
404 debuglevel = debuglevel+1
405 del sys.argv[1]
406 host = 'localhost'
407 if sys.argv[1:]:
408 host = sys.argv[1]
409 port = 0
410 if sys.argv[2:]:
411 portstr = sys.argv[2]
412 try:
413 port = int(portstr)
414 except ValueError:
415 port = socket.getservbyname(portstr, 'tcp')
416 tn = Telnet()
417 tn.set_debuglevel(debuglevel)
418 tn.open(host, port)
419 tn.interact()
420 tn.close()
421
422if __name__ == '__main__':
423 test()