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);
103 transfer->complete_func(transfer->obex, err, transfer->user_data);
104 /* Check if the complete_func removed the transfer */
105 if (find_transfer(id) == NULL)
108 transfer_free(transfer);
111 static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
114 struct transfer *transfer = user_data;
116 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
118 transfer->req_id = 0;
120 /* Intentionally override error */
121 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
122 "Operation was aborted");
123 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
124 transfer_complete(transfer, err);
129 static gssize put_get_data(void *buf, gsize len, gpointer user_data)
131 struct transfer *transfer = user_data;
136 ret = transfer->data_producer(buf, len, transfer->user_data);
137 if (ret == 0 || ret == -EAGAIN)
141 /* Check if SRM is active */
142 if (!g_obex_srm_active(transfer->obex))
145 /* Generate next packet */
146 req = g_obex_packet_new(transfer->opcode, FALSE,
148 g_obex_packet_add_body(req, put_get_data, transfer);
149 transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
150 transfer_response, transfer,
155 transfer->req_id = g_obex_abort(transfer->obex, transfer_abort_response,
159 transfer_complete(transfer, err);
166 static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
169 GObexHeader *body = g_obex_packet_get_body(rsp);
177 g_obex_header_get_bytes(body, &buf, &len);
181 ret = transfer->data_consumer(buf, len, transfer->user_data);
183 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
184 "Data consumer callback failed");
189 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
192 struct transfer *transfer = user_data;
194 gboolean rspcode, final;
197 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
199 id = transfer->req_id;
200 transfer->req_id = 0;
203 transfer_complete(transfer, err);
207 rspcode = g_obex_packet_get_operation(rsp, &final);
208 if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
209 err = g_error_new(G_OBEX_ERROR, rspcode, "%s",
210 g_obex_strerror(rspcode));
214 if (transfer->opcode == G_OBEX_OP_GET) {
215 handle_get_body(transfer, rsp, &err);
220 if (rspcode == G_OBEX_RSP_SUCCESS) {
221 transfer_complete(transfer, NULL);
225 if (transfer->opcode == G_OBEX_OP_PUT) {
226 req = g_obex_packet_new(transfer->opcode, FALSE,
228 g_obex_packet_add_body(req, put_get_data, transfer);
229 } else if (!g_obex_srm_active(transfer->obex)) {
230 req = g_obex_packet_new(transfer->opcode, TRUE,
233 /* Keep id since request still outstanting */
234 transfer->req_id = id;
238 transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response,
242 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
243 transfer_complete(transfer, err);
248 static struct transfer *transfer_new(GObex *obex, guint8 opcode,
249 GObexFunc complete_func, gpointer user_data)
251 static guint next_id = 1;
252 struct transfer *transfer;
254 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
256 transfer = g_new0(struct transfer, 1);
258 transfer->id = next_id++;
259 transfer->opcode = opcode;
260 transfer->obex = g_obex_ref(obex);
261 transfer->complete_func = complete_func;
262 transfer->user_data = user_data;
264 transfers = g_slist_append(transfers, transfer);
269 guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
270 GObexDataProducer data_func, GObexFunc complete_func,
271 gpointer user_data, GError **err)
273 struct transfer *transfer;
275 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
277 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
280 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
281 transfer->data_producer = data_func;
283 g_obex_packet_add_body(req, put_get_data, transfer);
285 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
286 transfer_response, transfer, err);
287 if (transfer->req_id == 0) {
288 transfer_free(transfer);
292 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
297 guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
298 GObexFunc complete_func, gpointer user_data,
299 GError **err, guint8 first_hdr_id, ...)
304 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
306 va_start(args, first_hdr_id);
307 req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
311 return g_obex_put_req_pkt(obex, req, data_func, complete_func,
315 static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
317 struct transfer *transfer = user_data;
321 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
323 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
324 "Request was aborted");
325 rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
326 g_obex_send(obex, rsp, NULL);
328 transfer_complete(transfer, err);
332 static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
340 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
342 g_obex_packet_get_operation(req, &final);
344 rsp = G_OBEX_RSP_SUCCESS;
346 rsp = G_OBEX_RSP_CONTINUE;
348 body = g_obex_packet_get_body(req);
352 g_obex_header_get_bytes(body, &buf, &len);
356 if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
357 rsp = G_OBEX_RSP_FORBIDDEN;
362 static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
363 guint8 first_hdr_id, va_list args)
369 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
371 rspcode = put_get_bytes(transfer, req);
373 rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
375 if (!g_obex_send(transfer->obex, rsp, &err)) {
376 transfer_complete(transfer, err);
381 if (rspcode != G_OBEX_RSP_CONTINUE)
382 transfer_complete(transfer, NULL);
385 static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
387 struct transfer *transfer = user_data;
392 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
394 rspcode = put_get_bytes(transfer, req);
396 /* Don't send continue while SRM is active */
397 if (g_obex_srm_active(transfer->obex) &&
398 rspcode == G_OBEX_RSP_CONTINUE)
401 rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
403 if (!g_obex_send(obex, rsp, &err)) {
404 transfer_complete(transfer, err);
410 if (rspcode != G_OBEX_RSP_CONTINUE)
411 transfer_complete(transfer, NULL);
414 guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
415 GObexDataConsumer data_func, GObexFunc complete_func,
416 gpointer user_data, GError **err,
417 guint8 first_hdr_id, ...)
419 struct transfer *transfer;
423 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
425 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
426 transfer->data_consumer = data_func;
428 va_start(args, first_hdr_id);
429 transfer_put_req_first(transfer, req, first_hdr_id, args);
431 if (!g_slist_find(transfers, transfer))
434 id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
436 transfer->put_id = id;
438 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
439 transfer_abort_req, transfer);
440 transfer->abort_id = id;
442 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
447 guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
448 GObexDataConsumer data_func, GObexFunc complete_func,
449 gpointer user_data, GError **err)
451 struct transfer *transfer;
453 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
455 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
458 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
459 transfer->data_consumer = data_func;
460 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
461 transfer_response, transfer, err);
462 if (transfer->req_id == 0) {
463 transfer_free(transfer);
467 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
472 guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
473 GObexFunc complete_func, gpointer user_data,
474 GError **err, guint8 first_hdr_id, ...)
476 struct transfer *transfer;
480 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
482 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
483 transfer->data_consumer = data_func;
485 va_start(args, first_hdr_id);
486 req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
490 transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
491 transfer_response, transfer, err);
492 if (transfer->req_id == 0) {
493 transfer_free(transfer);
497 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
502 static gssize get_get_data(void *buf, gsize len, gpointer user_data)
504 struct transfer *transfer = user_data;
505 GObexPacket *req, *rsp;
510 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
512 ret = transfer->data_producer(buf, len, transfer->user_data);
514 if (!g_obex_srm_active(transfer->obex))
517 /* Generate next response */
518 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
520 g_obex_packet_add_body(rsp, get_get_data, transfer);
522 if (!g_obex_send(transfer->obex, rsp, &err)) {
523 transfer_complete(transfer, err);
534 transfer_complete(transfer, NULL);
538 op = g_obex_errno_to_rsp(ret);
540 req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
541 g_obex_send(transfer->obex, req, NULL);
543 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
544 "Data producer function failed");
545 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
546 transfer_complete(transfer, err);
552 static gboolean transfer_get_req_first(struct transfer *transfer,
557 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
559 g_obex_packet_add_body(rsp, get_get_data, transfer);
561 if (!g_obex_send(transfer->obex, rsp, &err)) {
562 transfer_complete(transfer, err);
570 static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
572 struct transfer *transfer = user_data;
576 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
578 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
579 g_obex_packet_add_body(rsp, get_get_data, transfer);
581 if (!g_obex_send(obex, rsp, &err)) {
582 transfer_complete(transfer, err);
587 guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
588 GObexDataProducer data_func, GObexFunc complete_func,
589 gpointer user_data, GError **err)
591 struct transfer *transfer;
594 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
596 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
597 transfer->data_producer = data_func;
599 if (!transfer_get_req_first(transfer, rsp))
602 if (!g_slist_find(transfers, transfer))
605 id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
607 transfer->get_id = id;
609 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
610 transfer_abort_req, transfer);
611 transfer->abort_id = id;
613 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
618 guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
619 GObexFunc complete_func, gpointer user_data,
620 GError **err, guint8 first_hdr_id, ...)
625 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
627 va_start(args, first_hdr_id);
628 rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
632 return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
636 gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
639 struct transfer *transfer = NULL;
642 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
644 transfer = find_transfer(id);
646 if (transfer == NULL)
649 if (complete_func == NULL)
652 transfer->complete_func = complete_func;
653 transfer->user_data = user_data;
655 if (!transfer->req_id) {
656 transfer->req_id = g_obex_abort(transfer->obex,
657 transfer_abort_response,
659 if (transfer->req_id)
663 ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
668 transfer_free(transfer);