Meilleur auteur de réponses
[Bluetooth] Comment récupérer le port/canal d'un service RFCOMM enregistré dans un SDP

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
- Modifié Nemirtingas mardi 25 février 2020 12:54
Réponses
-
Tu peux voir l'exemple à : Bluetooth sockets
- Marqué comme réponse Nemirtingas mardi 25 février 2020 23:37
-
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
Toutes les réponses
-
Tu peux voir l'exemple à : Bluetooth sockets
- Marqué comme réponse Nemirtingas mardi 25 février 2020 23:37
-
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...
- Modifié Nemirtingas mardi 25 février 2020 19:26
-
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