Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not receiving UNIX_FD property #54

Open
ukBaz opened this issue May 1, 2017 · 7 comments
Open

Not receiving UNIX_FD property #54

ukBaz opened this issue May 1, 2017 · 7 comments

Comments

@ukBaz
Copy link

ukBaz commented May 1, 2017

This looks similar to #42 but the suggested modifications by @LEW21 do not seem to be having an effect. However I am right at the edge of my knowledge so apologies if this is a duplicate.

I am looking to implement the BlueZ Profile DBus APi
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/profile-api.txt#n104

I have implemented, published and registered the NewConnection method

class Profile(object):
    """
      <node>
        <interface name='org.bluez.Profile1'>
          <method name='Release'>
          </method>
          <method name='NewConnection'>
            <arg type='o' name='path' direction='in'/>
            <arg type='h' name='fd' direction='in'/>
            <arg type='a{sv}' name='properties' direction='in'/>
          </method>
          <method name='RequestDisconnection'>
            <arg type='o' name='path' direction='in'/>
          </method>
        </interface>
      </node>
    """

    def NewConnection(self, path, fd, properties):
        print('New connection', path, type(fd), properties)
        print('fd: ', fd)
        print('Is a tty? ', os.isatty(fd))
        print('tty name: ', os.ttyname(fd))

When a new connection is made the the Bluetooth daemon calls the NewConnection method but the value of fd is wrong:

New connection /org/bluez/hci0/dev_64_BC_0C_F6_22_F8 <class 'int'> {}
fd:  0
Is a tty?  True
tty name:  /dev/pts/0

I say wrong because it gives the tty of the terminal I'm running in and If I monitor the bus then I can see the bluetoothd sending the command with UNIX_FD = 4

linaro@linaro-alip:~/python/pydbus/pydbus$ sudo busctl monitor org.bluez
‣ Type=method_call  Endian=l  Flags=0  Version=1  Priority=0 Cookie=67
  Sender=:1.120  Destination=:1.132  Path=/ukBaz/bluezero/spp  Interface=org.bluez.Profile1  Member=NewConnection
  UniqueName=:1.120
  MESSAGE "oha{sv}" {
          OBJECT_PATH "/org/bluez/hci0/dev_64_BC_0C_F6_22_F8";
          UNIX_FD 4;
          ARRAY "{sv}" {
          };
  };

To confirm what the sender is

linaro@linaro-alip:~/python/pydbus/pydbus$ sudo busctl list
NAME                                       PID PROCESS         USER             CONNECTION    UNIT                      SESSION    DESCRIPTION        
:1.0                                      1696 systemd-logind  root             :1.0          systemd-logind.service    -          -                  
:1.1                                         1 systemd         root             :1.1          init.scope                -          -                  
:1.10                                     1844 systemd-resolve systemd-resolve  :1.10         systemd-resolved.service  -          -                  
:1.11                                     1860 sddm            root             :1.11         sddm.service              -          -                  
:1.12                                     1904 Xorg            root             :1.12         sddm.service              -          -                  
:1.120                                    7147 bluetoothd      root             :1.120        bluetooth.service         -          -     
...

Versions I am running

$ pip3 freeze | grep pydbus
pydbus==0.6.0
$python3 -V
Python 3.5.3
$ uname -a
Linux linaro-alip 4.9.0-linaro-lt-qcom #1 SMP PREEMPT Mon Apr 10 16:08:49 UTC 2017 aarch64 GNU/Linux

As I say, I am right on the edge of my knowledge so I am not sure how to fix this. If someone can give me some guidance then I am willing to do more on this.

@molobrakos
Copy link

Just stumbled upon this bug as well, is there any workaround?

@molobrakos
Copy link

