BlueZ не может принять входящее соединение во время рекламы с SDP из-за Bluetooth - PullRequest
0 голосов
/ 13 апреля 2020

Я пытаюсь использовать Pi для эмуляции устройства Bluetooth с использованием API BlueZ C. Я могу отдельно 1) настроить сервер SDP для объявления правильной услуги и 2) прослушать и установить sh соединение L2CAP. Тем не менее, я не могу сделать и то и другое одновременно.

Проблема в том, что sdp_record_register () будет вызывать ошибку , если bluetoothd не запущен и не находится в режиме совместимости. Однако accept () не вернется для сокета Bluetooth , если bluetoothd работает, потому что bluetoothd украдет запрос.

Так что я могу либо:

  1. Зарегистрировать / прорекламировать мой сервис с помощью SDP, но не иметь возможности принимать входящие соединения, запустив bluetoothd (в режиме совместимости).
  2. Возможность принимать входящие соединения, но не может регистрировать / рекламировать мою службу, не запуская 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 работает в режиме совместимости, но будет зависать, если он не работает или не работает в режиме по умолчанию.

Принятие соединения Bluetooth

  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 не запущено, но accept() никогда не вернется, если bluetoothd работает (в любом режиме).

Мне не удалось решить эти две проблемы. Кажется, что идеальным решением было бы как-то сказать bluetoothd игнорировать соединения на PSM 0x11 (поскольку это означает, что его агент все еще может обрабатывать сопряжение), но я не могу понять, как это сделать.

1 Ответ

0 голосов
/ 19 апреля 2020

(неудовлетворительный, но правильный) ответ - не использовать hci* API. Этот API явно устарел, поэтому ошибки, подобные этому segfault, не будут исправлены. Правильный способ сделать это - использовать API DBus. Этот API почти такой же громоздкий, как API hci, но, по крайней мере, он задокументирован.

После замены огромного количества кода на основе hci, который я написал с помощью API gdbus, предлагаемого glib- 2.0, чтобы настроить службу SDP, я наконец смог рекламировать услугу и подключиться одновременно. Мой код сокета работал без изменений.

...