scripts: set timeout when waiting for qemu monitor connection
[qemu/ar7.git] / scripts / qmp / qmp.py
blob2d0d926b3140613ae10668ed3a4cff3fd6c28e98
1 # QEMU Monitor Protocol Python class
3 # Copyright (C) 2009, 2010 Red Hat Inc.
5 # Authors:
6 # Luiz Capitulino <lcapitulino@redhat.com>
8 # This work is licensed under the terms of the GNU GPL, version 2. See
9 # the COPYING file in the top-level directory.
11 import json
12 import errno
13 import socket
14 import sys
16 class QMPError(Exception):
17 pass
19 class QMPConnectError(QMPError):
20 pass
22 class QMPCapabilitiesError(QMPError):
23 pass
25 class QMPTimeoutError(QMPError):
26 pass
28 class QEMUMonitorProtocol:
29 def __init__(self, address, server=False, debug=False):
30 """
31 Create a QEMUMonitorProtocol class.
33 @param address: QEMU address, can be either a unix socket path (string)
34 or a tuple in the form ( address, port ) for a TCP
35 connection
36 @param server: server mode listens on the socket (bool)
37 @raise socket.error on socket connection errors
38 @note No connection is established, this is done by the connect() or
39 accept() methods
40 """
41 self.__events = []
42 self.__address = address
43 self._debug = debug
44 self.__sock = self.__get_sock()
45 if server:
46 self.__sock.bind(self.__address)
47 self.__sock.listen(1)
49 def __get_sock(self):
50 if isinstance(self.__address, tuple):
51 family = socket.AF_INET
52 else:
53 family = socket.AF_UNIX
54 return socket.socket(family, socket.SOCK_STREAM)
56 def __negotiate_capabilities(self):
57 greeting = self.__json_read()
58 if greeting is None or not greeting.has_key('QMP'):
59 raise QMPConnectError
60 # Greeting seems ok, negotiate capabilities
61 resp = self.cmd('qmp_capabilities')
62 if "return" in resp:
63 return greeting
64 raise QMPCapabilitiesError
66 def __json_read(self, only_event=False):
67 while True:
68 data = self.__sockfile.readline()
69 if not data:
70 return
71 resp = json.loads(data)
72 if 'event' in resp:
73 if self._debug:
74 print >>sys.stderr, "QMP:<<< %s" % resp
75 self.__events.append(resp)
76 if not only_event:
77 continue
78 return resp
80 error = socket.error
82 def __get_events(self, wait=False):
83 """
84 Check for new events in the stream and cache them in __events.
86 @param wait (bool): block until an event is available.
87 @param wait (float): If wait is a float, treat it as a timeout value.
89 @raise QMPTimeoutError: If a timeout float is provided and the timeout
90 period elapses.
91 @raise QMPConnectError: If wait is True but no events could be retrieved
92 or if some other error occurred.
93 """
95 # Check for new events regardless and pull them into the cache:
96 self.__sock.setblocking(0)
97 try:
98 self.__json_read()
99 except socket.error as err:
100 if err[0] == errno.EAGAIN:
101 # No data available
102 pass
103 self.__sock.setblocking(1)
105 # Wait for new events, if needed.
106 # if wait is 0.0, this means "no wait" and is also implicitly false.
107 if not self.__events and wait:
108 if isinstance(wait, float):
109 self.__sock.settimeout(wait)
110 try:
111 ret = self.__json_read(only_event=True)
112 except socket.timeout:
113 raise QMPTimeoutError("Timeout waiting for event")
114 except:
115 raise QMPConnectError("Error while reading from socket")
116 if ret is None:
117 raise QMPConnectError("Error while reading from socket")
118 self.__sock.settimeout(None)
120 def connect(self, negotiate=True):
122 Connect to the QMP Monitor and perform capabilities negotiation.
124 @return QMP greeting dict
125 @raise socket.error on socket connection errors
126 @raise QMPConnectError if the greeting is not received
127 @raise QMPCapabilitiesError if fails to negotiate capabilities
129 self.__sock.connect(self.__address)
130 self.__sockfile = self.__sock.makefile()
131 if negotiate:
132 return self.__negotiate_capabilities()
134 def accept(self):
136 Await connection from QMP Monitor and perform capabilities negotiation.
138 @return QMP greeting dict
139 @raise socket.error on socket connection errors
140 @raise QMPConnectError if the greeting is not received
141 @raise QMPCapabilitiesError if fails to negotiate capabilities
143 self.__sock.settimeout(15)
144 self.__sock, _ = self.__sock.accept()
145 self.__sockfile = self.__sock.makefile()
146 return self.__negotiate_capabilities()
148 def cmd_obj(self, qmp_cmd):
150 Send a QMP command to the QMP Monitor.
152 @param qmp_cmd: QMP command to be sent as a Python dict
153 @return QMP response as a Python dict or None if the connection has
154 been closed
156 if self._debug:
157 print >>sys.stderr, "QMP:>>> %s" % qmp_cmd
158 try:
159 self.__sock.sendall(json.dumps(qmp_cmd))
160 except socket.error as err:
161 if err[0] == errno.EPIPE:
162 return
163 raise socket.error(err)
164 resp = self.__json_read()
165 if self._debug:
166 print >>sys.stderr, "QMP:<<< %s" % resp
167 return resp
169 def cmd(self, name, args=None, id=None):
171 Build a QMP command and send it to the QMP Monitor.
173 @param name: command name (string)
174 @param args: command arguments (dict)
175 @param id: command id (dict, list, string or int)
177 qmp_cmd = { 'execute': name }
178 if args:
179 qmp_cmd['arguments'] = args
180 if id:
181 qmp_cmd['id'] = id
182 return self.cmd_obj(qmp_cmd)
184 def command(self, cmd, **kwds):
185 ret = self.cmd(cmd, kwds)
186 if ret.has_key('error'):
187 raise Exception(ret['error']['desc'])
188 return ret['return']
190 def pull_event(self, wait=False):
192 Get and delete the first available QMP event.
194 @param wait (bool): block until an event is available.
195 @param wait (float): If wait is a float, treat it as a timeout value.
197 @raise QMPTimeoutError: If a timeout float is provided and the timeout
198 period elapses.
199 @raise QMPConnectError: If wait is True but no events could be retrieved
200 or if some other error occurred.
202 @return The first available QMP event, or None.
204 self.__get_events(wait)
206 if self.__events:
207 return self.__events.pop(0)
208 return None
210 def get_events(self, wait=False):
212 Get a list of available QMP events.
214 @param wait (bool): block until an event is available.
215 @param wait (float): If wait is a float, treat it as a timeout value.
217 @raise QMPTimeoutError: If a timeout float is provided and the timeout
218 period elapses.
219 @raise QMPConnectError: If wait is True but no events could be retrieved
220 or if some other error occurred.
222 @return The list of available QMP events.
224 self.__get_events(wait)
225 return self.__events
227 def clear_events(self):
229 Clear current list of pending events.
231 self.__events = []
233 def close(self):
234 self.__sock.close()
235 self.__sockfile.close()
237 timeout = socket.timeout
239 def settimeout(self, timeout):
240 self.__sock.settimeout(timeout)
242 def get_sock_fd(self):
243 return self.__sock.fileno()
245 def is_scm_available(self):
246 return self.__sock.family == socket.AF_UNIX