static void pbap_free(void *data) { struct pbap_data *pbap = data; obc_session_unref(pbap->session); g_free(pbap); }
static void map_free(void *data) { struct map_data *map = data; obc_session_unref(map->session); g_free(map); }
static void connect_cb(GObex *obex, GError *err, GObexPacket *rsp, gpointer user_data) { struct callback_data *callback = user_data; GError *gerr = NULL; uint8_t rsp_code; if (err != NULL) { error("connect_cb: %s", err->message); gerr = g_error_copy(err); goto done; } rsp_code = g_obex_packet_get_operation(rsp, NULL); if (rsp_code != G_OBEX_RSP_SUCCESS) gerr = g_error_new(OBEX_IO_ERROR, -EIO, "OBEX Connect failed with 0x%02x", rsp_code); done: callback->func(callback->session, NULL, gerr, callback->data); if (gerr != NULL) g_error_free(gerr); obc_session_unref(callback->session); g_free(callback); }
static void obc_transfer_free(struct obc_transfer *transfer) { struct obc_session *session = transfer->session; DBG("%p", transfer); if (transfer->xfer) g_obex_cancel_transfer(transfer->xfer); if (transfer->fd > 0) close(transfer->fd); obc_session_remove_transfer(session, transfer); obc_session_unref(session); if (transfer->params != NULL) { g_free(transfer->params->data); g_free(transfer->params); } if (transfer->conn) dbus_connection_unref(transfer->conn); g_free(transfer->callback); g_free(transfer->filename); g_free(transfer->name); g_free(transfer->type); g_free(transfer->path); g_free(transfer->buffer); g_free(transfer); }
static void adapter_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; struct callback_data *callback = user_data; struct obc_session *session = callback->session; struct pending_req *req = find_session_request(session, call); reply = dbus_pending_call_steal_reply(call); session->pending_calls = g_slist_remove(session->pending_calls, req); pending_req_finalize(req); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("manager replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto failed; } if (session_connect(session, callback) < 0) goto failed; goto proceed; failed: obc_session_unref(session); g_free(callback); proceed: dbus_message_unref(reply); }
struct obc_session *obc_session_create(const char *source, const char *destination, const char *service, uint8_t channel, const char *owner, session_callback_t function, void *user_data) { DBusConnection *conn; struct obc_session *session; struct obc_transport *transport; struct obc_driver *driver; if (destination == NULL) return NULL; session = session_find(source, destination, service, channel, owner); if (session != NULL) goto proceed; /* FIXME: Do proper transport lookup when the API supports it */ transport = obc_transport_find("Bluetooth"); if (transport == NULL) return NULL; driver = obc_driver_find(service); if (driver == NULL) return NULL; conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); if (conn == NULL) return NULL; session = g_try_malloc0(sizeof(*session)); if (session == NULL) return NULL; session->refcount = 1; session->transport = transport; session->driver = driver; session->conn = conn; session->source = g_strdup(source); session->destination = g_strdup(destination); session->channel = channel; session->queue = g_queue_new(); if (owner) obc_session_set_owner(session, owner, owner_disconnected); proceed: if (session_connect(session, function, user_data) < 0) { obc_session_unref(session); return NULL; } DBG("session %p transport %s driver %s", session, session->transport->name, session->driver->service); return session; }
static void session_process_queue(struct obc_session *session) { struct pending_request *p; if (session->p != NULL) return; if (session->queue == NULL || g_queue_is_empty(session->queue)) return; obc_session_ref(session); while ((p = g_queue_pop_head(session->queue))) { GError *gerr = NULL; DBG("Transfer(%p) started", p->transfer); if (obc_transfer_start(p->transfer, session->obex, &gerr)) { session->p = p; break; } if (p->func) p->func(session, p->transfer, gerr, p->data); g_clear_error(&gerr); pending_request_free(p); } obc_session_unref(session); }
static void session_process_queue(struct obc_session *session) { struct pending_request *p; if (session->p != NULL) return; if (session->queue == NULL || g_queue_is_empty(session->queue)) return; obc_session_ref(session); while ((p = g_queue_pop_head(session->queue))) { GError *gerr = NULL; if (p->process(p, &gerr) == 0) break; if (p->func) p->func(session, p->transfer, gerr, p->data); g_clear_error(&gerr); pending_request_free(p); } obc_session_unref(session); }
static void session_terminate_transfer(struct obc_session *session, struct obc_transfer *transfer, GError *gerr) { struct pending_request *p = session->p; if (p == NULL || p->transfer != transfer) { GList *match; match = g_list_find_custom(session->queue->head, transfer, pending_transfer_cmptransfer); if (match == NULL) return; p = match->data; g_queue_delete_link(session->queue, match); } else session->p = NULL; obc_session_ref(session); if (p->func) p->func(session, p->transfer, gerr, p->data); pending_request_free(p); if (session->p == NULL) session_process_queue(session); obc_session_unref(session); }
static void callback_destroy(struct callback_data *callback, GError *err) { struct obc_session *session = callback->session; callback->func(session, NULL, err, callback->data); g_free(callback); session->callback = NULL; obc_session_unref(session); }
static void transport_func(GIOChannel *io, GError *err, gpointer user_data) { struct callback_data *callback = user_data; struct obc_session *session = callback->session; struct obc_driver *driver = session->driver; struct obc_transport *transport = session->transport; GObex *obex; GObexTransportType type; int tx_mtu = -1; int rx_mtu = -1; DBG(""); if (err != NULL) { error("%s", err->message); goto done; } g_io_channel_set_close_on_unref(io, FALSE); if (transport->getpacketopt && transport->getpacketopt(io, &tx_mtu, &rx_mtu) == 0) type = G_OBEX_TRANSPORT_PACKET; else type = G_OBEX_TRANSPORT_STREAM; obex = g_obex_new(io, type, tx_mtu, rx_mtu); if (obex == NULL) goto done; g_io_channel_set_close_on_unref(io, TRUE); if (driver->target != NULL) g_obex_connect(obex, connect_cb, callback, &err, G_OBEX_HDR_TARGET, driver->target, driver->target_len, G_OBEX_HDR_INVALID); else g_obex_connect(obex, connect_cb, callback, &err, G_OBEX_HDR_INVALID); if (err != NULL) { error("%s", err->message); g_obex_unref(obex); goto done; } session->obex = obex; sessions = g_slist_prepend(sessions, session); g_obex_set_disconnect_function(obex, session_disconnected, session); return; done: callback->func(callback->session, NULL, err, callback->data); obc_session_unref(callback->session); g_free(callback); }
static void unregister_session(void *data) { struct obc_session *session = data; if (g_slist_find(sessions, session) == NULL) return; sessions = g_slist_remove(sessions, session); obc_session_unref(session); }
static void pending_request_free(struct pending_request *p) { if (p->transfer) obc_transfer_unregister(p->transfer); if (p->session) obc_session_unref(p->session); g_free(p); }
static void map_free(void *data) { struct map_data *map = data; set_notification_registration(map, false); obc_session_unref(map->session); g_hash_table_unref(map->messages); g_free(map); }
static int session_connect(struct obc_session *session, session_callback_t function, void *user_data) { struct callback_data *callback; struct obc_transport *transport = session->transport; struct obc_driver *driver = session->driver; callback = g_try_malloc0(sizeof(*callback)); if (callback == NULL) return -ENOMEM; callback->func = function; callback->data = user_data; callback->session = obc_session_ref(session); /* Connection completed */ if (session->obex) { g_idle_add(connection_complete, callback); return 0; } /* Ongoing connection */ if (session->id > 0) { obc_session_unref(callback->session); g_free(callback); return 0; } session->id = transport->connect(session->source, session->destination, driver->uuid, session->channel, transport_func, callback); if (session->id == 0) { obc_session_unref(callback->session); g_free(callback); return -EINVAL; } session->callback = callback; return 0; }
static gboolean connection_complete(gpointer data) { struct callback_data *cb = data; cb->func(cb->session, NULL, NULL, cb->data); obc_session_unref(cb->session); g_free(cb); return FALSE; }
static gboolean service_callback(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct callback_data *callback = user_data; struct obc_session *session = callback->session; sdp_list_t *search, *attrid; uint32_t range = 0x0000ffff; GError *gerr = NULL; uuid_t uuid; if (cond & (G_IO_NVAL | G_IO_ERR)) goto failed; if (sdp_set_notify(callback->sdp, search_callback, callback) < 0) goto failed; if (bt_string2uuid(&uuid, session->driver->uuid) < 0) goto failed; search = sdp_list_append(NULL, &uuid); attrid = sdp_list_append(NULL, &range); if (sdp_service_search_attr_async(callback->sdp, search, SDP_ATTR_REQ_RANGE, attrid) < 0) { sdp_list_free(attrid, NULL); sdp_list_free(search, NULL); goto failed; } sdp_list_free(attrid, NULL); sdp_list_free(search, NULL); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, process_callback, callback); return FALSE; failed: g_io_channel_shutdown(session->io, TRUE, NULL); g_io_channel_unref(session->io); session->io = NULL; g_set_error(&gerr, OBEX_IO_ERROR, -EIO, "Unable to find service record"); callback->func(callback->session, gerr, callback->data); g_clear_error(&gerr); obc_session_unref(callback->session); g_free(callback); return FALSE; }
static void manager_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; char *adapter; struct callback_data *callback = user_data; struct obc_session *session = callback->session; struct pending_req *req = find_session_request(session, call); reply = dbus_pending_call_steal_reply(call); session->pending_calls = g_slist_remove(session->pending_calls, req); pending_req_finalize(req); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("manager replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto failed; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &adapter, DBUS_TYPE_INVALID)) { DBG("adapter path %s", adapter); session->adapter = g_strdup(adapter); req = send_method_call(session->conn_system, BT_BUS_NAME, adapter, BT_ADAPTER_IFACE, "RequestSession", adapter_reply, callback, DBUS_TYPE_INVALID); if (!req) goto failed; session->pending_calls = g_slist_prepend(session->pending_calls, req); } else goto failed; goto proceed; failed: obc_session_unref(session); g_free(callback); proceed: dbus_message_unref(reply); }
static void pending_request_free(struct pending_request *p) { if (p->req_id > 0) g_obex_cancel_req(p->session->obex, p->req_id, TRUE); if (p->destroy) p->destroy(p->data); if (p->transfer) obc_transfer_unregister(p->transfer); if (p->session) obc_session_unref(p->session); g_free(p); }
static void disconnect_cb(GObex *obex, GError *err, GObexPacket *rsp, gpointer user_data) { struct pending_request *p = user_data; struct obc_session *session = p != NULL ? p->session : NULL; DBG("Finalizing disconnection. "); pending_request_free(p); if (session != NULL && session->id > 0 && session->transport != NULL) { session->transport->disconnect(session->id); session->id = 0; } obc_session_unref(session); }
void obc_session_shutdown(struct obc_session *session) { struct pending_request *p; GError *err; DBG("%p", session); obc_session_ref(session); /* Unregister any pending transfer */ err = g_error_new(OBEX_IO_ERROR, OBEX_IO_DISCONNECTED, "Session closed by user"); if (session->p != NULL && session->p->id != 0) { p = session->p; session->p = NULL; if (p->func) p->func(session, p->transfer, err, p->data); pending_request_free(p); } while ((p = g_queue_pop_head(session->queue))) { if (p->func) p->func(session, p->transfer, err, p->data); pending_request_free(p); } g_error_free(err); /* Unregister interfaces */ if (session->path) session_unregistered(session); /* Disconnect transport */ if (session->id > 0 && session->transport != NULL) { session->transport->disconnect(session->id); session->id = 0; } obc_session_unref(session); }
static void session_terminate_transfer(struct obc_session *session, struct obc_transfer *transfer, GError *gerr) { struct session_callback *callback = session->callback; if (callback) { callback->func(session, gerr, callback->data); return; } obc_session_ref(session); obc_transfer_unregister(transfer); if (session->pending) session_request(session, session_prepare_put, session->pending->data); obc_session_unref(session); }
void obc_session_shutdown(struct obc_session *session) { DBG("%p", session); obc_session_ref(session); /* Unregister any pending transfer */ g_slist_foreach(session->pending, (GFunc) obc_transfer_unregister, NULL); /* Unregister interfaces */ if (session->path) session_unregistered(session); /* Shutdown io */ if (session->io) { int fd = g_io_channel_unix_get_fd(session->io); shutdown(fd, SHUT_RDWR); } obc_session_unref(session); }
static void rfcomm_callback(GIOChannel *io, GError *err, gpointer user_data) { struct callback_data *callback = user_data; struct obc_session *session = callback->session; struct obc_driver *driver = session->driver; GwObex *obex; int fd; DBG(""); if (err != NULL) { error("%s", err->message); goto done; } /* do not close when gw_obex is using the fd */ g_io_channel_set_close_on_unref(session->io, FALSE); g_io_channel_unref(session->io); session->io = NULL; fd = g_io_channel_unix_get_fd(io); obex = gw_obex_setup_fd(fd, driver->target, driver->target_len, NULL, NULL); session->obex = obex; sessions = g_slist_prepend(sessions, session); done: callback->func(callback->session, err, callback->data); obc_session_unref(callback->session); g_free(callback); }
static void search_callback(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) { struct callback_data *callback = user_data; struct obc_session *session = callback->session; unsigned int scanned, bytesleft = size; int seqlen = 0; uint8_t dataType, channel = 0; GError *gerr = NULL; if (status || type != SDP_SVC_SEARCH_ATTR_RSP) goto failed; scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); if (!scanned || !seqlen) goto failed; rsp += scanned; bytesleft -= scanned; do { sdp_record_t *rec; sdp_list_t *protos; int recsize, ch = -1; recsize = 0; rec = sdp_extract_pdu(rsp, bytesleft, &recsize); if (!rec) break; if (!recsize) { sdp_record_free(rec); break; } if (!sdp_get_access_protos(rec, &protos)) { ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); protos = NULL; } sdp_record_free(rec); if (ch > 0) { channel = ch; break; } scanned += recsize; rsp += recsize; bytesleft -= recsize; } while (scanned < size && bytesleft > 0); if (channel == 0) goto failed; session->channel = channel; g_io_channel_set_close_on_unref(session->io, FALSE); g_io_channel_unref(session->io); session->io = rfcomm_connect(&session->src, &session->dst, channel, rfcomm_callback, callback); if (session->io != NULL) { sdp_close(callback->sdp); return; } failed: g_io_channel_shutdown(session->io, TRUE, NULL); g_io_channel_unref(session->io); session->io = NULL; g_set_error(&gerr, OBEX_IO_ERROR, -EIO, "Unable to find service record"); callback->func(session, gerr, callback->data); g_clear_error(&gerr); obc_session_unref(callback->session); g_free(callback); }
struct obc_session *obc_session_create(const char *source, const char *destination, const char *service, uint8_t channel, const char *owner, session_callback_t function, void *user_data) { struct obc_session *session; struct callback_data *callback; struct pending_req *req; struct obc_driver *driver; if (destination == NULL) return NULL; session = session_find(source, destination, service, channel, owner); if (session) { obc_session_ref(session); goto proceed; } driver = obc_driver_find(service); if (!driver) return NULL; session = g_try_malloc0(sizeof(*session)); if (session == NULL) return NULL; session->refcount = 1; session->channel = channel; session->conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); if (session->conn == NULL) { session_free(session); return NULL; } session->conn_system = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL); if (session->conn_system == NULL) { session_free(session); return NULL; } if (source == NULL) bacpy(&session->src, BDADDR_ANY); else str2ba(source, &session->src); str2ba(destination, &session->dst); session->driver = driver; DBG("driver %s", driver->service); proceed: callback = g_try_malloc0(sizeof(*callback)); if (callback == NULL) { obc_session_unref(session); return NULL; } callback->session = obc_session_ref(session); callback->func = function; callback->data = user_data; if (source) { req = send_method_call(session->conn_system, BT_BUS_NAME, BT_PATH, BT_MANAGER_IFACE, "FindAdapter", manager_reply, callback, DBUS_TYPE_STRING, &source, DBUS_TYPE_INVALID); } else { req = send_method_call(session->conn_system, BT_BUS_NAME, BT_PATH, BT_MANAGER_IFACE, "DefaultAdapter", manager_reply, callback, DBUS_TYPE_INVALID); } if (!req) { obc_session_unref(session); g_free(callback); return NULL; } session->pending_calls = g_slist_prepend(session->pending_calls, req); if (owner) obc_session_set_owner(session, owner, owner_disconnected); return session; }
void obc_session_shutdown(struct obc_session *session) { struct pending_request *p; GError *err; DBG("%p", session); if (session->disconnecting == TRUE) { DBG("%p already disconnecting", session); return; } session->disconnecting = TRUE; obc_session_ref(session); /* Unregister any pending transfer */ err = g_error_new(OBEX_IO_ERROR, OBEX_IO_DISCONNECTED, "Session closed by user"); if (session->p != NULL && session->p->id != 0) { p = session->p; session->p = NULL; if (p->func) p->func(session, p->transfer, err, p->data); pending_request_free(p); } while ((p = g_queue_pop_head(session->queue))) { if (p->func) p->func(session, p->transfer, err, p->data); pending_request_free(p); } g_error_free(err); /* Unregister interfaces */ if (session->path) session_unregistered(session); DBG("Checking the need for disconnect request"); /* Send a disconnect request and wait for reply */ if (session->id > 0 && session->transport != NULL && session->obex != NULL) { DBG("Generating disconnect request. "); err = NULL; p = pending_request_new(session, NULL, NULL, NULL); p->req_id = g_obex_disconnect(session->obex, disconnect_cb, p, &err); if (err != NULL) { DBG("Generating disconnect request failed. "); disconnect_cb(session->obex, NULL, NULL, p); } else { /* Finalize when reply arrives */ DBG("Generating disconnect request succeeded. "); } } else { DBG("Unreferring without disconnect request."); obc_session_unref(session); } }
static void shutdown_session(struct obc_session *session) { obc_session_shutdown(session); obc_session_unref(session); }