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 zcmeI2&yO2L7RM_q1nUskEc^ky^Z;(}dfJnK5E?MV@=U@=ahM%D15y-Os=smAJyU+HS|0MBE}FRMvbvcGas_ zufFe9l{C|%wcV{AJrO*{@H)=ek=IUae)aDu+qjppF^>=U%iQ+-=8GreTtq>)A8hBb z424lL*xa~q%a~W^4qK^`u~B&|<#8hNAUn9l)HOH-oC0@1fyYjrTwC!@(1Q=$xoE1*gHY zpauR4j)QORXY6b6AMh5q3?2pdfzR(_>|^jAcmuo+E&&hR1^#!8vG2f_;0y3JNI?S5 zf(>vSe2Zriz5t(r55emo0#AV_!BOz-QO5oS{t4a$8f0J>^uZJ0ry66QfLA~YE`v7k zz(e2|`1#L_{Q$lPpMm$myWkzL55}Mmc7WCH|5iWuatb&FoB~b(r@$RkfQW>BaL%u9 zZ1s0G&vte;>djfxVBZ9`%iwo^&^f<>K6-?%)h9|D$x~5ZC$DpEtGgM5I>;6e>xroF zt~bduBAl#x^mo#+5nGY(@gxq#t+oxAc&Duqyd+!-vzqWxpz=Mh!59LJ(@f=N5!6zX zPED4?BNmToIJ6-RhwZjE93pHv9D3`F)wIa3;;FzZMQr?r9a^<$A)|8TXLg?NHOV)s z8HSA}rFw7Kj@mSzCFu7C+kS7*K~yzWm>^7)7I0d_5SZDfJz=i$q$pdbIhK?M3D+j$ zxt+bXf*;C-DRN0>A}AGF^F2W$6&={F^Jr23UY84<18JQ+SpL>=+iF1x^DWFri;!MlycNAmVf z3)zUJ*QATS7fyJtg~6A4p;x&MaoaIH*Gwz z+{0+^a2UvOAA2Ln~J()$It<>}8a!F~CnArN8 zt&Jzhi{vK0D(viKQj{dEQbD~79c@z}X)&mk#{0r5zSOkj0>OwBV-!tQ{t}IZfp=?N zPCZL=HGdU2squ3Dm)EhRV{fasxwUKD#6u2)hm*>}6JLJcn#ztlHS z=riiJef?r|8G^z9$+Vv;Q4W{qNQAu5VzD8rEkt5J!!S*;u{w+d#bte$DhNYGHWPQm zbsW+>NkI^x%qc?!&Zk9BE|#=FJ@io1FU-nJi;M*#} zDrV(Z9EjNN=HCsZ^+SVy#nAHPe zCu`61SPgI8TyP_Zll8M&O*q^4agyMGkl07`+@N>PddO5(Bs^!47|+f?^5=rhX0ds- zd503`F-^msdbOO#NR)R$z9iLDl0C9LVl|Oyv2MF(XHcT{Vu`GXi))uI*2`~0`?Y=v zHj7R;=2;wcq>`N|Ju6J#p4H@YG@xeiWf(^|CA=FBJbN^tP!l2jxj}>4Z92J5h+^Jy zv)_LdB0sR6E63M7iBoJ?-8SBOxe9yAUx#x$IUHQ8cM3D<2{TcVy^n13L8=PvU58B; z!(=~A@+`zP5%kNuz<;rKZfCnY>~HSuZtgS**TV=0dHW29IE_+f8z641YHBO#O@rXI zJ~1ZK>#f#wIz4o4wYJZ7JKI~WI%D>3X?wcJ>m$V^T$dfWZjLj60 z=+xTU<3s}-u!FqNMj*2|ofgmD(*=oh5@(P(AiuI`1lG}sR-yCOD3-140Q$>Q>{rAA B22ub3 diff --git a/.monitor.py.swo b/.monitor.py.swo deleted file mode 100644 index dfe059847bd5f31e1af064c6c589c12847da7945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 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 diff --git a/plc.py b/plc.py new file mode 100644 index 0000000..42335aa --- /dev/null +++ b/plc.py @@ -0,0 +1,225 @@ +# +# plc.py +# +# Helper functions that minipulate the PLC api. +# +# Faiyaz Ahmed ", "\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.43.0