Beispiel #1
0
static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
		struct service_adapter *serv_adapter,
		dbus_uint32_t handle, sdp_record_t *sdp_record)
{
	bdaddr_t src;
	int err;

	if (remove_record_from_server(handle) < 0) {
		sdp_record_free(sdp_record);
		return btd_error_not_available(msg);
	}

	if (serv_adapter->adapter)
		adapter_get_address(serv_adapter->adapter, &src);
	else
		bacpy(&src, BDADDR_ANY);

	sdp_record->handle = handle;
	err = add_record_to_server(&src, sdp_record);
	if (err < 0) {
		sdp_record_free(sdp_record);
		error("Failed to update the service record");
		return btd_error_failed(msg, strerror(-err));
	}

	return dbus_message_new_method_return(msg);
}
Beispiel #2
0
bool bt_pan_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
{
    sdp_record_t *nap_rec, *panu_rec;
    int err;

    DBG("");

    bacpy(&adapter_addr, addr);

    nap_rec = nap_record();
    if (bt_adapter_add_record(nap_rec, SVC_HINT_NETWORKING) < 0) {
        sdp_record_free(nap_rec);
        error("Failed to allocate PAN-NAP sdp record");
        return false;
    }

    panu_rec = panu_record();
    if (bt_adapter_add_record(panu_rec, SVC_HINT_NETWORKING) < 0) {
        sdp_record_free(nap_rec);
        sdp_record_free(panu_rec);
        error("Failed to allocate PAN-PANU sdp record");
        return false;
    }

    err = bnep_init();
    if (err < 0) {
        error("Failed to init BNEP");
        bt_adapter_remove_record(nap_rec->handle);
        bt_adapter_remove_record(panu_rec->handle);
        return false;
    }

    err = register_nap_server();
    if (err < 0) {
        error("Failed to register NAP server");
        bt_adapter_remove_record(nap_rec->handle);
        bt_adapter_remove_record(panu_rec->handle);
        bnep_cleanup();
        return false;
    }

    nap_rec_id = nap_rec->handle;
    panu_rec_id = panu_rec->handle;

    hal_ipc = ipc;
    ipc_register(hal_ipc, HAL_SERVICE_ID_PAN, cmd_handlers,
                 G_N_ELEMENTS(cmd_handlers));

    return true;
}
static DBusMessage *add_sap_service_record(DBusConnection *conn, DBusMessage *msg,
                        void *data)
{
   DBG("");

   sdp_record_t *record = NULL;
   GError *gerr = NULL;

	record = create_sap_record(SAP_SERVER_CHANNEL);
	if (!record) {
		error("Creating SAP SDP record failed.");
		goto sdp_err;
	}

	if (add_record_to_server(&server->src, record) < 0) {
		error("Adding SAP SDP record to the SDP server failed.");
		sdp_record_free(record);
		goto sdp_err;
	}

	server->record_id = record->handle;

   DBG("EXIT");

   return dbus_message_new_method_return(msg);

sdp_err:
	server_free(server);
	sap_exit();
   return dbus_message_new_method_return(msg);
}
Beispiel #4
0
static int del_service(sdp_session_t *session, uint32_t handle)
{
	sdp_record_t *rec;

	logDebug("Deleting Service Record.\n");

	if (!session) {
		logDebug("Bad local SDP session!\n");
		return -1;
	}

	rec = sdp_record_alloc();

	if (rec == NULL) {
		return -1;
	}

	rec->handle = handle;

	if (sdp_device_record_unregister(session, &loc_addr.rc_bdaddr, rec) != 0) {
		/*
		 If Bluetooth is shut off, the sdp daemon will not be running and it is
		 therefore common that this function will fail in that case. This is fine
		 since the record is removed when the daemon shuts down. We only have
		 to free our record handle here then....
		 */
		//CM_DBG("Failed to unregister service record: %s\n", strerror(errno));
		sdp_record_free(rec);
		return -1;
	}

	logDebug("Service Record deleted.");

	return 0;
}
Beispiel #5
0
/*
 * collect all services registered over this socket
 */
void sdp_svcdb_collect_all(int sock)
{
	sdp_list_t *p, *q;

	for (p = socket_index, q = 0; p; ) {
		sdp_indexed_t *item = p->data;
		if (item->sock == sock) {
			sdp_list_t *next = p->next;
			sdp_record_remove(item->record->handle);
			sdp_record_free(item->record);
			free(item);
			if (q)
				q->next = next;
			else
				socket_index = next;
			free(p);
			p = next;
		} else if (item->sock > sock)
			return;
		else {
			q = p;
			p = p->next;
		}
	}
}
Beispiel #6
0
static sdp_record_t *sdp_xml_parse_record(const char *data, int size)
{
	GMarkupParseContext *ctx;
	struct context_data *ctx_data;
	sdp_record_t *record;

	ctx_data = malloc(sizeof(*ctx_data));
	if (!ctx_data)
		return NULL;

	record = sdp_record_alloc();
	if (!record) {
		free(ctx_data);
		return NULL;
	}

	memset(ctx_data, 0, sizeof(*ctx_data));
	ctx_data->record = record;

	ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);

	if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
		error("XML parsing error");
		g_markup_parse_context_free(ctx);
		sdp_record_free(record);
		free(ctx_data);
		return NULL;
	}

	g_markup_parse_context_free(ctx);

	free(ctx_data);

	return record;
}
Beispiel #7
0
/*
 * Remove a registered service record
 */
int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
{
	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
	uint32_t handle = bt_get_be32(p);
	sdp_record_t *rec;
	int status = 0;

	/* extract service record handle */

	rec = sdp_record_find(handle);
	if (rec) {
		sdp_svcdb_collect(rec);
		status = sdp_record_remove(handle);
		sdp_record_free(rec);
		if (status == 0)
			update_db_timestamp();
	} else {
		status = SDP_INVALID_RECORD_HANDLE;
		SDPDBG("Could not find record : 0x%x", handle);
	}

	p = rsp->data;
	bt_put_be16(status, p);
	rsp->data_size = sizeof(uint16_t);

	return status;
}
Beispiel #8
0
static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,
					uint8_t codec)
{
	struct a2dp_sep *sep;
	GSList **l;
	sdp_record_t *(*create_record)(void);
	uint32_t *record_id;
	sdp_record_t *record;
	struct avdtp_sep_ind *ind;

	sep = g_new0(struct a2dp_sep, 1);

	ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
	sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO, codec,
					ind, &cfm, sep);
	if (sep->sep == NULL) {
		g_free(sep);
		return NULL;
	}

	sep->codec = codec;
	sep->type = type;

	if (type == AVDTP_SEP_TYPE_SOURCE) {
		l = &sources;
		create_record = a2dp_source_record;
		record_id = &source_record_id;
	} else {
		l = &sinks;
		create_record = a2dp_sink_record;
		record_id = &sink_record_id;
	}

	if (*record_id != 0)
		goto add;

	record = create_record();
	if (!record) {
		error("Unable to allocate new service record");
		avdtp_unregister_sep(sep->sep);
		g_free(sep);
		return NULL;
	}

	if (add_record_to_server(BDADDR_ANY, record) < 0) {
		error("Unable to register A2DP service record");\
		sdp_record_free(record);
		avdtp_unregister_sep(sep->sep);
		g_free(sep);
		return NULL;
	}
	*record_id = record->handle;

