From 7fad46f10daadc869e71ffc0325724e10a5b8986 Mon Sep 17 00:00:00 2001 From: Faiyaz Ahmed Date: Tue, 14 Nov 2006 19:27:09 +0000 Subject: [PATCH] *** empty log message *** --- .mailer.py.swp | Bin 12288 -> 0 bytes .monitor.py.swo | Bin 20480 -> 0 bytes .monitor.py.swp | Bin 12288 -> 0 bytes plc.py | 225 +++++++++++++++++ reboot.py | 508 +++++++++++++++++++++++++++++++++++++ telnetlib.py | 659 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1392 insertions(+) delete mode 100644 .mailer.py.swp delete mode 100644 .monitor.py.swo delete mode 100644 .monitor.py.swp create mode 100644 plc.py create mode 100755 reboot.py create mode 100644 telnetlib.py diff --git a/.mailer.py.swp b/.mailer.py.swp deleted file mode 100644 index 287fd2a0641ee53a51b4d58e7f6f3ff2cef6bddb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 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", "\r\n\r\n") + + # Login + telnet_answer(telnet, "Password >", password) + + # P# - Pulse relay + if not dryrun: + telnet_answer(telnet, "Enter >", "P%d" % port) + + telnet.read_until("Enter >", TELNET_TIMEOUT) + + # Close + telnet.close() + return 0 + + except EOFError, err: + if verbose: + logger.debug(err) + telnet.close() + return errno.ECONNRESET + except Exception, err: + if verbose: + logger.debug(err) + if telnet: + telnet.close() + return errno.ETIMEDOUT + + +def apc_reboot(ip, username, password, port): + global dryrun, verbose + + telnet = None + + try: + telnet = telnetlib.Telnet(ip, timeout=TELNET_TIMEOUT) + telnet.set_debuglevel(verbose) + + # Login + telnet_answer(telnet, "User Name", username) + telnet_answer(telnet, "Password", password) + + # 1- Device Manager + # 2- Network + # 3- System + # 4- Logout + + # 1- Device Manager + telnet_answer(telnet, "\r\n> ", "1") + + # 1- Phase Monitor/Configuration + # 2- Outlet Restriction Configuration + # 3- Outlet Control/Config + # 4- Power Supply Status + + # 3- Outlet Control/Config + telnet_answer(telnet, "\r\n> ", "3") + + # 1- Outlet 1 + # 2- Outlet 2 + # ... + + # n- Outlet n + telnet_answer(telnet, "\r\n> ", str(port)) + + # 1- Control Outlet + # 2- Configure Outlet + + # 1- Control Outlet + telnet_answer(telnet, "\r\n> ", "1") + + # 1- Immediate On + # 2- Immediate Off + # 3- Immediate Reboot + # 4- Delayed On + # 5- Delayed Off + # 6- Delayed Reboot + # 7- Cancel + + # 3- Immediate Reboot + telnet_answer(telnet, "\r\n> ", "3") + + if not dryrun: + telnet_answer(telnet, + "Enter 'YES' to continue or to cancel", "YES\r\n") + telnet_answer(telnet, + "Press to continue...", "") + + # Close + telnet.close() + return 0 + + except EOFError, err: + if verbose: + logger.debug(err) + if telnet: + telnet.close() + return errno.ECONNRESET + except Exception, err: + if verbose: + logger.debug(err) + if telnet: + telnet.close() + return errno.ETIMEDOUT + + +def baytech_reboot(ip, username, password, port): + global dryrun, verbose + + ssh = None + + try: + ssh = pyssh.Ssh(username, ip) + ssh.open() + + # Login + telnet_answer(ssh, "password:", password) + + # PL1 comm output (2 ,1).........1 + # PL2 comm output (2 ,2).........2 + # PL3 comm output (2 ,3).........3 + # no machine (2 ,4).........4 + # Control Outlets (5 ,1).........5 + # Logout..........................T + + # Control Outlets (5 ,1).........5 + telnet_answer(ssh, "Enter Request :", "5") + + # Reboot N + telnet_answer(ssh, "DS-RPC>", "Reboot %d" % port) + + # Reboot Outlet N (Y/N)? + if dryrun: + telnet_answer(ssh, "(Y/N)?", "N") + else: + telnet_answer(ssh, "(Y/N)?", "Y") + telnet_answer(ssh, "DS-RPC>", "") + + # Close + output = ssh.close() + if verbose: + logger.debug(err) + return 0 + + except Exception, err: + if verbose: + logger.debug(err) + if ssh: + output = ssh.close() + if verbose: + logger.debug(err) + return errno.ETIMEDOUT + +### rebooting european BlackBox PSE boxes +# Thierry Parmentelat - May 11 2005 +# tested on 4-ports models known as PSE505-FR +# uses http to POST a data 'P=r' +# relies on basic authentication within http1.0 +# first curl-based script was +# curl --http1.0 --basic --user : --data P=r \ +# http://:/cmd.html && echo OK + +def bbpse_reboot (pcu_ip,username,password,port_in_pcu,http_port): + + global dryrun, verbose + + url = "http://%s:%d/cmd.html" % (pcu_ip,http_port) + data= "P%d=r" % port_in_pcu + if verbose: + logger.debug("POSTing '%s' on %s" % (data,url)) + + authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm() + uri = "%s:%d" % (pcu_ip,http_port) + authinfo.add_password (None, uri, username, password) + authhandler = urllib2.HTTPBasicAuthHandler( authinfo ) + + opener = urllib2.build_opener(authhandler) + urllib2.install_opener(opener) + + if (dryrun): + return 0 + + try: + f = urllib2.urlopen(url,data) + + r= f.read() + if verbose: + logger.debug(r) + return 0 + + except urllib2.URLError,err: + logger.info('Could not open http connection', err) + return -1 + +### rebooting x10toggle based systems addressed by port +# Marc E. Fiuczynski - May 31 2005 +# tested on 4-ports models known as PSE505-FR +# uses ssh and password to login to an account +# that will cause the system to be powercycled. + +def x10toggle_reboot(ip, username, password, port): + global dryrun, verbose + + ssh = None + try: + ssh = pyssh.Ssh(username, ip) + ssh.open() + + # Login + telnet_answer(ssh, "password:", password) + + if not dryrun: + # Reboot + telnet_answer(ssh, "x10toggle>", "A%d" % port) + + # Close + output = ssh.close() + if verbose: + logger.debug(output) + return 0 + + except Exception, err: + if verbose: + logger.debug(err) + if ssh: + output = ssh.close() + if verbose: + logger.debug(output) + return errno.ETIMEDOUT + +### rebooting Dell systems via RAC card +# Marc E. Fiuczynski - June 01 2005 +# tested with David Lowenthal's itchy/scratchy nodes at UGA +# + +def runcmd(command, args, username, password, timeout = None): + + result = [None] + result_ready = threading.Condition() + + def set_result(x): + + result_ready.acquire() + try: + result[0] = x + finally: + result_ready.notify() + result_ready.release() + + def do_command(command, username, password): + + try: + # Popen4 is a popen-type class that combines stdout and stderr + p = popen2.Popen4(command) + + # read all output data + p.tochild.write("%s\n" % username) + p.tochild.write("%s\n" % password) + p.tochild.close() + data = p.fromchild.read() + + while True: + # might get interrupted by a signal in poll() or waitpid() + try: + retval = p.wait() + set_result((retval, data)) + break + except OSError, ex: + if ex.errno == errno.EINTR: + continue + raise ex + except Exception, ex: + set_result(ex) + + if args: + command = " ".join([command] + args) + + worker = threading.Thread(target = do_command, args = (command, username, password, )) + worker.setDaemon(True) + result_ready.acquire() + worker.start() + result_ready.wait(timeout) + try: + if result == [None]: + raise Exception, "command timed-out: '%s'" % command + finally: + result_ready.release() + result = result[0] + + if isinstance(result, Exception): + raise result + else: + (retval, data) = result + if os.WIFEXITED(retval) and os.WEXITSTATUS(retval) == 0: + return data + else: + out = "system command ('%s') " % command + if os.WIFEXITED(retval): + out += "failed, rc = %d" % os.WEXITSTATUS(retval) + else: + out += "killed by signal %d" % os.WTERMSIG(retval) + if data: + out += "; output follows:\n" + data + raise Exception, out + +def racadm_reboot(ip, username, password, port): + global dryrun, verbose + + try: + cmd = "/usr/sbin/racadm" + os.stat(cmd) + if not dryrun: + output = runcmd(cmd, ["-r %s -i serveraction powercycle" % ip], + username, password) + else: + output = "dryrun of racadm command" + + logger.debug("runcmd returned without output %s" % output) + if verbose: + logger.debug(output) + return 0 + + except Exception, err: + logger.debug("runcmd raised exception %s" % err) + if verbose: + logger.debug(err) + return errno.ETIMEDOUT + +# Returns true if rebooted via PCU +def reboot(nodename): + pcu = plc.getpcu(nodename) + if not pcu: + plc.nodePOD(nodename) + return False + # Try the PCU first + logger.debug("Trying PCU %s %s" % (pcu['hostname'], pcu['model'])) + + # APC Masterswitch (Berkeley) + if pcu['protocol'] == "telnet" and pcu['model'] == "APC Masterswitch": + err = apc_reboot(pcu['ip'], pcu['username'],pcu['password'], pcu[nodename]) + + # DataProbe iPal (many sites) + elif pcu['protocol'] == "telnet" and pcu['model'].find("IP-4") >= 0: + err = ipal_reboot(pcu['ip'],pcu['password'], pcu[nodename]) + + # BayTech DS4-RPC + elif pcu['protocol'] == "ssh" and \ + (pcu['model'].find("Baytech") >= 0 or pcu['model'].find("DS4") >= 0): + err = baytech_reboot(pcu['ip'], pcu['username'],pcu['password'], pcu[nodename]) + + # BlackBox PSExxx-xx (e.g. PSE505-FR) + elif pcu['protocol'] == "http" and (pcu['model'] == "bbpse"): + err = bbpse_reboot(pcu['ip'], pcu['username'], pcu['password'], pcu[nodename],80) + + # x10toggle + elif pcu['protocol'] == "ssh" and (pcu['model'] == "x10toggle"): + err = x10toggle_reboot(pcu['ip'], pcu['username'],pcu['password'], pcu[nodename]) + + # x10toggle + elif pcu['protocol'] == "racadm" and (pcu['model'] == "RAC"): + err = racadm_reboot(pcu['ip'], pcu['username'],pcu['password'], pcu_[nodename]) + + # Unknown or unsupported + else: + err = errno.EPROTONOSUPPORT + return False + return True + +#def get_suggested(suggestion_id,db): +# +# sql= """select node_id,pcu_id from nodes where suggestion = %d """\ +# % (suggestion_id) +# try: +# nodes = db.query(sql).dictresult() +# except pg.ProgrammingError, err: +# print( "Database error for query: %s\n%s" % (sql,err) ) +# sys.exit(1) +# return nodes + +#def get_pcu_info(node_id,pcu_id,db): +# sql= """select port_number from pcu_ports where node_id = %d and pcu_id = %d """\ +# % (node_id,pcu_id) +# try: +# port_number = db.query(sql).dictresult() +# except pg.ProgrammingError, err: +# print( "Database error for query: %s\n%s" % (sql,err) ) +# sys.exit(1) +# +# sql= """select * from pcu where pcu_id = %d """\ +# % (pcu_id) +# try: +# pcu = db.query(sql).dictresult() +# except pg.ProgrammingError, err: +# print( "Database error for query: %s\n%s" % (sql,err) ) +# sys.exit(1) +# +# result = {'node_id':node_id,'pcu_id':pcu_id,'port_number':port_number[0]['port_number'], +# 'ip':pcu[0]['ip'],'username':pcu[0]['username'],'password':pcu[0]['password'],\ +# 'model':pcu[0]['model'],'protocol':pcu[0]['protocol'],'hostname':pcu[0]['hostname']} +# +# return result + +#def add_plc_event(node_id,err,db): +# site_id = plc_db_utils.get_site_from_node_id(node_id,db) +# message = "PCU reboot by monitor-msgs@planet-lab.org: %s" % os.strerror(err) +# +# sql = """insert into events (event_class_id,message,person_id,node_id,site_id) values """\ +# """(%d,'%s',%d,%d,%d)""" % (NODE_POWER_CONTROL,message,MONITOR_USER_ID,node_id,site_id) +# print sql +# +# try: +# db.query(sql) +# except pg.ProgrammingError, err: +# print( "Database error for: %s\n%s" % (sql,err) ) +# sys.exit(1) + + +def main(): + logger.setLevel(logging.DEBUG) + ch = logging.StreamHandler() + ch.setLevel(logging.DEBUG) + formatter = logging.Formatter('LOGGER - %(message)s') + ch.setFormatter(formatter) + logger.addHandler(ch) + + + try: + reboot("planetlab2.cs.uchicago.edu") + reboot("alice.cs.princeton.edu") + except Exception, err: + print err + # used later for pretty printing +# pp = pprint.PrettyPrinter(indent=2) + +# user = "Monitor" +# password = None + +# plc_db = plc_dbs.open_plc_db_write() +# mon_db = plc_dbs.open_mon_db() + + # 5 = needs script reboot - fix this later +# nodes = get_suggested(5,mon_db) + +# for row in nodes: + +# pcu = get_pcu_info(row['node_id'],row['pcu_id'],plc_db) +# add_plc_event(row['node_id'],err,plc_db) + +if __name__ == '__main__': + import plc + logger = logging.getLogger("monitor") + main() diff --git a/telnetlib.py b/telnetlib.py new file mode 100644 index 0000000..cfa96c9 --- /dev/null +++ b/telnetlib.py @@ -0,0 +1,659 @@ +"""TELNET client class. + +Based on RFC 854: TELNET Protocol Specification, by J. Postel and +J. Reynolds + +Example: + +>>> from telnetlib import Telnet +>>> tn = Telnet('www.python.org', 79) # connect to finger port +>>> tn.write('guido\r\n') +>>> print tn.read_all() +Login Name TTY Idle When Where +guido Guido van Rossum pts/2 snag.cnri.reston.. + +>>> + +Note that read_all() won't read until eof -- it just reads some data +-- but it guarantees to read at least one byte unless EOF is hit. + +It is possible to pass a Telnet object to select.select() in order to +wait until more data is available. Note that in this case, +read_eager() may return '' even if there was data on the socket, +because the protocol negotiation may have eaten the data. This is why +EOFError is needed in some cases to distinguish between "no data" and +"connection closed" (since the socket also appears ready for reading +when it is closed). + +To do: +- option negotiation +- timeout should be intrinsic to the connection object instead of an + option on one of the read calls only + +""" + + +# Imported modules +import sys +import socket +import select + +__all__ = ["Telnet"] + +# Tunable parameters +DEBUGLEVEL = 0 + +# Telnet protocol defaults +TELNET_PORT = 23 + +# Telnet protocol characters (don't change) +IAC = chr(255) # "Interpret As Command" +DONT = chr(254) +DO = chr(253) +WONT = chr(252) +WILL = chr(251) +theNULL = chr(0) + +SE = chr(240) # Subnegotiation End +NOP = chr(241) # No Operation +DM = chr(242) # Data Mark +BRK = chr(243) # Break +IP = chr(244) # Interrupt process +AO = chr(245) # Abort output +AYT = chr(246) # Are You There +EC = chr(247) # Erase Character +EL = chr(248) # Erase Line +GA = chr(249) # Go Ahead +SB = chr(250) # Subnegotiation Begin + + +# Telnet protocol options code (don't change) +# These ones all come from arpa/telnet.h +BINARY = chr(0) # 8-bit data path +ECHO = chr(1) # echo +RCP = chr(2) # prepare to reconnect +SGA = chr(3) # suppress go ahead +NAMS = chr(4) # approximate message size +STATUS = chr(5) # give status +TM = chr(6) # timing mark +RCTE = chr(7) # remote controlled transmission and echo +NAOL = chr(8) # negotiate about output line width +NAOP = chr(9) # negotiate about output page size +NAOCRD = chr(10) # negotiate about CR disposition +NAOHTS = chr(11) # negotiate about horizontal tabstops +NAOHTD = chr(12) # negotiate about horizontal tab disposition +NAOFFD = chr(13) # negotiate about formfeed disposition +NAOVTS = chr(14) # negotiate about vertical tab stops +NAOVTD = chr(15) # negotiate about vertical tab disposition +NAOLFD = chr(16) # negotiate about output LF disposition +XASCII = chr(17) # extended ascii character set +LOGOUT = chr(18) # force logout +BM = chr(19) # byte macro +DET = chr(20) # data entry terminal +SUPDUP = chr(21) # supdup protocol +SUPDUPOUTPUT = chr(22) # supdup output +SNDLOC = chr(23) # send location +TTYPE = chr(24) # terminal type +EOR = chr(25) # end or record +TUID = chr(26) # TACACS user identification +OUTMRK = chr(27) # output marking +TTYLOC = chr(28) # terminal location number +VT3270REGIME = chr(29) # 3270 regime +X3PAD = chr(30) # X.3 PAD +NAWS = chr(31) # window size +TSPEED = chr(32) # terminal speed +LFLOW = chr(33) # remote flow control +LINEMODE = chr(34) # Linemode option +XDISPLOC = chr(35) # X Display Location +OLD_ENVIRON = chr(36) # Old - Environment variables +AUTHENTICATION = chr(37) # Authenticate +ENCRYPT = chr(38) # Encryption option +NEW_ENVIRON = chr(39) # New - Environment variables +# the following ones come from +# http://www.iana.org/assignments/telnet-options +# Unfortunately, that document does not assign identifiers +# to all of them, so we are making them up +TN3270E = chr(40) # TN3270E +XAUTH = chr(41) # XAUTH +CHARSET = chr(42) # CHARSET +RSP = chr(43) # Telnet Remote Serial Port +COM_PORT_OPTION = chr(44) # Com Port Control Option +SUPPRESS_LOCAL_ECHO = chr(45) # Telnet Suppress Local Echo +TLS = chr(46) # Telnet Start TLS +KERMIT = chr(47) # KERMIT +SEND_URL = chr(48) # SEND-URL +FORWARD_X = chr(49) # FORWARD_X +PRAGMA_LOGON = chr(138) # TELOPT PRAGMA LOGON +SSPI_LOGON = chr(139) # TELOPT SSPI LOGON +PRAGMA_HEARTBEAT = chr(140) # TELOPT PRAGMA HEARTBEAT +EXOPL = chr(255) # Extended-Options-List +NOOPT = chr(0) + +class Telnet: + + """Telnet interface class. + + An instance of this class represents a connection to a telnet + server. The instance is initially not connected; the open() + method must be used to establish a connection. Alternatively, the + host name and optional port number can be passed to the + constructor, too. + + Don't try to reopen an already connected instance. + + This class has many read_*() methods. Note that some of them + raise EOFError when the end of the connection is read, because + they can return an empty string for other reasons. See the + individual doc strings. + + read_until(expected, [timeout]) + Read until the expected string has been seen, or a timeout is + hit (default is no timeout); may block. + + read_all() + Read all data until EOF; may block. + + read_some() + Read at least one byte or EOF; may block. + + read_very_eager() + Read all data available already queued or on the socket, + without blocking. + + read_eager() + Read either data already queued or some data available on the + socket, without blocking. + + read_lazy() + Read all data in the raw queue (processing it first), without + doing any socket I/O. + + read_very_lazy() + Reads all data in the cooked queue, without doing any socket + I/O. + + read_sb_data() + Reads available data between SB ... SE sequence. Don't block. + + set_option_negotiation_callback(callback) + Each time a telnet option is read on the input flow, this callback + (if set) is called with the following parameters : + callback(telnet socket, command, option) + option will be chr(0) when there is no option. + No other action is done afterwards by telnetlib. + + """ + + def __init__(self, host=None, port=0, timeout=None): + """Constructor. + + When called without arguments, create an unconnected instance. + With a hostname argument, it connects the instance; a port + number and connect timeout is optional. + + """ + self.debuglevel = DEBUGLEVEL + self.host = host + self.port = port + self.sock = None + self.rawq = '' + self.irawq = 0 + self.cookedq = '' + self.eof = 0 + self.iacseq = '' # Buffer for IAC sequence. + self.sb = 0 # flag for SB and SE sequence. + self.sbdataq = '' + self.option_callback = None + if host is not None: + self.open(host, port, timeout) + + def open(self, host, port=0, timeout=None): + """Connect to a host. + + The optional second argument is the port number, which + defaults to the standard telnet port (23). The optional third + argument is a timeout in seconds; if None, the default timeout + of the underlying socket will be used. + + Don't try to reopen an already connected instance. + + """ + self.eof = 0 + if not port: + port = TELNET_PORT + self.host = host + self.port = port + msg = "getaddrinfo returns an empty list" + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + try: + self.sock = socket.socket(af, socktype, proto) + if timeout is not None: + self.sock.settimeout(timeout) + self.sock.connect(sa) + except socket.error, msg: + if self.sock: + self.sock.close() + self.sock = None + continue + break + if not self.sock: + raise socket.error, msg + + def __del__(self): + """Destructor -- close the connection.""" + self.close() + + def msg(self, msg, *args): + """Print a debug message, when the debug level is > 0. + + If extra arguments are present, they are substituted in the + message using the standard string formatting operator. + + """ + if self.debuglevel > 0: + print 'Telnet(%s,%d):' % (self.host, self.port), + if args: + print msg % args + else: + print msg + + def set_debuglevel(self, debuglevel): + """Set the debug level. + + The higher it is, the more debug output you get (on sys.stdout). + + """ + self.debuglevel = debuglevel + + def close(self): + """Close the connection.""" + if self.sock: + self.sock.close() + self.sock = 0 + self.eof = 1 + self.iacseq = '' + self.sb = 0 + + def get_socket(self): + """Return the socket object used internally.""" + return self.sock + + def fileno(self): + """Return the fileno() of the socket object used internally.""" + return self.sock.fileno() + + def write(self, buffer): + """Write a string to the socket, doubling any IAC characters. + + Can block if the connection is blocked. May raise + socket.error if the connection is closed. + + """ + if IAC in buffer: + buffer = buffer.replace(IAC, IAC+IAC) + self.msg("send %s", `buffer`) + self.sock.sendall(buffer) + + def read_until(self, match, timeout=None): + """Read until a given string is encountered or until timeout. + + When no match is found, return whatever is available instead, + possibly the empty string. Raise EOFError if the connection + is closed and no cooked data is available. + + """ + n = len(match) + self.process_rawq() + i = self.cookedq.find(match) + if i >= 0: + i = i+n + buf = self.cookedq[:i] + self.cookedq = self.cookedq[i:] + return buf + s_reply = ([self], [], []) + s_args = s_reply + if timeout is not None: + s_args = s_args + (timeout,) + while not self.eof and select.select(*s_args) == s_reply: + i = max(0, len(self.cookedq)-n) + self.fill_rawq() + self.process_rawq() + i = self.cookedq.find(match, i) + if i >= 0: + i = i+n + buf = self.cookedq[:i] + self.cookedq = self.cookedq[i:] + return buf + return self.read_very_lazy() + + def read_all(self): + """Read all data until EOF; block until connection closed.""" + self.process_rawq() + while not self.eof: + self.fill_rawq() + self.process_rawq() + buf = self.cookedq + self.cookedq = '' + return buf + + def read_some(self): + """Read at least one byte of cooked data unless EOF is hit. + + Return '' if EOF is hit. Block if no data is immediately + available. + + """ + self.process_rawq() + while not self.cookedq and not self.eof: + self.fill_rawq() + self.process_rawq() + buf = self.cookedq + self.cookedq = '' + return buf + + def read_very_eager(self): + """Read everything that's possible without blocking in I/O (eager). + + Raise EOFError if connection closed and no cooked data + available. Return '' if no cooked data available otherwise. + Don't block unless in the midst of an IAC sequence. + + """ + self.process_rawq() + while not self.eof and self.sock_avail(): + self.fill_rawq() + self.process_rawq() + return self.read_very_lazy() + + def read_eager(self): + """Read readily available data. + + Raise EOFError if connection closed and no cooked data + available. Return '' if no cooked data available otherwise. + Don't block unless in the midst of an IAC sequence. + + """ + self.process_rawq() + while not self.cookedq and not self.eof and self.sock_avail(): + self.fill_rawq() + self.process_rawq() + return self.read_very_lazy() + + def read_lazy(self): + """Process and return data that's already in the queues (lazy). + + Raise EOFError if connection closed and no data available. + Return '' if no cooked data available otherwise. Don't block + unless in the midst of an IAC sequence. + + """ + self.process_rawq() + return self.read_very_lazy() + + def read_very_lazy(self): + """Return any data available in the cooked queue (very lazy). + + Raise EOFError if connection closed and no data available. + Return '' if no cooked data available otherwise. Don't block. + + """ + buf = self.cookedq + self.cookedq = '' + if not buf and self.eof and not self.rawq: + raise EOFError, 'telnet connection closed' + return buf + + def read_sb_data(self): + """Return any data available in the SB ... SE queue. + + Return '' if no SB ... SE available. Should only be called + after seeing a SB or SE command. When a new SB command is + found, old unread SB data will be discarded. Don't block. + + """ + buf = self.sbdataq + self.sbdataq = '' + return buf + + def set_option_negotiation_callback(self, callback): + """Provide a callback function called after each receipt of a telnet option.""" + self.option_callback = callback + + def process_rawq(self): + """Transfer from raw queue to cooked queue. + + Set self.eof when connection is closed. Don't block unless in + the midst of an IAC sequence. + + """ + buf = ['', ''] + try: + while self.rawq: + c = self.rawq_getchar() + if not self.iacseq: + if c == theNULL: + continue + if c == "\021": + continue + if c != IAC: + buf[self.sb] = buf[self.sb] + c + continue + else: + self.iacseq += c + elif len(self.iacseq) == 1: + 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]' + if c in (DO, DONT, WILL, WONT): + self.iacseq += c + continue + + self.iacseq = '' + if c == IAC: + buf[self.sb] = buf[self.sb] + c + else: + if c == SB: # SB ... SE start. + self.sb = 1 + self.sbdataq = '' + elif c == SE: + self.sb = 0 + self.sbdataq = self.sbdataq + buf[1] + buf[1] = '' + if self.option_callback: + # Callback is supposed to look into + # the sbdataq + self.option_callback(self.sock, c, NOOPT) + else: + # We can't offer automatic processing of + # suboptions. Alas, we should not get any + # unless we did a WILL/DO before. + self.msg('IAC %d not recognized' % ord(c)) + elif len(self.iacseq) == 2: + cmd = self.iacseq[1] + self.iacseq = '' + opt = c + if cmd in (DO, DONT): + self.msg('IAC %s %d', + cmd == DO and 'DO' or 'DONT', ord(opt)) + if self.option_callback: + self.option_callback(self.sock, cmd, opt) + else: + self.sock.sendall(IAC + WONT + opt) + elif cmd in (WILL, WONT): + self.msg('IAC %s %d', + cmd == WILL and 'WILL' or 'WONT', ord(opt)) + if self.option_callback: + self.option_callback(self.sock, cmd, opt) + else: + self.sock.sendall(IAC + DONT + opt) + except EOFError: # raised by self.rawq_getchar() + self.iacseq = '' # Reset on EOF + self.sb = 0 + pass + self.cookedq = self.cookedq + buf[0] + self.sbdataq = self.sbdataq + buf[1] + + def rawq_getchar(self): + """Get next char from raw queue. + + Block if no data is immediately available. Raise EOFError + when connection is closed. + + """ + if not self.rawq: + self.fill_rawq() + if self.eof: + raise EOFError + c = self.rawq[self.irawq] + self.irawq = self.irawq + 1 + if self.irawq >= len(self.rawq): + self.rawq = '' + self.irawq = 0 + return c + + def fill_rawq(self): + """Fill raw queue from exactly one recv() system call. + + Block if no data is immediately available. Set self.eof when + connection is closed. + + """ + if self.irawq >= len(self.rawq): + self.rawq = '' + self.irawq = 0 + # The buffer size should be fairly small so as to avoid quadratic + # behavior in process_rawq() above + buf = self.sock.recv(50) + self.msg("recv %s", `buf`) + self.eof = (not buf) + self.rawq = self.rawq + buf + + def sock_avail(self): + """Test whether data is available on the socket.""" + return select.select([self], [], [], 0) == ([self], [], []) + + def interact(self): + """Interaction function, emulates a very dumb telnet client.""" + if sys.platform == "win32": + self.mt_interact() + return + while 1: + rfd, wfd, xfd = select.select([self, sys.stdin], [], []) + if self in rfd: + try: + text = self.read_eager() + except EOFError: + print '*** Connection closed by remote host ***' + break + if text: + sys.stdout.write(text) + sys.stdout.flush() + if sys.stdin in rfd: + line = sys.stdin.readline() + if not line: + break + self.write(line) + + def mt_interact(self): + """Multithreaded version of interact().""" + import thread + thread.start_new_thread(self.listener, ()) + while 1: + line = sys.stdin.readline() + if not line: + break + self.write(line) + + def listener(self): + """Helper for mt_interact() -- this executes in the other thread.""" + while 1: + try: + data = self.read_eager() + except EOFError: + print '*** Connection closed by remote host ***' + return + if data: + sys.stdout.write(data) + else: + sys.stdout.flush() + + def expect(self, list, timeout=None): + """Read until one from a list of a regular expressions matches. + + The first argument is a list of regular expressions, either + compiled (re.RegexObject instances) or uncompiled (strings). + The optional second argument is a timeout, in seconds; default + is no timeout. + + Return a tuple of three items: the index in the list of the + first regular expression that matches; the match object + returned; and the text read up till and including the match. + + If EOF is read and no text was read, raise EOFError. + Otherwise, when nothing matches, return (-1, None, text) where + text is the text received so far (may be the empty string if a + timeout happened). + + If a regular expression ends with a greedy match (e.g. '.*') + or if more than one expression can match the same input, the + results are undeterministic, and may depend on the I/O timing. + + """ + re = None + list = list[:] + indices = range(len(list)) + for i in indices: + if not hasattr(list[i], "search"): + if not re: import re + list[i] = re.compile(list[i]) + while 1: + self.process_rawq() + for i in indices: + m = list[i].search(self.cookedq) + if m: + e = m.end() + text = self.cookedq[:e] + self.cookedq = self.cookedq[e:] + return (i, m, text) + if self.eof: + break + if timeout is not None: + r, w, x = select.select([self.fileno()], [], [], timeout) + if not r: + break + self.fill_rawq() + text = self.read_very_lazy() + if not text and self.eof: + raise EOFError + return (-1, None, text) + + +def test(): + """Test program for telnetlib. + + Usage: python telnetlib.py [-d] ... [host [port]] + + Default host is localhost; default port is 23. + + """ + debuglevel = 0 + while sys.argv[1:] and sys.argv[1] == '-d': + debuglevel = debuglevel+1 + del sys.argv[1] + host = 'localhost' + if sys.argv[1:]: + host = sys.argv[1] + port = 0 + if sys.argv[2:]: + portstr = sys.argv[2] + try: + port = int(portstr) + except ValueError: + port = socket.getservbyname(portstr, 'tcp') + tn = Telnet() + tn.set_debuglevel(debuglevel) + tn.open(host, port) + tn.interact() + tn.close() + +if __name__ == '__main__': + test() -- 2.47.0