OSDN Git Service

Move SDP client functions from glib-helper.c to sdp-client.c
authorJohan Hedberg <johan.hedberg@intel.com>
Tue, 18 Oct 2011 08:15:23 +0000 (11:15 +0300)
committerJohan Hedberg <johan.hedberg@intel.com>
Tue, 18 Oct 2011 08:15:23 +0000 (11:15 +0300)
Makefile.am
audio/gateway.c
audio/headset.c
health/hdp_util.c
serial/port.c
src/device.c
src/glib-helper.c
src/glib-helper.h
src/sdp-client.c [new file with mode: 0644]
src/sdp-client.h [new file with mode: 0644]

index eec458e..06332de 100644 (file)
@@ -301,6 +301,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
                        src/sdpd-service.c src/sdpd-database.c \
                        src/attrib-server.h src/attrib-server.c \
                        src/sdp-xml.h src/sdp-xml.c \
+                       src/sdp-client.h src/sdp-client.c \
                        src/textfile.h src/textfile.c src/glib-compat.h \
                        src/glib-helper.h src/glib-helper.c \
                        src/oui.h src/oui.c src/uinput.h src/ppoll.h \
index fb16a3d..9b1aab3 100644 (file)
@@ -43,7 +43,7 @@
 #include <bluetooth/sdp_lib.h>
 
 #include "glib-compat.h"
-#include "glib-helper.h"
+#include "sdp-client.h"
 #include "device.h"
 #include "gateway.h"
 #include "log.h"
index e45e216..6aef6a8 100644 (file)
@@ -54,7 +54,7 @@
 #include "telephony.h"
 #include "headset.h"
 #include "glib-compat.h"
-#include "glib-helper.h"
+#include "sdp-client.h"
 #include "btio.h"
 #include "dbus-common.h"
 #include "../src/adapter.h"
index 9c088d4..e62ed46 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <sdpd.h>
 #include <bluetooth/sdp_lib.h>
+#include <sdp-client.h>
 #include <glib-helper.h>
 
 #include <btio.h>
index 045f459..fa302be 100644 (file)
@@ -50,6 +50,7 @@
 #include "log.h"
 #include "glib-compat.h"
 #include "glib-helper.h"
+#include "sdp-client.h"
 #include "btio.h"
 
 #include "error.h"
index 339c001..bb97089 100644 (file)
@@ -56,6 +56,7 @@
 #include "error.h"
 #include "glib-compat.h"
 #include "glib-helper.h"
+#include "sdp-client.h"
 #include "gatt.h"
 #include "agent.h"
 #include "sdp-xml.h"
index bb8883e..8189a09 100644 (file)
@@ -27,9 +27,6 @@
 
 #include <stdlib.h>
 #include <errno.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <glib.h>
 
 #include "btio.h"
-#include "sdpd.h"
 #include "glib-compat.h"
 #include "glib-helper.h"
 
