hypfvieh / dbus-java

Improved version of java DBus library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/)
https://hypfvieh.github.io/dbus-java/
MIT License
185 stars 73 forks source link

File Descriptors aren't handled properly #197

Closed drivera73 closed 1 year ago

drivera73 commented 1 year ago

When trying to invoke systemd-logind's Inhibit functionality to keep the system from sleeping while a critical task is completed, it turns out that the library chokes when examining the return value (which is of type "h").

Please see the difference between the screenshot from d-feet (left), and the one from dj-feet (right).

image

For convenience, here are the method coordinates and signature (for copy+paste):

The issue seems to be that file descriptors aren't ever handled during message construction, and even if they were, the collection is never submitted because it's always given as null:

// from InputStreamMessageReader.java, line 163 ... note the "null" at the end ...
final Message m = MessageFactory.createMessage(type, buf, header, body, null);

Specifically, I believe the problem is that the list of file descriptors is expected to be retrieved during message decoding, but no effort is done towards that. Thus, there are no file descriptors received out-of-band, and when the code attempts to access the "n-th" file descriptor as described in the response, everything blows up because all indexes will be out of range (i.e. no FD's to choose from).

For reference, using the below code I was able to correctly listen for, and handle the PrepareForSleep signal as intended, which was nice :).

Here's the Java code for the interface in question:

package org.freedesktop.login1;

import org.freedesktop.dbus.FileDescriptor;
import org.freedesktop.dbus.annotations.DBusInterfaceName;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.interfaces.DBusInterface;
import org.freedesktop.dbus.messages.DBusSignal;

@DBusInterfaceName("org.freedesktop.login1.Manager")
public interface Manager extends DBusInterface {

    public FileDescriptor Inhibit(String what, String who, String why, String mode);

    public class PrepareForSleep extends DBusSignal {
        private final boolean starting;

        public PrepareForSleep(String _objectPath, boolean starting) throws DBusException {
            super(_objectPath, starting);
            this.starting = starting;
        }

        public PrepareForSleep(String _source, String _path, String _iface, String _member, String _sig,
            boolean starting) throws DBusException {
            super(_source, _path, _iface, _member, _sig, starting);
            this.starting = starting;
        }

        public final boolean isStarting() {
            return this.starting;
        }
    }
}

PS/ I'm well aware that once I have that FileDescriptor instance, I'll have a whole other problem in my hands with regards to how to close() it ... but I'll cross that bridge when I get to it. I'm desperately trying to avoid native code, but I may not have a choice...

Regardless, it's moot until the above issue is fixed!

drivera73 commented 1 year ago

Reading up on this old issue it seems that my problem is the reverse: how to receive FDs from the base DBus process (specifically, systemd-logind).

drivera73 commented 1 year ago

Ok so using that nativefd library did fix the problem.

Regardless, perhaps you should add a mechanism for the library to check with the selected transport to see if FD passing is supported, and turn it off accordingly.

Still, great work! This has helped me a ton!

Now all I have to do is figure out how to close that FD! But jnr-posix (already pulled in from the dbus-java-nativefd library) solves that problem for me!

Question: why don't you merge the dbus-java-nativefd library into the base code? Seems like it might be a good idea to have it all in one place...