none
[Bluetooth] Comment récupérer le port/canal d'un service RFCOMM enregistré dans un SDP RRS feed

  • Question

  • Bonjour,

    J'aimerais savoir si quelqu'un sait comment interroger le SDP d'un appareil distant et de récupérer le port RFCOMM enregistré pour un UUID particulier.

    J'arrive bien à me connecter à ce UUID directement depuis les WINAPI grâce à la structure SOCKADDR_BTH:

    typedef struct _SOCKADDR_BTH
    {
        USHORT      addressFamily;  // Always AF_BTH
        BTH_ADDR    btAddr;         // Bluetooth device address
        GUID        serviceClassId; // [OPTIONAL] system will query SDP for port
        ULONG       port;           // RFCOMM channel or L2CAP PSM
    } SOCKADDR_BTH, *PSOCKADDR_BTH;
    Par contre, en me basant sur le code suivant, je n'arrive pas à trouver le port RFCOMM du SDP.

    https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms883458%28v%3dmsdn.10%29

    https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms881237%28v%3dmsdn.10%29

    static int PerformServiceSearch(BTH_ADDR* pb)
    {
        int iResult = 0;
        BTHNS_RESTRICTIONBLOB RBlob;
        memset(&RBlob, 0, sizeof(RBlob));
        RBlob.type = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
        RBlob.numRange = 1;
        RBlob.pRange[0].minAttribute = SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST;
        RBlob.pRange[0].maxAttribute = SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST;
        RBlob.uuids[0].uuidType = SDP_ST_UUID16;
        RBlob.uuids[0].u.uuid16 = SerialPortServiceClassID_UUID16;
        BLOB blob;
        blob.cbSize = sizeof(RBlob);
        blob.pBlobData = (BYTE*)&RBlob;
        SOCKADDR_BTH sa;
        memset(&sa, 0, sizeof(sa));
        sa.btAddr = *pb;
        sa.addressFamily = AF_BTH;
        CSADDR_INFO csai;
        memset(&csai, 0, sizeof(csai));
        csai.RemoteAddr.lpSockaddr = (sockaddr*)&sa;
        csai.RemoteAddr.iSockaddrLength = sizeof(sa);
        WSAQUERYSET wsaq;
        memset(&wsaq, 0, sizeof(wsaq));
        wsaq.dwSize = sizeof(wsaq);
        wsaq.dwNameSpace = NS_ALL;
        wsaq.lpBlob = &blob;
        wsaq.lpcsaBuffer = &csai;
        HANDLE hLookup;
        int iRet = WSALookupServiceBegin(&wsaq, 0, &hLookup);
        if (ERROR_SUCCESS == iRet)
        {
            CHAR buf[5000];
            LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET)buf;
            DWORD dwSize = sizeof(buf);
            memset(pwsaResults, 0, sizeof(WSAQUERYSET));
            pwsaResults->dwSize = sizeof(WSAQUERYSET);
            pwsaResults->dwNameSpace = NS_BTH;
            pwsaResults->lpBlob = NULL;
            iRet = WSALookupServiceNext(hLookup, 0, &dwSize, pwsaResults);
            if (iRet == ERROR_SUCCESS) // Success - got the stream
            {
                //Parse the SDP result set by using the FindRFCOMMChannel function.
                //if (ERROR_SUCCESS == FindRFCOMMChannel(pwsaResults->lpBlob->pBlobData, pwsaResults->lpBlob->cbSize, &cChannel))
                //    iResult = cChannel;
            }
            WSALookupServiceEnd(hLookup);
        }
        return iResult;
    }


    Dans le code ci-dessus, WSALookupServiceBegin me retourne -1 si je remplace

    wsaq.dwNameSpace = NS_ALL;

    par

    wsaq.dwNameSpace = NS_BTH;

    Je ne trouve pas la fonction FindRFCOMMChannel.

    J'ai la même fonction sous Linux qui fonctionne parfaitement.

    Pour ceux que ça interressent, mon code complet se trouve ici: https://gitlab.com/Nemirtingas/socket/-/blob/master/bluetooth/bluetooth_socket.cpp#L262


    mardi 25 février 2020 12:42