-/* Number of seconds to keep a sdp_session_t in the cache */
-#define CACHE_TIMEOUT 2
-
-struct cached_sdp_session {
-       bdaddr_t src;
-       bdaddr_t dst;
-       sdp_session_t *session;
-       guint timer;
-};
-
-static GSList *cached_sdp_sessions = NULL;
-
-static gboolean cached_session_expired(gpointer user_data)
-{
-       struct cached_sdp_session *cached = user_data;
-
-       cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, cached);
-
-       sdp_close(cached->session);
-
-       g_free(cached);
-
-       return FALSE;
-}
-
-static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       GSList *l;
-
-       for (l = cached_sdp_sessions; l != NULL; l = l->next) {
-               struct cached_sdp_session *c = l->data;
-               sdp_session_t *session;
-
-               if (bacmp(&c->src, src) || bacmp(&c->dst, dst))
-                       continue;
-
-               g_source_remove(c->timer);
-
-               session = c->session;
-
-               cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, c);
-               g_free(c);
-
-               return session;
-       }
-
-       return sdp_connect(src, dst, SDP_NON_BLOCKING);
-}
-
-static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
-                                               sdp_session_t *session)
-{
-       struct cached_sdp_session *cached;
-
-       cached = g_new0(struct cached_sdp_session, 1);
-
-       bacpy(&cached->src, src);
-       bacpy(&cached->dst, dst);
-
-       cached->session = session;
-
-       cached_sdp_sessions = g_slist_append(cached_sdp_sessions, cached);
-
-       cached->timer = g_timeout_add_seconds(CACHE_TIMEOUT,
-                                               cached_session_expired,
-                                               cached);
-}
-
-struct search_context {
-       bdaddr_t                src;
-       bdaddr_t                dst;
-       sdp_session_t           *session;
-       bt_callback_t           cb;
-       bt_destroy_t            destroy;
-       gpointer                user_data;
-       uuid_t                  uuid;
-       guint                   io_id;
-};
-
-static GSList *context_list = NULL;
-
-static void search_context_cleanup(struct search_context *ctxt)
-{
-       context_list = g_slist_remove(context_list, ctxt);
-
-       if (ctxt->destroy)
-               ctxt->destroy(ctxt->user_data);
-
-       g_free(ctxt);
-}
-
-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);
-}
-
-static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond,
-                                                       gpointer user_data)
-{
-       struct search_context *ctxt = user_data;
-       int err = 0;
-
-       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
-               err = EIO;
-               goto failed;
-       }
-
-       if (sdp_process(ctxt->session) < 0)
-               goto failed;
-
-       return TRUE;
-
-failed:
-       if (err) {
-               sdp_close(ctxt->session);
-               ctxt->session = NULL;
-
-               if (ctxt->cb)
-                       ctxt->cb(NULL, err, ctxt->user_data);
-
-               search_context_cleanup(ctxt);
-       }
-
-       return FALSE;
-}
-
-static gboolean connect_watch(GIOChannel *chan, GIOCondition cond,
-                                                       gpointer user_data)
-{
-       struct search_context *ctxt = user_data;
-       sdp_list_t *search, *attrids;
-       uint32_t range = 0x0000ffff;
-       socklen_t len;
-       int sk, err = 0;
-
-       sk = g_io_channel_unix_get_fd(chan);
-       ctxt->io_id = 0;
-
-       len = sizeof(err);
-       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
-               err = errno;
-               goto failed;
-       }
-
-       if (err != 0)
-               goto failed;
-
-       if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
-               err = EIO;
-               goto failed;
-       }
-
-       search = sdp_list_append(NULL, &ctxt->uuid);
-       attrids = sdp_list_append(NULL, &range);
-       if (sdp_service_search_attr_async(ctxt->session,
-                               search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
-               sdp_list_free(attrids, NULL);
-               sdp_list_free(search, NULL);
-               err = EIO;
-               goto failed;
-       }
-
-       sdp_list_free(attrids, NULL);
-       sdp_list_free(search, NULL);
-
-       /* Set callback responsible for update the internal SDP transaction */
-       ctxt->io_id = g_io_add_watch(chan,
-                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                               search_process_cb, ctxt);
-       return FALSE;
-
-failed:
-       sdp_close(ctxt->session);
-       ctxt->session = NULL;
-
-       if (ctxt->cb)
-               ctxt->cb(NULL, -err, ctxt->user_data);
-
-       search_context_cleanup(ctxt);
-
-       return FALSE;
-}
-
-static int create_search_context(struct search_context **ctxt,
-                                       const bdaddr_t *src,
-                                       const bdaddr_t *dst,
-                                       uuid_t *uuid)
-{
-       sdp_session_t *s;
-       GIOChannel *chan;
-
-       if (!ctxt)
-               return -EINVAL;
-
-       s = get_sdp_session(src, dst);
-       if (!s)
-               return -errno;
-
-       *ctxt = g_try_malloc0(sizeof(struct search_context));
-       if (!*ctxt) {
-               sdp_close(s);
-               return -ENOMEM;
-       }
-
-       bacpy(&(*ctxt)->src, src);
-       bacpy(&(*ctxt)->dst, dst);
-       (*ctxt)->session = s;
-       (*ctxt)->uuid = *uuid;
-
-       chan = g_io_channel_unix_new(sdp_get_socket(s));
-       (*ctxt)->io_id = g_io_add_watch(chan,
-                               G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                               connect_watch, *ctxt);
-       g_io_channel_unref(chan);
-
-       return 0;
-}
-
-int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
-                       uuid_t *uuid, bt_callback_t cb, void *user_data,
-                       bt_destroy_t destroy)
-{
-       struct search_context *ctxt = NULL;
-       int err;
-
-       if (!cb)
-               return -EINVAL;
-
-       err = create_search_context(&ctxt, src, dst, uuid);
-       if (err < 0)
-               return err;
-
-       ctxt->cb        = cb;
-       ctxt->destroy   = destroy;
-       ctxt->user_data = user_data;
-
-       context_list = g_slist_append(context_list, ctxt);
-
-       return 0;
-}
-
-static gint find_by_bdaddr(gconstpointer data, gconstpointer user_data)
-{
-       const struct search_context *ctxt = data, *search = user_data;
-       int ret;
-
-       ret = bacmp(&ctxt->src, &search->src);
-       if (ret != 0)
-               return ret;
-
-       return bacmp(&ctxt->dst, &search->dst);
-}
-
-int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       struct search_context match, *ctxt;
-       GSList *l;
-
-       memset(&match, 0, sizeof(match));
-       bacpy(&match.src, src);
-       bacpy(&match.dst, dst);
-
-       /* Ongoing SDP Discovery */
-       l = g_slist_find_custom(context_list, &match, find_by_bdaddr);
-       if (l == NULL)
-               return -ENOENT;
-
-       ctxt = l->data;
-
-       if (!ctxt->session)
-               return -ENOTCONN;
-
-       if (ctxt->io_id)
-               g_source_remove(ctxt->io_id);
-
-       if (ctxt->session)
-               sdp_close(ctxt->session);
-
-       search_context_cleanup(ctxt);
-
-       return 0;
-}
-
 char *bt_uuid2string(uuid_t *uuid)
 {
        gchar *str;
index c83f5e2..8836804 100644 (file)
  *
  */
 
-typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data);
-typedef void (*bt_destroy_t) (gpointer user_data);
-
-int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
-                       uuid_t *uuid, bt_callback_t cb, void *user_data,
-                       bt_destroy_t destroy);
-int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst);
-
 gchar *bt_uuid2string(uuid_t *uuid);
 char *bt_name2string(const char *string);
 int bt_string2uuid(uuid_t *uuid, const char *string);
