Browse Source

mgmt: add support for events-sending methods

Standard methods return only one value, after operation is completed,
but events-related methods may return multiple values during the method
execution time. Provide a callback for such cases.
Also, according to specification, avoid sending both event and non-event
values.

QubesOS/qubes-issues#2622
Marek Marczykowski-Górecki 7 years ago
parent
commit
40a86efd66
2 changed files with 10 additions and 2 deletions
  1. 4 1
      qubes/mgmt.py
  2. 6 1
      qubes/tools/qubesd.py

+ 4 - 1
qubes/mgmt.py

@@ -96,7 +96,7 @@ class AbstractQubesMgmt(object):
     There are also two helper functions for firing events associated with API
     calls.
     '''
-    def __init__(self, app, src, method, dest, arg):
+    def __init__(self, app, src, method, dest, arg, send_event=None):
         #: :py:class:`qubes.Qubes` object
         self.app = app
 
@@ -112,6 +112,9 @@ class AbstractQubesMgmt(object):
         #: name of the method
         self.method = method.decode('ascii')
 
+        #: callback for sending events if applicable
+        self.send_event = send_event
+
         #: is this operation cancellable?
         self.cancellable = False
 

+ 6 - 1
qubes/tools/qubesd.py

@@ -32,6 +32,7 @@ class QubesDaemonProtocol(asyncio.Protocol):
         self.len_untrusted_buffer = 0
         self.transport = None
         self.debug = debug
+        self.event_sent = False
         self.mgmt = None
 
     def connection_made(self, transport):
@@ -81,6 +82,7 @@ class QubesDaemonProtocol(asyncio.Protocol):
                 self.send_event)
             response = yield from self.mgmt.execute(
                 untrusted_payload=untrusted_payload)
+            assert not (self.event_sent and response)
             if self.transport is None:
                 return
 
@@ -116,7 +118,8 @@ class QubesDaemonProtocol(asyncio.Protocol):
                     src, method, dest, arg, len(untrusted_payload))
 
         else:
-            self.send_response(response)
+            if not self.event_sent:
+                self.send_response(response)
             try:
                 self.transport.write_eof()
             except NotImplementedError:
@@ -133,11 +136,13 @@ class QubesDaemonProtocol(asyncio.Protocol):
         self.transport.write(self.header.pack(*args))
 
     def send_response(self, content):
+        assert not self.event_sent
         self.send_header(0x30)
         if content is not None:
             self.transport.write(content.encode('utf-8'))
 
     def send_event(self, subject, event, **kwargs):
+        self.event_sent = True
         self.send_header(0x31)
 
         if subject is not self.app: