由于蓝牙,BlueZ 在使用 SDP 进行广告时无法接受传入连接

BlueZ unable to accept incoming connection while advertising with SDP due to bluetoothd

我正在尝试使用 Pi 来模拟使用 BlueZ C 的蓝牙设备 api。我能够分别 1) 配置 SDP 服务器以通告正确的服务和 2) 监听并建立 L2CAP 连接。但是,我无法同时进行这两项操作。

问题是 sdp_record_register() will segfault unless bluetoothd is both running and in compatibility mode. However, accept() won't return for the Bluetooth socket 如果 bluetoothd 是 运行,因为 bluetoothd 会窃取请求。

所以我可以:

  1. Register/advertise 我的服务使用 SDP,但无法接受传入连接,运行 bluetoothd(在兼容模式下)。
  2. 能够接受传入连接,但不能register/advertise我的服务,不运行 bluetoothd

设置 SDP 服务

  int deviceID = hci_get_route(NULL);
  if (deviceID < 0) {
    printf("Error: Bluetooth device not found\n");
    exit(1);
  }

  int bluetoothHCISocket = hci_open_dev(deviceID);
  if (bluetoothHCISocket < 0) {
    perror("hci_open_device");
    exit(2);
  }

  /* some HCI config */

  sdp_session_t *session = sdp_connect(&myBDAddrAny, &myBDAddrLocal, SDP_RETRY_IF_BUSY);
  sdp_record_t record;
  bzero(&record, sizeof(sdp_record_t));
  record.handle = 0x10000;

  /* register all of the attributes for my service */

  printf("Might segfault\n");
  if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
    perror("sdp_record_register");
    exit(7);
  }
  printf("Didn't segfault\n");

这在 bluetoothd 在兼容模式下是 运行 时有效,但在默认模式下它不是 运行 或 运行 时会出现段错误。

正在接受蓝牙连接

  int btSocket = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
  if (btSocket < 0) {
    perror("socket");
    exit(3);
  }
  struct sockaddr_l2 loc_addr = { 0 };
  loc_addr.l2_family = AF_BLUETOOTH;
  loc_addr.l2_bdaddr = myBDAddrAny;
  loc_addr.l2_psm = htobs(0x11);

  if (bind(btSocket, (struct sockaddr *)&loc_addr, sizeof(loc_addr))) {
    perror("bind");
    exit(4);
  }
  if (listen(btSocket, 1)) {
    perror("listen");
    exit(6);
  }

  struct sockaddr_l2 remoteAddress;
  socklen_t socketSize = sizeof(remoteAddress);
  printf("Waiting for connection\n");
  int clientSocket = accept(btSocket, (struct sockaddr *)&remoteAddress, &socketSize);

bluetoothd 不是 运行 时,这将正确地接受传入连接,但如果 bluetoothd 是 运行,accept() 永远不会 return ](在任何模式下)。

我一直无法调和这两个问题。看起来理想的解决方案是以某种方式告诉 bluetoothd 忽略 PSM 0x11 上的连接(因为这意味着它的代理仍然可以处理配对),但我不知道该怎么做。

(不令人满意但正确的)答案是不使用 hci* API。 API 显然已被弃用,因此不会修复像段错误这样的错误。正确的做法是使用 DBus API。 API 几乎和 hci API 一样麻烦,但至少有文档记录。

在换掉我用 glib-2.0 提供的 gdbus API 编写的大量基于 hci 的代码来设置 SDP 服务之后,我终于可以做广告了服务并同时连接。我的套接字代码无需修改即可工作。