diff --git a/src/sdp-client.c b/src/sdp-client.c
new file mode 100644 (file)
index 0000000..ebd760e
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "btio.h"
+#include "sdp-client.h"
+
+/* Number of seconds to keep a sdp_session_t in the cache */
+#define CACHE_TIMEOUT 2
+
+struct cached_sdp_session {
+       bdaddr_t src;
+       bdaddr_t dst;
+       sdp_session_t *session;
+       guint timer;
+};
+
+static GSList *cached_sdp_sessions = NULL;
+
+static gboolean cached_session_expired(gpointer user_data)
+{
+       struct cached_sdp_session *cached = user_data;
+
+       cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, cached);
+
+       sdp_close(cached->session);
+
+       g_free(cached);
+
+       return FALSE;
+}
+
+static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       GSList *l;
+
+       for (l = cached_sdp_sessions; l != NULL; l = l->next) {
+               struct cached_sdp_session *c = l->data;
+               sdp_session_t *session;
+
+               if (bacmp(&c->src, src) || bacmp(&c->dst, dst))
+                       continue;
+
+               g_source_remove(c->timer);
+
+               session = c->session;
+
+               cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, c);
+               g_free(c);
+
+               return session;
+       }
+
+       return sdp_connect(src, dst, SDP_NON_BLOCKING);
+}
+
+static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
+                                               sdp_session_t *session)
+{
+       struct cached_sdp_session *cached;
+
+       cached = g_new0(struct cached_sdp_session, 1);
+
+       bacpy(&cached->src, src);
+       bacpy(&cached->dst, dst);
+
+       cached->session = session;
+
+       cached_sdp_sessions = g_slist_append(cached_sdp_sessions, cached);
+
+       cached->timer = g_timeout_add_seconds(CACHE_TIMEOUT,
+                                               cached_session_expired,
+                                               cached);
+}
+
+struct search_context {
+       bdaddr_t                src;
+       bdaddr_t                dst;
+       sdp_session_t           *session;
+       bt_callback_t           cb;
+       bt_destroy_t            destroy;
+       gpointer                user_data;
+       uuid_t                  uuid;
+       guint                   io_id;
+};
+
+static GSList *context_list = NULL;
+
+static void search_context_cleanup(struct search_context *ctxt)
+{
+       context_list = g_slist_remove(context_list, ctxt);
+
+       if (ctxt->destroy)
+               ctxt->destroy(ctxt->user_data);
+
+       g_free(ctxt);
+}
+
+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);
+}
+
+static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct search_context *ctxt = user_data;
+       int err = 0;
+
+       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+               err = EIO;
+               goto failed;
+       }
+
+       if (sdp_process(ctxt->session) < 0)
+               goto failed;
+
+       return TRUE;
+
+failed:
+       if (err) {
+               sdp_close(ctxt->session);
+               ctxt->session = NULL;
+
+               if (ctxt->cb)
+                       ctxt->cb(NULL, err, ctxt->user_data);
+
+               search_context_cleanup(ctxt);
+       }
+
+       return FALSE;
+}
+
+static gboolean connect_watch(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct search_context *ctxt = user_data;
+       sdp_list_t *search, *attrids;
+       uint32_t range = 0x0000ffff;
+       socklen_t len;
+       int sk, err = 0;
+
+       sk = g_io_channel_unix_get_fd(chan);
+       ctxt->io_id = 0;
+
+       len = sizeof(err);
+       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
+               err = errno;
+               goto failed;
+       }
+
+       if (err != 0)
+               goto failed;
+
+       if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
+               err = EIO;
+               goto failed;
+       }
+
+       search = sdp_list_append(NULL, &ctxt->uuid);
+       attrids = sdp_list_append(NULL, &range);
+       if (sdp_service_search_attr_async(ctxt->session,
+                               search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
+               sdp_list_free(attrids, NULL);
+               sdp_list_free(search, NULL);
+               err = EIO;
+               goto failed;
+       }
+
+       sdp_list_free(attrids, NULL);
+       sdp_list_free(search, NULL);
+
+       /* Set callback responsible for update the internal SDP transaction */
+       ctxt->io_id = g_io_add_watch(chan,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               search_process_cb, ctxt);
+       return FALSE;
+
+failed:
+       sdp_close(ctxt->session);
+       ctxt->session = NULL;
+
+       if (ctxt->cb)
+               ctxt->cb(NULL, -err, ctxt->user_data);
+
+       search_context_cleanup(ctxt);
+
+       return FALSE;
+}
+
+static int create_search_context(struct search_context **ctxt,
+                                       const bdaddr_t *src,
+                                       const bdaddr_t *dst,
+                                       uuid_t *uuid)
+{
+       sdp_session_t *s;
+       GIOChannel *chan;
+
+       if (!ctxt)
+               return -EINVAL;
+
+       s = get_sdp_session(src, dst);
+       if (!s)
+               return -errno;
+
+       *ctxt = g_try_malloc0(sizeof(struct search_context));
+       if (!*ctxt) {
+               sdp_close(s);
+               return -ENOMEM;
+       }
+
+       bacpy(&(*ctxt)->src, src);
+       bacpy(&(*ctxt)->dst, dst);
+       (*ctxt)->session = s;
+       (*ctxt)->uuid = *uuid;
+
+       chan = g_io_channel_unix_new(sdp_get_socket(s));
+       (*ctxt)->io_id = g_io_add_watch(chan,
+                               G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               connect_watch, *ctxt);
+       g_io_channel_unref(chan);
+
+       return 0;
+}
+
+int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
+                       uuid_t *uuid, bt_callback_t cb, void *user_data,
+                       bt_destroy_t destroy)
+{
+       struct search_context *ctxt = NULL;
+       int err;
+
+       if (!cb)
+               return -EINVAL;
+
+       err = create_search_context(&ctxt, src, dst, uuid);
+       if (err < 0)
+               return err;
+
+       ctxt->cb        = cb;
+       ctxt->destroy   = destroy;
+       ctxt->user_data = user_data;
+
+       context_list = g_slist_append(context_list, ctxt);
+
+       return 0;
+}
+
+static gint find_by_bdaddr(gconstpointer data, gconstpointer user_data)
+{
+       const struct search_context *ctxt = data, *search = user_data;
+       int ret;
+
+       ret = bacmp(&ctxt->src, &search->src);
+       if (ret != 0)
+               return ret;
+
+       return bacmp(&ctxt->dst, &search->dst);
+}
+
+int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       struct search_context match, *ctxt;
+       GSList *l;
+
+       memset(&match, 0, sizeof(match));
+       bacpy(&match.src, src);
+       bacpy(&match.dst, dst);
+
+       /* Ongoing SDP Discovery */
+       l = g_slist_find_custom(context_list, &match, find_by_bdaddr);
+       if (l == NULL)
+               return -ENOENT;
+
+       ctxt = l->data;
+
+       if (!ctxt->session)
+               return -ENOTCONN;
+
+       if (ctxt->io_id)
+               g_source_remove(ctxt->io_id);
+
+       if (ctxt->session)
+               sdp_close(ctxt->session);
+
+       search_context_cleanup(ctxt);
+
+       return 0;
+}
+
diff --git a/src/sdp-client.h b/src/sdp-client.h
new file mode 100644 (file)
index 0000000..13d9121
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data);
+typedef void (*bt_destroy_t) (gpointer user_data);
+
+int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
+                       uuid_t *uuid, bt_callback_t cb, void *user_data,
+                       bt_destroy_t destroy);
+int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst);