Bluez DBUS api NewConnection 方法给出了错误的文件描述符

问题描述

我正在尝试使用 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()
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...