add:
	*l = g_slist_append(*l, sep);

	return sep;
}
gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
{
	sdp_record_t *sdp_record;
	bdaddr_t addr;

	if (adapter->sdp_handler)
		remove_record_from_server(adapter->sdp_handler);

	if (!app_list) {
		adapter->sdp_handler = 0;
		return TRUE;
	}

	sdp_record = sdp_record_alloc();
	if (!sdp_record)
		return FALSE;

	if (adapter->sdp_handler)
		sdp_record->handle = adapter->sdp_handler;
	else
		sdp_record->handle = 0xffffffff; /* Set automatically */

	if (is_app_role(app_list, HDP_SINK))
		set_sdp_services_uuid(sdp_record, HDP_SINK);
	if (is_app_role(app_list, HDP_SOURCE))
		set_sdp_services_uuid(sdp_record, HDP_SOURCE);

	if (!register_service_protocols(adapter, sdp_record))
		goto fail;
	if (!register_service_profiles(sdp_record))
		goto fail;
	if (!register_service_additional_protocols(adapter, sdp_record))
		goto fail;

	sdp_set_info_attr(sdp_record, HDP_SERVICE_NAME, HDP_SERVICE_PROVIDER,
							HDP_SERVICE_DSC);
	if (!register_service_sup_features(app_list, sdp_record))
		goto fail;
	if (!register_data_exchange_spec(sdp_record))
		goto fail;

	register_mcap_features(sdp_record);

	if (sdp_set_record_state(sdp_record, adapter->record_state++))
		goto fail;

	adapter_get_address(adapter->btd_adapter, &addr);

	if (add_record_to_server(&addr, sdp_record) < 0)
		goto fail;
	adapter->sdp_handler = sdp_record->handle;
	return TRUE;

fail:
	if (sdp_record)
		sdp_record_free(sdp_record);
	return FALSE;
}
Beispiel #10
0
static struct a2dp_sep *a2dp_add_sep(struct a2dp_server *server, uint8_t type,
                                     uint8_t codec, gboolean delay_reporting)
{
    struct a2dp_sep *sep;
    GSList **l;
    uint32_t *record_id;
    sdp_record_t *record;
    struct avdtp_sep_ind *ind;

    sep = g_new0(struct a2dp_sep, 1);

    ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
    sep->sep = avdtp_register_sep(&server->src, type,
                                  AVDTP_MEDIA_TYPE_AUDIO, codec,
                                  delay_reporting, ind, &cfm, sep);
    if (sep->sep == NULL) {
        g_free(sep);
        return NULL;
    }

    sep->codec = codec;
    sep->type = type;
    sep->delay_reporting = delay_reporting;

    if (type == AVDTP_SEP_TYPE_SOURCE) {
        l = &server->sources;
        record_id = &server->source_record_id;
    } else {
        l = &server->sinks;
        record_id = &server->sink_record_id;
    }

    if (*record_id != 0)
        goto add;

    record = a2dp_record(type, server->version);
    if (!record) {
        error("Unable to allocate new service record");
        avdtp_unregister_sep(sep->sep);
        g_free(sep);
        return NULL;
    }

    if (add_record_to_server(&server->src, record) < 0) {
        error("Unable to register A2DP service record");
        \
        sdp_record_free(record);
        avdtp_unregister_sep(sep->sep);
        g_free(sep);
        return NULL;
    }
    *record_id = record->handle;

add:
    *l = g_slist_append(*l, sep);

    return sep;
}
Beispiel #11
0
int main(int argc, char const *argv[])
{
	uint32_t svc_uuid_int[] = {0, 0, 0, 0xABCD};
	int status;
	bdaddr_t target, source;
	uuid_t svc_uuid;
	sdp_list_t *response_list, *search_list, *attrid_list;
	sdp_session_t *session = 0;
	uint32_t range = 0x0000ffff;
	uint8_t port = 0;


	//connect to the SDP server running on the remote machine
	str2ba(dest, &target);
	str2ba(src, &source);

	session = sdp_connect(&source, &target, 0);
	if (session == NULL) {
		perror("sdp_connect");
		exit(1);
	}

	sdp_uuid128_create(&svc_uuid, &svc_uuid_int);
	search_list = sdp_list_append(0, &svc_uuid);
	attrid_list = sdp_list_append(0, &range);

	//get a list of service records that have UUID 0xabcd
	response_list = NULL;
	status = sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
	if (status == 0) {
		sdp_list_t *proto_list = NULL;
		sdp_list_t *r = response_list;

		//go through each of the service records
		for (; r; r = r->next) {
			sdp_record_t *rec = (sdp_record_t *)r->data;

			//get a list of the protocol sequences
			if (sdp_get_access_protos(rec, &proto_list) == 0) {
				// get the RFCOMM port number
				port = sdp_get_proto_port(proto_list, RFCOMM_UUID);
				sdp_list_free(proto_list, 0);
			}
			sdp_record_free(rec);
		}
	}
	sdp_list_free(response_list, 0);
	sdp_list_free(search_list, 0);
	sdp_list_free(attrid_list, 0);
	sdp_close(session);

	if (port != 0) {
		printf("found service running on RFCOMM Port %d\n", port);
	}

	return 0;
}
Beispiel #12
0
static int gateway_server_init(struct audio_adapter *adapter)
{
	uint8_t chan = DEFAULT_HFP_HS_CHANNEL;
	sdp_record_t *record;
	gboolean master = TRUE;
	GError *err = NULL;
	GIOChannel *io;
	bdaddr_t src;

	if (config) {
		gboolean tmp;

		tmp = g_key_file_get_boolean(config, "General", "Master",
						&err);
		if (err) {
			DBG("audio.conf: %s", err->message);
			g_clear_error(&err);
		} else
			master = tmp;
	}

	adapter_get_address(adapter->btd_adapter, &src);

	io = bt_io_listen(BT_IO_RFCOMM, NULL, hf_io_cb, adapter, NULL, &err,
				BT_IO_OPT_SOURCE_BDADDR, &src,
				BT_IO_OPT_CHANNEL, chan,
				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
				BT_IO_OPT_MASTER, master,
				BT_IO_OPT_INVALID);
	if (!io) {
		error("%s", err->message);
		g_error_free(err);
		return -1;
	}

	adapter->hfp_hs_server = io;
	record = hfp_hs_record(chan);
	if (!record) {
		error("Unable to allocate new service record");
		return -1;
	}

	if (add_record_to_server(&src, record) < 0) {
		error("Unable to register HFP HS service record");
		sdp_record_free(record);
		g_io_channel_unref(adapter->hfp_hs_server);
		adapter->hfp_hs_server = NULL;
		return -1;
	}

	adapter->hfp_hs_record_id = record->handle;

	return 0;
}
Beispiel #13
0
static DBusMessage *proxy_enable(DBusConnection *conn,
                                 DBusMessage *msg, void *data)
{
    struct serial_proxy *prx = data;
    sdp_record_t *record;
    GError *err = NULL;
    DBusMessage *reply;

    if (prx->io)
        return failed(msg, "Already enabled");

    /* Listen */
    prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx,
                           NULL, &err,
                           BT_IO_OPT_SOURCE_BDADDR, &prx->src,
                           BT_IO_OPT_INVALID);
    if (!prx->io)
        goto failed;

    bt_io_get(prx->io, BT_IO_RFCOMM, &err,
              BT_IO_OPT_CHANNEL, &prx->channel,
              BT_IO_OPT_INVALID);
    if (err) {
        g_io_channel_unref(prx->io);
        prx->io = NULL;
        goto failed;
    }

    debug("Allocated channel %d", prx->channel);

    g_io_channel_set_close_on_unref(prx->io, TRUE);

    record = proxy_record_new(prx->uuid128, prx->channel);
    if (!record) {
        g_io_channel_unref(prx->io);
        return failed(msg, "Unable to allocate new service record");
    }

    if (add_record_to_server(&prx->src, record) < 0) {
        sdp_record_free(record);
        g_io_channel_unref(prx->io);
        return failed(msg, "Service registration failed");
    }

    prx->record_id = record->handle;

    return dbus_message_new_method_return(msg);

