Re: RFC: adding fd-passing to win32
Hailun Tan <[email protected]> Wed, 10 Aug 2022 09:29:09 +1000
| Newsgroups | gmane.comp.freedesktop.dbus |
|---|---|
| Message-ID | <CAEjDU6r1=XXASFGGEkNE+abCQsJJ-Qfbsq2QczTZYtGwE7qtQw@mail.gmail.com> |
Unsubscribed for the god sake. On Fri, 5 Aug 2022 at 5:36 pm, Marc-André Lureau <[email protected]> wrote: > Hi > > On Thu, Aug 4, 2022 at 11:36 PM Simon McVittie <smcv-ZGY8ohtN/[email protected]> wrote: > >> On Wed, 03 Aug 2022 at 14:54:21 +0400, Marc-André Lureau wrote: >> > The array elements have >> > the handle type & value or details for SOCKET. The body 'H' arguments >> index the >> > array, similar to 'h' FDs values. >> >> Is there a reason why the wire protocol can't use the same 'h' type as >> on Unix? In the wire protocol, the 'h' type is just a special sort of >> integer, with the conventional semantics being that it is an index into an >> array of out-of-band file descriptors. Can the Windows equivalent be >> making >> it an index into an array of HANDLEs? >> > > As you probably know, HANDLEs are not FD. And Windows has the 2 types, and > functions to map to/from the 2 (_get_osfhandle/_open_osfhandle). > > With the addition of AF_UNIX socket support, Windows developers have shown > interest in adding more features over time ( > https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/#unsupportedunavailable), > including SCM_RIGHTS/fdpass. > > If some day, Windows has SCM_RIGHTS, we should enable that code too. For > those reasons, I think we should add a new type. If 'H' is not a good > character, please advise. > > >> This would work very well for GDBus, which literally represents the 'h' >> type as an integer index into the GUnixFdList, but might be a bit weird >> in libdbus, which transparently replaces the integer index with the actual >> file descriptor (which of course will usually be numerically unequal to >> either the index, or the fd in the sender) while iterating a received >> message's arguments, or transparently replaces a fd with an index into >> the array of fds to be sent while building a new message to be sent. >> HANDLEs are not the same size as int, so the ABI for dealing with handles >> would be different on Unix and Windows. >> > > I handled that in my dev branch. I introduced a new type to wrap HANDLE or > SOCKET (or future handle kinds as needed): > > /* > * Handles which are not yet supported: > * - Change notification: FindCloseChangeNotification > * - Event log: CloseEventLog > * - Find file: FindClose > * - Update resource: EndUpdateResource > */ > > typedef struct DBusWinHandle DBusWinHandle; > > struct DBusWinHandle { > int type; > union { > SOCKET socket; > HANDLE handle; > } u; > }; > > > >> I can see why the authors of fd-passing in libdbus did it this way, >> but with hindsight, GDBus' approach is probably better. >> > > may be :) in my glib/gio wip branch, I re-use the fdlist (mapping HANDLEs > to FD). The problem with that approach is that the client looses the HANDLE > type information, which may be hard to get back (there are "bad" & > undocumented windows API to do that). I plan to change that, to introduce a > HANDLE list & API instead. > > > >> If the Windows HANDLEs or SOCKETs have to be sent in-band as ordinary >> bytes in the message stream, rather than out-of-band as a special >> kernel-mediated capability (which seems odd to me, but I'm not a >> Windows expert), then they should probably be in a new header field of >> > > yes, you have to use DuplicateHandle/wsaduplicatesocket and send the > handle details to the target, via ipc. > > >> an appropriate type (perhaps 'at' if a bare 64-bit integer is enough, >> or 'a(t...)' if you need a 64-bit integer plus metadata, or something >> along those lines). >> >> Something like this (in GVariant-ish pseudocode): >> >> header = ( >> byte endianness, >> byte message type, >> byte flags, >> byte major_version, >> uint32 body_length, >> uint32 serial, >> @a(yv) { >> PATH: <'/foo'>, >> INTERFACE: <'com.example.ArbitraryCodeExecution'>, >> MEMBER: <'ExecCommand'>, >> ..., >> WINDOWS_HANDLES: @a(t...) [ # a new header field >> (0x12345678, 'this one is stdin', ...), >> (0x87654321, 'this one is stdout', ...), >> (0x12121212, 'this one is stderr', ...), >> ], >> } >> ) >> >> # 0-7 bytes of padding here, to reach next 8-byte boundary >> >> body = ( >> bytestring b'dir c:\', >> handle 0, # stdin is the 0'th item in WINDOWS_HANDLES, i.e. >> 0x12345678 >> handle 1, # stdout is the 1st item >> handle 2, # stderr is the 2nd item >> ) # for a total of body_length bytes >> >> so that where Unix would have the number of out-of-band fds in the >> existing UNIX_FDS header field, Windows would instead have the in-band >> HANDLEs in the WINDOWS_HANDLES header field. >> > > > Yes, that's an idea I discussed with Thiago: > > 2) if the 'handle array' is itself embedded in the header fields, the > header content will need to be updated for each receiver when broadcasting. > > The second option might not be so bad after all, but my original design > kept the original message (header+body) untouched. > > > >> > It seems the D-Bus protocol was designed so that the message size can be >> > computed from the header alone, with header + body + fields array size. >> The >> > reference implementation relies on that >> (_dbus_header_have_message_untrusted >> > for ex). >> >> Yes, the framing layer of the wire protocol is intended to make it >> possible >> to know how long the whole message is going to be by reading its first 16 >> bytes. This should remain true. >> > > Ok > > -- > Marc-André Lureau >