Réponses

  • Tu peux voir l'exemple à : Bluetooth sockets
    • Marqué comme réponse Nemirtingas mardi 25 février 2020 23:37
    mardi 25 février 2020 18:05
  • Bonsoir,

    J'ai enfin réussi à faire ce que je voulais... Hourra!

    Comme j'ai assez galéré à trouver des infos et/ou du code sur comment faire je poste mon code là, peut-être que ça aidera quelqu'un:

    #include <bluetoothapis.h>
    
    int sdp_get_proto_port(SDP_ELEMENT_DATA& protocol_container, WORD proto_uuid)
    {
        int port = -1;
        // HBLUETOOTH_CONTAINER_ELEMENT is actually just a PBYTE with offset to the next SDP type
        HBLUETOOTH_CONTAINER_ELEMENT hProtocolContainer = NULL;
        SDP_ELEMENT_DATA protocol_sequence;
        SDP_ELEMENT_DATA elem;
    
        while (BluetoothSdpGetContainerElementData(protocol_container.data.sequence.value, protocol_container.data.sequence.length, &hProtocolContainer, &protocol_sequence) == ERROR_SUCCESS)
        {
            HBLUETOOTH_CONTAINER_ELEMENT hProtocolSequence = NULL;
            int proto_port = -1;
            WORD uuid;
            while (BluetoothSdpGetContainerElementData(protocol_sequence.data.sequence.value, protocol_sequence.data.sequence.length, &hProtocolSequence, &elem) == ERROR_SUCCESS)
            {
                switch(elem.type)
                {
                    case SDP_TYPE_UUID:
                        switch(elem.specificType)
                        {
                            case SDP_ST_UUID16:
                                uuid = elem.data.uuid16;
                                break;
    
                            case SDP_ST_UUID32:
                                uuid = static_cast<WORD>(elem.data.uuid32);
                                break;
    
                            case SDP_ST_UUID128:
                                uuid = BluetoothSocket::uuid128_to_uuid16(elem.data.uuid128);
                                break;
                        }
                        break;
    
                    case SDP_TYPE_UINT:
                        switch (elem.specificType)
                        {
                            case SDP_ST_UINT8 : proto_port = elem.data.uint8 ; break;
                            case SDP_ST_UINT16: proto_port = elem.data.uint16; break;
                        }
                        break;
    
                    case SDP_TYPE_INT:
                        switch (elem.specificType)
                        {
                            case SDP_ST_INT8 : proto_port = elem.data.int8 ; break;
                            case SDP_ST_INT16: proto_port = elem.data.int16; break;
                        }
                        break;
                }
            }
            if (uuid == proto_uuid)
            {
                port = proto_port;
                break;
            }
        }
    
        return port;
    }
    
    int BluetoothSocket::scanOpenPortFromUUID(uuid_t const& uuid, bdaddr_t const& addr)
    {
        int port = -1;
    
        WSAQUERYSETW* querySet = new WSAQUERYSETW;
        if (querySet == nullptr)
            return port;
    
        HANDLE hLookup;
        GUID protocol = RFCOMM_PROTOCOL_UUID;
        std::string str_addr = BluetoothSocket::inet_ntoa(addr);
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        std::wstring addressAsString = converter.from_bytes("(" + str_addr + ")");
        DWORD flags = LUP_FLUSHCACHE | LUP_RETURN_BLOB;
        int result;
    
        memset(querySet, 0, sizeof(*querySet));
        querySet->dwSize = sizeof(*querySet);
        querySet->lpServiceClassId = &protocol;
        querySet->dwNameSpace = NS_BTH;
        querySet->lpszContext = (LPWSTR)addressAsString.c_str();
    
        if (WSALookupServiceBeginW(querySet, flags, &hLookup) == ERROR_SUCCESS)
        {
            DWORD bufferLength = sizeof(WSAQUERYSETW);
            WSAQUERYSET* pResults = reinterpret_cast<WSAQUERYSETW*>(new char[bufferLength]);
            if (pResults != nullptr)
            {
                while (1)
                {
                    result = WSALookupServiceNextW(hLookup, flags, &bufferLength, pResults);
    
                    if (result != ERROR_SUCCESS && WSAGetLastError() == WSAEFAULT && bufferLength > 0)
                    {
                        delete[] reinterpret_cast<char*>(pResults);
                        pResults = reinterpret_cast<WSAQUERYSETW*>(new char[bufferLength]);
                        result = WSALookupServiceNextW(hLookup, flags, &bufferLength, pResults);
                    }
    
                    if (result != ERROR_SUCCESS)
                        break;
    
                    if (pResults->lpBlob)
                    {
                        const BLOB* pBlob = (BLOB*)pResults->lpBlob;
    
                        SDP_ELEMENT_DATA elem;
    
                        if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, SDP_ATTRIB_SERVICE_ID, &elem) == ERROR_SUCCESS)
                        {
                            if (elem.type == SDP_TYPE_UUID)
                            {
                                uuid_t sdp_uuid;
    
                                switch (elem.specificType)
                                {
                                    case SDP_ST_UUID16 : sdp_uuid = uuid16_to_uuid128(elem.data.uuid16); break;
                                    case SDP_ST_UUID32 : sdp_uuid = uuid32_to_uuid128(elem.data.uuid32); break;
                                    case SDP_ST_UUID128: sdp_uuid = elem.data.uuid128; break;
                                }
    
                                if (sdp_uuid == uuid)
                                {
                                    SDP_ELEMENT_DATA protocol_container;
    
                                    // Open the decriptor list sequence
                                    if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, &protocol_container) == ERROR_SUCCESS)
                                    {
                                        port = sdp_get_proto_port(protocol_container, RFCOMM_PROTOCOL_UUID16);
                                    }
    
                                    // If you need theses, just uncomment these lines & use the values
                                    //if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0100, &elem) == ERROR_SUCCESS)
                                    //{
                                    //    if (elem.type == SDP_TYPE_STRING)// Service Name
                                    //    {
                                    //        std::string().assign((char*)elem.data.string.value, elem.data.string.length);
                                    //    }
                                    //}
                                    //if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0101, &elem) == ERROR_SUCCESS)
                                    //{
                                    //    if (elem.type == SDP_TYPE_STRING)// Service Provider
                                    //    {
                                    //        std::string().assign((char*)elem.data.string.value, elem.data.string.length);
                                    //    }
                                    //}
                                    //if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0102, &elem) == ERROR_SUCCESS)
                                    //{
                                    //    if (elem.type == SDP_TYPE_STRING)// Service Description
                                    //    {
                                    //        std::string().assign((char*)elem.data.string.value, elem.data.string.length);
                                    //    }
                                    //}
                                }
                            }
                        }
                    }
                }
    
                delete[] reinterpret_cast<char*>(pResults);
            }
            WSALookupServiceEnd(hLookup);
        }
    
        delete querySet;
        return port;
    }
    
    
    
    

    • Marqué comme réponse Nemirtingas mardi 25 février 2020 23:37
    mardi 25 février 2020 23:37

