问题描述
我正在尝试使用 DBUS bluez api 实现 RFCOMM 配置文件。我已经实现了 org.bluez.Profile1
接口并调用了 NewConnection
方法,但是文件描述符参数是错误的。每次调用该方法时,文件描述符为 0。当我尝试写入时,我将 errno 设置为 Bad file descriptor
。
这是method_call回调的代码:
val methodCall = staticCFunction<
CPointer<GDBusConnection>?,CPointer<gcharVar>?,CPointer<GVariant>?,CPointer<GDBusMethodInvocation>?,gpointer?,Unit >
{dbus,sender,objectPath,interfaceName,methodName,parameters,invocation,userData ->
memScoped {
val caller = allocPointerTo<gcharVar>()
val fd = alloc<gint32Var>()
val properties = allocPointerTo<GVariantIter>()
fd.value = -1
g_variant_get(parameters,"(oha{sv})",caller.ptr,fd,properties.ptr)
"""
Method call sender: ${sender?.toKString()}
objectPath: ${objectPath?.toKString()}
interfaceName: ${interfaceName?.toKString()}
methodName: ${methodName?.toKString()}
caller: ${caller.value?.toKString()}
fd: ${fd.value}
""".debug()
val text = "text".cstr
"Written: ${write(fd.value,text,text.size.convert())} bytes".debug()
strerror(errno)?.toKString()?.error()
}
}
产生这个输出:
11:43:43 [DEBUG]
Method call sender: :1.3
objectPath: /org/bluez/myprofile
interfaceName: org.bluez.Profile1
methodName: NewConnection
caller: /org/bluez/hci0/dev_......
fd: 0
11:43:43 [DEBUG] Written: -1 bytes
11:43:43 [ERROR] Bad file descriptor
fun registerBluetoothProfileObject() {
val interfaceDesc =
"""
<node>
<interface name='org.bluez.Profile1'>
<method name='Release' />
<method name='NewConnection'>
<arg type='o' name='device' direction='in' />
<arg type='h' name='fd' direction='in' />
<arg type='a{sv}' name='fd_properties' direction='in' />
</method>
<method name='Requestdisconnection'>
<arg type='o' name='device' direction='in' />
</method>
</interface>
</node>
"""
val vTable = cValue<GDBusInterfaceVTable> {
method_call = Bluetooth.methodCall //This points to the method_call callback
set_property = Bluetooth.setProperty
get_property = Bluetooth.getProperty
}
memScoped {
val error = allocPointerTo<GError>()
val nodeInfo = g_dbus_node_info_new_for_xml(interfaceDesc,error.ptr)
error.value?.let {
"Error creating node from xml ${it.pointed.message?.toKString()}".error()
}
val interfaceInfo = g_dbus_node_info_lookup_interface(nodeInfo,"org.bluez.Profile1")
g_dbus_connection_register_object(
dbus,Bluetooth.PROFILE_OBJECT_PATH,interfaceInfo,vTable.ptr,null,error.ptr
)
error.value?.let {
"Error registering sdp profile object: ${it.pointed.message?.toKString()}".error()
}
}
}
解决方法
所以我发现了问题所在。接口中调用fd
的参数其实不是文件描述符。它是文件描述符字段的索引。所以我得到的 0
值是文件描述符数组中文件描述符的索引,可以使用这样的东西获得
val fdList = g_dbus_message_get_unix_fd_list(g_dbus_method_invocation_get_message(invocation))
传递给 invocation
方法的 g_dbus_method_invocation_get_message
参数来自 callMethod
回调参数。这将返回列表,然后可以使用
val fd = g_unix_fd_list_get(fdList,fdIndex.value,null)
所以回调函数是唯一需要改变的东西。现在看起来像这样
val methodCall = staticCFunction<
CPointer<GDBusConnection>?,CPointer<gcharVar>?,CPointer<GVariant>?,CPointer<GDBusMethodInvocation>?,gpointer?,Unit >
{dbus,sender,objectPath,interfaceName,methodName,parameters,invocation,userData ->
memScoped {
val caller = allocPointerTo<gcharVar>()
val fdIndex = alloc<gint32Var>()
val properties = allocPointerTo<GVariantIter>()
g_variant_get(parameters,"(oha{sv})",caller.ptr,fdIndex,properties.ptr)
"""
Method call sender: ${sender?.toKString()}
objectPath: ${objectPath?.toKString()}
interfaceName: ${interfaceName?.toKString()}
methodName: ${methodName?.toKString()}
caller: ${caller.value?.toKString()}
fd: ${fdIndex.value}
""".debug()
val fdList = g_dbus_message_get_unix_fd_list(g_dbus_method_invocation_get_message(invocation))
val fd = g_unix_fd_list_get(fdList,null)
val text = "text".cstr
"Written: ${write(fd,text,text.size.convert())} bytes".debug()
}
}