Not receiving UNIX_FD property
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.
Just stumbled upon this bug as well, is there any workaround?
Implemented support here: https://github.com/LEW21/pydbus/compare/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)?
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?
@ukBaz, thanks for testing! The file descriptor will be received as int (not dbus.UnixFd), have you tried reading from it using os.read?
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)
~~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.
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.