1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * OBEX library with GLib integration
6 * Copyright (C) 2011 Intel Corporation. All rights reserved.
17 #include "gobex/gobex.h"
18 #include "gobex/gobex-debug.h"
20 #define FIRST_PACKET_TIMEOUT 60
22 static GSList *transfers = NULL;
24 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
39 GObexDataProducer data_producer;
40 GObexDataConsumer data_consumer;
41 GObexFunc complete_func;
46 static void transfer_free(struct transfer *transfer)
48 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
50 transfers = g_slist_remove(transfers, transfer);
52 if (transfer->req_id > 0)
53 g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE);
55 if (transfer->put_id > 0)
56 g_obex_remove_request_function(transfer->obex,
59 if (transfer->get_id > 0)
60 g_obex_remove_request_function(transfer->obex,
63 if (transfer->abort_id > 0)
64 g_obex_remove_request_function(transfer->obex,
67 g_obex_unref(transfer->obex);
71 static struct transfer *find_transfer(guint id)
75 for (l = transfers; l != NULL; l = g_slist_next(l)) {
76 struct transfer *t = l->data;
84 static void transfer_complete(struct transfer *transfer, GError *err)
86 guint id = transfer->id;
88 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
91 /* No further tx must be performed */
92 g_obex_drop_tx_queue(transfer->obex);
95 transfer->complete_func(transfer->obex, err, transfer->user_data);
96 /* Check if the complete_func removed the transfer */
97 if (find_transfer(id) == NULL)
100 transfer_free(transfer);
103 static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
106 struct transfer *transfer = user_data;
108 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
110 transfer->req_id = 0;
112 /* Intentionally override error */
113 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
114 "Operation was aborted");
115 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
116 transfer_complete(transfer, err);
121 static gssize put_get_data(void *buf, gsize len, gpointer user_data)
123 struct transfer *transfer = user_data;
128 ret = transfer->data_producer(buf, len, transfer->user_data);
129 if (ret == 0 || ret == -EAGAIN)
133 /* Check if SRM is active */
134 if (!g_obex_srm_active(transfer->obex))
137 /* Generate next packet */
138 req = g_obex_packet_new(transfer->opcode, FALSE,
140 g_obex_packet_add_body(req, put_get_data, transfer);
141 transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
142 transfer_response, transfer,
147 transfer->req_id = g_obex_abort(transfer->obex, transfer_abort_response,
151 transfer_complete(transfer, err);
158 static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
161 GObexHeader *body = g_obex_packet_get_body(rsp);
169 g_obex_header_get_bytes(body, &buf, &len);
173 ret = transfer->data_consumer(buf, len, transfer->user_data);
175 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
176 "Data consumer callback failed");
181 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
184 struct transfer *transfer = user_data;
186 gboolean rspcode, final;
189 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
191 id = transfer->req_id;
192 transfer->req_id = 0;
195 transfer_complete(transfer, err);
199 rspcode = g_obex_packet_get_operation(rsp, &final);
200 if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
201 err = g_error_new(G_OBEX_ERROR, rspcode, "%s",
202 g_obex_strerror(rspcode));
206 if (transfer->opcode == G_OBEX_OP_GET) {
207 handle_get_body(transfer, rsp, &err);
212 if (rspcode == G_OBEX_RSP_SUCCESS) {
213 transfer_complete(transfer, NULL);
217 if (transfer->opcode == G_OBEX_OP_PUT) {
218 req = g_obex_packet_new(transfer->opcode, FALSE,
220 g_obex_packet_add_body(req, put_get_data, transfer);
221 } else if (!g_obex_srm_active(transfer->obex)) {
222 req = g_obex_packet_new(transfer->opcode, TRUE,
225 /* Keep id since request still outstanting */
226 transfer->req_id = id;
230 transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response,
234 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
235 transfer_complete(transfer, err);
240 static struct transfer *transfer_new(GObex *obex, guint8 opcode,
241 GObexFunc complete_func, gpointer user_data)
243 static guint next_id = 1;
244 struct transfer *transfer;
246 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
248 transfer = g_new0(struct transfer, 1);
250 transfer->id = next_id++;
251 transfer->opcode = opcode;
252 transfer->obex = g_obex_ref(obex);
253 transfer->complete_func = complete_func;
254 transfer->user_data = user_data;
256 transfers = g_slist_append(transfers, transfer);
261 guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
262 GObexDataProducer data_func, GObexFunc complete_func,
263 gpointer user_data, GError **err)
265 struct transfer *transfer;
267 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
269 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
272 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
273 transfer->data_producer = data_func;
275 g_obex_packet_add_body(req, put_get_data, transfer);
277 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
278 transfer_response, transfer, err);
279 if (transfer->req_id == 0) {
280 transfer_free(transfer);
284 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
289 guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
290 GObexFunc complete_func, gpointer user_data,
291 GError **err, guint first_hdr_id, ...)
296 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
298 va_start(args, first_hdr_id);
299 req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
303 return g_obex_put_req_pkt(obex, req, data_func, complete_func,
307 static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
309 struct transfer *transfer = user_data;
313 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
315 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
316 "Request was aborted");
317 rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
318 g_obex_send(obex, rsp, NULL);
320 transfer_complete(transfer, err);
324 static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
332 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
334 g_obex_packet_get_operation(req, &final);
336 rsp = G_OBEX_RSP_SUCCESS;
338 rsp = G_OBEX_RSP_CONTINUE;
340 body = g_obex_packet_get_body(req);
344 g_obex_header_get_bytes(body, &buf, &len);
348 if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
349 rsp = G_OBEX_RSP_FORBIDDEN;
354 static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
355 guint8 first_hdr_id, va_list args)
361 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
363 rspcode = put_get_bytes(transfer, req);
365 rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
367 if (!g_obex_send(transfer->obex, rsp, &err)) {
368 transfer_complete(transfer, err);
373 if (rspcode != G_OBEX_RSP_CONTINUE)
374 transfer_complete(transfer, NULL);
377 static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
379 struct transfer *transfer = user_data;
384 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
386 rspcode = put_get_bytes(transfer, req);
388 /* Don't send continue while SRM is active */
389 if (g_obex_srm_active(transfer->obex) &&
390 rspcode == G_OBEX_RSP_CONTINUE)
393 rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
395 if (!g_obex_send(obex, rsp, &err)) {
396 transfer_complete(transfer, err);
402 if (rspcode != G_OBEX_RSP_CONTINUE)
403 transfer_complete(transfer, NULL);
406 guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
407 GObexDataConsumer data_func, GObexFunc complete_func,
408 gpointer user_data, GError **err,
409 guint first_hdr_id, ...)
411 struct transfer *transfer;
415 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
417 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
418 transfer->data_consumer = data_func;
420 va_start(args, first_hdr_id);
421 transfer_put_req_first(transfer, req, first_hdr_id, args);
423 if (!g_slist_find(transfers, transfer))
426 id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
428 transfer->put_id = id;
430 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
431 transfer_abort_req, transfer);
432 transfer->abort_id = id;
434 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
439 guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
440 GObexDataConsumer data_func, GObexFunc complete_func,
441 gpointer user_data, GError **err)
443 struct transfer *transfer;
445 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
447 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
450 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
451 transfer->data_consumer = data_func;
452 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
453 transfer_response, transfer, err);
454 if (transfer->req_id == 0) {
455 transfer_free(transfer);
459 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
464 guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
465 GObexFunc complete_func, gpointer user_data,
466 GError **err, guint first_hdr_id, ...)
468 struct transfer *transfer;
472 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
474 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
475 transfer->data_consumer = data_func;
477 va_start(args, first_hdr_id);
478 req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
482 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
483 transfer_response, transfer, err);
484 if (transfer->req_id == 0) {
485 transfer_free(transfer);
489 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
494 static gssize get_get_data(void *buf, gsize len, gpointer user_data)
496 struct transfer *transfer = user_data;
497 GObexPacket *req, *rsp;
502 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
504 ret = transfer->data_producer(buf, len, transfer->user_data);
506 if (!g_obex_srm_active(transfer->obex))
509 /* Generate next response */
510 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
512 g_obex_packet_add_body(rsp, get_get_data, transfer);
514 if (!g_obex_send(transfer->obex, rsp, &err)) {
515 transfer_complete(transfer, err);
526 transfer_complete(transfer, NULL);
530 op = g_obex_errno_to_rsp(ret);
532 req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
533 g_obex_send(transfer->obex, req, NULL);
535 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
536 "Data producer function failed");
537 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
538 transfer_complete(transfer, err);
544 static gboolean transfer_get_req_first(struct transfer *transfer,
549 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
551 g_obex_packet_add_body(rsp, get_get_data, transfer);
553 if (!g_obex_send(transfer->obex, rsp, &err)) {
554 transfer_complete(transfer, err);
562 static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
564 struct transfer *transfer = user_data;
568 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
570 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
571 g_obex_packet_add_body(rsp, get_get_data, transfer);
573 if (!g_obex_send(obex, rsp, &err)) {
574 transfer_complete(transfer, err);
579 guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
580 GObexDataProducer data_func, GObexFunc complete_func,
581 gpointer user_data, GError **err)
583 struct transfer *transfer;
586 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
588 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
589 transfer->data_producer = data_func;
591 if (!transfer_get_req_first(transfer, rsp))
594 if (!g_slist_find(transfers, transfer))
597 id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
599 transfer->get_id = id;
601 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
602 transfer_abort_req, transfer);
603 transfer->abort_id = id;
605 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
610 guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
611 GObexFunc complete_func, gpointer user_data,
612 GError **err, guint first_hdr_id, ...)
617 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
619 va_start(args, first_hdr_id);
620 rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
624 return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
628 gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
631 struct transfer *transfer = NULL;
634 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
636 transfer = find_transfer(id);
638 if (transfer == NULL)
641 if (complete_func == NULL)
644 transfer->complete_func = complete_func;
645 transfer->user_data = user_data;
647 if (!transfer->req_id) {
648 transfer->req_id = g_obex_abort(transfer->obex,
649 transfer_abort_response,
651 if (transfer->req_id)
655 ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
660 transfer_free(transfer);