gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err) { struct pending_pkt *p; gboolean ret; g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); if (obex == NULL || pkt == NULL) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS, "Invalid arguments"); g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message); return FALSE; } switch (obex->rx_last_op) { case G_OBEX_OP_CONNECT: prepare_connect_rsp(obex, pkt); break; case G_OBEX_OP_GET: case G_OBEX_OP_PUT: prepare_srm_rsp(obex, pkt); break; } p = g_new0(struct pending_pkt, 1); p->pkt = pkt; ret = g_obex_send_internal(obex, p, err); if (ret == FALSE) pending_pkt_free(p); return ret; }
static void handle_response(GObex *obex, GError *err, GObexPacket *rsp) { struct pending_pkt *p = obex->pending_req; gboolean disconn = err ? TRUE : FALSE, final_rsp = TRUE; if (rsp != NULL) final_rsp = parse_response(obex, rsp); if (p->cancelled) err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, "The operation was cancelled"); if (err) g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); if (p->rsp_func) { p->rsp_func(obex, err, rsp, p->rsp_data); /* Check if user callback removed the request */ if (p != obex->pending_req) return; } if (p->cancelled) g_error_free(err); if (final_rsp) { pending_pkt_free(p); obex->pending_req = NULL; } if (!disconn && g_queue_get_length(obex->tx_queue) > 0) enable_tx(obex); }
void g_obex_unref(GObex *obex) { gboolean last_ref; last_ref = g_atomic_int_dec_and_test(&obex->ref_count); g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", obex->ref_count); if (!last_ref) return; g_slist_free_full(obex->req_handlers, g_free); g_queue_foreach(obex->tx_queue, (GFunc) pending_pkt_free, NULL); g_queue_free(obex->tx_queue); if (obex->io != NULL) g_io_channel_unref(obex->io); if (obex->io_source > 0) g_source_remove(obex->io_source); if (obex->write_source > 0) g_source_remove(obex->write_source); g_free(obex->rx_buf); g_free(obex->tx_buf); g_free(obex->srm); if (obex->pending_req) pending_pkt_free(obex->pending_req); g_free(obex); }
void g_obex_unref(GObex *obex) { int refs; refs = __sync_sub_and_fetch(&obex->ref_count, 1); g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs); if (refs > 0) return; g_slist_free_full(obex->req_handlers, g_free); g_queue_foreach(obex->tx_queue, (GFunc) pending_pkt_free, NULL); g_queue_free(obex->tx_queue); if (obex->io != NULL) g_io_channel_unref(obex->io); if (obex->io_source > 0) g_source_remove(obex->io_source); if (obex->write_source > 0) g_source_remove(obex->write_source); g_free(obex->rx_buf); g_free(obex->tx_buf); g_free(obex->srm); if (obex->pending_req) pending_pkt_free(obex->pending_req); g_free(obex); }
guint g_obex_send_req(GObex *obex, GObexPacket *req, gint timeout, GObexResponseFunc func, gpointer user_data, GError **err) { GObexHeader *hdr; struct pending_pkt *p; static guint id = 1; guint8 op; g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); op = g_obex_packet_get_operation(req, NULL); if (op == G_OBEX_OP_PUT || op == G_OBEX_OP_GET) { /* Only enable SRM automatically for GET and PUT */ prepare_srm_req(obex, req); } if (obex->conn_id == CONNID_INVALID) goto create_pending; if (obex->rx_last_op == G_OBEX_RSP_CONTINUE) goto create_pending; if (g_obex_srm_active(obex) && obex->pending_req != NULL) goto create_pending; hdr = g_obex_packet_get_header(req, G_OBEX_HDR_CONNECTION); if (hdr != NULL) goto create_pending; hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id); g_obex_packet_prepend_header(req, hdr); create_pending: p = g_new0(struct pending_pkt, 1); p->pkt = req; p->id = id++; p->rsp_func = func; p->rsp_data = user_data; if (timeout < 0) p->timeout = G_OBEX_DEFAULT_TIMEOUT; else p->timeout = timeout; if (!g_obex_send_internal(obex, p, err)) { pending_pkt_free(p); return 0; } return p->id; }
static gboolean cancel_complete(gpointer user_data) { struct pending_pkt *p = user_data; GObex *obex = p->obex; GError *err; g_assert(p->rsp_func != NULL); err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, "The request was cancelled"); p->rsp_func(obex, err, NULL, p->rsp_data); g_error_free(err); pending_pkt_free(p); return FALSE; }
gboolean g_obex_cancel_req(GObex *obex, guint req_id, gboolean remove_callback) { GList *match; struct pending_pkt *p; if (obex->pending_req && obex->pending_req->id == req_id) { if (!g_obex_pending_req_abort(obex, NULL)) { p = obex->pending_req; obex->pending_req = NULL; goto immediate_completion; } if (remove_callback) obex->pending_req->rsp_func = NULL; return TRUE; } match = g_queue_find_custom(obex->tx_queue, GUINT_TO_POINTER(req_id), pending_pkt_cmp); if (match == NULL) return FALSE; p = match->data; g_queue_delete_link(obex->tx_queue, match); immediate_completion: p->cancelled = TRUE; p->obex = g_obex_ref(obex); if (remove_callback || p->rsp_func == NULL) pending_pkt_free(p); else g_idle_add(cancel_complete, p); return TRUE; }
static gboolean req_timeout(gpointer user_data) { GObex *obex = user_data; struct pending_pkt *p = obex->pending_req; GError *err; g_assert(p != NULL); obex->pending_req = NULL; err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT, "Timed out waiting for response"); g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); if (p->rsp_func) p->rsp_func(obex, err, NULL, p->rsp_data); g_error_free(err); pending_pkt_free(p); return FALSE; }
static gboolean write_data(GIOChannel *io, GIOCondition cond, gpointer user_data) { GObex *obex = user_data; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) goto stop_tx; if (obex->tx_data == 0) { struct pending_pkt *p = g_queue_pop_head(obex->tx_queue); ssize_t len; if (p == NULL) goto stop_tx; setup_srm(obex, p->pkt, TRUE); if (g_obex_srm_active(obex)) goto encode; /* Can't send a request while there's a pending one */ if (obex->pending_req && p->id > 0) { g_queue_push_head(obex->tx_queue, p); goto stop_tx; } encode: len = g_obex_packet_encode(p->pkt, obex->tx_buf, obex->tx_mtu); if (len == -EAGAIN) { g_queue_push_head(obex->tx_queue, p); g_obex_suspend(obex); goto stop_tx; } if (len < 0) { pending_pkt_free(p); goto done; } if (p->id > 0) { if (obex->pending_req != NULL) pending_pkt_free(obex->pending_req); obex->pending_req = p; p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex); } else { /* During packet encode final bit can be set */ if (obex->tx_buf[0] & FINAL_BIT) check_srm_final(obex, obex->tx_buf[0] & ~FINAL_BIT); pending_pkt_free(p); } obex->tx_data = len; obex->tx_sent = 0; } if (obex->suspended) { obex->write_source = 0; return FALSE; } if (!obex->write(obex, NULL)) goto stop_tx; done: if (obex->tx_data > 0 || g_queue_get_length(obex->tx_queue) > 0) return TRUE; stop_tx: obex->rx_last_op = G_OBEX_OP_NONE; obex->tx_data = 0; obex->write_source = 0; return FALSE; }