int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec) { sdp_data_t *data; sdp_list_t *pattern; if (rec->handle == 0xffffffff) { rec->handle = sdp_next_handle(); if (rec->handle < 0x10000) return -ENOSPC; } else { if (sdp_record_find(rec->handle)) return -EEXIST; } DBG("Adding record with handle 0x%05x", rec->handle); sdp_record_add(src, rec); data = sdp_data_alloc(SDP_UINT32, &rec->handle); sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data); if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) { uuid_t uuid; sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); sdp_pattern_add_uuid(rec, &uuid); } for (pattern = rec->pattern; pattern; pattern = pattern->next) { char uuid[32]; if (pattern->data == NULL) continue; sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid)); DBG("Record pattern UUID %s", uuid); } update_db_timestamp(); return 0; }
/* Allows this service to be discovered when running sdptool. For example, you can find this service * after starting it by running * * $ sdptool browse local * * (Adapted from http://www.btessentials.com/examples/bluez/sdp-register.c) * */ sdp_session_t *register_service(uint8_t rfcomm_channel) { /* A 128-bit number used to identify this service. The words are ordered from most to least * significant, but within each word, the octets are ordered from least to most significant. * For example, the UUID represneted by this array is 00001101-0000-1000-8000-00805F9B34FB. (The * hyphenation is a convention specified by the Service Discovery Protocol of the Bluetooth Core * Specification, but is not particularly important for this program.) * * This UUID is the Bluetooth Base UUID and is commonly used for simple Bluetooth applications. * Regardless of the UUID used, it must match the one that the Armatus Android app is searching * for. */ uint32_t svc_uuid_int[] = { 0x01110000, 0x00100000, 0x80000080, 0xFB349B5F }; const char *service_name = "Armatus Bluetooth server"; const char *svc_dsc = "A HERMIT server that interfaces with the Armatus Android app"; const char *service_prov = "Armatus"; uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class_uuid; sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_class_list = 0, *profile_list = 0; sdp_data_t *channel = 0; sdp_profile_desc_t profile; sdp_record_t record = { 0 }; sdp_session_t *session = 0; // set the general service ID sdp_uuid128_create(&svc_uuid, &svc_uuid_int); sdp_set_service_id(&record, svc_uuid); char str[256] = ""; sdp_uuid2strn(&svc_uuid, str, 256); printf("Registering UUID %s\n", str); // set the service class sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID); svc_class_list = sdp_list_append(0, &svc_class_uuid); sdp_set_service_classes(&record, svc_class_list); // set the Bluetooth profile information sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID); profile.version = 0x0100; profile_list = sdp_list_append(0, &profile); sdp_set_profile_descs(&record, profile_list); // 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); // register the RFCOMM channel for RFCOMM sockets 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); 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, svc_dsc); // connect to the local SDP server, register the service record, // and disconnect session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); 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); sdp_list_free(svc_class_list, 0); sdp_list_free(profile_list, 0); return session; }
static DBusMessage *request_authorization(DBusConnection *conn, DBusMessage *msg, void *data) { struct record_data *user_record; struct service_adapter *serv_adapter = data; sdp_record_t *record; sdp_list_t *services; const char *sender; dbus_uint32_t handle; const char *address; struct pending_auth *auth; char uuid_str[MAX_LEN_UUID_STR]; uuid_t *uuid, *uuid128; bdaddr_t src; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID) == FALSE) return NULL; sender = dbus_message_get_sender(msg); if (find_pending_by_sender(serv_adapter, sender)) return btd_error_does_not_exist(msg); user_record = find_record(serv_adapter, handle, sender); if (!user_record) { user_record = find_record(serv_adapter_any, handle, sender); if (!user_record) return btd_error_not_authorized(msg); } record = sdp_record_find(user_record->handle); if (record == NULL) return btd_error_not_authorized(msg); if (sdp_get_service_classes(record, &services) < 0) { sdp_record_free(record); return btd_error_not_authorized(msg); } if (services == NULL) return btd_error_not_authorized(msg); uuid = services->data; uuid128 = sdp_uuid_to_uuid128(uuid); sdp_list_free(services, bt_free); if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) { bt_free(uuid128); return btd_error_not_authorized(msg); } bt_free(uuid128); auth = g_new0(struct pending_auth, 1); auth->msg = dbus_message_ref(msg); auth->conn = dbus_connection_ref(connection); auth->sender = user_record->sender; memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR); str2ba(address, &auth->dst); serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list, auth); auth = next_pending(serv_adapter); if (auth == NULL) return btd_error_does_not_exist(msg); if (serv_adapter->adapter) adapter_get_address(serv_adapter->adapter, &src); else bacpy(&src, BDADDR_ANY); if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb, serv_adapter) < 0) { serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list, auth); g_free(auth); return btd_error_not_authorized(msg); } return NULL; }
static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &xmlOutput) { if (!data) return; const int length = indentation*2 + 1; QByteArray indentString(length, ' '); char snBuffer[BUFFER_SIZE]; xmlOutput.append(indentString); // deal with every dtd type switch (data->dtd) { case SDP_DATA_NIL: xmlOutput.append("<nil/>\n"); break; case SDP_UINT8: qsnprintf(snBuffer, BUFFER_SIZE, "<uint8 value=\"0x%02x\"/>\n", data->val.uint8); xmlOutput.append(snBuffer); break; case SDP_UINT16: qsnprintf(snBuffer, BUFFER_SIZE, "<uint16 value=\"0x%04x\"/>\n", data->val.uint16); xmlOutput.append(snBuffer); break; case SDP_UINT32: qsnprintf(snBuffer, BUFFER_SIZE, "<uint32 value=\"0x%08x\"/>\n", data->val.uint32); xmlOutput.append(snBuffer); break; case SDP_UINT64: qsnprintf(snBuffer, BUFFER_SIZE, "<uint64 value=\"0x%016x\"/>\n", data->val.uint64); xmlOutput.append(snBuffer); break; case SDP_UINT128: xmlOutput.append("<uint128 value=\"0x"); for (int i = 0; i < 16; i++) ::sprintf(&snBuffer[i * 2], "%02x", data->val.uint128.data[i]); xmlOutput.append(snBuffer); xmlOutput.append("\"/>\n"); break; case SDP_INT8: qsnprintf(snBuffer, BUFFER_SIZE, "<int8 value=\"%d\"/>/n", data->val.int8); xmlOutput.append(snBuffer); break; case SDP_INT16: qsnprintf(snBuffer, BUFFER_SIZE, "<int16 value=\"%d\"/>/n", data->val.int16); xmlOutput.append(snBuffer); break; case SDP_INT32: qsnprintf(snBuffer, BUFFER_SIZE, "<int32 value=\"%d\"/>/n", data->val.int32); xmlOutput.append(snBuffer); break; case SDP_INT64: qsnprintf(snBuffer, BUFFER_SIZE, "<int64 value=\"%d\"/>/n", data->val.int64); xmlOutput.append(snBuffer); break; case SDP_INT128: xmlOutput.append("<int128 value=\"0x"); for (int i = 0; i < 16; i++) ::sprintf(&snBuffer[i * 2], "%02x", data->val.int128.data[i]); xmlOutput.append(snBuffer); xmlOutput.append("\"/>\n"); break; case SDP_UUID_UNSPEC: break; case SDP_UUID16: case SDP_UUID32: xmlOutput.append("<uuid value=\"0x"); sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE); xmlOutput.append(snBuffer); xmlOutput.append("\"/>\n"); break; case SDP_UUID128: xmlOutput.append("<uuid value=\""); sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE); xmlOutput.append(snBuffer); xmlOutput.append("\"/>\n"); break; case SDP_TEXT_STR_UNSPEC: break; case SDP_TEXT_STR8: case SDP_TEXT_STR16: case SDP_TEXT_STR32: { xmlOutput.append("<text "); QByteArray text = QByteArray::fromRawData(data->val.str, data->unitSize); bool hasNonPrintableChar = false; for (int i = 0; i < text.count(); i++) { if (text[i] == '\0') { text.resize(i); // cut trailing content break; } else if (!isprint(text[i])) { hasNonPrintableChar = true; text.resize(text.indexOf('\0')); // cut trailing content break; } } if (hasNonPrintableChar) { xmlOutput.append("encoding=\"hex\" value=\""); xmlOutput.append(text.toHex()); } else { text.replace('&', "&"); text.replace('<', "<"); text.replace('>', ">"); text.replace('"', """); xmlOutput.append("value=\""); xmlOutput.append(text); } xmlOutput.append("\"/>\n"); break; } case SDP_BOOL: if (data->val.uint8) xmlOutput.append("<boolean value=\"true\"/>\n"); else xmlOutput.append("<boolean value=\"false\"/>\n"); break; case SDP_SEQ_UNSPEC: break; case SDP_SEQ8: case SDP_SEQ16: case SDP_SEQ32: xmlOutput.append("<sequence>\n"); parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput); xmlOutput.append(indentString); xmlOutput.append("</sequence>\n"); break; case SDP_ALT_UNSPEC: break; case SDP_ALT8: case SDP_ALT16: case SDP_ALT32: xmlOutput.append("<alternate>\n"); parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput); xmlOutput.append(indentString); xmlOutput.append("</alternate>\n"); break; case SDP_URL_STR_UNSPEC: break; case SDP_URL_STR8: case SDP_URL_STR16: case SDP_URL_STR32: strncpy(snBuffer, data->val.str, data->unitSize - 1); xmlOutput.append("<url value=\""); xmlOutput.append(snBuffer); xmlOutput.append("\"/>\n"); break; default: fprintf(stderr, "Unknown dtd type\n"); } parseAttributeValues(data->next, indentation, xmlOutput); }