failed:
    error("%s", err->message);
    reply = failed(msg, err->message);
    g_error_free(err);
    return reply;
}
Beispiel #14
0
static DBusMessage *update_record(DBusMessage *msg,
				struct service_adapter *serv_adapter,
				dbus_uint32_t handle, sdp_record_t *sdp_record)
{
	int err;

	if (remove_record_from_server(handle) < 0) {
		sdp_record_free(sdp_record);
		return btd_error_not_available(msg);
	}

	sdp_record->handle = handle;
	err = add_record_to_server(get_address(serv_adapter), sdp_record);
	if (err < 0) {
		sdp_record_free(sdp_record);
		error("Failed to update the service record");
		return btd_error_failed(msg, strerror(-err));
	}

	return dbus_message_new_method_return(msg);
}
Beispiel #15
0
static int enable_proxy(struct serial_proxy *prx)
{
	sdp_record_t *record;
	GError *gerr = NULL;
	int err;

	if (prx->io)
		return -EALREADY;

	/* Listen */
	prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx,
				NULL, &gerr,
				BT_IO_OPT_SOURCE_BDADDR, &prx->src,
				BT_IO_OPT_INVALID);
	if (!prx->io)
		goto failed;

	bt_io_get(prx->io, BT_IO_RFCOMM, &gerr,
			BT_IO_OPT_CHANNEL, &prx->channel,
			BT_IO_OPT_INVALID);
	if (gerr) {
		g_io_channel_unref(prx->io);
		prx->io = NULL;
		goto failed;
	}

	debug("Allocated channel %d", prx->channel);

	g_io_channel_set_close_on_unref(prx->io, TRUE);

	record = proxy_record_new(prx->uuid128, prx->channel);
	if (!record) {
		g_io_channel_unref(prx->io);
		return -ENOMEM;
	}

	err = add_record_to_server(&prx->src, record);
	if (err < 0) {
		sdp_record_free(record);
		g_io_channel_unref(prx->io);
		return err;
	}

	prx->record_id = record->handle;

	return 0;

