Hi Luiz, On 30 October 2012 10:08, Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx> wrote: > 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 > I didn't notice sdp_get_proto_port when I was reading client/bluetooth.c code :) >> + } >> + 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. > In client/bluetooth.c these lines (in search_callback): data = sdp_data_get(rec, 0x0200); /* PSM must be odd and lsb of upper byte must be 0 */ if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001) ch = data->val.uint16; Are responsible for L2CAP psm, right? >> + 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. > Right, when I was removing 'g' from gobexfuse I forgot to change gobexhlp to obexhlp. I'll send RFC v3 after LinuxCon :) >> + 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 Thanks, Michal -- 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