Re: [RFC v2 obexd 03/11] fuse: Add obexhlp_connect/disconnect functions with helpers
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2012-10-30 09:08:01
Hi Michal, On Sun, Oct 28, 2012 at 2:29 AM, Michał Poczwardowski [off-list ref] wrote:
quoted hunk ↗ jump to hunk
--- fuse/helpers.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fuse/helpers.h | 4 + fuse/obexfuse.c | 40 ++++++++++ 3 files changed, 265 insertions(+), 0 deletions(-)diff --git a/fuse/helpers.c b/fuse/helpers.c index c36072d..856e1d5 100644 --- a/fuse/helpers.c +++ b/fuse/helpers.c@@ -43,6 +43,9 @@ #define OBEX_FTP_LS "x-obex/folder-listing" +static GCond *gobexhlp_cond; +static GMutex *gobexhlp_mutex; + struct gobexhlp_request { gchar *name; gboolean complete;@@ -52,3 +55,221 @@ struct gobexhlp_location { gchar *dir; gchar *file; }; + +static uint16_t find_rfcomm_uuid(void *user_data) +{ + sdp_list_t *pds = (sdp_list_t*) user_data; + uint16_t channel = 0; + + for (;pds;pds = pds->next) { + 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) + channel = d->val.int8; + break; + } + } + } + return channel; +} + +static uint16_t get_ftp_channel(bdaddr_t *src, bdaddr_t *dst) +{ + sdp_session_t *sdp; + sdp_list_t *r, *search_list, *attrid_list; + sdp_list_t *response_list = NULL; + uuid_t uuid; + + /* FTP_SDP_UUID "00001106-0000-1000-8000-00805f9b34fb" */ + uint8_t uuid_int[] = {0, 0, 0x11, 0x06, 0, 0, 0x10, 0, 0x80, + 0, 0, 0x80, 0x5f, 0x9b, 0x34, 0xfb}; + uint32_t range = 0x0000ffff; + uint16_t channel = 0; + + sdp = sdp_connect(src, dst, SDP_RETRY_IF_BUSY ); + if (sdp == NULL) + return channel; + + sdp_uuid128_create(&uuid, uuid_int); + search_list = sdp_list_append(NULL, &uuid); + attrid_list = sdp_list_append(NULL, &range); + sdp_service_search_attr_req(sdp, search_list, SDP_ATTR_REQ_RANGE, + attrid_list, &response_list); + r = response_list; + + for (; r;r = r->next) { + sdp_record_t *rec = (sdp_record_t*) r->data; + sdp_list_t *proto_list; + + if (sdp_get_access_protos(rec, &proto_list ) == 0) { + sdp_list_t *p = proto_list; + for (; p; p = p->next) { + sdp_list_t *pds = (sdp_list_t*) p->data; + channel = find_rfcomm_uuid(pds); + sdp_list_free((sdp_list_t*) p->data, 0);
You dont really need to iterate in the list of protos there exist a function that does that for you take a look at sdp_get_proto_port, btw there exist a similar code in client/bluetooth.c
+ }
+ sdp_list_free(proto_list, 0);
+ }
+ sdp_record_free(rec);
+ }
+ sdp_close(sdp);
+
+ g_free(search_list);
+ g_free(attrid_list);
+ g_free(response_list);
+
+ return channel;
+}
+
+/* taken from client/bluetooth.c - bluetooth_getpacketopt */
+static int get_packet_opt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
+{
+ int sk = g_io_channel_unix_get_fd(io);
+ int type;
+ int omtu = -1;
+ int imtu = -1;
+ socklen_t len = sizeof(int);
+
+ if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+ return -errno;
+
+ if (type != SOCK_SEQPACKET)
+ return -EINVAL;
+
+ if (!bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, &omtu,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_INVALID))
+ return -EINVAL;
+
+ if (tx_mtu)
+ *tx_mtu = omtu;
+
+ if (rx_mtu)
+ *rx_mtu = imtu;
+
+ return 0;
+}
+
+static void obex_callback(GObex *obex, GError *err, GObexPacket *rsp,
+ gpointer user_data)
+{
+ if (err != NULL) {
+ g_debug("Connect failed: %s\n", err->message);
+ g_error_free(err);
+ } else {
+ g_debug("Connect succeeded\n");
+ }
+}
+
+static void bt_io_callback(GIOChannel *io, GError *err, gpointer user_data)
+{
+ struct gobexhlp_session *session = user_data;
+ GObexTransportType type;
+ int tx_mtu = -1;
+ int rx_mtu = -1;
+
+ if (err != NULL) {
+ g_printerr("%s\n", err->message);
+ g_error_free(err);
+ return;
+ }
+
+ g_debug("Bluetooth socket connected\n");
+
+ g_io_channel_set_flags(session->io, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_close_on_unref(session->io, TRUE);
+
+ if (get_packet_opt(session->io, &tx_mtu, &rx_mtu) == 0) {
+ type = G_OBEX_TRANSPORT_PACKET;
+ g_debug("PACKET transport tx:%d rx:%d\n", tx_mtu, rx_mtu);
+ } else {
+ type = G_OBEX_TRANSPORT_STREAM;
+ g_debug("STREAM transport\n");
+ }
+
+ session->obex = g_obex_new(io, type, tx_mtu, rx_mtu);
+ g_obex_connect(session->obex, obex_callback, session, NULL,
+ G_OBEX_HDR_TARGET, OBEX_FTP_UUID,
+ OBEX_FTP_UUID_LEN, G_OBEX_HDR_INVALID);
+}
+
+struct gobexhlp_session* gobexhlp_connect(const char *srcstr,
+ const char *dststr)
+{
+ struct gobexhlp_session *session;
+ uint16_t channel;
+ bdaddr_t src, dst;
+
+ session = g_try_malloc0(sizeof(struct gobexhlp_session));
+ if (session == NULL)
+ return NULL;
+
+ if (srcstr == NULL)
+ bacpy(&src, BDADDR_ANY);
+ else
+ str2ba(srcstr, &src);
+
+ str2ba(dststr, &dst);
+ channel = get_ftp_channel(&src, &dst);
+
+ if (channel == 0)
+ return NULL;Currently you are not checking for L2CAP psm just RFCOMM channel so the code bellow would never be used.
quoted hunk ↗ jump to hunk
+ if (channel > 31) + session->io = bt_io_connect(BT_IO_L2CAP, bt_io_callback, + session, NULL, &session->err, + BT_IO_OPT_SOURCE_BDADDR, &src, + BT_IO_OPT_DEST_BDADDR, &dst, + BT_IO_OPT_PSM, channel, + BT_IO_OPT_MODE, BT_IO_MODE_ERTM, + BT_IO_OPT_OMTU, BT_TX_MTU, + BT_IO_OPT_IMTU, BT_RX_MTU, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, + BT_IO_OPT_INVALID); + else + session->io = bt_io_connect(BT_IO_RFCOMM, bt_io_callback, + session, NULL, &session->err, + BT_IO_OPT_SOURCE_BDADDR, &src, + BT_IO_OPT_DEST_BDADDR, &dst, + BT_IO_OPT_CHANNEL, channel, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, + BT_IO_OPT_INVALID); + + if (session->err != NULL) + return NULL; + + session->file_stat = g_hash_table_new_full( g_str_hash, g_str_equal, + g_free, g_free); + session->setpath = g_strdup("/"); + + gobexhlp_mutex = g_mutex_new(); + gobexhlp_cond = g_cond_new(); + + return session; +} + +void gobexhlp_disconnect(struct gobexhlp_session* session) +{ + if (session == NULL) + return; + + g_obex_unref(session->obex); + g_free(session->io); + + g_hash_table_remove_all(session->file_stat); + g_list_free_full(session->lsfiles, g_free); + g_free(session->setpath); + + g_mutex_free(gobexhlp_mutex); + g_cond_free(gobexhlp_cond); + + g_free(session); +}diff --git a/fuse/helpers.h b/fuse/helpers.h index 142403f..29dc6cf 100644 --- a/fuse/helpers.h +++ b/fuse/helpers.h@@ -46,3 +46,7 @@ struct gobexhlp_session { int status; GError *err; }; + +struct gobexhlp_session* gobexhlp_connect(const char *srcstr, + const char *dstsrc); +void gobexhlp_disconnect(struct gobexhlp_session* session);diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c index fe4f4da..79eb990 100644 --- a/fuse/obexfuse.c +++ b/fuse/obexfuse.c@@ -33,6 +33,10 @@ #include "helpers.h" +struct gobexhlp_session* session = NULL; +static GMainLoop *main_loop; +static GThread *main_gthread; + struct options { char* dststr; char* srcstr;@@ -60,7 +64,34 @@ static struct fuse_opt obexfuse_opts[] = FUSE_OPT_END }; +gpointer main_loop_func(gpointer user_data) +{ + main_loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(main_loop); + + return 0; +} + +void* obexfuse_init(struct fuse_conn_info *conn) +{ + main_gthread = g_thread_create(main_loop_func, NULL, TRUE, NULL); + + conn->async_read = 0; + conn->want &= ~FUSE_CAP_ASYNC_READ; + + return 0; +} + +void obexfuse_destroy() +{ + gobexhlp_disconnect(session); + g_main_loop_quit(main_loop); + g_thread_join(main_gthread); +} + static struct fuse_operations obexfuse_oper = { + .init = obexfuse_init, + .destroy = obexfuse_destroy, }; static int obexfuse_opt_proc(void *data, const char *arg, int key,@@ -111,6 +142,15 @@ int main(int argc, char *argv[]) g_thread_init(NULL);
I would suggest not mixing gobex prefix with your helper functions, in fact it is probably fine to just use obexfuse e.g. obexfuse_connect.
+ session = gobexhlp_connect(options.srcstr, options.dststr);
+ if (session == NULL || session->io == NULL) {
+ g_printerr("Connection to %s failed\n", options.dststr);
+ gobexhlp_disconnect(session);
+ return -EHOSTUNREACH;
+ } else {
+ g_print("Connected\nMounting %s\n", options.dststr);
+ }
+
fuse_opt_add_arg(&args, "-s"); /* force single threaded mode */
retfuse = fuse_main(args.argc, args.argv, &obexfuse_oper, NULL);
--
1.7.8.6
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html-- Luiz Augusto von Dentz