Example #1
0
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;
}
Example #2
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;
}
Example #3
0
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;
}
Example #4
0
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('&', "&amp;");
            text.replace('<', "&lt;");
            text.replace('>', "&gt;");
            text.replace('"', "&quot;");

            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);
}