static gboolean parse_response(GObex *obex, GObexPacket *rsp) { struct pending_pkt *p = obex->pending_req; guint8 opcode, rspcode; gboolean final; rspcode = g_obex_packet_get_operation(rsp, &final); opcode = g_obex_packet_get_operation(p->pkt, NULL); if (opcode == G_OBEX_OP_CONNECT) parse_connect_data(obex, rsp); setup_srm(obex, rsp, FALSE); if (!g_obex_srm_active(obex)) return final; /* * Resposes have final bit set but in case of GET with SRM * we should not remove the request since the remote side will * continue sending responses until the transfer is finished */ if (opcode == G_OBEX_OP_GET && rspcode == G_OBEX_RSP_CONTINUE) { g_source_remove(p->timeout_id); p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex); return FALSE; } return final; }
static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp, gpointer user_data) { struct transfer *transfer = user_data; GObexPacket *req; gboolean rspcode, final; guint id; g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); id = transfer->req_id; transfer->req_id = 0; if (err != NULL) { transfer_complete(transfer, err); return; } rspcode = g_obex_packet_get_operation(rsp, &final); if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) { err = g_error_new(G_OBEX_ERROR, rspcode, "%s", g_obex_strerror(rspcode)); goto failed; } if (transfer->opcode == G_OBEX_OP_GET) { handle_get_body(transfer, rsp, &err); if (err != NULL) goto failed; } if (rspcode == G_OBEX_RSP_SUCCESS) { transfer_complete(transfer, NULL); return; } if (transfer->opcode == G_OBEX_OP_PUT) { req = g_obex_packet_new(transfer->opcode, FALSE, G_OBEX_HDR_INVALID); g_obex_packet_add_body(req, put_get_data, transfer); } else if (!g_obex_srm_active(transfer->obex)) { req = g_obex_packet_new(transfer->opcode, TRUE, G_OBEX_HDR_INVALID); } else { /* Keep id since request still outstanting */ transfer->req_id = id; return; } transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response, transfer, &err); failed: if (err != NULL) { g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); transfer_complete(transfer, err); g_error_free(err); } }
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 gssize put_get_data(void *buf, gsize len, gpointer user_data) { struct transfer *transfer = user_data; GObexPacket *req; GError *err = NULL; gssize ret; ret = transfer->data_producer(buf, len, transfer->user_data); if (ret == 0 || ret == -EAGAIN) return ret; if (ret > 0) { /* Check if SRM is active */ if (!g_obex_srm_active(transfer->obex)) return ret; /* Generate next packet */ req = g_obex_packet_new(transfer->opcode, FALSE, G_OBEX_HDR_INVALID); g_obex_packet_add_body(req, put_get_data, transfer); transfer->req_id = g_obex_send_req(transfer->obex, req, -1, transfer_response, transfer, &err); goto done; } req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID); transfer->req_id = g_obex_send_req(transfer->obex, req, -1, transfer_abort_response, transfer, &err); done: if (err != NULL) { transfer_complete(transfer, err); g_error_free(err); } return ret; }
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; }