ahh, decserver doesn't always echo
[uccvend-vendserver.git] / sql-edition / servers / LATClient.py
1 from socket import *
2 from select import select
3 from os import popen4
4 from time import sleep
5
6 LATCP_SOCKET = '/var/run/latlogin'
7
8 LAT_VERSION = '1.21'
9 LATCP_CMD_VERSION = 8
10 LATCP_CMD_TERMINALSESSION = 26
11 LATCP_CMD_ERRORMSG = 99
12
13 class LATClientException(Exception): pass
14
15 def read_for_a_bit(rfh):
16         message = ''
17         while 1:
18                 r = select([rfh], [], [], 5.0)[0]
19                 if r:
20                         message = message + rfh.read(1)
21                 else:
22                         break
23         print "Received message: ", repr(message)
24         return message
25
26 def write_expecting_echo(rfh, wfh, message):
27         print "Writing message:", repr(message)
28         while len(message) > 0:
29                 wfh.write(message[0])
30                 wfh.flush()
31                 if message[0] == '\n':
32                         echo = rfh.read(2)
33                         expected_echo = '\r\n'
34                 else:
35                         echo = rfh.read(1)
36                         expected_echo = message[0]
37                 if echo != expected_echo:
38                         print "Gah, expected echo when writing", repr(message[0]), "but got", repr(echo)
39                 message = message[1:]
40         print "  --> Sent and echoed."
41
42 class LATClient:
43         def __init__(self, service = None, node = None, port = None,
44                      localport = None, password = None, is_queued = False,
45                      server_name = '', connect_password='', priv_password=''):
46
47                 self.server_name = server_name
48                 self.connect_password = connect_password
49                 self.priv_password = priv_password
50                 
51                 self.sock = socket(AF_UNIX, SOCK_STREAM, 0);
52                 self.sock.connect(LATCP_SOCKET)
53                 self.send_msg(LATCP_CMD_VERSION, LAT_VERSION+'\000')
54                 (cmd, msg) = self.read_reply()
55                 if service == None: service = ''
56                 if node == None: node = ''
57                 if port == None: port = ''
58                 if localport == None: localport = ''
59                 if password == None: password = ''
60                 if is_queued == True:
61                         is_queued = 1
62                 else:
63                         is_queued = 0
64                 self.send_msg(LATCP_CMD_TERMINALSESSION, '%c%c%s%c%s%c%s%c%s%c%s' % \
65                         (is_queued,
66                          len(service), service,
67                          len(node), node,
68                          len(port), port,
69                          len(localport), localport,
70                          len(password), password
71                          ))
72                 (cmd, msg) = self.read_reply()
73                 if ord(cmd) == LATCP_CMD_ERRORMSG:
74                         raise LATClientException(msg)
75
76                 self.rfh = self.sock.makefile('r')
77                 self.wfh = self.sock.makefile('w')
78
79                 r = select([self.rfh], [], [], 2.0)[0]
80                 if r:
81                         l = self.rfh.readline()
82                         if l.find('Service in use') >= 0:
83                                 print "Service in use, apparently: restarting DEC server"
84                                 self.reboot_server()
85
86         def __del__(self):
87                 try:
88                         self.sock.close()
89                         self.sock.shutdown(2)
90                 except:
91                         pass
92                 del self.sock
93
94         def send_msg(self, cmd, msg):
95                 self.sock.send('%c%c%c%s'%(cmd, len(msg)/256, len(msg)%256, msg))
96
97         def reboot_server(self):
98                 self.sock.shutdown(2)
99                 self.sock.close()
100                 mopw, mopr = popen4('/usr/sbin/moprc '+self.server_name)
101                 read_for_a_bit(mopr)
102                 mopw.write('\n')
103                 read_for_a_bit(mopr)
104                 mopw.write(self.connect_password+'\n')
105                 read_for_a_bit(mopr)
106                 write_expecting_echo(mopr, mopw, 'grim reaper\n')
107                 read_for_a_bit(mopr)
108                 write_expecting_echo(mopr, mopw, 'set priv\n')
109                 read_for_a_bit(mopr)
110                 write_expecting_echo(mopr, mopw, self.priv_password+'\n')
111                 read_for_a_bit(mopr)
112                 write_expecting_echo(mopr, mopw, 'init del 0\n')
113                 read_for_a_bit(mopr)
114                 mopr.close()
115                 mopw.close()
116                 print
117                 print "Waiting 10 seconds for DEC server to come back to life..."
118                 sleep(10)
119                 print "Rightyo, back to vending!"
120                 print
121                 raise LATClientException('needed to reboot server')
122
123         def read_reply(self):
124                 head = self.sock.recv(3)
125                 if len(head) != 3:
126                         raise LATClientException('Short LAT packet')
127                 cmd = head[0]
128                 length = ord(head[1])*256 + ord(head[2])
129                 msg = self.sock.recv(length)
130                 if cmd == LATCP_CMD_ERRORMSG:
131                         raise LATClientException('Received LAT error: %s'%msg)
132                 return (cmd, msg)
133         
134         def get_fh(self):
135                 return (self.rfh, self.wfh)

UCC git Repository :: git.ucc.asn.au