Toutes les réponses

  • Tu peux voir l'exemple à : Bluetooth sockets
    • Marqué comme réponse Nemirtingas mardi 25 février 2020 23:37
    mardi 25 février 2020 18:05
  • Bonsoir,

    Merci, j'avais trouvé quelque-chose de similaire en cherchant autre-chose.

    J'y suis presque arrivé, voilà où j'en suis:

    int iResult = -1; char buff[5000]; WSAQUERYSET* querySet2 = (WSAQUERYSET*)buff; memset(querySet2, 0, sizeof(*querySet2)); querySet2->dwSize = sizeof(buff); GUID protocol = RFCOMM_PROTOCOL_UUID; querySet2->lpServiceClassId = &protocol; querySet2->dwNameSpace = NS_BTH; std::string str_addr = BluetoothSocket::inet_ntoa(addr); std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; std::wstring addressAsString = converter.from_bytes("(" + str_addr + ")"); querySet2->lpszContext = (LPWSTR)addressAsString.c_str(); HANDLE hLookup2; DWORD flags = LUP_FLUSHCACHE | LUP_RETURN_ADDR | LUP_RETURN_BLOB; int result = WSALookupServiceBegin(querySet2, flags, &hLookup2); if (0 == result) { while (0 == result) { BYTE buffer[2000]; DWORD bufferLength = sizeof(buffer); WSAQUERYSET* pResults = (WSAQUERYSET*)&buffer; result = WSALookupServiceNext(hLookup2, flags, &bufferLength, pResults); if (result == 0) { if (pResults->lpBlob) { const BLOB* pBlob = (BLOB*)pResults->lpBlob; SDP_ELEMENT_DATA elem; BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, SDP_ATTRIB_SERVICE_ID, &elem); if (elem.type == SDP_TYPE_UUID) { uuid_t sdp_uuid; switch (elem.specificType) { case SDP_ST_UUID16: sdp_uuid = { elem.data.uuid16, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB} }; break; case SDP_ST_UUID32: sdp_uuid = { elem.data.uuid32, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB} }; break; case SDP_ST_UUID128: sdp_uuid = elem.data.uuid128; break; } if (sdp_uuid == uuid) {

    // Bloqué ICI HBLUETOOTH_CONTAINER_ELEMENT hElem = NULL; BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, &elem); //BluetoothSdpGetContainerElementData(elem.data.sequence.value, elem.data.sequence.length, &hElem, &elem); BluetoothSdpGetAttributeValue(elem.data.sequence.value, elem.data.sequence.length, RFCOMM_PROTOCOL_UUID16, &elem);

    // Bloqué BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0100, &elem); if (elem.type == SDP_TYPE_STRING)// Service Name { //std::string().assign((char*)elem.data.string.value, elem.data.string.length); } BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0101, &elem); if (elem.type == SDP_TYPE_STRING)// Service Provider { //std::string().assign((char*)elem.data.string.value, elem.data.string.length); } BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0102, &elem); if (elem.type == SDP_TYPE_STRING)// Service Description { //std::string().assign((char*)elem.data.string.value, elem.data.string.length); } } } pBlob = nullptr; } } } result = WSALookupServiceEnd(hLookup2); } return iResult;

    }


    Pour le moment ça marche à l'exception que je n'arrive pas à récupérer le port RFCOMM de mon SDP.

    Voici comment je déclare mon SDP sur mon serveur sous Linux avec BlueZ 5:

    <?xml version="1.0" encoding="UTF-8" ?>
    <record>
      <attribute id="0x0003">
        <uuid value="uuid128" />
      </attribute>
      <attribute id="0x0004">
        <sequence>
          <sequence>
            <uuid value="0x0100" />
          </sequence>
          <sequence>
            <uuid value="0x0003" />
            <uint8 value="0x00 channel" />
          </sequence>
        </sequence>
      </attribute>
      <attribute id="0x0005">
      <sequence>
        <uuid value="0x1002" />
        </sequence>
      </attribute>
      <attribute id="0x0100">
        <text value="srv_name"" />
      </attribute>
      <attribute id="0x0101">
        <text value="srv_prov" />
      </attribute>
      <attribute id="0x0102">
        <text value="srv_desc" />
      </attribute>
    </record>

    Il faut que j'ouvre la séquence d'attribut 0x0004 (SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST) et que je récupère l'attribute qui se trouve dans la sous-séquence 0x0003(RFCOMM_PROTOCOL_UUID16).

    Je continue de chercher, je dois pas être loin.

    J'aimerais bien finir ma lib depuis le temps que je traine dans un coin cette fonction Bluetooth manquante sur Windows...


    mardi 25 février 2020 18:32
  • Bonsoir,

    J'ai enfin réussi à faire ce que je voulais... Hourra!

    Comme j'ai assez galéré à trouver des infos et/ou du code sur comment faire je poste mon code là, peut-être que ça aidera quelqu'un:

    #include <bluetoothapis.h>
    
    int sdp_get_proto_port(SDP_ELEMENT_DATA& protocol_container, WORD proto_uuid)
    {
        int port = -1;
        // HBLUETOOTH_CONTAINER_ELEMENT is actually just a PBYTE with offset to the next SDP type
        HBLUETOOTH_CONTAINER_ELEMENT hProtocolContainer = NULL;
        SDP_ELEMENT_DATA protocol_sequence;
        SDP_ELEMENT_DATA elem;
    
        while (BluetoothSdpGetContainerElementData(protocol_container.data.sequence.value, protocol_container.data.sequence.length, &hProtocolContainer, &protocol_sequence) == ERROR_SUCCESS)
        {
            HBLUETOOTH_CONTAINER_ELEMENT hProtocolSequence = NULL;
            int proto_port = -1;
            WORD uuid;
            while (BluetoothSdpGetContainerElementData(protocol_sequence.data.sequence.value, protocol_sequence.data.sequence.length, &hProtocolSequence, &elem) == ERROR_SUCCESS)
            {
                switch(elem.type)
                {
                    case SDP_TYPE_UUID:
                        switch(elem.specificType)
                        {
                            case SDP_ST_UUID16:
                                uuid = elem.data.uuid16;
                                break;
    
                            case SDP_ST_UUID32:
                                uuid = static_cast<WORD>(elem.data.uuid32);
                                break;
    
                            case SDP_ST_UUID128:
                                uuid = BluetoothSocket::uuid128_to_uuid16(elem.data.uuid128);
                                break;
                        }
                        break;
    
                    case SDP_TYPE_UINT:
                        switch (elem.specificType)
                        {
                            case SDP_ST_UINT8 : proto_port = elem.data.uint8 ; break;
                            case SDP_ST_UINT16: proto_port = elem.data.uint16; break;
                        }
                        break;
    
                    case SDP_TYPE_INT:
                        switch (elem.specificType)
                        {
                            case SDP_ST_INT8 : proto_port = elem.data.int8 ; break;
                            case SDP_ST_INT16: proto_port = elem.data.int16; break;
                        }
                        break;
                }
            }
            if (uuid == proto_uuid)
            {
                port = proto_port;
                break;
            }
        }
    
        return port;
    }
    
    int BluetoothSocket::scanOpenPortFromUUID(uuid_t const& uuid, bdaddr_t const& addr)
    {
        int port = -1;
    
        WSAQUERYSETW* querySet = new WSAQUERYSETW;
        if (querySet == nullptr)
            return port;
    
        HANDLE hLookup;
        GUID protocol = RFCOMM_PROTOCOL_UUID;
        std::string str_addr = BluetoothSocket::inet_ntoa(addr);
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        std::wstring addressAsString = converter.from_bytes("(" + str_addr + ")");
        DWORD flags = LUP_FLUSHCACHE | LUP_RETURN_BLOB;
        int result;
    
        memset(querySet, 0, sizeof(*querySet));
        querySet->dwSize = sizeof(*querySet);
        querySet->lpServiceClassId = &protocol;
        querySet->dwNameSpace = NS_BTH;
        querySet->lpszContext = (LPWSTR)addressAsString.c_str();
    
        if (WSALookupServiceBeginW(querySet, flags, &hLookup) == ERROR_SUCCESS)
        {
            DWORD bufferLength = sizeof(WSAQUERYSETW);
            WSAQUERYSET* pResults = reinterpret_cast<WSAQUERYSETW*>(new char[bufferLength]);
            if (pResults != nullptr)
            {
                while (1)
                {
                    result = WSALookupServiceNextW(hLookup, flags, &bufferLength, pResults);
    
                    if (result != ERROR_SUCCESS && WSAGetLastError() == WSAEFAULT && bufferLength > 0)
                    {
                        delete[] reinterpret_cast<char*>(pResults);
                        pResults = reinterpret_cast<WSAQUERYSETW*>(new char[bufferLength]);
                        result = WSALookupServiceNextW(hLookup, flags, &bufferLength, pResults);
                    }
    
                    if (result != ERROR_SUCCESS)
                        break;
    
                    if (pResults->lpBlob)
                    {
                        const BLOB* pBlob = (BLOB*)pResults->lpBlob;
    
                        SDP_ELEMENT_DATA elem;
    
                        if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, SDP_ATTRIB_SERVICE_ID, &elem) == ERROR_SUCCESS)
                        {
                            if (elem.type == SDP_TYPE_UUID)
                            {
                                uuid_t sdp_uuid;
    
                                switch (elem.specificType)
                                {
                                    case SDP_ST_UUID16 : sdp_uuid = uuid16_to_uuid128(elem.data.uuid16); break;
                                    case SDP_ST_UUID32 : sdp_uuid = uuid32_to_uuid128(elem.data.uuid32); break;
                                    case SDP_ST_UUID128: sdp_uuid = elem.data.uuid128; break;
                                }
    
                                if (sdp_uuid == uuid)
                                {
                                    SDP_ELEMENT_DATA protocol_container;
    
                                    // Open the decriptor list sequence
                                    if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, &protocol_container) == ERROR_SUCCESS)
                                    {
                                        port = sdp_get_proto_port(protocol_container, RFCOMM_PROTOCOL_UUID16);
                                    }
    
                                    // If you need theses, just uncomment these lines & use the values
                                    //if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0100, &elem) == ERROR_SUCCESS)
                                    //{
                                    //    if (elem.type == SDP_TYPE_STRING)// Service Name
                                    //    {
                                    //        std::string().assign((char*)elem.data.string.value, elem.data.string.length);
                                    //    }
                                    //}
                                    //if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0101, &elem) == ERROR_SUCCESS)
                                    //{
                                    //    if (elem.type == SDP_TYPE_STRING)// Service Provider
                                    //    {
                                    //        std::string().assign((char*)elem.data.string.value, elem.data.string.length);
                                    //    }
                                    //}
                                    //if (BluetoothSdpGetAttributeValue(pBlob->pBlobData, pBlob->cbSize, 0x0102, &elem) == ERROR_SUCCESS)
                                    //{
                                    //    if (elem.type == SDP_TYPE_STRING)// Service Description
                                    //    {
                                    //        std::string().assign((char*)elem.data.string.value, elem.data.string.length);
                                    //    }
                                    //}
                                }
                            }
                        }
                    }
                }
    
                delete[] reinterpret_cast<char*>(pResults);
            }
            WSALookupServiceEnd(hLookup);
        }
    
        delete querySet;
        return port;
    }
    
    
    
    

    • Marqué comme réponse Nemirtingas mardi 25 février 2020 23:37
    mardi 25 février 2020 23:37