4#include <QtCore/QByteArray>
5#include <QtCore/QDebug>
9#include <bluetooth/bluetooth.h>
10#include <bluetooth/sdp.h>
11#include <bluetooth/sdp_lib.h>
13#define RETURN_SUCCESS 0
15#define RETURN_INVALPARAM 2
16#define RETURN_SDP_ERROR 3
20 fprintf(stderr,
"Usage:\n");
21 fprintf(stderr,
"\tsdpscanner <remote bdaddr> <local bdaddr> [Options] ({uuids})\n\n");
22 fprintf(stderr,
"Performs an SDP scan on remote device, using the SDP server\n"
23 "represented by the local Bluetooth device.\n\n"
25 " -p Show scan results in human-readable form\n"
26 " -u [list of uuids] List of uuids which should be scanned for.\n"
27 " Each uuid must be enclosed in {}.\n"
28 " If the list is empty PUBLIC_BROWSE_GROUP scan is used.\n");
31#define BUFFER_SIZE 1024
38 const int length = indentation*2 + 1;
43 xmlOutput.
append(indentString);
48 xmlOutput.
append(
"<nil/>\n");
52 xmlOutput.
append(snBuffer);
56 xmlOutput.
append(snBuffer);
60 xmlOutput.
append(snBuffer);
64 xmlOutput.
append(snBuffer);
67 xmlOutput.
append(
"<uint128 value=\"0x");
68 for (
int i = 0;
i < 16;
i++)
69 ::sprintf(&snBuffer[
i * 2],
"%02x",
data->val.uint128.data[
i]);
70 xmlOutput.
append(snBuffer);
71 xmlOutput.
append(
"\"/>\n");
75 xmlOutput.
append(snBuffer);
79 xmlOutput.
append(snBuffer);
83 xmlOutput.
append(snBuffer);
87 xmlOutput.
append(snBuffer);
90 xmlOutput.
append(
"<int128 value=\"0x");
91 for (
int i = 0;
i < 16;
i++)
92 ::sprintf(&snBuffer[
i * 2],
"%02x",
data->val.int128.data[
i]);
93 xmlOutput.
append(snBuffer);
94 xmlOutput.
append(
"\"/>\n");
100 xmlOutput.
append(
"<uuid value=\"0x");
102 xmlOutput.
append(snBuffer);
103 xmlOutput.
append(
"\"/>\n");
106 xmlOutput.
append(
"<uuid value=\"");
108 xmlOutput.
append(snBuffer);
109 xmlOutput.
append(
"\"/>\n");
111 case SDP_TEXT_STR_UNSPEC:
117 xmlOutput.
append(
"<text ");
120 bool hasNonPrintableChar =
false;
122 if (
text[
i] ==
'\0') {
125 }
else if (!isprint(
text[
i])) {
126 hasNonPrintableChar =
true;
128 if (firstNullIdx > 0)
134 if (hasNonPrintableChar) {
135 xmlOutput.
append(
"encoding=\"hex\" value=\"");
143 xmlOutput.
append(
"value=\"");
147 xmlOutput.
append(
"\"/>\n");
152 xmlOutput.
append(
"<boolean value=\"true\"/>\n");
154 xmlOutput.
append(
"<boolean value=\"false\"/>\n");
161 xmlOutput.
append(
"<sequence>\n");
163 xmlOutput.
append(indentString);
164 xmlOutput.
append(
"</sequence>\n");
171 xmlOutput.
append(
"<alternate>\n");
173 xmlOutput.
append(indentString);
174 xmlOutput.
append(
"</alternate>\n");
176 case SDP_URL_STR_UNSPEC:
182 xmlOutput.
append(
"<url value=\"");
189 xmlOutput.
append(
"\"/>\n");
193 fprintf(stderr,
"Unknown dtd type\n");
211 xmlOutput->
append(
" </attribute>\n");
222 xmlOutput.
append(
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<record>\n");
225 xmlOutput.
append(
"</record>");
238 fprintf(stderr,
"SDP for %s %s\n", argv[1], argv[2]);
242 int result = str2ba(argv[1], &remote);
244 fprintf(stderr,
"Invalid remote address: %s\n", argv[1]);
248 result = str2ba(argv[2], &local);
250 fprintf(stderr,
"Invalid local address: %s\n", argv[2]);
254 bool showHumanReadable =
false;
255 std::vector<std::string> targetServices;
257 for (
int i = 3;
i < argc;
i++) {
258 if (argv[
i][0] !=
'-') {
266 showHumanReadable =
true;
271 for ( ;
i < argc && argv[
i][0] ==
'{';
i++)
272 targetServices.push_back(argv[
i]);
277 fprintf(stderr,
"Wrong argument: %s\n", argv[
i]);
283 std::vector<uuid_t> uuids;
284 for (std::vector<std::string>::const_iterator
iter = targetServices.cbegin();
285 iter != targetServices.cend(); ++
iter) {
288 uint16_t field1, field2, field3, field5;
289 uint32_t field0, field4;
291 fprintf(stderr,
"Target scan for %s\n", (*iter).c_str());
292 if (sscanf((*iter).c_str(),
"{%08x-%04hx-%04hx-%04hx-%08x%04hx}", &field0,
293 &field1, &field2, &field3, &field4, &field5) != 6) {
294 fprintf(stderr,
"Skipping invalid uuid: %s\n", ((*iter).c_str()));
300 field0 = htonl(field0);
301 field4 = htonl(field4);
302 field1 = htons(field1);
303 field2 = htons(field2);
304 field3 = htons(field3);
305 field5 = htons(field5);
307 uint8_t* temp = (uint8_t*) &temp128;
308 memcpy(&temp[0], &field0, 4);
309 memcpy(&temp[4], &field1, 2);
310 memcpy(&temp[6], &field2, 2);
311 memcpy(&temp[8], &field3, 2);
312 memcpy(&temp[10], &field4, 4);
313 memcpy(&temp[14], &field5, 2);
316 sdp_uuid128_create(&sdpUuid, &temp128);
317 uuids.push_back(sdpUuid);
320 sdp_session_t *session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
323 session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
327 fprintf(stderr,
"Cannot establish sdp session\n");
333 fprintf(stderr,
"Using PUBLIC_BROWSE_GROUP for SDP search\n");
334 uuid_t publicBrowseGroupUuid;
335 sdp_uuid16_create(&publicBrowseGroupUuid, PUBLIC_BROWSE_GROUP);
336 uuids.push_back(publicBrowseGroupUuid);
339 uint32_t attributeRange = 0x0000ffff;
340 sdp_list_t *attributes;
341 attributes = sdp_list_append(
nullptr, &attributeRange);
343 sdp_list_t *sdpResults, *sdpIter;
344 sdp_list_t *totalResults =
nullptr;
345 sdp_list_t* serviceFilter;
347 for (uuid_t &uuid : uuids) {
348 serviceFilter = sdp_list_append(
nullptr, &uuid);
349 result = sdp_service_search_attr_req(session, serviceFilter,
351 attributes, &sdpResults);
352 sdp_list_free(serviceFilter,
nullptr);
354 fprintf(stderr,
"sdp_service_search_attr_req failed\n");
355 sdp_list_free(attributes,
nullptr);
364 totalResults = sdpResults;
365 sdpIter = totalResults;
368 sdpIter->next = sdpResults;
371 while (sdpIter->next)
372 sdpIter = sdpIter->next;
374 sdp_list_free(attributes,
nullptr);
377 sdpResults = totalResults;
381 sdp_record_t *
record = (sdp_record_t *) sdpResults->data;
386 sdpIter = sdpResults;
387 sdpResults = sdpResults->next;
393 if (showHumanReadable)
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toBase64(Base64Options options=Base64Encoding) const
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
QByteArray & replace(qsizetype index, qsizetype len, const char *s, qsizetype alen)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString & replace(qsizetype i, qsizetype len, QChar after)
qsizetype size() const
Returns the number of characters in this string.
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
void resize(qsizetype size)
Sets the size of the string to size characters.
QByteArray toEncoded(FormattingOptions options=FullyEncoded) const
Returns the encoded representation of the URL if it's valid; otherwise an empty QByteArray is returne...
static QUrl fromEncoded(QByteArrayView input, ParsingMode mode=TolerantMode)
Parses input and returns the corresponding QUrl.
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
size_t qstrnlen(const char *str, size_t maxlen)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
QByteArray parseSdpRecord(sdp_record_t *record)
#define RETURN_INVALPARAM
static void parseAttribute(void *value, void *extraData)
static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &xmlOutput)
QUrl url("example.com")
[constructor-url-reference]