+from socket import *
+from select import select
+from os import popen4
+from time import sleep
+import logging
+
+LATCP_SOCKET = '/var/run/latlogin'
+
+LAT_VERSION = '1.22'
+LAT_VERSION = '1.24' # for running on Mermaid. [DAA] 20071107
+LATCP_CMD_VERSION = 8
+LATCP_CMD_TERMINALSESSION = 26
+LATCP_CMD_ERRORMSG = 99
+
+class LATClientException(Exception): pass
+
+def read_for_a_bit(rfh):
+ message = ''
+ while 1:
+ r = select([rfh], [], [], 5.0)[0]
+ if r:
+ try:
+ ch = rfh.read(1)
+ except socket.error:
+ ch = ''
+ if ch == '':
+ break
+ message = message + ch
+ else:
+ break
+ logging.debug("Received message: ", repr(message))
+ return message
+
+def write_and_get_response(rfh, wfh, message, expect_echo=True):
+ logging.debug("Writing message:", repr(message))
+ wfh.write(message+'\r\n')
+ wfh.flush()
+ logging.debug(" --> Sent")
+ response = read_for_a_bit(rfh)
+ if response.find(message) == -1 and expect_echo:
+ raise LATClientException("Talking to DEC server, expected to find original message in echo but didn't")
+ return response
+
+class LATClient:
+ def __init__(self, service = None, node = None, port = None,
+ localport = None, password = None, is_queued = False,
+ server_name = '', connect_password='', priv_password=''):
+
+ self.server_name = server_name
+ self.connect_password = connect_password
+ self.priv_password = priv_password
+
+ self.sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ self.sock.connect(LATCP_SOCKET)
+ self.send_msg(LATCP_CMD_VERSION, LAT_VERSION+'\000')
+ (cmd, msg) = self.read_reply()
+ if service == None: service = ''
+ if node == None: node = ''
+ if port == None: port = ''
+ if localport == None: localport = ''
+ if password == None: password = ''
+ if is_queued == True:
+ is_queued = 1
+ else:
+ is_queued = 0
+ self.send_msg(LATCP_CMD_TERMINALSESSION, '%c%c%s%c%s%c%s%c%s%c%s' % \
+ (is_queued,
+ len(service), service,
+ len(node), node,
+ len(port), port,
+ len(localport), localport,
+ len(password), password
+ ))
+ (cmd, msg) = self.read_reply()
+ if ord(cmd) == LATCP_CMD_ERRORMSG:
+ raise LATClientException(msg)
+
+ self.rfh = self.sock.makefile('r')
+ self.wfh = self.sock.makefile('w')
+
+ r = select([self.rfh], [], [], 2.0)[0]
+ if r:
+ l = self.rfh.readline()
+ if l.find('Service in use') >= 0:
+ logging.warning("Service in use, apparently: restarting DEC server")
+ self.reboot_server()
+
+ def __del__(self):
+ try:
+ self.sock.close()
+ self.sock.shutdown(2)
+ except:
+ pass
+ del self.sock
+
+ def send_msg(self, cmd, msg):
+ self.sock.send('%c%c%c%s'%(cmd, len(msg)/256, len(msg)%256, msg))
+
+ def reboot_server(self):
+ self.sock.shutdown(2)
+ self.sock.close()
+
+ logging.info('Logging into DEC server')
+ mopw, mopr = popen4('/usr/sbin/moprc '+self.server_name)
+ write_and_get_response(mopr, mopw, '')
+
+ logging.info('Sending password')
+ r = write_and_get_response(mopr, mopw, self.connect_password, False)
+ if r.find('Enter username> ') == -1:
+ logging.warning("Expected username prompt, got " + repr(r))
+ raise LATClientException('failed to reboot server')
+
+ logging.info('Sending username')
+ r = write_and_get_response(mopr, mopw, 'grim reaper')
+ if r.find('Local> ') == -1:
+ logging.warning("Expected DEC server prompt, got " + repr(r))
+ raise LATClientException('failed to reboot server')
+
+ logging.info('Requesting privileges')
+ r = write_and_get_response(mopr, mopw, 'set priv')
+ if r.find('Password> ') == -1:
+ logging.warning("Expected priv password prompt, got " + repr(r))
+ raise LATClientException('failed to reboot server')
+
+ logging.info('Sending password')
+ r = write_and_get_response(mopr, mopw, self.priv_password, False)
+ if r.find('Local> ') == -1:
+ logging.warning("Expected DEC server prompt, got " + repr(r))
+ raise LATClientException('failed to reboot server')
+
+ logging.info('Sending reboot request')
+ r = write_and_get_response(mopr, mopw, 'init del 0')
+ if r.find('Target does not respond') == -1:
+ logging.warning("Expected DEC server to die, got " + repr(r))
+ raise LATClientException('failed to reboot server')
+
+ logging.info('Closed connection to server')
+ mopr.close()
+ mopw.close()
+ logging.info("Waiting 10 seconds for DEC server to come back to life...")
+ sleep(10)
+ logging.info("Rightyo, back to vending!")
+ raise LATClientException('needed to reboot server')
+
+ def read_reply(self):
+ head = self.sock.recv(3)
+ if len(head) != 3:
+ raise LATClientException('Short LAT packet')
+ cmd = head[0]
+ length = ord(head[1])*256 + ord(head[2])
+ msg = self.sock.recv(length)
+ if cmd == LATCP_CMD_ERRORMSG:
+ raise LATClientException('Received LAT error: %s'%msg)
+ return (cmd, msg)
+
+ def get_fh(self):
+ return (self.rfh, self.wfh)