failed:
	error("%s", gerr->message);
	g_error_free(gerr);
	return -EIO;

}
static void search_completed_cb(uint8_t type, uint16_t status,
			uint8_t *rsp, size_t size, void *user_data)
{
	struct search_context *ctxt = user_data;
	sdp_list_t *recs = NULL;
	int scanned, seqlen = 0, bytesleft = size;
	uint8_t dataType;
	int err = 0;

	if (status || type != SDP_SVC_SEARCH_ATTR_RSP) {
		err = -EPROTO;
		goto done;
	}

	scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
	if (!scanned || !seqlen)
		goto done;

	rsp += scanned;
	bytesleft -= scanned;
	do {
		sdp_record_t *rec;
		int recsize;

		recsize = 0;
		rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
		if (!rec)
			break;

		if (!recsize) {
			sdp_record_free(rec);
			break;
		}

		scanned += recsize;
		rsp += recsize;
		bytesleft -= recsize;

		recs = sdp_list_append(recs, rec);
	} while (scanned < (ssize_t) size && bytesleft > 0);

done:
	cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session);

	if (ctxt->cb)
		ctxt->cb(recs, err, ctxt->user_data);

	if (recs)
		sdp_list_free(recs, (sdp_free_func_t) sdp_record_free);

	search_context_cleanup(ctxt);
}
Beispiel #17
0
static int detect_channel(bdaddr_t * bdaddr)
{
	uuid_t group;
	bdaddr_t interface;
	sdp_list_t *attrid, *search, *seq, *next;
	uint32_t range = 0x0000ffff;
	sdp_session_t *sess;
	int channel = 2;
	int searchresult;

	bacpy(&interface, BDADDR_ANY);

	sdp_uuid16_create(&group, 0x1108);
	sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
	if (!sess) {
		fprintf(stderr, "Failed to connect to SDP server: %s\nAssuming channel %d\n",
					strerror(errno), channel);
		return channel;
	}

	attrid = sdp_list_append(0, &range);
	search = sdp_list_append(0, &group);
	searchresult = sdp_service_search_attr_req(sess, search,
					SDP_ATTR_REQ_RANGE, attrid, &seq);
	sdp_list_free(attrid, 0);
	sdp_list_free(search, 0);

	if (searchresult) {
		fprintf(stderr, "Service Search failed: %s\nAssuming channel %d\n",
					strerror(errno), channel);
		sdp_close(sess);
		return channel;
	}

	for (; seq; seq = next) {
		sdp_record_t *rec = (sdp_record_t *) seq->data;
		sdp_list_t *list = 0;
		if (sdp_get_access_protos(rec, &list) == 0) {
			channel = sdp_get_proto_port(list, RFCOMM_UUID);
		}
		next = seq->next;
		free(seq);
		sdp_record_free(rec);
	}

	sdp_close(sess);
	return channel;
}
Beispiel #18
0
bool bt_a2dp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
{
	GError *err = NULL;
	sdp_record_t *rec;

	DBG("");

	bacpy(&adapter_addr, addr);

	server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
				BT_IO_OPT_PSM, AVDTP_PSM,
				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
				BT_IO_OPT_MASTER, true,
				BT_IO_OPT_INVALID);
	if (!server) {
		error("Failed to listen on AVDTP channel: %s", err->message);
		g_error_free(err);
		return false;
	}

	rec = a2dp_record();
	if (!rec) {
		error("Failed to allocate A2DP record");
		goto fail;
	}

	if (bt_adapter_add_record(rec, SVC_HINT_CAPTURING) < 0) {
		error("Failed to register A2DP record");
		sdp_record_free(rec);
		goto fail;
	}
	record_id = rec->handle;

	hal_ipc = ipc;

	ipc_register(hal_ipc, HAL_SERVICE_ID_A2DP, cmd_handlers,
						G_N_ELEMENTS(cmd_handlers));

	if (bt_audio_register(audio_disconnected))
		return true;

fail:
	g_io_channel_shutdown(server, TRUE, NULL);
	g_io_channel_unref(server);
	server = NULL;
	return false;
}
JNIEXPORT jboolean JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_populateServiceRecordAttributeValuesImpl
  (JNIEnv *env, jobject peer, jlong localDeviceBTAddress, jlong remoteDeviceAddressLong, jlong sdpSession, jlong handle, jintArray attrIDs, jobject serviceRecord) {
    sdp_session_t* session = (sdp_session_t*)jlong2ptr(sdpSession);
    sdp_session_t* close_session_on_return = NULL;
    if (session != NULL) {
        debug("populateServiceRecordAttributeValuesImpl connected %p, recordHandle %li", session, handle);
    } else {
        debug("populateServiceRecordAttributeValuesImpl connects, recordHandle %li", handle);
        bdaddr_t localAddr;
        longToDeviceAddr(localDeviceBTAddress, &localAddr);
        bdaddr_t remoteAddress;
        longToDeviceAddr(remoteDeviceAddressLong, &remoteAddress);
        session = sdp_connect(&localAddr, &remoteAddress, SDP_RETRY_IF_BUSY);
        if (session == NULL) {
            debug("populateServiceRecordAttributeValuesImpl can't connect");
            return JNI_FALSE;
        }
        // Close session on exit
       close_session_on_return = session;
    }

    sdp_list_t *attr_list = NULL;
    jboolean isCopy = JNI_FALSE;
    jint* ids = (*env)->GetIntArrayElements(env, attrIDs, &isCopy);
    int i;
    for(i = 0; i < (*env)->GetArrayLength(env, attrIDs); i++) {
        uint16_t* id = (uint16_t*)malloc(sizeof(uint16_t));
        *id=(uint16_t)ids[i];
        attr_list = sdp_list_append(attr_list,id);
    }

    jboolean rc = JNI_FALSE;
    sdp_record_t *sdpRecord = sdp_service_attr_req(session, (uint32_t)handle, SDP_ATTR_REQ_INDIVIDUAL, attr_list);
    if (!sdpRecord) {
        debug("sdp_service_attr_req return error");
        rc = JNI_FALSE;
    } else {
        populateServiceRecord(env, serviceRecord, sdpRecord, attr_list);
        sdp_record_free(sdpRecord);
        rc = JNI_TRUE;
    }
    sdp_list_free(attr_list, free);
    if (close_session_on_return != NULL) {
        sdp_close(close_session_on_return);
    }

    return rc;
}
Beispiel #20
0
int remove_record_from_server(uint32_t handle)
{
	sdp_record_t *rec;

	DBG("Removing record with handle 0x%05x", handle);

	rec = sdp_record_find(handle);
	if (!rec)
		return -ENOENT;

	if (sdp_record_remove(handle) == 0)
		update_db_timestamp();

	sdp_record_free(rec);

	return 0;
}
Beispiel #21
0
static uint32_t register_server_record(struct network_server *ns)
{
	sdp_record_t *record;

	record = server_record_new(ns->name, ns->id);
	if (!record) {
		error("Unable to allocate new service record");
		return 0;
	}

	if (add_record_to_server(&ns->src, record) < 0) {
		error("Failed to register service record");
		sdp_record_free(record);
		return 0;
	}

	DBG("got record id 0x%x", record->handle);

	return record->handle;
}
Beispiel #22
0
static int add_xml_record(DBusConnection *conn, const char *sender,
			struct service_adapter *serv_adapter,
			const char *record, dbus_uint32_t *handle)
{
	struct record_data *user_record;
	sdp_record_t *sdp_record;
	bdaddr_t src;

	sdp_record = sdp_xml_parse_record(record, strlen(record));
	if (!sdp_record) {
		error("Parsing of XML service record failed");
		return -EIO;
	}

	if (serv_adapter->adapter)
		adapter_get_address(serv_adapter->adapter, &src);
	else
		bacpy(&src, BDADDR_ANY);

	if (add_record_to_server(&src, sdp_record) < 0) {
		error("Failed to register service record");
		sdp_record_free(sdp_record);
		return -EIO;
	}

	user_record = g_new0(struct record_data, 1);
	user_record->handle = sdp_record->handle;
	user_record->sender = g_strdup(sender);
	user_record->serv_adapter = serv_adapter;
	user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
					exit_callback, user_record, NULL);

	serv_adapter->records = g_slist_append(serv_adapter->records,
								user_record);

	DBG("listener_id %d", user_record->listener_id);

	*handle = user_record->handle;

	return 0;
}
Beispiel #23
0
static uint16_t ext_register_record(struct ext_profile *ext,
							const bdaddr_t *src)
{
	sdp_record_t *rec;

	if (ext->record)
		rec = sdp_xml_parse_record(ext->record, strlen(ext->record));
	else
		rec = ext_get_record(ext);

	if (!rec)
		return 0;

	if (add_record_to_server(src, rec) < 0) {
		error("Failed to register service record");
		sdp_record_free(rec);
		return 0;
	}

	return rec->handle;
}
Beispiel #24
0
int remove_record_from_server(uint32_t handle)
{
	sdp_record_t *rec;

	/* Refuse to remove the server's own record */
	if (handle == SDP_SERVER_RECORD_HANDLE)
		return -EINVAL;

	DBG("Removing record with handle 0x%05x", handle);

	rec = sdp_record_find(handle);
	if (!rec)
		return -ENOENT;

	if (sdp_record_remove(handle) == 0)
		update_db_timestamp();

	sdp_record_free(rec);

	return 0;
}
Beispiel #25
0
static DBusMessage *update_xml_record(DBusConnection *conn,
				DBusMessage *msg,
				struct service_adapter *serv_adapter)
{
	struct record_data *user_record;
	sdp_record_t *sdp_record;
	const char *record;
	dbus_uint32_t handle;
	int len;