Implemented support here: master...molobrakos:unixfd
Both passing and receiving unix file descriptors should work, but I have mainly tested receiving, and verified that receiving file descriptors for org.bluez.Profile1:NewConnection works, which is my main use case right now.
@ukBaz, maybe you are interested in testing this out as well?
@LEW21, feel free to steal/modify the code, or please let me know it you want it as a PR as-is (thank you for your beautiful and very useful library btw)?

@ukBaz
Copy link
Author

ukBaz commented Mar 23, 2019

Thanks @molobrakos for taking a look at this. I've had time to do some testing tonight.

It is still not coming out as <type 'dbus.UnixFd'> in my tests . When I run with your unixfd branch I still see <type 'int'>

I've been using org.bluez.Profile1:NewConnection to create a Serial Port Profile. Do you have some example code?

@molobrakos
Copy link

@ukBaz, thanks for testing! The file descriptor will be received as int (not dbus.UnixFd), have you tried reading from it using os.read?

@molobrakos
Copy link

molobrakos commented Mar 24, 2019

I could add a proper test case to the tests-directory (but it wasn't obvious anyone, including the maintainer, cared). Anyway, here is how I use it:

UUID_SPP = "00001101-0000-1000-8000-00805f9b34fb"

class Profile:

    def __init__(self, read_callback):
        _LOGGER.debug("Init profile")
        self.read_callback = read_callback
        self.fd = None

    def Release(self):
        _LOGGER.debug("Release")

    def NewConnection(self, path, fd, properties):

        _LOGGER.error("New connection %s %s %s",
                      path, fd, properties)

        if self.fd != None:
            _LOGGER.error("Should not happen")

        self.fd = os.dup(fd)

        _LOGGER.debug("Got fd %s, dup as %d", fd, self.fd)

        def fd_read_callback(fd, conditions):
            _LOGGER.debug("io cb on fd %d (self.fd: %d)", fd, self.fd)
            assert(self.fd == fd)
            data = os.read(fd, 1024)
            _LOGGER.debug("Read %d bytes: %s: %s", len(data), 
                 binascii.hexlify(data), data.decode("ascii"))
            self.read_callback(path, data.decode("ascii"))

            # We are done
            # os.close(self.fd)
            # gobject.source_remove(io_id)
            # self.fd = None

            return True

        io_id = GObject.io_add_watch(self.fd,
                                     GObject.PRIORITY_DEFAULT,
                                     GObject.IO_IN | GObject.IO_PRI,
                                     fd_read_callback)

    def RequestDisconnection(self, path):
        _LOGGER.debug("RequestDisconnection: %s", path)
        if self.fd:
            os.close(self.fd)
            # gobject.source_remove(io_id)
            self.fd = None


def register_spp_profile():
    profile_path = "/foo/bar/profile"
    opts = dict(
        AutoConnect=pydbus.Variant("b", True),
        Role=pydbus.Variant("s", "server"),
        Channel=pydbus.Variant("q", 1),
        RequireAuthorization=pydbus.Variant("b", False),
        RequireAuthentication=pydbus.Variant("b", False),
        Name=pydbus.Variant("s", "Foobar")
    )

    _LOGGER.info("Creating Serial Port Profile")

    def read_cb(path, value):
        _LOGGER.debug("Read value %s", value)

    pydbus.SystemBus().register_object(
        profile_path,
        Profile(read_cb),
        pathlib.Path(__file__).with_name("btspp.xml").read_text())

    blus.profile_manager().RegisterProfile(
        profile_path,
        UUID_SPP, opts)

    _LOGGER.info("Registered profile on %s", profile_path)

(Btw, I don't think I have seen Release or RequestDisconnection being called, but I guess that is a Bluez-issue)

@molobrakos
Copy link

molobrakos commented Mar 25, 2019

Actually there seems to be a problem returning fd:s with the current code (as in direction="out"). Sending and receiving should work. Fixed in latest commit. Also added a test case.

@penguin359
Copy link

Any chance this has been merged in yet? I am looking to use something like this for accepting incoming RFCOMM connections passed in from BlueZ.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants