Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 1 | # A TELNET client class. Based on RFC 854: TELNET Protocol |
| 2 | # Specification, by J. Postel and J. Reynolds |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 3 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 4 | |
| 5 | # Example: |
| 6 | # |
| 7 | # >>> from telnetlib import Telnet |
| 8 | # >>> tn = Telnet('voorn.cwi.nl', 79) # connect to finger port |
| 9 | # >>> tn.write('guido\r\n') |
| 10 | # >>> print tn.read_all() |
| 11 | # Login name: guido In real life: Guido van Rossum |
| 12 | # Office: M353, x4127 Home phone: 020-6225521 |
| 13 | # Directory: /ufs/guido Shell: /usr/local/bin/esh |
| 14 | # On since Oct 28 11:02:16 on ttyq1 |
| 15 | # Project: Multimedia Kernel Systems |
| 16 | # No Plan. |
| 17 | # >>> |
| 18 | # |
| 19 | # Note that read() won't read until eof -- it just reads some data |
| 20 | # (but it guarantees to read at least one byte unless EOF is hit). |
| 21 | # |
| 22 | # It is possible to pass a Telnet object to select.select() in order |
| 23 | # to wait until more data is available. Note that in this case, |
| 24 | # read_eager() may return '' even if there was data on the socket, |
| 25 | # because the protocol negotiation may have eaten the data. |
| 26 | # This is why EOFError is needed to distinguish between "no data" |
| 27 | # and "connection closed" (since the socket also appears ready for |
| 28 | # reading when it is closed). |
| 29 | # |
| 30 | # Bugs: |
| 31 | # - may hang when connection is slow in the middle of an IAC sequence |
| 32 | # |
| 33 | # To do: |
| 34 | # - option negotiation |
| 35 | |
| 36 | |
| 37 | # Imported modules |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 38 | import socket |
| 39 | import select |
| 40 | import string |
| 41 | import regsub |
| 42 | |
| 43 | # Tunable parameters |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 44 | DEBUGLEVEL = 0 |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 45 | |
| 46 | # Telnet protocol defaults |
| 47 | TELNET_PORT = 23 |
| 48 | |
| 49 | # Telnet protocol characters (don't change) |
| 50 | IAC = chr(255) # "Interpret As Command" |
| 51 | DONT = chr(254) |
| 52 | DO = chr(253) |
| 53 | WONT = chr(252) |
| 54 | WILL = chr(251) |
| 55 | |
| 56 | |
| 57 | # Telnet interface class |
| 58 | |
| 59 | class Telnet: |
| 60 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 61 | # Constructor |
| 62 | def __init__(self, host, *args): |
| 63 | if not args: |
| 64 | port = TELNET_PORT |
| 65 | else: |
| 66 | if len(args) > 1: raise TypeError, 'too many args' |
| 67 | port = args[0] |
| 68 | if not port: port = TELNET_PORT |
| 69 | self.debuglevel = DEBUGLEVEL |
| 70 | self.host = host |
| 71 | self.port = port |
| 72 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 73 | self.sock.connect((self.host, self.port)) |
| 74 | self.rawq = '' |
| 75 | self.irawq = 0 |
| 76 | self.cookedq = '' |
| 77 | self.eof = 0 |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 78 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 79 | # Destructor |
| 80 | def __del__(self): |
| 81 | self.close() |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 82 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 83 | # Debug message |
| 84 | def msg(self, msg, *args): |
| 85 | if self.debuglevel > 0: |
| 86 | print 'Telnet(%s,%d):' % (self.host, self.port), msg % args |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 87 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 88 | # Set debug level |
| 89 | def set_debuglevel(self, debuglevel): |
| 90 | self.debuglevel = debuglevel |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 91 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 92 | # Explicit close |
| 93 | def close(self): |
| 94 | if self.sock: |
| 95 | self.sock.close() |
| 96 | self.sock = None |
| 97 | self.eof = 1 |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 98 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 99 | # Return socket (e.g. for select) |
| 100 | def get_socket(self): |
| 101 | return self.sock |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 102 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 103 | # Return socket's fileno (e.g. for select) |
| 104 | def fileno(self): |
| 105 | return self.sock.fileno() |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 106 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 107 | # Write a string to the socket, doubling any IAC characters |
| 108 | # Might block if the connection is blocked |
| 109 | # May raise socket.error if the connection is closed |
| 110 | def write(self, buffer): |
| 111 | if IAC in buffer: |
| 112 | buffer = regsub.gsub(IAC, IAC+IAC, buffer) |
| 113 | self.sock.send(buffer) |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 114 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 115 | # The following read_* methods exist: |
| 116 | # Special case: |
| 117 | # - read_until() reads until a string is encountered or a timeout is hit |
| 118 | # These may block: |
| 119 | # - read_all() reads all data until EOF |
| 120 | # - read_some() reads at least one byte until EOF |
| 121 | # These may do I/O but won't block doing it: |
| 122 | # - read_very_eager() reads all data available on the socket |
| 123 | # - read_eager() reads either data already queued or some data |
| 124 | # available on the socket |
| 125 | # These don't do I/O: |
| 126 | # - read_lazy() reads all data in the raw queue (processing it first) |
| 127 | # - read_very_lazy() reads all data in the cooked queue |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 128 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 129 | # Read until a given string is encountered or until timeout |
| 130 | # Raise EOFError if connection closed and no cooked data available |
| 131 | # Return '' if no cooked data available otherwise |
| 132 | def read_until(self, match, *args): |
| 133 | if not args: |
| 134 | timeout = None |
| 135 | else: |
| 136 | if len(args) > 1: raise TypeError, 'too many args' |
| 137 | timeout = args[0] |
| 138 | n = len(match) |
| 139 | self.process_rawq() |
| 140 | i = string.find(self.cookedq, match) |
| 141 | if i >= 0: |
| 142 | i = i+n |
| 143 | buf = self.cookedq[:i] |
| 144 | self.cookedq = self.cookedq[i:] |
| 145 | return buf |
| 146 | s_reply = ([self], [], []) |
| 147 | s_args = s_reply |
| 148 | if timeout is not None: |
| 149 | s_args = s_args + (timeout,) |
| 150 | while not self.eof and apply(select.select, s_args) == s_reply: |
| 151 | i = max(0, len(self.cookedq)-n) |
| 152 | self.fill_rawq() |
| 153 | self.process_rawq() |
| 154 | i = string.find(self.cookedq, match, i) |
| 155 | if i >= 0: |
| 156 | i = i+n |
| 157 | buf = self.cookedq[:i] |
| 158 | self.cookedq = self.cookedq[i:] |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 159 | return buf |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 160 | return self.read_very_lazy() |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 161 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 162 | # Read all data until EOF |
| 163 | # Block until connection closed |
| 164 | def read_all(self): |
| 165 | self.process_rawq() |
| 166 | while not self.eof: |
| 167 | self.fill_rawq() |
| 168 | self.process_rawq() |
| 169 | buf = self.cookedq |
| 170 | self.cookedq = '' |
| 171 | return buf |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 172 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 173 | # Read at least one byte of cooked data unless EOF is hit |
| 174 | # Return '' if EOF is hit |
| 175 | # Block if no data is immediately available |
| 176 | def read_some(self): |
| 177 | self.process_rawq() |
| 178 | while not self.cookedq and not self.eof: |
| 179 | self.fill_rawq() |
| 180 | self.process_rawq() |
| 181 | buf = self.cookedq |
| 182 | self.cookedq = '' |
| 183 | return buf |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 184 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 185 | # Read everything that's possible without blocking in I/O (eager) |
| 186 | # Raise EOFError if connection closed and no cooked data available |
| 187 | # Return '' if no cooked data available otherwise |
| 188 | # Don't block unless in the midst of an IAC sequence |
| 189 | def read_very_eager(self): |
| 190 | self.process_rawq() |
| 191 | while not self.eof and self.sock_avail(): |
| 192 | self.fill_rawq() |
| 193 | self.process_rawq() |
| 194 | return self.read_very_lazy() |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 195 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 196 | # Read readily available data |
| 197 | # Raise EOFError if connection closed and no cooked data available |
| 198 | # Return '' if no cooked data available otherwise |
| 199 | # Don't block unless in the midst of an IAC sequence |
| 200 | def read_eager(self): |
| 201 | self.process_rawq() |
| 202 | while not self.cookedq and not self.eof and self.sock_avail(): |
| 203 | self.fill_rawq() |
| 204 | self.process_rawq() |
| 205 | return self.read_very_lazy() |
Guido van Rossum | 74b3f8a | 1993-10-28 09:53:13 +0000 | [diff] [blame] | 206 | |
Guido van Rossum | e36f735 | 1993-11-01 14:49:37 +0000 | [diff] [blame] | 207 | # Process and return data that's already in the queues (lazy) |
| 208 | # Raise EOFError if connection closed and no data available |
| 209 | # Return '' if no cooked data available otherwise |
| 210 | # Don't block unless in the midst of an IAC sequence |
| 211 | def read_lazy(self): |
| 212 | self.process_rawq() |
| 213 | return self.read_very_lazy() |
| 214 | |
| 215 | # Return any data available in the cooked queue (very lazy) |
| 216 | # Raise EOFError if connection closed and no data available |
| 217 | # Return '' if no cooked data available otherwise |
| 218 | # Don't block |
| 219 | def read_very_lazy(self): |
| 220 | buf = self.cookedq |
| 221 | self.cookedq = '' |
| 222 | if not buf and self.eof and not self.rawq: |
| 223 | raise EOFError, 'telnet connection closed' |
| 224 | return buf |
| 225 | |
| 226 | # Transfer from raw queue to cooked queue |
| 227 | # Set self.eof when connection is closed |
| 228 | # Don't block unless in the midst of an IAC sequence |
| 229 | def process_rawq(self): |
| 230 | buf = '' |
| 231 | try: |
| 232 | while self.rawq: |
| 233 | c = self.rawq_getchar() |
| 234 | if c != IAC: |
| 235 | buf = buf + c |
| 236 | continue |
| 237 | c = self.rawq_getchar() |
| 238 | if c == IAC: |
| 239 | buf = buf + c |
| 240 | elif c in (DO, DONT): |
| 241 | opt = self.rawq_getchar() |
| 242 | self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c)) |
| 243 | self.sock.send(IAC + WONT + opt) |
| 244 | elif c in (WILL, WONT): |
| 245 | opt = self.rawq_getchar() |
| 246 | self.msg('IAC %s %d', |
| 247 | c == WILL and 'WILL' or 'WONT', ord(c)) |
| 248 | else: |
| 249 | self.msg('IAC %s not recognized' % `c`) |
| 250 | except EOFError: # raised by self.rawq_getchar() |
| 251 | pass |
| 252 | self.cookedq = self.cookedq + buf |
| 253 | |
| 254 | # Get next char from raw queue |
| 255 | # Block if no data is immediately available |
| 256 | # Raise EOFError when connection is closed |
| 257 | def rawq_getchar(self): |
| 258 | if not self.rawq: |
| 259 | self.fill_rawq() |
| 260 | if self.eof: |
| 261 | raise EOFError |
| 262 | c = self.rawq[self.irawq] |
| 263 | self.irawq = self.irawq + 1 |
| 264 | if self.irawq >= len(self.rawq): |
| 265 | self.rawq = '' |
| 266 | self.irawq = 0 |
| 267 | return c |
| 268 | |
| 269 | # Fill raw queue from exactly one recv() system call |
| 270 | # Block if no data is immediately available |
| 271 | # Set self.eof when connection is closed |
| 272 | def fill_rawq(self): |
| 273 | if self.irawq >= len(self.rawq): |
| 274 | self.rawq = '' |
| 275 | self.irawq = 0 |
| 276 | # The buffer size should be fairly small so as to avoid quadratic |
| 277 | # behavior in process_rawq() above |
| 278 | buf = self.sock.recv(50) |
| 279 | self.eof = (not buf) |
| 280 | self.rawq = self.rawq + buf |
| 281 | |
| 282 | # Test whether data is available on the socket |
| 283 | def sock_avail(self): |
| 284 | return select.select([self], [], [], 0) == ([self], [], []) |
| 285 | |
| 286 | |
| 287 | # Test program |
| 288 | # Usage: test [-d] ... [host [port]] |
| 289 | def test(): |
| 290 | import sys, string, socket, select |
| 291 | debuglevel = 0 |
| 292 | while sys.argv[1:] and sys.argv[1] == '-d': |
| 293 | debuglevel = debuglevel+1 |
| 294 | del sys.argv[1] |
| 295 | host = 'localhost' |
| 296 | if sys.argv[1:]: |
| 297 | host = sys.argv[1] |
| 298 | port = 0 |
| 299 | if sys.argv[2:]: |
| 300 | portstr = sys.argv[2] |
| 301 | try: |
| 302 | port = string.atoi(portstr) |
| 303 | except string.atoi_error: |
| 304 | port = socket.getservbyname(portstr, 'tcp') |
| 305 | tn = Telnet(host, port) |
| 306 | tn.set_debuglevel(debuglevel) |
| 307 | while 1: |
| 308 | rfd, wfd, xfd = select.select([tn, sys.stdin], [], []) |
| 309 | if sys.stdin in rfd: |
| 310 | line = sys.stdin.readline() |
| 311 | tn.write(line) |
| 312 | if tn in rfd: |
| 313 | try: |
| 314 | text = tn.read_eager() |
| 315 | except EOFError: |
| 316 | print '*** Connection closed by remote host ***' |
| 317 | break |
| 318 | if text: |
| 319 | sys.stdout.write(text) |
| 320 | sys.stdout.flush() |
| 321 | tn.close() |