	if (dbus_message_get_args(msg, NULL,
				DBUS_TYPE_UINT32, &handle,
				DBUS_TYPE_STRING, &record,
				DBUS_TYPE_INVALID) == FALSE)
		return NULL;

	len = (record ? strlen(record) : 0);
	if (len == 0)
		return invalid_arguments(msg);

	user_record = find_record(serv_adapter, handle,
				dbus_message_get_sender(msg));
	if (!user_record)
		return g_dbus_create_error(msg,
				ERROR_INTERFACE ".NotAvailable",
				"Not Available");

	sdp_record = sdp_xml_parse_record(record, len);
	if (!sdp_record) {
		error("Parsing of XML service record failed");
		sdp_record_free(sdp_record);
		return g_dbus_create_error(msg,
				ERROR_INTERFACE ".Failed",
				strerror(EIO));
	}

	return update_record(conn, msg, serv_adapter, handle, sdp_record);
}
Beispiel #26
0
static void session_destroy(struct bluetooth_session *session)
{
	DBG("%p", session);

	if (g_slist_find(sessions, session) == NULL)
		return;

	sessions = g_slist_remove(sessions, session);

	if (session->io != NULL) {
		g_io_channel_shutdown(session->io, TRUE, NULL);
		g_io_channel_unref(session->io);
	}

	if (session->sdp)
		sdp_close(session->sdp);

	if (session->sdp_record)
		sdp_record_free(session->sdp_record);

	g_free(session->service);
	g_free(session);
}
Beispiel #27
0
static int hidp_add_connection(struct input_device *idev)
{
    struct hidp_connadd_req *req;
    sdp_record_t *rec;
    char src_addr[18], dst_addr[18];
    char filename[PATH_MAX + 1];
    GKeyFile *key_file;
    char handle[11], *str;
    GError *gerr = NULL;
    int err;

    req = g_new0(struct hidp_connadd_req, 1);
    req->ctrl_sock = g_io_channel_unix_get_fd(idev->ctrl_io);
    req->intr_sock = g_io_channel_unix_get_fd(idev->intr_io);
    req->flags     = 0;
    req->idle_to   = idle_timeout;

    ba2str(&idev->src, src_addr);
    ba2str(&idev->dst, dst_addr);

    snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", src_addr,
             dst_addr);
    filename[PATH_MAX] = '\0';
    sprintf(handle, "0x%8.8X", idev->handle);

    key_file = g_key_file_new();
    g_key_file_load_from_file(key_file, filename, 0, NULL);
    str = g_key_file_get_string(key_file, "ServiceRecords", handle, NULL);
    g_key_file_free(key_file);

    if (!str) {
        error("Rejected connection from unknown device %s", dst_addr);
        err = -EPERM;
        goto cleanup;
    }

    rec = record_from_string(str);
    g_free(str);

    err = extract_hid_record(rec, req);
    sdp_record_free(rec);
    if (err < 0) {
        error("Could not parse HID SDP record: %s (%d)", strerror(-err),
              -err);
        goto cleanup;
    }

    req->vendor = btd_device_get_vendor(idev->device);
    req->product = btd_device_get_product(idev->device);
    req->version = btd_device_get_version(idev->device);

    if (idev->name)
        strncpy(req->name, idev->name, sizeof(req->name) - 1);

    /* Encryption is mandatory for keyboards */
    if (req->subclass & 0x40) {
        if (!bt_io_set(idev->intr_io, &gerr,
                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                       BT_IO_OPT_INVALID)) {
            error("btio: %s", gerr->message);
            g_error_free(gerr);
            err = -EFAULT;
            goto cleanup;
        }

        idev->req = req;
        idev->sec_watch = g_io_add_watch(idev->intr_io, G_IO_OUT,
                                         encrypt_notify, idev);

        return 0;
    }

    err = ioctl_connadd(req);

