void avctp_shutdown(struct avctp *session) { if (!session) return; if (session->browsing) avctp_channel_destroy(session->browsing); if (session->control) avctp_channel_destroy(session->control); if (session->destroy) session->destroy(session->data); g_free(session->handler); if (session->key.timer > 0) g_source_remove(session->key.timer); if (session->uinput >= 0) { DBG("AVCTP: closing uinput"); ioctl(session->uinput, UI_DEV_DESTROY); close(session->uinput); session->uinput = -1; } g_free(session); }
static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err, gpointer data) { struct avctp *session = data; struct avctp_channel *browsing = session->browsing; struct avctp_queue *queue; char address[18]; uint16_t imtu, omtu; GError *gerr = NULL; if (err) { error("Browsing: %s", err->message); goto fail; } bt_io_get(chan, &gerr, BT_IO_OPT_DEST, &address, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_io_channel_shutdown(chan, TRUE, NULL); g_io_channel_unref(chan); g_error_free(gerr); goto fail; } DBG("AVCTP Browsing: connected to %s", address); if (browsing == NULL) { browsing = avctp_channel_create(session, chan, 1, avctp_destroy_browsing); session->browsing = browsing; } browsing->imtu = imtu; browsing->omtu = omtu; browsing->buffer = g_malloc0(MAX(imtu, omtu)); browsing->watch = g_io_add_watch(session->browsing->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) session_browsing_cb, session); avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED, 0); /* Process any request that was pending the connection to complete */ queue = g_slist_nth_data(browsing->queues, 0); if (queue->process_id == 0 && !g_queue_is_empty(queue->queue)) queue->process_id = g_idle_add(process_queue, queue); return; fail: avctp_set_state(session, AVCTP_STATE_CONNECTED, 0); if (session->browsing) { avctp_channel_destroy(session->browsing); session->browsing = NULL; } }
static void avctp_disconnected(struct avctp *session) { struct avctp_server *server; if (!session) return; if (session->browsing) avctp_channel_destroy(session->browsing); if (session->control) avctp_channel_destroy(session->control); if (session->auth_id != 0) { btd_cancel_authorization(session->auth_id); session->auth_id = 0; } if (session->key != NULL) { if (session->key->timer > 0) g_source_remove(session->key->timer); g_free(session->key); } if (session->uinput >= 0) { char address[18]; ba2str(device_get_address(session->device), address); DBG("AVCTP: closing uinput for %s", address); ioctl(session->uinput, UI_DEV_DESTROY); close(session->uinput); session->uinput = -1; } server = session->server; server->sessions = g_slist_remove(server->sessions, session); btd_device_unref(session->device); g_free(session); }
static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err, gpointer data) { struct avctp *session = data; char address[18]; uint16_t imtu, omtu; GError *gerr = NULL; if (err) { error("Browsing: %s", err->message); goto fail; } bt_io_get(chan, &gerr, BT_IO_OPT_DEST, &address, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_io_channel_shutdown(chan, TRUE, NULL); g_io_channel_unref(chan); g_error_free(gerr); goto fail; } DBG("AVCTP Browsing: connected to %s", address); if (session->browsing == NULL) session->browsing = avctp_channel_create(session, chan, avctp_destroy_browsing); session->browsing->imtu = imtu; session->browsing->omtu = omtu; session->browsing->buffer = g_malloc0(MAX(imtu, omtu)); session->browsing->watch = g_io_add_watch(session->browsing->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) session_browsing_cb, session); avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED); return; fail: avctp_set_state(session, AVCTP_STATE_CONNECTED); if (session->browsing) { avctp_channel_destroy(session->browsing); session->browsing = NULL; } }
static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct avctp *session = data; struct avctp_channel *browsing = session->browsing; uint8_t *buf = browsing->buffer; uint8_t *operands; struct avctp_header *avctp; int sock, ret, packet_size, operand_count; struct avctp_browsing_pdu_handler *handler; if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) goto failed; sock = g_io_channel_unix_get_fd(chan); ret = read(sock, buf, browsing->imtu); if (ret <= 0) goto failed; avctp = (struct avctp_header *) buf; if (avctp->packet_type != AVCTP_PACKET_SINGLE) goto failed; operands = buf + AVCTP_HEADER_LENGTH; ret -= AVCTP_HEADER_LENGTH; operand_count = ret; if (avctp->cr == AVCTP_RESPONSE) { browsing_response(browsing, avctp, operands, operand_count); return TRUE; } packet_size = AVCTP_HEADER_LENGTH; avctp->cr = AVCTP_RESPONSE; handler = g_slist_nth_data(browsing->handlers, 0); if (handler == NULL) { DBG("handler not found"); packet_size += avrcp_browsing_general_reject(operands); goto send; } packet_size += handler->cb(session, avctp->transaction, operands, operand_count, handler->user_data); send: if (packet_size != 0) { ret = write(sock, buf, packet_size); if (ret != packet_size) goto failed; } return TRUE; failed: DBG("AVCTP Browsing: disconnected"); avctp_set_state(session, AVCTP_STATE_CONNECTED); if (session->browsing) { avctp_channel_destroy(session->browsing); session->browsing = NULL; } return FALSE; }