Em Fri, 9 Aug 2024 00:41:37 +0200
Mauro Carvalho Chehab <mchehab+hua...@kernel.org> escreveu:

> > You should be able to use e.g.
> > 
> > legacy.py's QEMUMonitorProtocol class for synchronous connections, e.g.
> > 
> > from qemu.qmp.legacy import QEMUMonitorProtocol
> > 
> > qmp = QEMUMonitorProtocol((host, port))
> > qmp.connect(negotiate=True)  
> 
> That sounds interesting! I give it a try.

I applied the enclosed patch at the end of my patch series, but
somehow it is not working. For whatever reason, connect() is
raising a StateError apparently due to Runstate.CONNECTING.

I tried both as declaring (see enclosed patch):

        class qmp(QEMUMonitorProtocol)

and using:

-        super().__init__(self.host, self.port)
+        self.qmp_monitor = QEMUMonitorProtocol(self.host, self.port)

On both cases, it keeps waiting forever for a connection.

Regards,
Mauro

---

diff --git a/scripts/qmp_helper.py b/scripts/qmp_helper.py
index e9e9388bcb8b..62ca267cdc87 100644
--- a/scripts/qmp_helper.py
+++ b/scripts/qmp_helper.py
@@ -9,9 +9,23 @@
 import socket
 import sys
 
+from os import path
+
+try:
+    qemu_dir = path.abspath(path.dirname(path.dirname(__file__)))
+    sys.path.append(path.join(qemu_dir, 'python'))
+
+    from qemu.qmp.legacy import QEMUMonitorProtocol
+    from qemu.qmp.protocol import StateError
+
+except ModuleNotFoundError as exc:
+    print(f"Module '{exc.name}' not found.")
+    print("Try export PYTHONPATH=top-qemu-dir/python or run from top-qemu-dir")
+    sys.exit(1)
+
 from base64 import b64encode
 
-class qmp:
+class qmp(QEMUMonitorProtocol):
     """
     Opens a connection and send/receive QMP commands.
     """
@@ -21,22 +35,20 @@ def send_cmd(self, command, 
may_open=False,return_error=True):
 
         if may_open:
             self._connect()
-        elif not self.socket:
-            return None
+        elif not self.connected:
+            return False
 
         if isinstance(command, dict):
             data = json.dumps(command).encode("utf-8")
         else:
             data = command.encode("utf-8")
 
-        self.socket.sendall(data)
-        data = self.socket.recv(1024)
         try:
-            obj = json.loads(data.decode("utf-8"))
-        except json.JSONDecodeError as e:
-            print(f"Invalid QMP answer: {e}")
-            self._close()
-            return None
+            obj = self.cmd_obj(command)
+        except Exception as e:
+            print("Failed to inject error: {e}.")
+
+        print(obj)
 
         if "return" in obj:
             if isinstance(obj.get("return"), dict):
@@ -46,86 +58,47 @@ def send_cmd(self, command, 
may_open=False,return_error=True):
             else:
                 return obj["return"]
 
-        elif isinstance(obj.get("error"), dict):
-            error = obj["error"]
-            if return_error:
-                print(f'{error["class"]}: {error["desc"]}')
-        else:
-            print(json.dumps(obj))
-
         return None
 
     def _close(self):
         """Shutdown and close the socket, if opened"""
-        if not self.socket:
+        if not self.connected:
             return
 
-        self.socket.shutdown(socket.SHUT_WR)
-        while 1:
-            data = self.socket.recv(1024)
-            if data == b"":
-                break
-            try:
-                obj = json.loads(data.decode("utf-8"))
-            except json.JSONDecodeError as e:
-                print(f"Invalid QMP answer: {e}")
-                self.socket.close()
-                self.socket = None
-                return
-
-            if isinstance(obj.get("return"), dict):
-                print(json.dumps(obj["return"]))
-            if isinstance(obj.get("error"), dict):
-                error = obj["error"]
-                print(f'{error["class"]}: {error["desc"]}')
-            else:
-                print(json.dumps(obj))
-
-        self.socket.close()
-        self.socket = None
+        self.close()
+        self.connected = False
 
     def _connect(self):
         """Connect to a QMP TCP/IP port, if not connected yet"""
 
-        if self.socket:
+        if self.connected:
             return True
 
-        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        try:
-            self.socket.connect((self.host, self.port))
-        except ConnectionRefusedError:
-            sys.exit(f"Can't connect to QMP host {self.host}:{self.port}")
-
-        data = self.socket.recv(1024)
-        try:
-            obj = json.loads(data.decode("utf-8"))
-        except json.JSONDecodeError as e:
-            print(f"Invalid QMP answer: {e}")
-            self._close()
-            return False
-
-        if "QMP" not in obj:
-            print(f"Invalid QMP answer: {data.decode('utf-8')}")
-            self._close()
-            return False
+        is_connecting = True
+        while is_connecting:
+            try:
+                ret = self.connect(negotiate=True)
+                self.accept()
+                is_connecting = False
+            except ConnectionError:
+                sys.exit(f"Can't connect to QMP host {self.host}:{self.port}")
+                return False
+            except StateError as e:
+                print(f"StateError: {e}")
 
-        result = self.send_cmd('{ "execute": "qmp_capabilities" }')
-        if not result:
-            self._close()
-            return False
+        self.connected = True
 
         return True
 
     def __init__(self, host, port, debug=False):
         """Initialize variables used by the QMP send logic"""
 
-        self.socket = None
+        self.connected = False
         self.host = host
         self.port = port
         self.debug = debug
 
-    def __del__(self):
-        self._close()
+        super().__init__(self.host, self.port)
 
     #
     # Socket QMP send command
@@ -168,8 +141,12 @@ def send_cper(self, guid, data):
 
         self._connect()
 
-        if self.send_cmd(command):
-            print("Error injected.")
+        try:
+            self.cmd_obj(command)
+        except Exception as e:
+            print("Failed to inject error: {e}.")
+
+        print("Error injected.")
 
     def search_qom(self, path, prop, regex):
         """
@@ -180,8 +157,9 @@ def search_qom(self, path, prop, regex):
             ...
         """
 
-        found = []
+        self._connect()
 
+        found = []
         i = 0
         while 1:
             dev = f"{path}[{i}]"
@@ -192,7 +170,11 @@ def search_qom(self, path, prop, regex):
                     'property': prop
                 }
             }
-            ret = self.send_cmd(cmd, may_open=True, return_error=False)
+            try:
+                ret = self.cmd_obj(cmd)
+            except Exception as e:
+                print("Failed to inject error: {e}.")
+
             if not ret:
                 break
 



Thanks,
Mauro

Reply via email to