home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyth_os2.zip / python-1.0.2 / Demo / cwilib / telnetlib.py < prev    next >
Text File  |  1993-10-28  |  9KB  |  322 lines

  1. # A TELNET client class.  Based on RFC 854: TELNET Protocol
  2. # Specification, by J. Postel and J. Reynolds
  3.  
  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
  38. import socket
  39. import select
  40. import string
  41. import regsub
  42.  
  43. # Tunable parameters
  44. DEBUGLEVEL = 0
  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.  
  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
  78.  
  79.     # Destructor
  80.     def __del__(self):
  81.     self.close()
  82.  
  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
  87.  
  88.     # Set debug level
  89.     def set_debuglevel(self, debuglevel):
  90.     self.debuglevel = debuglevel
  91.  
  92.     # Explicit close
  93.     def close(self):
  94.     if self.sock:
  95.         self.sock.close()
  96.     self.sock = None
  97.     self.eof = 1
  98.  
  99.     # Return socket (e.g. for select)
  100.     def get_socket(self):
  101.     return self.sock
  102.  
  103.     # Return socket's fileno (e.g. for select)
  104.     def fileno(self):
  105.     return self.sock.fileno()
  106.  
  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)
  114.  
  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
  128.  
  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:]
  159.         return buf
  160.     return self.read_very_lazy()
  161.  
  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
  172.  
  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
  184.  
  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()
  195.  
  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()
  206.  
  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()
  322.