使用busctl通过DBus传递文件描述符出现异常的原因排查
问题:GDBus服务接收文件描述符时出现随机大负数
我使用GDBus实现了一个DBus服务,方法定义的XML代码如下:
<method name='GetMimeTypeData'> <arg name='id' type='s' direction='in'/> <arg name='mime_type' type='s' direction='in'/> <arg name='fd' type='h' direction='in'/> </method>
对应的C函数处理程序:
static gboolean get_mime_type_data_method_cb( BusClippor *object, GDBusMethodInvocation *invocation, const char *id, const char *mime_type, int fd, gpointer user_data ) { ClipporClipboard *cb = user_data; g_message("hello %d", fd); close(fd); bus_clippor_complete_get_mime_type_data(object, invocation); return G_DBUS_METHOD_INVOCATION_HANDLED; }
当我用busctl工具传递shell中创建的文件描述符时,服务端收到的是随机大负数,但方法调用本身能正常接收。调用命令如下:
exec {fd}> output.txt busctl --user call ... $fd
程序输出示例:
** Message: 20:04:40.651: hello -325137072
请问出现该行为的原因是什么?这是否是busctl的限制?
原因分析
这不是busctl的限制,而是传递文件描述符的方式错误:
- shell中
$fd是当前shell进程内的文件描述符编号,但直接将这个数字作为参数传给busctl时,busctl会把它当作普通整数处理,不会触发DBus的文件描述符传递机制。 - GDBus服务端定义的
h类型参数,期望接收的是通过DBus跨进程传递的文件描述符(由内核完成fd的映射)。当收到普通整数时,GDBus内部无法解析出有效的fd,最终得到的是无效的垃圾值,表现为你看到的随机大负数。
解决方法
busctl传递文件描述符需要使用特殊语法,将fd编号包装为fd:<number>格式,正确的调用命令应为:
exec {fd}> output.txt busctl --user call ... fd:$fd
这样busctl才会识别并通过DBus传递对应的文件描述符,服务端就能收到有效的fd数值。
内容的提问来源于stack exchange,提问作者expoodo
相关产品推荐
相关产品推荐

