bt_dbus: bypass nim-dbus getPrimitive bug with robust custom parser

This commit is contained in:
Niko Marmeladkov 2026-05-30 12:27:33 +03:00
parent d250f8b6ab
commit 7e3c8c8e47
Signed by untrusted user who does not match committer: Niko
GPG key ID: E3B955F9442D44E3
2 changed files with 105 additions and 8 deletions

View file

@ -41,12 +41,14 @@ build() {
patch_dbus patch_dbus
rm -rf "$srcdir/nimcache" rm -rf "$srcdir/nimcache"
nim c \ nim c \
--path:"$NIMBLE_DIR/pkgs2" \ --noNimblePath \
--nimblePath:"$NIMBLE_DIR/pkgs2" \
--nimcache:"$srcdir/nimcache" \ --nimcache:"$srcdir/nimcache" \
--mm:orc -d:release --opt:speed --hints:off \ --mm:orc -d:release --opt:speed --hints:off \
-o:build/nbt src/nbt.nim -o:build/nbt src/nbt.nim
nim c \ nim c \
--path:"$NIMBLE_DIR/pkgs2" \ --noNimblePath \
--nimblePath:"$NIMBLE_DIR/pkgs2" \
--nimcache:"$srcdir/nimcache" \ --nimcache:"$srcdir/nimcache" \
--mm:orc -d:release --opt:speed --hints:off \ --mm:orc -d:release --opt:speed --hints:off \
-o:build/nimbt-daemon src/nimbt_daemon.nim -o:build/nimbt-daemon src/nimbt_daemon.nim

View file

@ -22,6 +22,8 @@ proc newBluezConn*(): BluezConn =
result.adapters = @[] result.adapters = @[]
result.devices = @[] result.devices = @[]
proc readDbusValueRaw*(iter: ptr DBusMessageIter): DbusValue
proc dbusCall*(bz: BluezConn; path, iface, methodName: string; args: openarray[DbusValue] = []): Reply = proc dbusCall*(bz: BluezConn; path, iface, methodName: string; args: openarray[DbusValue] = []): Reply =
var msg = makeCall(BluezDest, path.ObjectPath, iface, methodName) var msg = makeCall(BluezDest, path.ObjectPath, iface, methodName)
for a in args: for a in args:
@ -32,8 +34,8 @@ proc dbusCall*(bz: BluezConn; path, iface, methodName: string; args: openarray[D
proc dbusGet*(bz: BluezConn; path, iface, prop: string): DbusValue = proc dbusGet*(bz: BluezConn; path, iface, prop: string): DbusValue =
let reply = bz.dbusCall(path, PropIface, "Get", @[iface.asDbusValue, prop.asDbusValue]) let reply = bz.dbusCall(path, PropIface, "Get", @[iface.asDbusValue, prop.asDbusValue])
var iter = reply.iterate() var inputIter = reply.iterate()
var val = iter.unpackCurrent(DbusValue) var val = readDbusValueRaw(cast[ptr DBusMessageIter](addr inputIter))
if val != nil and val.kind == dtVariant: if val != nil and val.kind == dtVariant:
val = val.variantValue val = val.variantValue
result = val result = val
@ -47,8 +49,8 @@ proc dbusCallMethod*(bz: BluezConn; path, iface, methodName: string; args: opena
proc dbusGetAll*(bz: BluezConn; path, iface: string): Table[string, DbusValue] = proc dbusGetAll*(bz: BluezConn; path, iface: string): Table[string, DbusValue] =
let reply = bz.dbusCall(path, PropIface, "GetAll", @[iface.asDbusValue]) let reply = bz.dbusCall(path, PropIface, "GetAll", @[iface.asDbusValue])
var iter = reply.iterate() var inputIter = reply.iterate()
let val = iter.unpackCurrent(DbusValue) let val = readDbusValueRaw(cast[ptr DBusMessageIter](addr inputIter))
if val.kind == dtArray: if val.kind == dtArray:
for entry in val.arrayValue: for entry in val.arrayValue:
if entry.kind == dtDictEntry: if entry.kind == dtDictEntry:
@ -107,10 +109,103 @@ proc propsToAdapter(path: string; props: Table[string, DbusValue]): Adapter =
result.discoverable = props.getOrDefault("Discoverable", DbusValue(kind: dtBool, boolValue: false)).boolValue result.discoverable = props.getOrDefault("Discoverable", DbusValue(kind: dtBool, boolValue: false)).boolValue
result.pairable = props.getOrDefault("Pairable", DbusValue(kind: dtBool, boolValue: false)).boolValue result.pairable = props.getOrDefault("Pairable", DbusValue(kind: dtBool, boolValue: false)).boolValue
proc readDbusValueRaw(iter: ptr DBusMessageIter): DbusValue =
let kind = cast[DbusTypeChar](dbus_message_iter_get_arg_type(iter))
case kind:
of dtNull:
return DbusValue(kind: dtNull)
of dtBool:
var v: dbus_uint32_t
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtBool, boolValue: v != 0)
of dtDouble:
var v: float64
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtDouble, doubleValue: v)
of dtInt32:
var v: int32
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtInt32, int32Value: v)
of dtInt16:
var v: int16
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtInt16, int16Value: v)
of dtUint16:
var v: uint16
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtUint16, uint16Value: v)
of dtUint64:
var v: uint64
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtUint64, uint64Value: v)
of dtUint32:
var v: dbus_uint32_t
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtUint32, uint32Value: v)
of dtInt64:
var v: int64
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtInt64, int64Value: v)
of dtByte:
var v: uint8
dbus_message_iter_get_basic(iter, addr v)
return DbusValue(kind: dtByte, byteValue: v)
of dtString:
var s: cstring
dbus_message_iter_get_basic(iter, addr s)
return DbusValue(kind: dtString, stringValue: $s)
of dtObjectPath:
var s: cstring
dbus_message_iter_get_basic(iter, addr s)
return DbusValue(kind: dtObjectPath, objectPathValue: ($s).ObjectPath)
of dtSignature:
var s: cstring
dbus_message_iter_get_basic(iter, addr s)
return DbusValue(kind: dtSignature, signatureValue: ($s).Signature)
of dtVariant:
var subiter: DBusMessageIter
dbus_message_iter_recurse(iter, addr subiter)
let subvalue = readDbusValueRaw(addr subiter)
return DbusValue(kind: dtVariant, variantType: subvalue.kind, variantValue: subvalue)
of dtDictEntry:
var subiter: DBusMessageIter
dbus_message_iter_recurse(iter, addr subiter)
let key = readDbusValueRaw(addr subiter)
discard dbus_message_iter_next(addr subiter)
let val = readDbusValueRaw(addr subiter)
return DbusValue(kind: dtDictEntry, dictKey: key, dictValue: val)
of dtArray:
var subiter: DBusMessageIter
dbus_message_iter_recurse(iter, addr subiter)
var values: seq[DbusValue]
var subkind: DbusType
while true:
let subkindInt = dbus_message_iter_get_arg_type(addr subiter)
subkind = cast[DbusTypeChar](subkindInt)
if subkind.kind == dtNull: break
values.add(readDbusValueRaw(addr subiter))
if dbus_message_iter_has_next(addr subiter) == 0: break
discard dbus_message_iter_next(addr subiter)
if values.len > 0 and subkind.kind == dtDictEntry:
subkind.keyType = values[0].dictKey.kind
subkind.valueType = values[0].dictValue.kind
return DbusValue(kind: dtArray, arrayValueType: subkind, arrayValue: values)
of dtStruct:
var subiter: DBusMessageIter
dbus_message_iter_recurse(iter, addr subiter)
var values: seq[DbusValue]
while true:
values.add(readDbusValueRaw(addr subiter))
if dbus_message_iter_has_next(addr subiter) == 0: break
discard dbus_message_iter_next(addr subiter)
return DbusValue(kind: dtStruct, structValues: values)
else:
raise newException(DbusException, "nim-bt does not support D-Bus type " & $kind)
proc refresh*(bz: BluezConn) = proc refresh*(bz: BluezConn) =
let reply = bz.dbusCall(BluezPath, ObjMgrIface, "GetManagedObjects") let reply = bz.dbusCall(BluezPath, ObjMgrIface, "GetManagedObjects")
var iter = reply.iterate() var inputIter = reply.iterate()
let root = iter.unpackCurrent(DbusValue) let root = readDbusValueRaw(cast[ptr DBusMessageIter](addr inputIter))
bz.adapters = @[] bz.adapters = @[]
bz.devices = @[] bz.devices = @[]
if root.kind == dtArray: if root.kind == dtArray: