| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- *
- * OBEX library with GLib integration
- *
- * Copyright (C) 2011 Intel Corporation. All rights reserved.
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <string.h>
- #include <errno.h>
- #include "gobex/gobex.h"
- #include "gobex/gobex-debug.h"
- #define FIRST_PACKET_TIMEOUT 60
- static GSList *transfers = NULL;
- static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
- gpointer user_data);
- struct transfer {
- guint id;
- guint8 opcode;
- GObex *obex;
- guint req_id;
- guint put_id;
- guint get_id;
- guint abort_id;
- GObexDataProducer data_producer;
- GObexDataConsumer data_consumer;
- GObexFunc complete_func;
- gpointer user_data;
- };
- static void transfer_free(struct transfer *transfer)
- {
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- transfers = g_slist_remove(transfers, transfer);
- if (transfer->req_id > 0)
- g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE);
- if (transfer->put_id > 0)
- g_obex_remove_request_function(transfer->obex,
- transfer->put_id);
- if (transfer->get_id > 0)
- g_obex_remove_request_function(transfer->obex,
- transfer->get_id);
- if (transfer->abort_id > 0)
- g_obex_remove_request_function(transfer->obex,
- transfer->abort_id);
- g_obex_unref(transfer->obex);
- g_free(transfer);
- }
- static struct transfer *find_transfer(guint id)
- {
- GSList *l;
- for (l = transfers; l != NULL; l = g_slist_next(l)) {
- struct transfer *t = l->data;
- if (t->id == id)
- return t;
- }
- return NULL;
- }
- static void transfer_complete(struct transfer *transfer, GError *err)
- {
- guint id = transfer->id;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
- if (err) {
- /* No further tx must be performed */
- g_obex_drop_tx_queue(transfer->obex);
- }
- transfer->complete_func(transfer->obex, err, transfer->user_data);
- /* Check if the complete_func removed the transfer */
- if (find_transfer(id) == NULL)
- return;
- transfer_free(transfer);
- }
- static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
- gpointer user_data)
- {
- struct transfer *transfer = user_data;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- transfer->req_id = 0;
- /* Intentionally override error */
- err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
- "Operation was aborted");
- g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
- transfer_complete(transfer, err);
- g_error_free(err);
- }
- 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;
- }
- transfer->req_id = g_obex_abort(transfer->obex, transfer_abort_response,
- transfer, &err);
- done:
- if (err != NULL) {
- transfer_complete(transfer, err);
- g_error_free(err);
- }
- return ret;
- }
- static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
- GError **err)
- {
- GObexHeader *body = g_obex_packet_get_body(rsp);
- gboolean ret;
- const guint8 *buf;
- gsize len;
- if (body == NULL)
- return TRUE;
- g_obex_header_get_bytes(body, &buf, &len);
- if (len == 0)
- return TRUE;
- ret = transfer->data_consumer(buf, len, transfer->user_data);
- if (ret == FALSE)
- g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
- "Data consumer callback failed");
- return ret;
- }
- 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);
- }
- }
- static struct transfer *transfer_new(GObex *obex, guint8 opcode,
- GObexFunc complete_func, gpointer user_data)
- {
- static guint next_id = 1;
- struct transfer *transfer;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
- transfer = g_new0(struct transfer, 1);
- transfer->id = next_id++;
- transfer->opcode = opcode;
- transfer->obex = g_obex_ref(obex);
- transfer->complete_func = complete_func;
- transfer->user_data = user_data;
- transfers = g_slist_append(transfers, transfer);
- return transfer;
- }
- guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
- GObexDataProducer data_func, GObexFunc complete_func,
- gpointer user_data, GError **err)
- {
- struct transfer *transfer;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
- if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
- return 0;
- transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
- transfer->data_producer = data_func;
- g_obex_packet_add_body(req, put_get_data, transfer);
- transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
- transfer_response, transfer, err);
- if (transfer->req_id == 0) {
- transfer_free(transfer);
- return 0;
- }
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- return transfer->id;
- }
- guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
- GObexFunc complete_func, gpointer user_data,
- GError **err, guint first_hdr_id, ...)
- {
- GObexPacket *req;
- va_list args;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
- va_start(args, first_hdr_id);
- req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
- first_hdr_id, args);
- va_end(args);
- return g_obex_put_req_pkt(obex, req, data_func, complete_func,
- user_data, err);
- }
- static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
- {
- struct transfer *transfer = user_data;
- GObexPacket *rsp;
- GError *err;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
- "Request was aborted");
- rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
- g_obex_send(obex, rsp, NULL);
- transfer_complete(transfer, err);
- g_error_free(err);
- }
- static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
- {
- GObexHeader *body;
- gboolean final;
- guint8 rsp;
- const guint8 *buf;
- gsize len;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- g_obex_packet_get_operation(req, &final);
- if (final)
- rsp = G_OBEX_RSP_SUCCESS;
- else
- rsp = G_OBEX_RSP_CONTINUE;
- body = g_obex_packet_get_body(req);
- if (body == NULL)
- return rsp;
- g_obex_header_get_bytes(body, &buf, &len);
- if (len == 0)
- return rsp;
- if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
- rsp = G_OBEX_RSP_FORBIDDEN;
- return rsp;
- }
- static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
- guint8 first_hdr_id, va_list args)
- {
- GError *err = NULL;
- GObexPacket *rsp;
- guint8 rspcode;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- rspcode = put_get_bytes(transfer, req);
- rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
- if (!g_obex_send(transfer->obex, rsp, &err)) {
- transfer_complete(transfer, err);
- g_error_free(err);
- return;
- }
- if (rspcode != G_OBEX_RSP_CONTINUE)
- transfer_complete(transfer, NULL);
- }
- static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
- {
- struct transfer *transfer = user_data;
- GError *err = NULL;
- GObexPacket *rsp;
- guint8 rspcode;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- rspcode = put_get_bytes(transfer, req);
- /* Don't send continue while SRM is active */
- if (g_obex_srm_active(transfer->obex) &&
- rspcode == G_OBEX_RSP_CONTINUE)
- goto done;
- rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
- if (!g_obex_send(obex, rsp, &err)) {
- transfer_complete(transfer, err);
- g_error_free(err);
- return;
- }
- done:
- if (rspcode != G_OBEX_RSP_CONTINUE)
- transfer_complete(transfer, NULL);
- }
- guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
- GObexDataConsumer data_func, GObexFunc complete_func,
- gpointer user_data, GError **err,
- guint first_hdr_id, ...)
- {
- struct transfer *transfer;
- va_list args;
- guint id;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
- transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
- transfer->data_consumer = data_func;
- va_start(args, first_hdr_id);
- transfer_put_req_first(transfer, req, first_hdr_id, args);
- va_end(args);
- if (!g_slist_find(transfers, transfer))
- return 0;
- id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
- transfer);
- transfer->put_id = id;
- id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
- transfer_abort_req, transfer);
- transfer->abort_id = id;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- return transfer->id;
- }
- guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
- GObexDataConsumer data_func, GObexFunc complete_func,
- gpointer user_data, GError **err)
- {
- struct transfer *transfer;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
- if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
- return 0;
- transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
- transfer->data_consumer = data_func;
- transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
- transfer_response, transfer, err);
- if (transfer->req_id == 0) {
- transfer_free(transfer);
- return 0;
- }
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- return transfer->id;
- }
- guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
- GObexFunc complete_func, gpointer user_data,
- GError **err, guint first_hdr_id, ...)
- {
- struct transfer *transfer;
- GObexPacket *req;
- va_list args;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
- transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
- transfer->data_consumer = data_func;
- va_start(args, first_hdr_id);
- req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
- first_hdr_id, args);
- va_end(args);
- transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
- transfer_response, transfer, err);
- if (transfer->req_id == 0) {
- transfer_free(transfer);
- return 0;
- }
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- return transfer->id;
- }
- static gssize get_get_data(void *buf, gsize len, gpointer user_data)
- {
- struct transfer *transfer = user_data;
- GObexPacket *req, *rsp;
- GError *err = NULL;
- gssize ret;
- guint8 op;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- ret = transfer->data_producer(buf, len, transfer->user_data);
- if (ret > 0) {
- if (!g_obex_srm_active(transfer->obex))
- return ret;
- /* Generate next response */
- rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
- G_OBEX_HDR_INVALID);
- g_obex_packet_add_body(rsp, get_get_data, transfer);
- if (!g_obex_send(transfer->obex, rsp, &err)) {
- transfer_complete(transfer, err);
- g_error_free(err);
- }
- return ret;
- }
- if (ret == -EAGAIN)
- return ret;
- if (ret == 0) {
- transfer_complete(transfer, NULL);
- return ret;
- }
- op = g_obex_errno_to_rsp(ret);
- req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
- g_obex_send(transfer->obex, req, NULL);
- err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
- "Data producer function failed");
- g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
- transfer_complete(transfer, err);
- g_error_free(err);
- return ret;
- }
- static gboolean transfer_get_req_first(struct transfer *transfer,
- GObexPacket *rsp)
- {
- GError *err = NULL;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- g_obex_packet_add_body(rsp, get_get_data, transfer);
- if (!g_obex_send(transfer->obex, rsp, &err)) {
- transfer_complete(transfer, err);
- g_error_free(err);
- return FALSE;
- }
- return TRUE;
- }
- static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
- {
- struct transfer *transfer = user_data;
- GError *err = NULL;
- GObexPacket *rsp;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
- g_obex_packet_add_body(rsp, get_get_data, transfer);
- if (!g_obex_send(obex, rsp, &err)) {
- transfer_complete(transfer, err);
- g_error_free(err);
- }
- }
- guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
- GObexDataProducer data_func, GObexFunc complete_func,
- gpointer user_data, GError **err)
- {
- struct transfer *transfer;
- guint id;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
- transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
- transfer->data_producer = data_func;
- if (!transfer_get_req_first(transfer, rsp))
- return 0;
- if (!g_slist_find(transfers, transfer))
- return 0;
- id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
- transfer);
- transfer->get_id = id;
- id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
- transfer_abort_req, transfer);
- transfer->abort_id = id;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
- return transfer->id;
- }
- guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
- GObexFunc complete_func, gpointer user_data,
- GError **err, guint first_hdr_id, ...)
- {
- GObexPacket *rsp;
- va_list args;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
- va_start(args, first_hdr_id);
- rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
- first_hdr_id, args);
- va_end(args);
- return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
- user_data, err);
- }
- gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
- gpointer user_data)
- {
- struct transfer *transfer = NULL;
- gboolean ret = TRUE;
- g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
- transfer = find_transfer(id);
- if (transfer == NULL)
- return FALSE;
- if (complete_func == NULL)
- goto done;
- transfer->complete_func = complete_func;
- transfer->user_data = user_data;
- if (!transfer->req_id) {
- transfer->req_id = g_obex_abort(transfer->obex,
- transfer_abort_response,
- transfer, NULL);
- if (transfer->req_id)
- return TRUE;
- }
- ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
- if (ret)
- return TRUE;
- done:
- transfer_free(transfer);
- return ret;
- }
|