Hi Michal, On Sun, Oct 28, 2012 at 2:29 AM, Michał Poczwardowski <dmp0x7c5@xxxxxxxxx> wrote: > --- > 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. > + 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@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Luiz Augusto von Dentz -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html