Не удается подключиться к серверу Bluetooth/BlueZ: не удалось создать сокет RFCOMM

Я пытаюсь создать простое и индивидуальное соединение Bluetooth между моим ноутбуком Linux и телефоном Android. Что касается Linux, я использую библиотеку BlueZ libbluetooth для настройки сервера. Код для него очень похож на другие, которые я видел на github:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>

sdp_session_t *register_service();

int main(int argc, char **argv)
{
    struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
    char buf[1024] = { 0 };
    char str[1024] = { 0 };
    int s, client, bytes_read;
    sdp_session_t *session;
    socklen_t opt = sizeof(rem_addr);

    session = register_service();
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    loc_addr.rc_family = AF_BLUETOOTH;
    loc_addr.rc_bdaddr = *BDADDR_ANY;
    loc_addr.rc_channel = (uint8_t) 11;

    printf("Trying to bind...");
    fflush(stdout);
    bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
    printf("bound\n");
    fflush(stdout);
    printf("Waiting for connection...");
    fflush(stdout);
    listen(s, 1);
    client = accept(s, (struct sockaddr *)&rem_addr, &opt);
    ba2str( &rem_addr.rc_bdaddr, buf );
    fprintf(stderr, "accepted connection from %s\n", buf);
    memset(buf, 0, sizeof(buf));
    bytes_read = read(client, buf, sizeof(buf));
    if( bytes_read > 0 ) {
     printf("received [%s]\n", buf);
    }
    sprintf(str,"to Android.");
    printf("sent [%s]\n",str);
    write(client, str, sizeof(str));
    close(client);
    close(s);
    sdp_close( session );

    return 0;
}

sdp_session_t *register_service()
{
  uint32_t svc_uuid_int[] = { 0x00000000,0x00000000,0x00000000,0x3233 };
  uint8_t rfcomm_channel = 11;
  const char *service_name = "Remote Host";
  const char *service_dsc = "What the remote should be connecting to.";
  const char *service_prov = "Your mother";

  uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid;
  sdp_list_t *l2cap_list = 0,
       *rfcomm_list = 0,
       *root_list = 0,
       *proto_list = 0,
       *access_proto_list = 0;
  sdp_data_t *channel = 0, *psm = 0;

  sdp_record_t *record = sdp_record_alloc();

  // set the general service ID
  sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
  sdp_set_service_id( record, svc_uuid );
  sdp_list_t service_class = {NULL, &svc_uuid};
  sdp_set_service_classes( record, &service_class);

  // make the service record publicly browsable
  sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
  root_list = sdp_list_append(0, &root_uuid);
  sdp_set_browse_groups( record, root_list );

  // set l2cap information
  sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
  l2cap_list = sdp_list_append( 0, &l2cap_uuid );
  proto_list = sdp_list_append( 0, l2cap_list );

  // set rfcomm information
  sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
  channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
  rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );
  sdp_list_append( rfcomm_list, channel );
  sdp_list_append( proto_list, rfcomm_list );

  // attach protocol information to service record
  access_proto_list = sdp_list_append( 0, proto_list );
  sdp_set_access_protos( record, access_proto_list );

  // set the name, provider, and description
  sdp_set_info_attr(record, service_name, service_prov, service_dsc);

  int err = 0;
  sdp_session_t *session = 0;

  // connect to the local SDP server, register the service record, and
  // disconnect
  session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY );
  err = sdp_record_register(session, record, 0);

  // cleanup
  //sdp_data_free( channel );
  sdp_list_free( l2cap_list, 0 );
  sdp_list_free( rfcomm_list, 0 );
  sdp_list_free( root_list, 0 );
  sdp_list_free( access_proto_list, 0 );

  return session;
}

Я могу запустить код на стороне сервера в Linux без ошибок:

$ ./bluetooth-server
Trying to bind...bound
Waiting for connection...

Затем я могу использовать sdptool, чтобы увидеть свой сокет и службу RFCOMM (описание, номер канала и вся остальная информация выглядят правильно):

Service Name: Remote Host
Service Description: What the remote should be connecting to.
Service Provider: Your mother
Service RecHandle: 0x10009
Service Class ID List:
  UUID 128: 00000000-0000-0000-0000-000033320000
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 11

Теперь, что касается Android, я сначала подключаю телефон к серверу Linux через стандартный экран настроек. После сопряжения я затем использую код на стороне Android для поиска устройств Bluetooth, и если это мое устройство Linux, я пытаюсь подключиться к нему. Я пробовал два разных метода, которые люди предложили при переполнении стека, чтобы установить соединение:

if (BluetoothDevice.ACTION_FOUND.equals(action)) {
    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    if(device.getName().equals("ubuntu-0")) {
        try {
            mBluetoothAdapter.cancelDiscovery();

            // This returns the value 00001103-0000-1000-8000-00805f9b34fb
            UUID uuid = device.getUuids()[0].getUuid();

            // This does not work
            //BluetoothSocket tmp = device.createRfcommSocketToServiceRecord(uuid);

            // And neither does this
            Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
            BluetoothSocket tmp = (BluetoothSocket) m.invoke(device, 11);  // Match channel 11

            tmp.connect();   // Exception is thrown here
        }
        catch(Exception e) {
            Log.e("BT", "Could not create RFCOMM socket " + e.toString());
        }
    }
}

Я продолжаю получать следующее исключение, когда я действительно пытаюсь выполнить вызов tmp.connect():

03-20 14:20:13.089: E/BT(16915): Could not create RFCOMM socket 
   java.io.IOException: read failed, socket might closed or timeout, read ret: -1

Кто-нибудь видит, что я делаю неправильно, пытаясь создать соединение? Обратите внимание, что я действительно получаю возвращаемый UUID при вызове UUID uuid = device.getUuids()[0].getUuid();... это наводит меня на мысль, что сопряжение в порядке, что возвращает значение 00001103-0000-1000-8000-00805f9b34fb.


person gnychis    schedule 20.03.2014    source источник
comment
0x1103 — это профиль DUN — это служба, которую вы пытаетесь подключить?   -  person TwinPrimesAreEz    schedule 25.03.2014
comment
У меня аналогичная логика приложения, и мне пришлось вручную создать правильный UUID на стороне Android с UUID.fromString("..."), потому что device.getUuids() возвращал null (а не другой UUID, как вы).   -  person kagmole    schedule 09.06.2017


Ответы (1)


Возможно, это может быть причиной, если вы подключаете свое устройство перед запуском ./bluetooth-server, тогда запись службы rfcomm не добавляется, и удаленное устройство не будет получать информацию об этом, и если удаленное устройство не выполняет обнаружение службы, то оно не сможет подключиться на ваше устройство.

person ASB    schedule 20.02.2015