3 * OBEX library with GLib integration
5 * Copyright (C) 2011 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "gobex/gobex.h"
31 #include "gobex/gobex-debug.h"
33 #define FIRST_PACKET_TIMEOUT 60
35 static GSList *transfers = NULL;
37 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
52 GObexDataProducer data_producer;
53 GObexDataConsumer data_consumer;
54 GObexFunc complete_func;
59 static void transfer_free(struct transfer *transfer)
61 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
63 transfers = g_slist_remove(transfers, transfer);
65 if (transfer->req_id > 0)
66 g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE);
68 if (transfer->put_id > 0)
69 g_obex_remove_request_function(transfer->obex,
72 if (transfer->get_id > 0)
73 g_obex_remove_request_function(transfer->obex,
76 if (transfer->abort_id > 0)
77 g_obex_remove_request_function(transfer->obex,
80 g_obex_unref(transfer->obex);
84 static struct transfer *find_transfer(guint id)
88 for (l = transfers; l != NULL; l = g_slist_next(l)) {
89 struct transfer *t = l->data;
97 static void transfer_complete(struct transfer *transfer, GError *err)
99 guint id = transfer->id;
101 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
104 /* No further tx must be performed */
105 g_obex_drop_tx_queue(transfer->obex);
108 transfer->complete_func(transfer->obex, err, transfer->user_data);
109 /* Check if the complete_func removed the transfer */
110 if (find_transfer(id) == NULL)
113 transfer_free(transfer);
116 static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
119 struct transfer *transfer = user_data;
121 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
123 transfer->req_id = 0;
125 /* Intentionally override error */
126 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
127 "Operation was aborted");
128 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
129 transfer_complete(transfer, err);
134 static gssize put_get_data(void *buf, gsize len, gpointer user_data)
136 struct transfer *transfer = user_data;
141 ret = transfer->data_producer(buf, len, transfer->user_data);
142 if (ret == 0 || ret == -EAGAIN)
146 /* Check if SRM is active */
147 if (!g_obex_srm_active(transfer->obex))
150 /* Generate next packet */
151 req = g_obex_packet_new(transfer->opcode, FALSE,
153 g_obex_packet_add_body(req, put_get_data, transfer);
154 transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
155 transfer_response, transfer,
160 transfer->req_id = g_obex_abort(transfer->obex, transfer_abort_response,
164 transfer_complete(transfer, err);
171 static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
174 GObexHeader *body = g_obex_packet_get_body(rsp);
182 g_obex_header_get_bytes(body, &buf, &len);
186 ret = transfer->data_consumer(buf, len, transfer->user_data);
188 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
189 "Data consumer callback failed");
194 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
197 struct transfer *transfer = user_data;
199 gboolean rspcode, final;
202 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
204 id = transfer->req_id;
205 transfer->req_id = 0;
208 transfer_complete(transfer, err);
212 rspcode = g_obex_packet_get_operation(rsp, &final);
213 if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
214 err = g_error_new(G_OBEX_ERROR, rspcode, "%s",
215 g_obex_strerror(rspcode));
219 if (transfer->opcode == G_OBEX_OP_GET) {
220 handle_get_body(transfer, rsp, &err);
225 if (rspcode == G_OBEX_RSP_SUCCESS) {
226 transfer_complete(transfer, NULL);
230 if (transfer->opcode == G_OBEX_OP_PUT) {
231 req = g_obex_packet_new(transfer->opcode, FALSE,
233 g_obex_packet_add_body(req, put_get_data, transfer);
234 } else if (!g_obex_srm_active(transfer->obex)) {
235 req = g_obex_packet_new(transfer->opcode, TRUE,
238 /* Keep id since request still outstanting */
239 transfer->req_id = id;
243 transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response,
247 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
248 transfer_complete(transfer, err);
253 static struct transfer *transfer_new(GObex *obex, guint8 opcode,
254 GObexFunc complete_func, gpointer user_data)
256 static guint next_id = 1;
257 struct transfer *transfer;
259 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
261 transfer = g_new0(struct transfer, 1);
263 transfer->id = next_id++;
264 transfer->opcode = opcode;
265 transfer->obex = g_obex_ref(obex);
266 transfer->complete_func = complete_func;
267 transfer->user_data = user_data;
269 transfers = g_slist_append(transfers, transfer);
274 guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
275 GObexDataProducer data_func, GObexFunc complete_func,
276 gpointer user_data, GError **err)
278 struct transfer *transfer;
280 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
282 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
285 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
286 transfer->data_producer = data_func;
288 g_obex_packet_add_body(req, put_get_data, transfer);
290 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
291 transfer_response, transfer, err);
292 if (transfer->req_id == 0) {
293 transfer_free(transfer);
297 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
302 guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
303 GObexFunc complete_func, gpointer user_data,
304 GError **err, guint first_hdr_id, ...)
309 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
311 va_start(args, first_hdr_id);
312 req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
316 return g_obex_put_req_pkt(obex, req, data_func, complete_func,
320 static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
322 struct transfer *transfer = user_data;
326 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
328 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
329 "Request was aborted");
330 rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
331 g_obex_send(obex, rsp, NULL);
333 transfer_complete(transfer, err);
337 static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
345 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
347 g_obex_packet_get_operation(req, &final);
349 rsp = G_OBEX_RSP_SUCCESS;
351 rsp = G_OBEX_RSP_CONTINUE;
353 body = g_obex_packet_get_body(req);
357 g_obex_header_get_bytes(body, &buf, &len);
361 if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
362 rsp = G_OBEX_RSP_FORBIDDEN;
367 static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
368 guint8 first_hdr_id, va_list args)
374 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
376 rspcode = put_get_bytes(transfer, req);
378 rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
380 if (!g_obex_send(transfer->obex, rsp, &err)) {
381 transfer_complete(transfer, err);
386 if (rspcode != G_OBEX_RSP_CONTINUE)
387 transfer_complete(transfer, NULL);
390 static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
392 struct transfer *transfer = user_data;
397 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
399 rspcode = put_get_bytes(transfer, req);
401 /* Don't send continue while SRM is active */
402 if (g_obex_srm_active(transfer->obex) &&
403 rspcode == G_OBEX_RSP_CONTINUE)
406 rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
408 if (!g_obex_send(obex, rsp, &err)) {
409 transfer_complete(transfer, err);
415 if (rspcode != G_OBEX_RSP_CONTINUE)
416 transfer_complete(transfer, NULL);
419 guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
420 GObexDataConsumer data_func, GObexFunc complete_func,
421 gpointer user_data, GError **err,
422 guint first_hdr_id, ...)
424 struct transfer *transfer;
428 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
430 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
431 transfer->data_consumer = data_func;
433 va_start(args, first_hdr_id);
434 transfer_put_req_first(transfer, req, first_hdr_id, args);
436 if (!g_slist_find(transfers, transfer))
439 id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
441 transfer->put_id = id;
443 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
444 transfer_abort_req, transfer);
445 transfer->abort_id = id;
447 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
452 guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
453 GObexDataConsumer data_func, GObexFunc complete_func,
454 gpointer user_data, GError **err)
456 struct transfer *transfer;
458 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
460 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
463 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
464 transfer->data_consumer = data_func;
465 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
466 transfer_response, transfer, err);
467 if (transfer->req_id == 0) {
468 transfer_free(transfer);
472 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
477 guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
478 GObexFunc complete_func, gpointer user_data,
479 GError **err, guint first_hdr_id, ...)
481 struct transfer *transfer;
485 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
487 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
488 transfer->data_consumer = data_func;
490 va_start(args, first_hdr_id);
491 req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
495 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
496 transfer_response, transfer, err);
497 if (transfer->req_id == 0) {
498 transfer_free(transfer);
502 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
507 static gssize get_get_data(void *buf, gsize len, gpointer user_data)
509 struct transfer *transfer = user_data;
510 GObexPacket *req, *rsp;
515 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
517 ret = transfer->data_producer(buf, len, transfer->user_data);
519 if (!g_obex_srm_active(transfer->obex))
522 /* Generate next response */
523 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
525 g_obex_packet_add_body(rsp, get_get_data, transfer);
527 if (!g_obex_send(transfer->obex, rsp, &err)) {
528 transfer_complete(transfer, err);
539 transfer_complete(transfer, NULL);
543 op = g_obex_errno_to_rsp(ret);
545 req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
546 g_obex_send(transfer->obex, req, NULL);
548 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
549 "Data producer function failed");
550 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
551 transfer_complete(transfer, err);
557 static gboolean transfer_get_req_first(struct transfer *transfer,
562 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
564 g_obex_packet_add_body(rsp, get_get_data, transfer);
566 if (!g_obex_send(transfer->obex, rsp, &err)) {
567 transfer_complete(transfer, err);
575 static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
577 struct transfer *transfer = user_data;
581 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
583 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
584 g_obex_packet_add_body(rsp, get_get_data, transfer);
586 if (!g_obex_send(obex, rsp, &err)) {
587 transfer_complete(transfer, err);
592 guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
593 GObexDataProducer data_func, GObexFunc complete_func,
594 gpointer user_data, GError **err)
596 struct transfer *transfer;
599 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
601 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
602 transfer->data_producer = data_func;
604 if (!transfer_get_req_first(transfer, rsp))
607 if (!g_slist_find(transfers, transfer))
610 id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
612 transfer->get_id = id;
614 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
615 transfer_abort_req, transfer);
616 transfer->abort_id = id;
618 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
623 guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
624 GObexFunc complete_func, gpointer user_data,
625 GError **err, guint first_hdr_id, ...)
630 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
632 va_start(args, first_hdr_id);
633 rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
637 return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
641 gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
644 struct transfer *transfer = NULL;
647 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
649 transfer = find_transfer(id);
651 if (transfer == NULL)
654 if (complete_func == NULL)
657 transfer->complete_func = complete_func;
658 transfer->user_data = user_data;
660 if (!transfer->req_id) {
661 transfer->req_id = g_obex_abort(transfer->obex,
662 transfer_abort_response,
664 if (transfer->req_id)
668 ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
673 transfer_free(transfer);