ia64/xen-unstable

view tools/xenmgr/lib/server/console.py @ 1592:24e2bbb841b3

bitkeeper revision 1.1020.1.1 (40df4b94lJE4UbrmICQf_fatdqMCOw)

Quieten down console connections. Remove telnet control sequence.
author kaf24@scramble.cl.cam.ac.uk
date Sun Jun 27 22:35:00 2004 +0000 (2004-06-27)
parents 2c6f86e0083e
children 5b1f0d05d6ca
line source
2 from twisted.internet import reactor
3 from twisted.internet import protocol
4 from twisted.protocols import telnet
6 import xend.utils
8 from xenmgr import EventServer
9 eserver = EventServer.instance()
11 import controller
12 from messages import *
13 from params import *
15 """Telnet binary option."""
16 TRANSMIT_BINARY = '0'
17 WILL = chr(251)
18 IAC = chr(255)
20 class ConsoleProtocol(protocol.Protocol):
21 """Asynchronous handler for a console TCP socket.
22 """
24 def __init__(self, controller, idx):
25 self.controller = controller
26 self.idx = idx
27 self.addr = None
28 self.binary = 0
30 def connectionMade(self):
31 peer = self.transport.getPeer()
32 self.addr = (peer.host, peer.port)
33 if self.controller.connect(self.addr, self):
34 self.transport.write("Cannot connect to console %d on domain %d\n"
35 % (self.idx, self.controller.dom))
36 self.loseConnection()
37 return
38 else:
39 # KAF: A nice quiet successful connect. Don't bother with telnet
40 # control sequence -- telnet is not the appropriate protocol here.
41 #self.transport.write("Connected to console %d on domain %d\n"
42 # % (self.idx, self.controller.dom))
43 #self.setTelnetTransmitBinary()
44 eserver.inject('xend.console.connect',
45 [self.idx, self.addr[0], self.addr[1]])
47 def setTelnetTransmitBinary(self):
48 """Send the sequence to set the telnet TRANSMIT-BINARY option.
49 """
50 self.write(IAC + WILL + TRANSMIT_BINARY)
52 def dataReceived(self, data):
53 if self.controller.handleInput(self, data):
54 self.loseConnection()
56 def write(self, data):
57 #if not self.connected: return -1
58 self.transport.write(data)
59 return len(data)
61 def connectionLost(self, reason=None):
62 eserver.inject('xend.console.disconnect',
63 [self.idx, self.addr[0], self.addr[1]])
64 self.controller.disconnect()
66 def loseConnection(self):
67 self.transport.loseConnection()
69 class ConsoleFactory(protocol.ServerFactory):
70 """Asynchronous handler for a console server socket.
71 """
72 protocol = ConsoleProtocol
74 def __init__(self, controller, idx):
75 #protocol.ServerFactory.__init__(self)
76 self.controller = controller
77 self.idx = idx
79 def buildProtocol(self, addr):
80 proto = self.protocol(self.controller, self.idx)
81 proto.factory = self
82 return proto
84 class ConsoleControllerFactory(controller.ControllerFactory):
85 """Factory for creating console controllers.
86 """
88 def createInstance(self, dom, console_port=None):
89 if console_port is None:
90 console_port = CONSOLE_PORT_BASE + dom
91 console = ConsoleController(self, dom, console_port)
92 self.addInstance(console)
93 eserver.inject('xend.console.create',
94 [console.idx, console.dom, console.console_port])
95 return console
97 def consoleClosed(self, console):
98 eserver.inject('xend.console.close', console.idx)
99 self.delInstance(console)
101 class ConsoleController(controller.Controller):
102 """Console controller for a domain.
103 Does not poll for i/o itself, but relies on the notifier to post console
104 output and the connected TCP sockets to post console input.
105 """
107 def __init__(self, factory, dom, console_port):
108 #print 'ConsoleController> dom=', dom
109 controller.Controller.__init__(self, factory, dom)
110 self.majorTypes = [ CMSG_CONSOLE ]
111 self.status = "new"
112 self.addr = None
113 self.conn = None
114 self.rbuf = xend.utils.buffer()
115 self.wbuf = xend.utils.buffer()
116 self.console_port = console_port
118 self.registerChannel()
119 self.listener = None
120 self.listen()
121 #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
123 def sxpr(self):
124 val =['console',
125 ['id', self.idx ],
126 ['domain', self.dom ],
127 ['local_port', self.channel.getLocalPort() ],
128 ['remote_port', self.channel.getRemotePort() ],
129 ['console_port', self.console_port ] ]
130 if self.addr:
131 val.append(['connected', self.addr[0], self.addr[1]])
132 return val
134 def ready(self):
135 return not (self.closed() or self.rbuf.empty())
137 def closed(self):
138 return self.status == 'closed'
140 def connected(self):
141 return self.status == 'connected'
143 def close(self):
144 self.status = "closed"
145 self.listener.stopListening()
146 self.deregisterChannel()
147 self.lostChannel()
149 def listen(self):
150 """Listen for TCP connections to the console port..
151 """
152 if self.closed(): return
153 self.status = "listening"
154 if self.listener:
155 #self.listener.startListening()
156 pass
157 else:
158 f = ConsoleFactory(self, self.idx)
159 self.listener = reactor.listenTCP(self.console_port, f)
161 def connect(self, addr, conn):
162 if self.closed(): return -1
163 if self.connected(): return -1
164 self.addr = addr
165 self.conn = conn
166 self.status = "connected"
167 self.handleOutput()
168 return 0
170 def disconnect(self):
171 self.addr = None
172 self.conn = None
173 self.listen()
175 def requestReceived(self, msg, type, subtype):
176 #print '***Console', self.dom, msg.get_payload()
177 self.rbuf.write(msg.get_payload())
178 self.handleOutput()
180 def responseReceived(self, msg, type, subtype):
181 pass
183 def produceRequests(self):
184 # Send as much pending console data as there is room for.
185 work = 0
186 while not self.wbuf.empty() and self.channel.writeReady():
187 msg = xend.utils.message(CMSG_CONSOLE, 0, 0)
188 msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
189 work += self.channel.writeRequest(msg, notify=0)
190 return work
192 def handleInput(self, conn, data):
193 """Handle some external input aimed at the console.
194 Called from a TCP connection (conn).
195 """
196 if self.closed(): return -1
197 if conn != self.conn: return 0
198 self.wbuf.write(data)
199 if self.produceRequests():
200 self.channel.notify()
201 return 0
203 def handleOutput(self):
204 """Handle buffered output from the console.
205 Sends it to the connected console (if any).
206 """
207 if self.closed():
208 #print 'Console>handleOutput> closed'
209 return -1
210 if not self.conn:
211 #print 'Console>handleOutput> not connected'
212 return 0
213 while not self.rbuf.empty():
214 try:
215 #print 'Console>handleOutput> writing...'
216 bytes = self.conn.write(self.rbuf.peek())
217 if bytes > 0:
218 self.rbuf.discard(bytes)
219 except socket.error, error:
220 pass
221 #print 'Console>handleOutput<'
222 return 0