aboutsummaryrefslogtreecommitdiffstats
path: root/tools/xend/lib/console.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/xend/lib/console.py')
-rw-r--r--tools/xend/lib/console.py83
1 files changed, 76 insertions, 7 deletions
diff --git a/tools/xend/lib/console.py b/tools/xend/lib/console.py
index aad6069979..57898817f5 100644
--- a/tools/xend/lib/console.py
+++ b/tools/xend/lib/console.py
@@ -5,7 +5,7 @@
#############################################################
import errno, re, os, select, signal, socket, struct, sys
-
+import xend.blkif, xend.main, xend.manager, xend.utils, Xc
##
## interface:
@@ -16,7 +16,7 @@ import errno, re, os, select, signal, socket, struct, sys
## CONNECTED: sending/receiving console data on TCP port 'self.port'
##
## A dictionary of all active interfaces, indexed by TCP socket descriptor,
-## is accessible as 'interface.interface_list'.
+## is accessible as 'interface.list_by_fd'.
##
## NB. When a class instance is to be destroyed you *must* call the 'close'
## method. Otherwise a stale reference will eb left in the interface list.
@@ -30,7 +30,11 @@ class interface:
# Dictionary of all active (non-closed) console interfaces.
- interface_list = {}
+ list_by_fd = {}
+
+
+ # Dictionary of all console interfaces, closed and open.
+ list = {}
# NB. 'key' is an opaque value that has no meaning in this class.
@@ -38,6 +42,9 @@ class interface:
self.status = interface.CLOSED
self.port = port
self.key = key
+ self.rbuf = xend.utils.buffer()
+ self.wbuf = xend.utils.buffer()
+ interface.list[key] = self
# Is this interface closed (inactive)?
@@ -58,14 +65,14 @@ class interface:
# Close the interface, if it is not closed already.
def close(self):
if not self.closed():
- del interface.interface_list[self.sock.fileno()]
+ del interface.list_by_fd[self.sock.fileno()]
self.sock.close()
del self.sock
self.status = interface.CLOSED
# Move the interface into the 'listening' state. Opens a new listening
- # socket and updates 'interface_list'.
+ # socket and updates 'list_by_fd'.
def listen(self):
# Close old socket (if any), and create a fresh one.
self.close()
@@ -80,7 +87,7 @@ class interface:
# Announce the new status of thsi interface.
self.status = interface.LISTENING
- interface.interface_list[self.sock.fileno()] = self
+ interface.list_by_fd[self.sock.fileno()] = self
except:
# In case of trouble ensure we get rid of dangling socket reference
@@ -105,7 +112,69 @@ class interface:
# Publish the new socket and the new interface state.
self.sock = sock
self.status = interface.CONNECTED
- interface.interface_list[self.sock.fileno()] = self
+ interface.list_by_fd[self.sock.fileno()] = self
return 1
+ # Completely sestroy a console interface.
+ def destroy(self):
+ self.close()
+ del interface.list[self.key]
+
+
+ # Do work triggered by resource availability on a console-interface socket.
+ def socket_work(self):
+ # If the interface is listening, check for pending connections.
+ if self.listening():
+ self.connect()
+
+ # All done if the interface is not connected.
+ if not self.connected():
+ return
+
+ # Send as much pending data as possible via the socket.
+ while not self.rbuf.empty():
+ try:
+ bytes = self.sock.send(self.rbuf.peek())
+ if bytes > 0:
+ self.rbuf.discard(bytes)
+ except socket.error, error:
+ pass
+
+ # Read as much data as is available. Don't worry about
+ # overflowing our buffer: it's more important to read the
+ # incoming data stream and detect errors or closure of the
+ # remote end in a timely manner.
+ try:
+ while 1:
+ data = self.sock.recv(2048)
+ # Return of zero means the remote end has disconnected.
+ # We therefore return the console interface to listening.
+ if not data:
+ self.listen()
+ break
+ self.wbuf.write(data)
+ except socket.error, error:
+ # Assume that most errors mean that the connection is dead.
+ # In such cases we return the interface to 'listening' state.
+ if error[0] != errno.EAGAIN:
+ print "Better return to listening"
+ self.listen()
+ print "New status: " + str(self.status)
+
+
+ # The parameter @port is the control-interface event channel. This method
+ # returns True if messages were written to the control interface.
+ def ctrlif_transmit_work(self, port):
+ work_done = False
+ while not self.wbuf.empty() and port.space_to_write_request():
+ msg = xend.utils.message(0, 0, 0)
+ msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
+ port.write_request(msg)
+ work_done = True
+ return work_done
+
+
+ def ctrlif_rx_req(self, port, msg):
+ self.rbuf.write(msg.get_payload())
+ port.write_response(msg)