Skip to content

Commit 6e2f6ec

Browse files
committed
python/aqmp: add send_fd_scm
Add an implementation for send_fd_scm to the async QMP implementation. Like socket_scm_helper mentions, a non-empty payload is required for QEMU to process the ancillary data. A space is most useful because it does not disturb the parsing of subsequent JSON objects. A note on "voiding the warranty": Python 3.11 removes support for calling sendmsg directly from a transport's socket. There is no other interface for doing this, our use case is, I suspect, "quite unique". As far as I can tell, this is safe to do -- send_fd_scm is a synchronous function and we can be guaranteed that the async coroutines will *not* be running when it is invoked. In testing, it works correctly. I investigated quite thoroughly the possibility of creating my own asyncio Transport (The class that ultimately manages the raw socket object) so that I could manage the socket myself, but this is so wildly invasive and unportable I scrapped the idea. It would involve a lot of copy-pasting of various python utilities and classes just to re-create the same infrastructure, and for extremely little benefit. Nah. Just boldly void the warranty instead, while I try to follow up on https://bugs.python.org/issue43232 Signed-off-by: John Snow <[email protected]> Reviewed-by: Paolo Bonzini <[email protected]> Reviewed-by: Eric Blake <[email protected]> Message-id: [email protected] Signed-off-by: John Snow <[email protected]>
1 parent 6bfebc7 commit 6e2f6ec

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

python/qemu/aqmp/qmp_client.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import asyncio
1111
import logging
12+
import socket
13+
import struct
1214
from typing import (
1315
Dict,
1416
List,
@@ -624,3 +626,23 @@ async def execute(self, cmd: str,
624626
"""
625627
msg = self.make_execute_msg(cmd, arguments, oob=oob)
626628
return await self.execute_msg(msg)
629+
630+
@upper_half
631+
@require(Runstate.RUNNING)
632+
def send_fd_scm(self, fd: int) -> None:
633+
"""
634+
Send a file descriptor to the remote via SCM_RIGHTS.
635+
"""
636+
assert self._writer is not None
637+
sock = self._writer.transport.get_extra_info('socket')
638+
639+
if sock.family != socket.AF_UNIX:
640+
raise AQMPError("Sending file descriptors requires a UNIX socket.")
641+
642+
# Void the warranty sticker.
643+
# Access to sendmsg in asyncio is scheduled for removal in Python 3.11.
644+
sock = sock._sock # pylint: disable=protected-access
645+
sock.sendmsg(
646+
[b' '],
647+
[(socket.SOL_SOCKET, socket.SCM_RIGHTS, struct.pack('@i', fd))]
648+
)

0 commit comments

Comments
 (0)