cleanup:
    g_free(req->rd_data);
    g_free(req);

    return err;
}
Beispiel #28
0
static int hidp_add_connection(const struct input_device *idev,
				const struct input_conn *iconn)
{
	struct hidp_connadd_req *req;
	struct fake_hid *fake_hid;
	struct fake_input *fake;
	sdp_record_t *rec;
	char src_addr[18], dst_addr[18];
	int err;

	req = g_new0(struct hidp_connadd_req, 1);
	req->ctrl_sock = g_io_channel_unix_get_fd(iconn->ctrl_io);
	req->intr_sock = g_io_channel_unix_get_fd(iconn->intr_io);
	req->flags     = 0;
	req->idle_to   = iconn->timeout;

	ba2str(&idev->src, src_addr);
	ba2str(&idev->dst, dst_addr);

	rec = fetch_record(src_addr, dst_addr, idev->handle);
	if (!rec) {
		error("Rejected connection from unknown device %s", dst_addr);
		err = -EPERM;
		goto cleanup;
	}

	extract_hid_record(rec, req);
	sdp_record_free(rec);

	read_device_id(src_addr, dst_addr, NULL,
				&req->vendor, &req->product, &req->version);

	fake_hid = get_fake_hid(req->vendor, req->product);
	if (fake_hid) {
		fake = g_new0(struct fake_input, 1);
		fake->connect = fake_hid_connect;
		fake->disconnect = fake_hid_disconnect;
		fake->priv = fake_hid;
		err = fake_hid_connadd(fake, iconn->intr_io, fake_hid);
		goto cleanup;
	}

	if (idev->name)
		strncpy(req->name, idev->name, sizeof(req->name) - 1);

	/* Encryption is mandatory for keyboards */
	if (req->subclass & 0x40) {
		err = bt_acl_encrypt(&idev->src, &idev->dst, encrypt_completed, req);
		if (err == 0) {
			/* Waiting async encryption */
			return 0;
		} else if (err != -EALREADY) {
			error("bt_acl_encrypt(): %s(%d)", strerror(-err), -err);
			goto cleanup;
		}
	}

	err = ioctl_connadd(req);

cleanup:
	free(req->rd_data);
	g_free(req);

	return err;
}
Beispiel #29
0
int main(void) {
	int i, j, err, sock, dev_id = -1;
	struct hci_dev_info dev_info;
	inquiry_info *info = NULL;
	bdaddr_t target;
	char addr[19] = { 0 };
	char name[248] = { 0 };
	uuid_t uuid = { 0 };
	//Change this to your apps UUID
	char *uuid_str="4e5d48e0-75df-11e3-981f-0800200c9a66";
	uint32_t range = 0x0000ffff;
	sdp_list_t *response_list = NULL, *search_list, *attrid_list;
	int s, loco_channel = -1, status;
	struct sockaddr_rc loc_addr = { 0 };
	pthread_t blueThread;
	
	FILE *fp_Setting;
	char message_Buffer[64];
	char mode[30], language[16], topic[16], topicLen[16];
	size_t len = 16;
	(void) signal(SIGINT, SIG_DFL);
	
	changeTopic_flag = 1;
///////////////////////////MRAA/////////////////////////////	
	//Initialize MRAA
        mraa_init();
        
        //Initialize MRAA Pin 8 == IO8 == GP49
        mraa_gpio_context BearButton = mraa_gpio_init(8);

        //Check for successful initialization or else return
        if (BearButton == NULL){
                printf("Error initializing Push to Talk Pin, IO2\n");
                return -1;
        }
        
		//Set pin to an input
		mraa_gpio_dir(BearButton, MRAA_GPIO_IN);
		printf("Set Pin to an input\n");
 
        
        int curr_pin = mraa_gpio_get_pin(BearButton);
        printf("The current pin number is %d\n", curr_pin);
        int curr_raw = mraa_gpio_get_pin_raw(BearButton);
        printf("The raw pin number is %d\n", curr_raw);

        printf("Going to start reading the button via polling\n");
	
//////////////////////AWS///////////////////////////////////
	aws_flag = 0;	
	IoT_Error_t rc = NONE_ERROR;
	char HostAddress[255] = AWS_IOT_MQTT_HOST;
	char certDirectory[PATH_MAX + 1] = "/AWS/SDK/certs/";
	uint32_t port = AWS_IOT_MQTT_PORT;
	
	MQTTMessageParams Msg = MQTTMessageParamsDefault;
	Msg.qos = QOS_0;
	char cPayload[100];
	Msg.pPayload = (void *) cPayload;
	
	char rootCA[PATH_MAX + 1];
	char clientCRT[PATH_MAX + 1];
	char clientKey[PATH_MAX + 1];
	
	char cafileName[] = AWS_IOT_ROOT_CA_FILENAME;
	char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME;
	char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME;
	
	sprintf(rootCA, "/%s/%s", certDirectory, cafileName);
	sprintf(clientCRT, "/%s/%s", certDirectory, clientCRTName);
	sprintf(clientKey, "/%s/%s", certDirectory, clientKeyName);
	
	MQTTConnectParams connectParams = MQTTConnectParamsDefault;

	connectParams.KeepAliveInterval_sec = 14000;
	connectParams.isCleansession = true;
	connectParams.MQTTVersion = MQTT_3_1_1;
	connectParams.pClientID = "TED";
	connectParams.pHostURL = HostAddress;
	connectParams.port = port;
	connectParams.isWillMsgPresent = false;
	connectParams.pRootCALocation = rootCA;
	connectParams.pDeviceCertLocation = clientCRT;
	connectParams.pDevicePrivateKeyLocation = clientKey;
	connectParams.mqttCommandTimeout_ms = 2000;
	connectParams.tlsHandshakeTimeout_ms = 5000;
	connectParams.isSSLHostnameVerify = true;// ensure this is set to true for production
	connectParams.disconnectHandler = disconnectCallbackHandler;
	
	MQTTPublishParams CurriculumParams = MQTTPublishParamsDefault;
	CurriculumParams.pTopic = "Bear/Curriculum/Request";
	
	
	MQTTPublishParams MetricsParams = MQTTPublishParamsDefault;
	MetricsParams.pTopic = "Bear/Curriculum/Metrics";

///////////////////////////////////////////////////////////////////////////////////////
	dev_id = hci_get_route(NULL);
	if (dev_id < 0) {
		perror("No Bluetooth Adapter Available");
		exit(1);
	}

	if (hci_devinfo(dev_id, &dev_info) < 0) {
		perror("Can't get device info");
		exit(1);
	}



	sock = hci_open_dev( dev_id );
	if (sock < 0) {
		perror("HCI device open failed");
		free(info);
		exit(1);
	}

	
	if( !str2uuid( uuid_str, &uuid ) ) {
		perror("Invalid UUID");
		free(info);
		exit(1);
	}

	do {
		printf("Scanning ...\n");
		
			sdp_session_t *session;
			int retries;
			int foundit, responses;
			str2ba(TABLET_ADDRESS,&target); 
			memset(name, 0, sizeof(name));
			if (hci_read_remote_name(sock, &target, sizeof(name), name, 0) < 0){
				strcpy(name, "[unknown]");
			}
			
			printf("Found %s  %s, searching for the the desired service on it now\n", addr, name);
			// connect to the SDP server running on the remote machine
sdpconnect:
			session = 0; retries = 0;
			while(!session) {
				session = sdp_connect( BDADDR_ANY, &target, SDP_RETRY_IF_BUSY );
				if(session) break;
				if(errno == EALREADY && retries < 5) {
					perror("Retrying");
					retries++;
					sleep(1);
					continue;
				}
				break;
			}
			if ( session == NULL ) {
				perror("Can't open session with the device");
				continue;
			}
			search_list = sdp_list_append( 0, &uuid );
			attrid_list = sdp_list_append( 0, &range );
			err = 0;
			err = sdp_service_search_attr_req( session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
			sdp_list_t *r = response_list;
			sdp_record_t *rec;
			// go through each of the service records
			foundit = 0;
			responses = 0;
			for (; r; r = r->next ) {
				responses++;
				rec = (sdp_record_t*) r->data;
				sdp_list_t *proto_list;
					
				// get a list of the protocol sequences
				if( sdp_get_access_protos( rec, &proto_list ) == 0 ) {
				sdp_list_t *p = proto_list;

					// go through each protocol sequence
					for( ; p ; p = p->next ) {
						sdp_list_t *pds = (sdp_list_t*)p->data;

						// go through each protocol list of the protocol sequence
						for( ; pds ; pds = pds->next ) {

							// check the protocol attributes
							sdp_data_t *d = (sdp_data_t*)pds->data;
							int proto = 0;
							for( ; d; d = d->next ) {
								switch( d->dtd ) { 
									case SDP_UUID16:
									case SDP_UUID32:
									case SDP_UUID128:
											proto = sdp_uuid_to_proto( &d->val.uuid );
											break;
									case SDP_UINT8:
										if( proto == RFCOMM_UUID ) {
												printf("rfcomm channel: %d\n",d->val.int8);
												loco_channel = d->val.int8;
												foundit = 1;
										}
										break;
								}
							}
						}
						sdp_list_free( (sdp_list_t*)p->data, 0 );
					}
					sdp_list_free( proto_list, 0 );

				}
				if (loco_channel > 0)
					break;

			}
			printf("No of Responses %d\n", responses);
			if ( loco_channel > 0 && foundit == 1 ) {
				printf("Found service on this device, now gonna blast it with dummy data\n");
				s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
				loc_addr.rc_family = AF_BLUETOOTH;
				loc_addr.rc_channel = loco_channel;
				loc_addr.rc_bdaddr = *(&target);
				status = connect(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
				if( status < 0 ) {
					perror("uh oh");
				}

				
				rc = pthread_create(&blueThread, NULL, threadListen, (void *)s);
					if (rc){
						printf("ERROR: %d\n", rc);
						exit(1);
					}
				MQTTSubscribeParams subParams = MQTTSubscribeParamsDefault;
				//Loop through trying to subscribe to AWS incase the first attempt fails, so will keep trying until the app sends the edison proper network info.
				do{
					INFO("Connecting...");
					rc = aws_iot_mqtt_connect(&connectParams);
					
					if (NONE_ERROR != rc) {
						ERROR("Error(%d) connecting to %s:%d", rc, connectParams.pHostURL, connectParams.port);
					}
					
					subParams.mHandler = MQTTcallbackHandler;
					subParams.pTopic = "Bear/Curriculum/Response";
					subParams.qos = QOS_0;

					if (NONE_ERROR == rc) {
						INFO("Subscribing...");
						rc = aws_iot_mqtt_subscribe(&subParams);
						if (NONE_ERROR != rc) {
							ERROR("Error subscribing");
						}
					}
					sleep(1);
				}while(NONE_ERROR != rc);
				aws_flag = 1;
//////////////////////////Start of teaching stuff//////////////////////////////////////////
				do {
					
				
					if(changeTopic_flag){
					
						sprintf(cPayload, "{\"BearID\":\"%s\"}",BEARID);
						Msg.PayloadLen = strlen(cPayload) + 1;
						CurriculumParams.MessageParams = Msg;
						rc = aws_iot_mqtt_publish(&CurriculumParams);
						while(rc == NONE_ERROR && changeTopic_flag){
							rc = aws_iot_mqtt_yield(100);
							INFO("-->sleep");
							sleep(1);
						}								
						changeTopic_flag = 0;
					}
					
					
					fp_Setting = fopen("/Curriculum/BearSettings.txt", "r");
					fgets(language, sizeof(language), fp_Setting);
					fgets(mode, sizeof(mode), fp_Setting);
					fgets(topic, sizeof(topic), fp_Setting);
					fgets(topicLen, sizeof(topicLen), fp_Setting);
					language[strlen(language)-1] = 0;
					mode[strlen(mode)-1] = 0;
					topic[strlen(topic)-1] = 0;
					topicLen[strlen(topicLen)-1] = 0;
					fclose(fp_Setting);

					//Wait for the tablet to tell the edison to start the lesson
					while(strcmp(threadMessage, "learning")){
						printf("Waiting for learning, got: %s\n", threadMessage);
						if(!strcmp(threadMessage, "crash")){
							memset(threadMessage, 0, sizeof(threadMessage));
							goto CRASHED;
						}
						memset(threadMessage, 0, sizeof(threadMessage));
						sleep(1);
					}

					
					printf("Current Mode: %s\n", mode);
					printf("Current Language: %s\n", language);
					printf("Current topic: %s\n", topic);

					//Call a different function depending on what teaching mode it is, also write to the tablet based on the topic info and lesson
					if(!strcmp(mode, "Repeat After Me")){
						sprintf(message_Buffer,"%s,1,%s",language, topicLen);
						status = write(s,message_Buffer,sizeof(message_Buffer));
						if(!strcmp(language, "English")){
							status = repeat_after_me_english(s, topic, MetricsParams, BearButton);
						}
						else{
							status = repeat_after_me_foreign(s, language, topic, MetricsParams, BearButton);
						}
					}
					else if(!strcmp(mode, "English to Foreign")){
						sprintf(message_Buffer,"%s,3,%s",language, topicLen);
						status = write(s,message_Buffer,sizeof(message_Buffer));
						status = english_to_foreign(s, language, topic, MetricsParams, BearButton);
					}
					else if(!strcmp(mode, "Foreign to English")){
						sprintf(message_Buffer,"%s,2,%s",language, topicLen);
						status = write(s,message_Buffer,sizeof(message_Buffer));
						status = foreign_to_english(s, language, topic, MetricsParams, BearButton);
					}
					
					
					changeTopic_flag = 1;
					printf("Changing Topic");
					sleep(5);
				} while (status > 0);
CRASHED:
				printf("\nBluetooth Disconnected\n");
				close(s);
				sdp_record_free( rec );
			}

			sdp_close(session);
			if (loco_channel > 0) {
				goto sdpconnect;
				//break;
			}
		sleep(1);
	} while (1);

	printf("Exiting...\n");
}
Beispiel #30
0
/*
 * utility function to perform an SDP search on a connected session.  Builds
 * and returns a python list of dictionaries.  Each dictionary represents a
 * service record match
 */
static PyObject *
do_search( sdp_session_t *sess, uuid_t *uuid )
{
    sdp_list_t *response_list = NULL, *attrid_list, *search_list, *r;
    uint32_t range = 0x0000ffff;
    char buf[1024] = { 0 };
    int err = 0;
    PyObject *result = 0;

    PyObject *rtn_list = PyList_New(0);
    if( ! rtn_list ) return 0;
    search_list = sdp_list_append( 0, uuid );
    attrid_list = sdp_list_append( 0, &range );

    // perform the search
    Py_BEGIN_ALLOW_THREADS
    err = sdp_service_search_attr_req( sess, search_list, \
                                       SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
    Py_END_ALLOW_THREADS
    if( err ) {
        PyErr_SetFromErrno( bluetooth_error );
        result = 0;
        goto cleanup;
    }

    // parse the results (ewww....)

    // go through each of the service records
    for (r = response_list; r; r = r->next ) {
        PyObject *dict = PyDict_New();
        sdp_record_t *rec = (sdp_record_t*) r->data;
        sdp_list_t *proto_list = NULL,
                    *svc_class_list = NULL,
                     *profile_list = NULL;
        PyObject *py_class_list = NULL, *py_profile_list = NULL;
        uuid_t service_id = { 0 };

        if( ! dict ) return 0;

        // initialize service class list
        py_class_list = PyList_New(0);
        if( ! py_class_list ) return 0;
        dict_set_str_pyobj( dict, "service-classes", py_class_list );
        Py_DECREF( py_class_list );

        // initialize profile list
        py_profile_list = PyList_New(0);
        if( ! py_profile_list ) return 0;
        dict_set_str_pyobj( dict, "profiles", py_profile_list );
        Py_DECREF( py_profile_list );

        // set service name
        if( ! sdp_get_service_name( rec, buf, sizeof(buf) ) ) {
            dict_set_strings( dict, "name", buf );
            memset(buf, 0, sizeof( buf ) );
        } else {
            dict_set_str_pyobj( dict, "name", Py_None );
        }

        // set service description
        if( ! sdp_get_service_desc( rec, buf, sizeof(buf) ) ) {
            dict_set_strings( dict, "description", buf );
            memset(buf, 0, sizeof( buf ) );
        } else {
            dict_set_str_pyobj( dict, "description", Py_None );
        }

        // set service provider name
        if( ! sdp_get_provider_name( rec, buf, sizeof(buf) ) ) {
            dict_set_strings( dict, "provider", buf );
            memset(buf, 0, sizeof( buf ) );
        } else {
            dict_set_str_pyobj( dict, "provider", Py_None );
        }

        // set service id
        if( ! sdp_get_service_id( rec, &service_id ) ) {
            uuid2str( &service_id, buf );
            dict_set_strings( dict, "service-id", buf );
            memset(buf, 0, sizeof( buf ) );
        } else {
            dict_set_str_pyobj( dict, "service-id", Py_None );
        }

        // get a list of the protocol sequences
        if( sdp_get_access_protos( rec, &proto_list ) == 0 ) {
            sdp_list_t *p = proto_list;
            int port;

            if( ( port = sdp_get_proto_port( p, RFCOMM_UUID ) ) != 0 ) {
                dict_set_strings( dict, "protocol", "RFCOMM" );
                dict_set_str_long( dict, "port", port );
            } else if ( (port = sdp_get_proto_port( p, L2CAP_UUID ) ) != 0 ) {
                dict_set_strings( dict, "protocol", "L2CAP" );
                dict_set_str_long( dict, "port", port );
            } else {
                dict_set_strings( dict, "protocol", "UNKNOWN" );
                dict_set_str_pyobj( dict, "port", Py_None );
            }

            // sdp_get_access_protos allocates data on the heap for the
            // protocol list, so we need to free the results...
            for( ; p ; p = p->next ) {
                sdp_list_free( (sdp_list_t*)p->data, 0 );
            }
            sdp_list_free( proto_list, 0 );
        } else {
            dict_set_str_pyobj( dict, "protocol", Py_None );
            dict_set_str_pyobj( dict, "port", Py_None );
        }

        // get a list of the service classes
        if( sdp_get_service_classes( rec, &svc_class_list ) == 0 ) {
            sdp_list_t *iter;
            for( iter = svc_class_list; iter != NULL; iter = iter->next ) {
                PyObject *pystr;
                char uuid_str[40] = { 0 };

                uuid2str( (uuid_t*)iter->data, uuid_str );
                pystr = PyString_FromString( uuid_str );
                PyList_Append( py_class_list, pystr );
                Py_DECREF( pystr );
            }

            sdp_list_free( svc_class_list, free );
        }

        // get a list of the profiles
        if( sdp_get_profile_descs( rec, &profile_list ) == 0 ) {
            sdp_list_t *iter;
            for( iter = profile_list; iter != NULL; iter = iter->next ) {
                PyObject *tuple, *py_uuid, *py_version;
                sdp_profile_desc_t *desc = (sdp_profile_desc_t*)iter->data;
                char uuid_str[40] = { 0 };

                uuid2str( &desc->uuid, uuid_str );
                py_uuid = PyString_FromString( uuid_str );
                py_version = PyInt_FromLong( desc->version );

                tuple = PyTuple_New( 2 );
                PyList_Append( py_profile_list, tuple );
                Py_DECREF( tuple );

                PyTuple_SetItem( tuple, 0, py_uuid );
                PyTuple_SetItem( tuple, 1, py_version );
//                Py_DECREF( py_uuid );
//                Py_DECREF( py_version );
            }
            sdp_list_free( profile_list, free );
        }

        PyList_Append( rtn_list, dict );
        Py_DECREF( dict );

        sdp_record_free( rec );
    }

    result = rtn_list;

cleanup:
    sdp_list_free( response_list, 0 );
    sdp_list_free( search_list, 0 );
    sdp_list_free( attrid_list, 0 );
    return result;
}